Mercurial > public > mercurial-scm > hg
comparison mercurial/vfs.py @ 32748:ed66ec39933f
vfs: create copy at renaming to avoid file stat ambiguity if needed
In order to fix issue5418, bff5ccbe5ead made vfs.rename(checkambig=True)
omit advancing mtime of renamed file, if renamed file is owned by
another (EPERM is raised in this case).
But this omission causes rewinding mtime at restoration in such
situation, and makes avoiding file stat ambiguity difficult, because
ExactCacheValidationPlan assumes that mtime should be advanced, if a
file is changed in same ctime.
https://www.mercurial-scm.org/wiki/ExactCacheValidationPlan
Ambiguity of file stat also requires issue5584 to be fixed with other
than file stat, but "hash of file", "generation ID" and so on were
already rejected ideas (please see original RFC linked from "Outline
of issue" in ExactCacheValidationPlan page).
This omission occurs:
- only for non append-only files (dirstate, bookmarks, and phaseroots), and
- only if previous transaction is rollbacked by another user
The latter means "sharing a repository clone via group permission".
This is reasonable usecase, but not ordinary for many users, IMHO.
"hg rollback" itself has been deprecated since Mercurial 2.7, too.
Therefore, increasing the cost at rollbacking previous transaction
executed by another a little seems reasonable, for avoidance of file
stat ambiguity.
This patch does:
- create copy of (already renamed) source file, if advancing mtime
fails for EPERM
- rename from copied file to destination file, and
- advance mtime of renamed file, which is now owned by current user
This patch also factors "self.join(src)" out to reduce redundancy.
author | FUJIWARA Katsunori <foozy@lares.dti.ne.jp> |
---|---|
date | Fri, 09 Jun 2017 12:58:18 +0900 |
parents | 1a79de471d56 |
children | 7ad95626f6a7 |
comparison
equal
deleted
inserted
replaced
32747:1a79de471d56 | 32748:ed66ec39933f |
---|---|
172 | 172 |
173 checkambig argument is used with util.filestat, and is useful | 173 checkambig argument is used with util.filestat, and is useful |
174 only if destination file is guarded by any lock | 174 only if destination file is guarded by any lock |
175 (e.g. repo.lock or repo.wlock). | 175 (e.g. repo.lock or repo.wlock). |
176 """ | 176 """ |
177 srcpath = self.join(src) | |
177 dstpath = self.join(dst) | 178 dstpath = self.join(dst) |
178 oldstat = checkambig and util.filestat(dstpath) | 179 oldstat = checkambig and util.filestat(dstpath) |
179 if oldstat and oldstat.stat: | 180 if oldstat and oldstat.stat: |
180 def dorename(spath, dpath): | 181 def dorename(spath, dpath): |
181 ret = util.rename(spath, dpath) | 182 ret = util.rename(spath, dpath) |
182 newstat = util.filestat(dpath) | 183 newstat = util.filestat(dpath) |
183 if newstat.isambig(oldstat): | 184 if newstat.isambig(oldstat): |
184 # stat of renamed file is ambiguous to original one | 185 # stat of renamed file is ambiguous to original one |
185 return ret, newstat.avoidambig(dpath, oldstat) | 186 return ret, newstat.avoidambig(dpath, oldstat) |
186 return ret, True | 187 return ret, True |
187 ret, avoided = dorename(self.join(src), dstpath) | 188 ret, avoided = dorename(srcpath, dstpath) |
189 if not avoided: | |
190 # simply copy to change owner of srcpath (see issue5418) | |
191 util.copyfile(dstpath, srcpath) | |
192 ret, avoided = dorename(srcpath, dstpath) | |
188 return ret | 193 return ret |
189 return util.rename(self.join(src), dstpath) | 194 return util.rename(srcpath, dstpath) |
190 | 195 |
191 def readlink(self, path): | 196 def readlink(self, path): |
192 return os.readlink(self.join(path)) | 197 return os.readlink(self.join(path)) |
193 | 198 |
194 def removedirs(self, path=None): | 199 def removedirs(self, path=None): |