##// END OF EJS Templates
store: eliminate one level of lambda functions on _hybridencode
Adrian Buehlmann -
r17590:eb088468 default
parent child Browse files
Show More
@@ -1,449 +1,451 b''
1 1 # store.py - repository store handling for Mercurial
2 2 #
3 3 # Copyright 2008 Matt Mackall <mpm@selenic.com>
4 4 #
5 5 # This software may be used and distributed according to the terms of the
6 6 # GNU General Public License version 2 or any later version.
7 7
8 8 from i18n import _
9 9 import osutil, scmutil, util
10 10 import os, stat, errno
11 11
12 12 _sha = util.sha1
13 13
14 14 # This avoids a collision between a file named foo and a dir named
15 15 # foo.i or foo.d
16 16 def encodedir(path):
17 17 '''
18 18 >>> encodedir('data/foo.i')
19 19 'data/foo.i'
20 20 >>> encodedir('data/foo.i/bla.i')
21 21 'data/foo.i.hg/bla.i'
22 22 >>> encodedir('data/foo.i.hg/bla.i')
23 23 'data/foo.i.hg.hg/bla.i'
24 24 '''
25 25 return (path
26 26 .replace(".hg/", ".hg.hg/")
27 27 .replace(".i/", ".i.hg/")
28 28 .replace(".d/", ".d.hg/"))
29 29
30 30 def decodedir(path):
31 31 '''
32 32 >>> decodedir('data/foo.i')
33 33 'data/foo.i'
34 34 >>> decodedir('data/foo.i.hg/bla.i')
35 35 'data/foo.i/bla.i'
36 36 >>> decodedir('data/foo.i.hg.hg/bla.i')
37 37 'data/foo.i.hg/bla.i'
38 38 '''
39 39 if ".hg/" not in path:
40 40 return path
41 41 return (path
42 42 .replace(".d.hg/", ".d/")
43 43 .replace(".i.hg/", ".i/")
44 44 .replace(".hg.hg/", ".hg/"))
45 45
46 46 def _buildencodefun():
47 47 '''
48 48 >>> enc, dec = _buildencodefun()
49 49
50 50 >>> enc('nothing/special.txt')
51 51 'nothing/special.txt'
52 52 >>> dec('nothing/special.txt')
53 53 'nothing/special.txt'
54 54
55 55 >>> enc('HELLO')
56 56 '_h_e_l_l_o'
57 57 >>> dec('_h_e_l_l_o')
58 58 'HELLO'
59 59
60 60 >>> enc('hello:world?')
61 61 'hello~3aworld~3f'
62 62 >>> dec('hello~3aworld~3f')
63 63 'hello:world?'
64 64
65 65 >>> enc('the\x07quick\xADshot')
66 66 'the~07quick~adshot'
67 67 >>> dec('the~07quick~adshot')
68 68 'the\\x07quick\\xadshot'
69 69 '''
70 70 e = '_'
71 71 winreserved = [ord(x) for x in '\\:*?"<>|']
72 72 cmap = dict([(chr(x), chr(x)) for x in xrange(127)])
73 73 for x in (range(32) + range(126, 256) + winreserved):
74 74 cmap[chr(x)] = "~%02x" % x
75 75 for x in range(ord("A"), ord("Z")+1) + [ord(e)]:
76 76 cmap[chr(x)] = e + chr(x).lower()
77 77 dmap = {}
78 78 for k, v in cmap.iteritems():
79 79 dmap[v] = k
80 80 def decode(s):
81 81 i = 0
82 82 while i < len(s):
83 83 for l in xrange(1, 4):
84 84 try:
85 85 yield dmap[s[i:i + l]]
86 86 i += l
87 87 break
88 88 except KeyError:
89 89 pass
90 90 else:
91 91 raise KeyError
92 92 return (lambda s: "".join([cmap[c] for c in encodedir(s)]),
93 93 lambda s: decodedir("".join(list(decode(s)))))
94 94
95 95 encodefilename, decodefilename = _buildencodefun()
96 96
97 97 def _buildlowerencodefun():
98 98 '''
99 99 >>> f = _buildlowerencodefun()
100 100 >>> f('nothing/special.txt')
101 101 'nothing/special.txt'
102 102 >>> f('HELLO')
103 103 'hello'
104 104 >>> f('hello:world?')
105 105 'hello~3aworld~3f'
106 106 >>> f('the\x07quick\xADshot')
107 107 'the~07quick~adshot'
108 108 '''
109 109 winreserved = [ord(x) for x in '\\:*?"<>|']
110 110 cmap = dict([(chr(x), chr(x)) for x in xrange(127)])
111 111 for x in (range(32) + range(126, 256) + winreserved):
112 112 cmap[chr(x)] = "~%02x" % x
113 113 for x in range(ord("A"), ord("Z")+1):
114 114 cmap[chr(x)] = chr(x).lower()
115 115 return lambda s: "".join([cmap[c] for c in s])
116 116
117 117 lowerencode = _buildlowerencodefun()
118 118
119 119 # Windows reserved names: con, prn, aux, nul, com1..com9, lpt1..lpt9
120 120 _winres3 = ('aux', 'con', 'prn', 'nul') # length 3
121 121 _winres4 = ('com', 'lpt') # length 4 (with trailing 1..9)
122 122 def _auxencode(path, dotencode):
123 123 '''
124 124 Encodes filenames containing names reserved by Windows or which end in
125 125 period or space. Does not touch other single reserved characters c.
126 126 Specifically, c in '\\:*?"<>|' or ord(c) <= 31 are *not* encoded here.
127 127 Additionally encodes space or period at the beginning, if dotencode is
128 128 True. Parameter path is assumed to be all lowercase.
129 129 A segment only needs encoding if a reserved name appears as a
130 130 basename (e.g. "aux", "aux.foo"). A directory or file named "foo.aux"
131 131 doesn't need encoding.
132 132
133 133 >>> s = '.foo/aux.txt/txt.aux/con/prn/nul/foo.'
134 134 >>> _auxencode(s.split('/'), True)
135 135 ['~2efoo', 'au~78.txt', 'txt.aux', 'co~6e', 'pr~6e', 'nu~6c', 'foo~2e']
136 136 >>> s = '.com1com2/lpt9.lpt4.lpt1/conprn/com0/lpt0/foo.'
137 137 >>> _auxencode(s.split('/'), False)
138 138 ['.com1com2', 'lp~749.lpt4.lpt1', 'conprn', 'com0', 'lpt0', 'foo~2e']
139 139 >>> _auxencode(['foo. '], True)
140 140 ['foo.~20']
141 141 >>> _auxencode([' .foo'], True)
142 142 ['~20.foo']
143 143 '''
144 144 for i, n in enumerate(path):
145 145 if not n:
146 146 continue
147 147 if dotencode and n[0] in '. ':
148 148 n = "~%02x" % ord(n[0]) + n[1:]
149 149 path[i] = n
150 150 else:
151 151 l = n.find('.')
152 152 if l == -1:
153 153 l = len(n)
154 154 if ((l == 3 and n[:3] in _winres3) or
155 155 (l == 4 and n[3] <= '9' and n[3] >= '1'
156 156 and n[:3] in _winres4)):
157 157 # encode third letter ('aux' -> 'au~78')
158 158 ec = "~%02x" % ord(n[2])
159 159 n = n[0:2] + ec + n[3:]
160 160 path[i] = n
161 161 if n[-1] in '. ':
162 162 # encode last period or space ('foo...' -> 'foo..~2e')
163 163 path[i] = n[:-1] + "~%02x" % ord(n[-1])
164 164 return path
165 165
166 166 _maxstorepathlen = 120
167 167 _dirprefixlen = 8
168 168 _maxshortdirslen = 8 * (_dirprefixlen + 1) - 4
169 def _hybridencode(path, auxencode):
169 def _hybridencode(path, dotencode):
170 170 '''encodes path with a length limit
171 171
172 172 Encodes all paths that begin with 'data/', according to the following.
173 173
174 174 Default encoding (reversible):
175 175
176 176 Encodes all uppercase letters 'X' as '_x'. All reserved or illegal
177 177 characters are encoded as '~xx', where xx is the two digit hex code
178 178 of the character (see encodefilename).
179 179 Relevant path components consisting of Windows reserved filenames are
180 180 masked by encoding the third character ('aux' -> 'au~78', see auxencode).
181 181
182 182 Hashed encoding (not reversible):
183 183
184 184 If the default-encoded path is longer than _maxstorepathlen, a
185 185 non-reversible hybrid hashing of the path is done instead.
186 186 This encoding uses up to _dirprefixlen characters of all directory
187 187 levels of the lowerencoded path, but not more levels than can fit into
188 188 _maxshortdirslen.
189 189 Then follows the filler followed by the sha digest of the full path.
190 190 The filler is the beginning of the basename of the lowerencoded path
191 191 (the basename is everything after the last path separator). The filler
192 192 is as long as possible, filling in characters from the basename until
193 193 the encoded path has _maxstorepathlen characters (or all chars of the
194 194 basename have been taken).
195 195 The extension (e.g. '.i' or '.d') is preserved.
196 196
197 197 The string 'data/' at the beginning is replaced with 'dh/', if the hashed
198 198 encoding was used.
199 199 '''
200 res = '/'.join(auxencode(encodefilename(path).split('/')))
200 ef = encodefilename(path).split('/')
201 res = '/'.join(_auxencode(ef, dotencode))
201 202 if len(res) > _maxstorepathlen:
202 203 path = encodedir(path)
203 204 digest = _sha(path).hexdigest()
204 parts = auxencode(lowerencode(path).split('/')[1:])
205 le = lowerencode(path).split('/')[1:]
206 parts = _auxencode(le, dotencode)
205 207 basename = parts[-1]
206 208 _root, ext = os.path.splitext(basename)
207 209 sdirs = []
208 210 sdirslen = 0
209 211 for p in parts[:-1]:
210 212 d = p[:_dirprefixlen]
211 213 if d[-1] in '. ':
212 214 # Windows can't access dirs ending in period or space
213 215 d = d[:-1] + '_'
214 216 if sdirslen == 0:
215 217 t = len(d)
216 218 else:
217 219 t = sdirslen + 1 + len(d)
218 220 if t > _maxshortdirslen:
219 221 break
220 222 sdirs.append(d)
221 223 sdirslen = t
222 224 dirs = '/'.join(sdirs)
223 225 if len(dirs) > 0:
224 226 dirs += '/'
225 227 res = 'dh/' + dirs + digest + ext
226 228 spaceleft = _maxstorepathlen - len(res)
227 229 if spaceleft > 0:
228 230 filler = basename[:spaceleft]
229 231 res = 'dh/' + dirs + filler + digest + ext
230 232 return res
231 233
232 234 def _calcmode(path):
233 235 try:
234 236 # files in .hg/ will be created using this mode
235 237 mode = os.stat(path).st_mode
236 238 # avoid some useless chmods
237 239 if (0777 & ~util.umask) == (0777 & mode):
238 240 mode = None
239 241 except OSError:
240 242 mode = None
241 243 return mode
242 244
243 245 _data = ('data 00manifest.d 00manifest.i 00changelog.d 00changelog.i'
244 246 ' phaseroots obsstore')
245 247
246 248 class basicstore(object):
247 249 '''base class for local repository stores'''
248 250 def __init__(self, path, openertype):
249 251 self.path = path
250 252 self.createmode = _calcmode(path)
251 253 op = openertype(self.path)
252 254 op.createmode = self.createmode
253 255 self.opener = scmutil.filteropener(op, encodedir)
254 256
255 257 def join(self, f):
256 258 return self.path + '/' + encodedir(f)
257 259
258 260 def _walk(self, relpath, recurse):
259 261 '''yields (unencoded, encoded, size)'''
260 262 path = self.path
261 263 if relpath:
262 264 path += '/' + relpath
263 265 striplen = len(self.path) + 1
264 266 l = []
265 267 if os.path.isdir(path):
266 268 visit = [path]
267 269 while visit:
268 270 p = visit.pop()
269 271 for f, kind, st in osutil.listdir(p, stat=True):
270 272 fp = p + '/' + f
271 273 if kind == stat.S_IFREG and f[-2:] in ('.d', '.i'):
272 274 n = util.pconvert(fp[striplen:])
273 275 l.append((decodedir(n), n, st.st_size))
274 276 elif kind == stat.S_IFDIR and recurse:
275 277 visit.append(fp)
276 278 l.sort()
277 279 return l
278 280
279 281 def datafiles(self):
280 282 return self._walk('data', True)
281 283
282 284 def walk(self):
283 285 '''yields (unencoded, encoded, size)'''
284 286 # yield data files first
285 287 for x in self.datafiles():
286 288 yield x
287 289 # yield manifest before changelog
288 290 for x in reversed(self._walk('', False)):
289 291 yield x
290 292
291 293 def copylist(self):
292 294 return ['requires'] + _data.split()
293 295
294 296 def write(self):
295 297 pass
296 298
297 299 class encodedstore(basicstore):
298 300 def __init__(self, path, openertype):
299 301 self.path = path + '/store'
300 302 self.createmode = _calcmode(self.path)
301 303 op = openertype(self.path)
302 304 op.createmode = self.createmode
303 305 self.opener = scmutil.filteropener(op, encodefilename)
304 306
305 307 def datafiles(self):
306 308 for a, b, size in self._walk('data', True):
307 309 try:
308 310 a = decodefilename(a)
309 311 except KeyError:
310 312 a = None
311 313 yield a, b, size
312 314
313 315 def join(self, f):
314 316 return self.path + '/' + encodefilename(f)
315 317
316 318 def copylist(self):
317 319 return (['requires', '00changelog.i'] +
318 320 ['store/' + f for f in _data.split()])
319 321
320 322 class fncache(object):
321 323 # the filename used to be partially encoded
322 324 # hence the encodedir/decodedir dance
323 325 def __init__(self, opener):
324 326 self.opener = opener
325 327 self.entries = None
326 328 self._dirty = False
327 329
328 330 def _load(self):
329 331 '''fill the entries from the fncache file'''
330 332 self._dirty = False
331 333 try:
332 334 fp = self.opener('fncache', mode='rb')
333 335 except IOError:
334 336 # skip nonexistent file
335 337 self.entries = set()
336 338 return
337 339 self.entries = set(map(decodedir, fp.read().splitlines()))
338 340 if '' in self.entries:
339 341 fp.seek(0)
340 342 for n, line in enumerate(fp):
341 343 if not line.rstrip('\n'):
342 344 t = _('invalid entry in fncache, line %s') % (n + 1)
343 345 raise util.Abort(t)
344 346 fp.close()
345 347
346 348 def _write(self, files, atomictemp):
347 349 fp = self.opener('fncache', mode='wb', atomictemp=atomictemp)
348 350 if files:
349 351 fp.write('\n'.join(map(encodedir, files)) + '\n')
350 352 fp.close()
351 353 self._dirty = False
352 354
353 355 def rewrite(self, files):
354 356 self._write(files, False)
355 357 self.entries = set(files)
356 358
357 359 def write(self):
358 360 if self._dirty:
359 361 self._write(self.entries, True)
360 362
361 363 def add(self, fn):
362 364 if self.entries is None:
363 365 self._load()
364 366 if fn not in self.entries:
365 367 self._dirty = True
366 368 self.entries.add(fn)
367 369
368 370 def __contains__(self, fn):
369 371 if self.entries is None:
370 372 self._load()
371 373 return fn in self.entries
372 374
373 375 def __iter__(self):
374 376 if self.entries is None:
375 377 self._load()
376 378 return iter(self.entries)
377 379
378 380 class _fncacheopener(scmutil.abstractopener):
379 381 def __init__(self, op, fnc, encode):
380 382 self.opener = op
381 383 self.fncache = fnc
382 384 self.encode = encode
383 385
384 386 def _getmustaudit(self):
385 387 return self.opener.mustaudit
386 388
387 389 def _setmustaudit(self, onoff):
388 390 self.opener.mustaudit = onoff
389 391
390 392 mustaudit = property(_getmustaudit, _setmustaudit)
391 393
392 394 def __call__(self, path, mode='r', *args, **kw):
393 395 if mode not in ('r', 'rb') and path.startswith('data/'):
394 396 self.fncache.add(path)
395 397 return self.opener(self.encode(path), mode, *args, **kw)
396 398
397 399 class fncachestore(basicstore):
398 400 def __init__(self, path, openertype, encode):
399 401 self.encode = encode
400 402 self.path = path + '/store'
401 403 self.pathsep = self.path + '/'
402 404 self.createmode = _calcmode(self.path)
403 405 op = openertype(self.path)
404 406 op.createmode = self.createmode
405 407 fnc = fncache(op)
406 408 self.fncache = fnc
407 409 self.opener = _fncacheopener(op, fnc, encode)
408 410
409 411 def join(self, f):
410 412 return self.pathsep + self.encode(f)
411 413
412 414 def getsize(self, path):
413 415 return os.stat(self.pathsep + path).st_size
414 416
415 417 def datafiles(self):
416 418 rewrite = False
417 419 existing = []
418 420 for f in sorted(self.fncache):
419 421 ef = self.encode(f)
420 422 try:
421 423 yield f, ef, self.getsize(ef)
422 424 existing.append(f)
423 425 except OSError, err:
424 426 if err.errno != errno.ENOENT:
425 427 raise
426 428 # nonexistent entry
427 429 rewrite = True
428 430 if rewrite:
429 431 # rewrite fncache to remove nonexistent entries
430 432 # (may be caused by rollback / strip)
431 433 self.fncache.rewrite(existing)
432 434
433 435 def copylist(self):
434 436 d = ('data dh fncache phaseroots obsstore'
435 437 ' 00manifest.d 00manifest.i 00changelog.d 00changelog.i')
436 438 return (['requires', '00changelog.i'] +
437 439 ['store/' + f for f in d.split()])
438 440
439 441 def write(self):
440 442 self.fncache.write()
441 443
442 444 def store(requirements, path, openertype):
443 445 if 'store' in requirements:
444 446 if 'fncache' in requirements:
445 auxencode = lambda f: _auxencode(f, 'dotencode' in requirements)
446 encode = lambda f: _hybridencode(f, auxencode)
447 de = 'dotencode' in requirements
448 encode = lambda f: _hybridencode(f, de)
447 449 return fncachestore(path, openertype, encode)
448 450 return encodedstore(path, openertype)
449 451 return basicstore(path, openertype)
@@ -1,454 +1,453 b''
1 1 from mercurial import store
2 2
3 auxencode = lambda f: store._auxencode(f, True)
4 hybridencode = lambda f: store._hybridencode(f, auxencode)
3 hybridencode = lambda f: store._hybridencode(f, True)
5 4
6 5 enc = hybridencode # used for 'dotencode' repo format
7 6
8 7 def show(s):
9 8 print "A = '%s'" % s.encode("string_escape")
10 9 print "B = '%s'" % enc(s).encode("string_escape")
11 10 print
12 11
13 12 show("data/abcdefghijklmnopqrstuvwxyz0123456789 !#%&'()+,-.;=[]^`{}")
14 13
15 14 print "uppercase char X is encoded as _x"
16 15 show("data/ABCDEFGHIJKLMNOPQRSTUVWXYZ")
17 16
18 17 print "underbar is doubled"
19 18 show("data/_")
20 19
21 20 print "tilde is character-encoded"
22 21 show("data/~")
23 22
24 23 print "characters in ASCII code range 1..31"
25 24 show('data/\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f'
26 25 '\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f')
27 26
28 27 print "characters in ASCII code range 126..255"
29 28 show('data/\x7e\x7f'
30 29 '\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f'
31 30 '\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f')
32 31 show('data/\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf'
33 32 '\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf')
34 33 show('data/\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf'
35 34 '\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf')
36 35 show('data/\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef'
37 36 '\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff')
38 37
39 38 print "Windows reserved characters"
40 39 show('data/less <, greater >, colon :, double-quote ", backslash \\'
41 40 ', pipe |, question-mark ?, asterisk *')
42 41
43 42 print "encoding directories ending in .hg, .i or .d with '.hg' suffix"
44 43 show('data/x.hg/x.i/x.d/foo')
45 44 show('data/a.hg/a.i/a.d/foo')
46 45 show('data/au.hg/au.i/au.d/foo')
47 46 show('data/aux.hg/aux.i/aux.d/foo')
48 47 show('data/auxy.hg/auxy.i/auxy.d/foo')
49 48
50 49 print "but these are not encoded on *filenames*"
51 50 show('data/foo/x.hg')
52 51 show('data/foo/x.i')
53 52 show('data/foo/x.d')
54 53 show('data/foo/a.hg')
55 54 show('data/foo/a.i')
56 55 show('data/foo/a.d')
57 56 show('data/foo/au.hg')
58 57 show('data/foo/au.i')
59 58 show('data/foo/au.d')
60 59 show('data/foo/aux.hg')
61 60 show('data/foo/aux.i')
62 61 show('data/foo/aux.d')
63 62 show('data/foo/auxy.hg')
64 63 show('data/foo/auxy.i')
65 64 show('data/foo/auxy.d')
66 65
67 66 print "plain .hg, .i and .d directories have the leading dot encoded"
68 67 show('data/.hg/.i/.d/foo')
69 68
70 69 show('data/aux.bla/bla.aux/prn/PRN/lpt/com3/nul/coma/foo.NUL/normal.c.i')
71 70
72 71 show('data/AUX/SECOND/X.PRN/FOURTH/FI:FTH/SIXTH/SEVENTH/EIGHTH/NINETH/'
73 72 'TENTH/ELEVENTH/LOREMIPSUM.TXT.i')
74 73 show('data/enterprise/openesbaddons/contrib-imola/corba-bc/netbeansplugin/'
75 74 'wsdlExtension/src/main/java/META-INF/services/org.netbeans.modules'
76 75 '.xml.wsdl.bindingsupport.spi.ExtensibilityElementTemplateProvider.i')
77 76 show('data/AUX.THE-QUICK-BROWN-FOX-JU:MPS-OVER-THE-LAZY-DOG-THE-QUICK-'
78 77 'BROWN-FOX-JUMPS-OVER-THE-LAZY-DOG.TXT.i')
79 78 show('data/Project Planning/Resources/AnotherLongDirectoryName/'
80 79 'Followedbyanother/AndAnother/AndThenAnExtremelyLongFileName.txt')
81 80 show('data/Project.Planning/Resources/AnotherLongDirectoryName/'
82 81 'Followedbyanother/AndAnother/AndThenAnExtremelyLongFileName.txt')
83 82 show('data/foo.../foo / /a./_. /__/.x../ bla/.FOO/something.i')
84 83
85 84 show('data/c/co/com/com0/com1/com2/com3/com4/com5/com6/com7/com8/com9')
86 85 show('data/C/CO/COM/COM0/COM1/COM2/COM3/COM4/COM5/COM6/COM7/COM8/COM9')
87 86 show('data/c.x/co.x/com.x/com0.x/com1.x/com2.x/com3.x/com4.x/com5.x'
88 87 '/com6.x/com7.x/com8.x/com9.x')
89 88 show('data/x.c/x.co/x.com0/x.com1/x.com2/x.com3/x.com4/x.com5'
90 89 '/x.com6/x.com7/x.com8/x.com9')
91 90 show('data/cx/cox/comx/com0x/com1x/com2x/com3x/com4x/com5x'
92 91 '/com6x/com7x/com8x/com9x')
93 92 show('data/xc/xco/xcom0/xcom1/xcom2/xcom3/xcom4/xcom5'
94 93 '/xcom6/xcom7/xcom8/xcom9')
95 94
96 95 show('data/l/lp/lpt/lpt0/lpt1/lpt2/lpt3/lpt4/lpt5/lpt6/lpt7/lpt8/lpt9')
97 96 show('data/L/LP/LPT/LPT0/LPT1/LPT2/LPT3/LPT4/LPT5/LPT6/LPT7/LPT8/LPT9')
98 97 show('data/l.x/lp.x/lpt.x/lpt0.x/lpt1.x/lpt2.x/lpt3.x/lpt4.x/lpt5.x'
99 98 '/lpt6.x/lpt7.x/lpt8.x/lpt9.x')
100 99 show('data/x.l/x.lp/x.lpt/x.lpt0/x.lpt1/x.lpt2/x.lpt3/x.lpt4/x.lpt5'
101 100 '/x.lpt6/x.lpt7/x.lpt8/x.lpt9')
102 101 show('data/lx/lpx/lptx/lpt0x/lpt1x/lpt2x/lpt3x/lpt4x/lpt5x'
103 102 '/lpt6x/lpt7x/lpt8x/lpt9x')
104 103 show('data/xl/xlp/xlpt/xlpt0/xlpt1/xlpt2/xlpt3/xlpt4/xlpt5'
105 104 '/xlpt6/xlpt7/xlpt8/xlpt9')
106 105
107 106 show('data/con/p/pr/prn/a/au/aux/n/nu/nul')
108 107 show('data/CON/P/PR/PRN/A/AU/AUX/N/NU/NUL')
109 108 show('data/con.x/p.x/pr.x/prn.x/a.x/au.x/aux.x/n.x/nu.x/nul.x')
110 109 show('data/x.con/x.p/x.pr/x.prn/x.a/x.au/x.aux/x.n/x.nu/x.nul')
111 110 show('data/conx/px/prx/prnx/ax/aux/auxx/nx/nux/nulx')
112 111 show('data/xcon/xp/xpr/xprn/xa/xau/xaux/xn/xnu/xnul')
113 112
114 113 show('data/a./au./aux./auxy./aux.')
115 114 show('data/c./co./con./cony./con.')
116 115 show('data/p./pr./prn./prny./prn.')
117 116 show('data/n./nu./nul./nuly./nul.')
118 117 show('data/l./lp./lpt./lpt1./lpt1y./lpt1.')
119 118 show('data/lpt9./lpt9y./lpt9.')
120 119 show('data/com./com1./com1y./com1.')
121 120 show('data/com9./com9y./com9.')
122 121
123 122 show('data/a /au /aux /auxy /aux ')
124 123
125 124 print "largest unhashed path"
126 125 show('data/123456789-123456789-123456789-123456789-123456789-'
127 126 'unhashed--xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-'
128 127 '123456789-12345')
129 128
130 129 print "shortest hashed path"
131 130 show('data/123456789-123456789-123456789-123456789-123456789-'
132 131 'hashed----xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-'
133 132 '123456789-123456')
134 133
135 134 print "changing one char in part that's hashed away produces a different hash"
136 135 show('data/123456789-123456789-123456789-123456789-123456789-'
137 136 'hashed----xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-xxxxxxxxy-'
138 137 '123456789-123456')
139 138
140 139 print "uppercase hitting length limit due to encoding"
141 140 show('data/A23456789-123456789-123456789-123456789-123456789-'
142 141 'xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-'
143 142 '123456789-12345')
144 143 show('data/Z23456789-123456789-123456789-123456789-123456789-'
145 144 'xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-'
146 145 '123456789-12345')
147 146
148 147 print "compare with lowercase not hitting limit"
149 148 show('data/a23456789-123456789-123456789-123456789-123456789-'
150 149 'xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-'
151 150 '123456789-12345')
152 151 show('data/z23456789-123456789-123456789-123456789-123456789-'
153 152 'xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-'
154 153 '123456789-12345')
155 154
156 155 print "not hitting limit with any of these"
157 156 show("data/abcdefghijklmnopqrstuvwxyz0123456789 !#%&'()+,-.;="
158 157 "[]^`{}xxx-xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-"
159 158 "123456789-12345")
160 159
161 160 print "underbar hitting length limit due to encoding"
162 161 show('data/_23456789-123456789-123456789-123456789-123456789-'
163 162 'xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-'
164 163 '123456789-12345')
165 164
166 165 print "tilde hitting length limit due to encoding"
167 166 show('data/~23456789-123456789-123456789-123456789-123456789-'
168 167 'xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-'
169 168 '123456789-12345')
170 169
171 170 print "Windows reserved characters hitting length limit"
172 171 show('data/<23456789-123456789-123456789-123456789-123456789-'
173 172 'xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-'
174 173 '123456789-12345')
175 174 show('data/>23456789-123456789-123456789-123456789-123456789-'
176 175 'xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-'
177 176 '123456789-12345')
178 177 show('data/:23456789-123456789-123456789-123456789-123456789-'
179 178 'xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-'
180 179 '123456789-12345')
181 180 show('data/"23456789-123456789-123456789-123456789-123456789-'
182 181 'xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-'
183 182 '123456789-12345')
184 183 show('data/\\23456789-123456789-123456789-123456789-123456789-'
185 184 'xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-'
186 185 '123456789-12345')
187 186 show('data/|23456789-123456789-123456789-123456789-123456789-'
188 187 'xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-'
189 188 '123456789-12345')
190 189 show('data/?23456789-123456789-123456789-123456789-123456789-'
191 190 'xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-'
192 191 '123456789-12345')
193 192 show('data/*23456789-123456789-123456789-123456789-123456789-'
194 193 'xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-'
195 194 '123456789-12345')
196 195
197 196 print "initial space hitting length limit"
198 197 show('data/ 23456789-123456789-123456789-123456789-123456789-'
199 198 'xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-'
200 199 '123456789-12345')
201 200
202 201 print "initial dot hitting length limit"
203 202 show('data/.23456789-123456789-123456789-123456789-123456789-'
204 203 'xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-'
205 204 '123456789-12345')
206 205
207 206 print "trailing space in filename hitting length limit"
208 207 show('data/123456789-123456789-123456789-123456789-123456789-'
209 208 'xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-'
210 209 '123456789-1234 ')
211 210
212 211 print "trailing dot in filename hitting length limit"
213 212 show('data/123456789-123456789-123456789-123456789-123456789-'
214 213 'xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-'
215 214 '123456789-1234.')
216 215
217 216 print "initial space in directory hitting length limit"
218 217 show('data/ x/456789-123456789-123456789-123456789-123456789-'
219 218 'xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-'
220 219 '123456789-12345')
221 220
222 221 print "initial dot in directory hitting length limit"
223 222 show('data/.x/456789-123456789-123456789-123456789-123456789-'
224 223 'xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-'
225 224 '123456789-12345')
226 225
227 226 print "trailing space in directory hitting length limit"
228 227 show('data/x /456789-123456789-123456789-123456789-123456789-'
229 228 'xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-'
230 229 '123456789-12345')
231 230
232 231 print "trailing dot in directory hitting length limit"
233 232 show('data/x./456789-123456789-123456789-123456789-123456789-'
234 233 'xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-'
235 234 '123456789-12345')
236 235
237 236 print "with directories that need direncoding, hitting length limit"
238 237 show('data/x.i/56789-123456789-123456789-123456789-123456789-'
239 238 'xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-'
240 239 '123456789-12345')
241 240 show('data/x.d/56789-123456789-123456789-123456789-123456789-'
242 241 'xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-'
243 242 '123456789-12345')
244 243 show('data/x.hg/5789-123456789-123456789-123456789-123456789-'
245 244 'xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-'
246 245 '123456789-12345')
247 246
248 247 print "Windows reserved filenames, hitting length limit"
249 248 show('data/con/56789-123456789-123456789-123456789-123456789-'
250 249 'xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-'
251 250 '123456789-12345')
252 251 show('data/prn/56789-123456789-123456789-123456789-123456789-'
253 252 'xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-'
254 253 '123456789-12345')
255 254 show('data/aux/56789-123456789-123456789-123456789-123456789-'
256 255 'xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-'
257 256 '123456789-12345')
258 257 show('data/nul/56789-123456789-123456789-123456789-123456789-'
259 258 'xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-'
260 259 '123456789-12345')
261 260 show('data/com1/6789-123456789-123456789-123456789-123456789-'
262 261 'xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-'
263 262 '123456789-12345')
264 263 show('data/com9/6789-123456789-123456789-123456789-123456789-'
265 264 'xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-'
266 265 '123456789-12345')
267 266 show('data/lpt1/6789-123456789-123456789-123456789-123456789-'
268 267 'xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-'
269 268 '123456789-12345')
270 269 show('data/lpt9/6789-123456789-123456789-123456789-123456789-'
271 270 'xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-'
272 271 '123456789-12345')
273 272
274 273 print "non-reserved names, just not hitting limit"
275 274 show('data/123456789-123456789-123456789-123456789-123456789-'
276 275 '/com/com0/lpt/lpt0/-xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-'
277 276 '123456789-12345')
278 277
279 278 print "hashed path with largest untruncated 1st dir"
280 279 show('data/12345678/-123456789-123456789-123456789-123456789-'
281 280 'hashed----xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-'
282 281 '123456789-123456')
283 282
284 283 print "hashed path with smallest truncated 1st dir"
285 284 show('data/123456789/123456789-123456789-123456789-123456789-'
286 285 'hashed----xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-'
287 286 '123456789-123456')
288 287
289 288 print "hashed path with largest untruncated two dirs"
290 289 show('data/12345678/12345678/9-123456789-123456789-123456789-'
291 290 'hashed----xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-'
292 291 '123456789-123456')
293 292
294 293 print "hashed path with smallest truncated two dirs"
295 294 show('data/123456789/123456789/123456789-123456789-123456789-'
296 295 'hashed----xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-'
297 296 '123456789-123456')
298 297
299 298 print "hashed path with largest untruncated three dirs"
300 299 show('data/12345678/12345678/12345678/89-123456789-123456789-'
301 300 'hashed----xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-'
302 301 '123456789-123456')
303 302
304 303 print "hashed path with smallest truncated three dirs"
305 304 show('data/123456789/123456789/123456789/123456789-123456789-'
306 305 'hashed----xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-'
307 306 '123456789-123456')
308 307
309 308 print "hashed path with largest untruncated four dirs"
310 309 show('data/12345678/12345678/12345678/12345678/789-123456789-'
311 310 'hashed----xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-'
312 311 '123456789-123456')
313 312
314 313 print "hashed path with smallest truncated four dirs"
315 314 show('data/123456789/123456789/123456789/123456789/123456789-'
316 315 'hashed----xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-'
317 316 '123456789-123456')
318 317
319 318 print "hashed path with largest untruncated five dirs"
320 319 show('data/12345678/12345678/12345678/12345678/12345678/6789-'
321 320 'hashed----xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-'
322 321 '123456789-123456')
323 322
324 323 print "hashed path with smallest truncated five dirs"
325 324 show('data/123456789/123456789/123456789/123456789/123456789/'
326 325 'hashed----xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-'
327 326 '123456789-123456')
328 327
329 328 print "hashed path with largest untruncated six dirs"
330 329 show('data/12345678/12345678/12345678/12345678/12345678/12345'
331 330 '678/ed----xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-'
332 331 '123456789-123456')
333 332
334 333 print "hashed path with smallest truncated six dirs"
335 334 show('data/123456789/123456789/123456789/123456789/123456789/'
336 335 '123456789/xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-'
337 336 '123456789-123456')
338 337
339 338 print "hashed path with largest untruncated seven dirs"
340 339 show('data/12345678/12345678/12345678/12345678/12345678/12345'
341 340 '678/12345678/xxxxxx-xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-'
342 341 '123456789-123456')
343 342
344 343 print "hashed path with smallest truncated seven dirs"
345 344 show('data/123456789/123456789/123456789/123456789/123456789/'
346 345 '123456789/123456789/xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-'
347 346 '123456789-123456')
348 347
349 348 print "hashed path with largest untruncated eight dirs"
350 349 print "(directory 8 is dropped because it hits _maxshortdirslen)"
351 350 show('data/12345678/12345678/12345678/12345678/12345678/12345'
352 351 '678/12345678/12345678/xxxxxxx-xxxxxxxxx-xxxxxxxxx-'
353 352 '123456789-123456')
354 353
355 354 print "hashed path with smallest truncated eight dirs"
356 355 print "(directory 8 is dropped because it hits _maxshortdirslen)"
357 356 show('data/123456789/123456789/123456789/123456789/123456789/'
358 357 '123456789/123456789/123456789/xxxxxxxxx-xxxxxxxxx-'
359 358 '123456789-123456')
360 359
361 360 print "hashed path with largest non-dropped directory 8"
362 361 print "(just not hitting the _maxshortdirslen boundary)"
363 362 show('data/12345678/12345678/12345678/12345678/12345678/12345'
364 363 '678/12345678/12345/-xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-'
365 364 '123456789-123456')
366 365
367 366 print "...adding one truncated char to dir 1..7 won't drop dir 8"
368 367 show('data/12345678x/12345678/12345678/12345678/12345678/12345'
369 368 '678/12345678/12345/xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-'
370 369 '123456789-123456')
371 370 show('data/12345678/12345678x/12345678/12345678/12345678/12345'
372 371 '678/12345678/12345/xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-'
373 372 '123456789-123456')
374 373 show('data/12345678/12345678/12345678x/12345678/12345678/12345'
375 374 '678/12345678/12345/xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-'
376 375 '123456789-123456')
377 376 show('data/12345678/12345678/12345678/12345678x/12345678/12345'
378 377 '678/12345678/12345/xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-'
379 378 '123456789-123456')
380 379 show('data/12345678/12345678/12345678/12345678/12345678x/12345'
381 380 '678/12345678/12345/xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-'
382 381 '123456789-123456')
383 382 show('data/12345678/12345678/12345678/12345678/12345678/12345'
384 383 '678x/12345678/12345/xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-'
385 384 '123456789-123456')
386 385 show('data/12345678/12345678/12345678/12345678/12345678/12345'
387 386 '678/12345678x/12345/xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-'
388 387 '123456789-123456')
389 388
390 389 print "hashed path with shortest dropped directory 8"
391 390 print "(just hitting the _maxshortdirslen boundary)"
392 391 show('data/12345678/12345678/12345678/12345678/12345678/12345'
393 392 '678/12345678/123456/xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-'
394 393 '123456789-123456')
395 394
396 395 print "hashed path that drops dir 8 due to dot or space at end is"
397 396 print "encoded, and thus causing to hit _maxshortdirslen"
398 397 show('data/12345678/12345678/12345678/12345678/12345678/12345'
399 398 '678/12345678/1234./-xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-'
400 399 '123456789-123456')
401 400 show('data/12345678/12345678/12345678/12345678/12345678/12345'
402 401 '678/12345678/1234 /-xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-'
403 402 '123456789-123456')
404 403
405 404 print "... with dir 8 short enough for encoding"
406 405 show('data/12345678/12345678/12345678/12345678/12345678/12345'
407 406 '678/12345678/12./xx-xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-'
408 407 '123456789-123456')
409 408 show('data/12345678/12345678/12345678/12345678/12345678/12345'
410 409 '678/12345678/12 /xx-xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-'
411 410 '123456789-123456')
412 411
413 412 print "extensions are replicated on hashed paths (unbounded!)"
414 413 show('data/12345678/12345678/12345678/12345678/12345678/12345'
415 414 '678/12345678/12345/-xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-'
416 415 '123456789-12.345')
417 416 show('data/12345678/12345678/12345678/12345678/12345678/12345'
418 417 '678/12345678/12345/-xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-'
419 418 '123456789-12.3456')
420 419 show('data/12345678/12345678/12345678/12345678/12345678/12345'
421 420 '678/12345678/12345/-xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-'
422 421 '123456789-12.34567')
423 422 show('data/12345678/12345678/12345678/12345678/12345678/12345'
424 423 '678/12345678/12345/-xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-'
425 424 '123456789-12.345678')
426 425 show('data/12345678/12345678/12345678/12345678/12345678/12345'
427 426 '678/12345678/12345/-xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-'
428 427 '123456789-12.3456789')
429 428 show('data/12345678/12345678/12345678/12345678/12345678/12345'
430 429 '678/12345678/12345/-xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-'
431 430 '123456789-12.3456789-')
432 431 show('data/12345678/12345678/12345678/12345678/12345678/12345'
433 432 '678/12345678/12345/-xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-'
434 433 '123456789-12.3456789-1')
435 434 show('data/12345678/12345678/12345678/12345678/12345678/12345'
436 435 '678/12345678/12345/-xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-'
437 436 '123456789-12.3456789-12')
438 437 show('data/12345678/12345678/12345678/12345678/12345678/12345'
439 438 '678/12345678/12345/-xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-'
440 439 '123456789-12.3456789-123')
441 440 show('data/12345678/12345678/12345678/12345678/12345678/12345'
442 441 '678/12345678/12345/-xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-'
443 442 '123456789-12.3456789-1234')
444 443 show('data/12345678/12345678/12345678/12345678/12345678/12345'
445 444 '678/12345678/12345/-xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-'
446 445 '123456789-12.3456789-12345')
447 446 show('data/12345678/12345678/12345678/12345678/12345678/12345'
448 447 '678/12345678/12345/-xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-'
449 448 '123456789-12.3456789-12345-ABCDEFGHIJKLMNOPRSTUVWX'
450 449 'YZ-abcdefghjiklmnopqrstuvwxyz-ABCDEFGHIJKLMNOPRSTU'
451 450 'VWXYZ-1234567890-xxxxxxxxx-xxxxxxxxx-xxxxxxxx-xxxx'
452 451 'xxxxx-wwwwwwwww-wwwwwwwww-wwwwwwwww-wwwwwwwww-wwww'
453 452 'wwwww-wwwwwwwww-wwwwwwwww-wwwwwwwww-wwwwwwwww')
454 453
General Comments 0
You need to be logged in to leave comments. Login now