Show More
@@ -10,21 +10,7 b' import revlog' | |||
|
10 | 10 | class filelog(revlog.revlog): |
|
11 | 11 | def __init__(self, opener, path): |
|
12 | 12 | revlog.revlog.__init__(self, opener, |
|
13 |
"/".join(("data", |
|
|
14 | ||
|
15 | # This avoids a collision between a file named foo and a dir named | |
|
16 | # foo.i or foo.d | |
|
17 | def encodedir(self, path): | |
|
18 | return (path | |
|
19 | .replace(".hg/", ".hg.hg/") | |
|
20 | .replace(".i/", ".i.hg/") | |
|
21 | .replace(".d/", ".d.hg/")) | |
|
22 | ||
|
23 | def decodedir(self, path): | |
|
24 | return (path | |
|
25 | .replace(".d.hg/", ".d/") | |
|
26 | .replace(".i.hg/", ".i/") | |
|
27 | .replace(".hg.hg/", ".hg/")) | |
|
13 | "/".join(("data", path + ".i"))) | |
|
28 | 14 | |
|
29 | 15 | def read(self, node): |
|
30 | 16 | t = self.revision(node) |
@@ -2026,7 +2026,8 b' class localrepository(repo.repository):' | |||
|
2026 | 2026 | raise error.ResponseError( |
|
2027 | 2027 | _('Unexpected response from remote server:'), l) |
|
2028 | 2028 | self.ui.debug(_('adding %s (%s)\n') % (name, util.bytecount(size))) |
|
2029 | ofp = self.sopener(name, 'w') | |
|
2029 | # for backwards compat, name was partially encoded | |
|
2030 | ofp = self.sopener(store.decodedir(name), 'w') | |
|
2030 | 2031 | for chunk in util.filechunkiter(fp, limit=size): |
|
2031 | 2032 | ofp.write(chunk) |
|
2032 | 2033 | ofp.close() |
@@ -11,6 +11,24 b' import os, stat' | |||
|
11 | 11 | |
|
12 | 12 | _sha = util.sha1 |
|
13 | 13 | |
|
14 | # This avoids a collision between a file named foo and a dir named | |
|
15 | # foo.i or foo.d | |
|
16 | def encodedir(path): | |
|
17 | if not path.startswith('data/'): | |
|
18 | return path | |
|
19 | return (path | |
|
20 | .replace(".hg/", ".hg.hg/") | |
|
21 | .replace(".i/", ".i.hg/") | |
|
22 | .replace(".d/", ".d.hg/")) | |
|
23 | ||
|
24 | def decodedir(path): | |
|
25 | if not path.startswith('data/'): | |
|
26 | return path | |
|
27 | return (path | |
|
28 | .replace(".d.hg/", ".d/") | |
|
29 | .replace(".i.hg/", ".i/") | |
|
30 | .replace(".hg.hg/", ".hg/")) | |
|
31 | ||
|
14 | 32 | def _buildencodefun(): |
|
15 | 33 | e = '_' |
|
16 | 34 | win_reserved = [ord(x) for x in '\\:*?"<>|'] |
@@ -34,8 +52,8 b' def _buildencodefun():' | |||
|
34 | 52 | pass |
|
35 | 53 | else: |
|
36 | 54 | raise KeyError |
|
37 | return (lambda s: "".join([cmap[c] for c in s]), | |
|
38 | lambda s: "".join(list(decode(s)))) | |
|
55 | return (lambda s: "".join([cmap[c] for c in encodedir(s)]), | |
|
56 | lambda s: decodedir("".join(list(decode(s))))) | |
|
39 | 57 | |
|
40 | 58 | encodefilename, decodefilename = _buildencodefun() |
|
41 | 59 | |
@@ -104,6 +122,8 b' def hybridencode(path):' | |||
|
104 | 122 | ''' |
|
105 | 123 | if not path.startswith('data/'): |
|
106 | 124 | return path |
|
125 | # escape directories ending with .i and .d | |
|
126 | path = encodedir(path) | |
|
107 | 127 | ndpath = path[len('data/'):] |
|
108 | 128 | res = 'data/' + auxencode(encodefilename(ndpath)) |
|
109 | 129 | if len(res) > MAX_PATH_LEN_IN_HGSTORE: |
@@ -155,7 +175,7 b' class basicstore:' | |||
|
155 | 175 | self.opener.createmode = self.createmode |
|
156 | 176 | |
|
157 | 177 | def join(self, f): |
|
158 | return self.pathjoiner(self.path, f) | |
|
178 | return self.pathjoiner(self.path, encodedir(f)) | |
|
159 | 179 | |
|
160 | 180 | def _walk(self, relpath, recurse): |
|
161 | 181 | '''yields (unencoded, encoded, size)''' |
@@ -170,7 +190,7 b' class basicstore:' | |||
|
170 | 190 | fp = self.pathjoiner(p, f) |
|
171 | 191 | if kind == stat.S_IFREG and f[-2:] in ('.d', '.i'): |
|
172 | 192 | n = util.pconvert(fp[striplen:]) |
|
173 | l.append((n, n, st.st_size)) | |
|
193 | l.append((decodedir(n), n, st.st_size)) | |
|
174 | 194 | elif kind == stat.S_IFDIR and recurse: |
|
175 | 195 | visit.append(fp) |
|
176 | 196 | return sorted(l) |
@@ -215,6 +235,8 b' class encodedstore(basicstore):' | |||
|
215 | 235 | [self.pathjoiner('store', f) for f in _data.split()]) |
|
216 | 236 | |
|
217 | 237 | class fncache(object): |
|
238 | # the filename used to be partially encoded | |
|
239 | # hence the encodedir/decodedir dance | |
|
218 | 240 | def __init__(self, opener): |
|
219 | 241 | self.opener = opener |
|
220 | 242 | self.entries = None |
@@ -231,20 +253,20 b' class fncache(object):' | |||
|
231 | 253 | if (len(line) < 2) or (line[-1] != '\n'): |
|
232 | 254 | t = _('invalid entry in fncache, line %s') % (n + 1) |
|
233 | 255 | raise util.Abort(t) |
|
234 | self.entries.add(line[:-1]) | |
|
256 | self.entries.add(decodedir(line[:-1])) | |
|
235 | 257 | fp.close() |
|
236 | 258 | |
|
237 | 259 | def rewrite(self, files): |
|
238 | 260 | fp = self.opener('fncache', mode='wb') |
|
239 | 261 | for p in files: |
|
240 | fp.write(p + '\n') | |
|
262 | fp.write(encodedir(p) + '\n') | |
|
241 | 263 | fp.close() |
|
242 | 264 | self.entries = set(files) |
|
243 | 265 | |
|
244 | 266 | def add(self, fn): |
|
245 | 267 | if self.entries is None: |
|
246 | 268 | self._load() |
|
247 | self.opener('fncache', 'ab').write(fn + '\n') | |
|
269 | self.opener('fncache', 'ab').write(encodedir(fn) + '\n') | |
|
248 | 270 | |
|
249 | 271 | def __contains__(self, fn): |
|
250 | 272 | if self.entries is None: |
@@ -8,6 +8,8 b'' | |||
|
8 | 8 | import util, error |
|
9 | 9 | from i18n import _ |
|
10 | 10 | |
|
11 | from mercurial import store | |
|
12 | ||
|
11 | 13 | class StreamException(Exception): |
|
12 | 14 | def __init__(self, code): |
|
13 | 15 | Exception.__init__(self) |
@@ -46,7 +48,8 b' def stream_out(repo, untrusted=False):' | |||
|
46 | 48 | try: |
|
47 | 49 | repo.ui.debug(_('scanning\n')) |
|
48 | 50 | for name, ename, size in repo.store.walk(): |
|
49 | entries.append((name, size)) | |
|
51 | # for backwards compat, name was partially encoded | |
|
52 | entries.append((store.encodedir(name), size)) | |
|
50 | 53 | total_bytes += size |
|
51 | 54 | finally: |
|
52 | 55 | lock.release() |
@@ -36,8 +36,8 b' checking manifests' | |||
|
36 | 36 | crosschecking files in changesets and manifests |
|
37 | 37 | checking files |
|
38 | 38 | data/a.i@0: missing revlog! |
|
39 |
data/a.i.hg |
|
|
40 |
data/a.i |
|
|
39 | data/a.i.hg/c.i@2: missing revlog! | |
|
40 | data/a.i/b.i@1: missing revlog! | |
|
41 | 41 | 3 files, 3 changesets, 3 total revisions |
|
42 | 42 | 3 integrity errors encountered! |
|
43 | 43 | (first damaged changeset appears to be 0) |
General Comments 0
You need to be logged in to leave comments.
Login now