Show More
@@ -1381,6 +1381,69 b' def mktempcopy(name, emptyok=False, crea' | |||||
1381 | raise |
|
1381 | raise | |
1382 | return temp |
|
1382 | return temp | |
1383 |
|
1383 | |||
|
1384 | class filestat(object): | |||
|
1385 | """help to exactly detect change of a file | |||
|
1386 | ||||
|
1387 | 'stat' attribute is result of 'os.stat()' if specified 'path' | |||
|
1388 | exists. Otherwise, it is None. This can avoid preparative | |||
|
1389 | 'exists()' examination on client side of this class. | |||
|
1390 | """ | |||
|
1391 | def __init__(self, path): | |||
|
1392 | try: | |||
|
1393 | self.stat = os.stat(path) | |||
|
1394 | except OSError as err: | |||
|
1395 | if err.errno != errno.ENOENT: | |||
|
1396 | raise | |||
|
1397 | self.stat = None | |||
|
1398 | ||||
|
1399 | __hash__ = object.__hash__ | |||
|
1400 | ||||
|
1401 | def __eq__(self, old): | |||
|
1402 | try: | |||
|
1403 | # if ambiguity between stat of new and old file is | |||
|
1404 | # avoided, comparision of size, ctime and mtime is enough | |||
|
1405 | # to exactly detect change of a file regardless of platform | |||
|
1406 | return (self.stat.st_size == old.stat.st_size and | |||
|
1407 | self.stat.st_ctime == old.stat.st_ctime and | |||
|
1408 | self.stat.st_mtime == old.stat.st_mtime) | |||
|
1409 | except AttributeError: | |||
|
1410 | return False | |||
|
1411 | ||||
|
1412 | def isambig(self, old): | |||
|
1413 | """Examine whether new (= self) stat is ambiguous against old one | |||
|
1414 | ||||
|
1415 | "S[N]" below means stat of a file at N-th change: | |||
|
1416 | ||||
|
1417 | - S[n-1].ctime < S[n].ctime: can detect change of a file | |||
|
1418 | - S[n-1].ctime == S[n].ctime | |||
|
1419 | - S[n-1].ctime < S[n].mtime: means natural advancing (*1) | |||
|
1420 | - S[n-1].ctime == S[n].mtime: is ambiguous (*2) | |||
|
1421 | - S[n-1].ctime > S[n].mtime: never occurs naturally (don't care) | |||
|
1422 | - S[n-1].ctime > S[n].ctime: never occurs naturally (don't care) | |||
|
1423 | ||||
|
1424 | Case (*2) above means that a file was changed twice or more at | |||
|
1425 | same time in sec (= S[n-1].ctime), and comparison of timestamp | |||
|
1426 | is ambiguous. | |||
|
1427 | ||||
|
1428 | Base idea to avoid such ambiguity is "advance mtime 1 sec, if | |||
|
1429 | timestamp is ambiguous". | |||
|
1430 | ||||
|
1431 | But advancing mtime only in case (*2) doesn't work as | |||
|
1432 | expected, because naturally advanced S[n].mtime in case (*1) | |||
|
1433 | might be equal to manually advanced S[n-1 or earlier].mtime. | |||
|
1434 | ||||
|
1435 | Therefore, all "S[n-1].ctime == S[n].ctime" cases should be | |||
|
1436 | treated as ambiguous regardless of mtime, to avoid overlooking | |||
|
1437 | by confliction between such mtime. | |||
|
1438 | ||||
|
1439 | Advancing mtime "if isambig(oldstat)" ensures "S[n-1].mtime != | |||
|
1440 | S[n].mtime", even if size of a file isn't changed. | |||
|
1441 | """ | |||
|
1442 | try: | |||
|
1443 | return (self.stat.st_ctime == old.stat.st_ctime) | |||
|
1444 | except AttributeError: | |||
|
1445 | return False | |||
|
1446 | ||||
1384 | class atomictempfile(object): |
|
1447 | class atomictempfile(object): | |
1385 | '''writable file object that atomically updates a file |
|
1448 | '''writable file object that atomically updates a file | |
1386 |
|
1449 |
General Comments 0
You need to be logged in to leave comments.
Login now