Mercurial > hg
comparison mercurial/dirstate.py @ 42456:87a34c767384
merge: fix race that could cause wrong size in dirstate
The problem is that hg merge/update/etc work the following way:
1. figure out what files to update
2. apply the update to disk
3. apply the update to in-memory dirstate
4. write dirstate
where step3 looks at the filesystem and assumes it sees the result of
step2. If a file is changed between step2 and step3, step3 will record
incorrect information in the dirstate.
I avoid this by passing the size step3 needs directly from step2, for
the common path (not implemented for change/delete conflicts for
instance).
I didn't fix the same race for the exec bit for now, because it's less
likely to be problematic and I had trouble due to the fact that the
dirstate stores the permissions differently from the manifest (st_mode
vs '' 'l' 'x'), in combination with tests that pretend that symlinks
are not supported.
However, I moved the lstat from step3 to step2, which should tighten
the race window markedly, both for the exec bit and for the mtime.
Differential Revision: https://phab.mercurial-scm.org/D6475
author | Valentin Gatien-Baron <valentin.gatienbaron@gmail.com> |
---|---|
date | Mon, 27 May 2019 16:55:46 -0400 |
parents | a3a8887e4426 |
children | 760a7851e9ba |
comparison
equal
deleted
inserted
replaced
42455:5ca136bbd3f6 | 42456:87a34c767384 |
---|---|
389 (pycompat.bytestr(d), pycompat.bytestr(f))) | 389 (pycompat.bytestr(d), pycompat.bytestr(f))) |
390 self._dirty = True | 390 self._dirty = True |
391 self._updatedfiles.add(f) | 391 self._updatedfiles.add(f) |
392 self._map.addfile(f, oldstate, state, mode, size, mtime) | 392 self._map.addfile(f, oldstate, state, mode, size, mtime) |
393 | 393 |
394 def normal(self, f): | 394 def normal(self, f, parentfiledata=None): |
395 '''Mark a file normal and clean.''' | 395 '''Mark a file normal and clean. |
396 s = os.lstat(self._join(f)) | 396 |
397 mtime = s[stat.ST_MTIME] | 397 parentfiledata: (mode, size, mtime) of the clean file |
398 self._addpath(f, 'n', s.st_mode, | 398 |
399 s.st_size & _rangemask, mtime & _rangemask) | 399 parentfiledata should be computed from memory (for mode, |
400 size), as or close as possible from the point where we | |
401 determined the file was clean, to limit the risk of the | |
402 file having been changed by an external process between the | |
403 moment where the file was determined to be clean and now.''' | |
404 if parentfiledata: | |
405 (mode, size, mtime) = parentfiledata | |
406 else: | |
407 s = os.lstat(self._join(f)) | |
408 mode = s.st_mode | |
409 size = s.st_size | |
410 mtime = s[stat.ST_MTIME] | |
411 self._addpath(f, 'n', mode, size & _rangemask, mtime & _rangemask) | |
400 self._map.copymap.pop(f, None) | 412 self._map.copymap.pop(f, None) |
401 if f in self._map.nonnormalset: | 413 if f in self._map.nonnormalset: |
402 self._map.nonnormalset.remove(f) | 414 self._map.nonnormalset.remove(f) |
403 if mtime > self._lastnormaltime: | 415 if mtime > self._lastnormaltime: |
404 # Remember the most recent modification timeslot for status(), | 416 # Remember the most recent modification timeslot for status(), |