# HG changeset patch # User Siddharth Agarwal # Date 2015-12-12 18:58:05 # Node ID d9e3ebe56970dc6e86648351de3ad13d9ac47cf9 # Parent c48ecc0b5bc9c1c40205302dc3e1ba3700315236 record: don't dereference symlinks while copying over stat data Previously, we could be calling os.utime or os.chflags (via shutil.copystat) on a symlink. These functions dereference symlinks, so this would have caused the timestamp of the target to be set. On a read-only or similarly weird filesystem, this might cause an exception to be raised. This is pretty hard to test because conjuring up a read-only filesystem for test purposes is non-trivial. diff --git a/mercurial/cmdutil.py b/mercurial/cmdutil.py --- a/mercurial/cmdutil.py +++ b/mercurial/cmdutil.py @@ -7,7 +7,7 @@ from node import hex, bin, nullid, nullrev, short from i18n import _ -import os, sys, errno, re, tempfile, cStringIO, shutil +import os, sys, errno, re, tempfile, cStringIO import util, scmutil, templater, patch, error, templatekw, revlog, copies import match as matchmod import repair, graphmod, revset, phases, obsolete, pathutil @@ -166,8 +166,7 @@ def dorecord(ui, repo, commitfunc, cmdsu dir=backupdir) os.close(fd) ui.debug('backup %r as %r\n' % (f, tmpname)) - util.copyfile(repo.wjoin(f), tmpname) - shutil.copystat(repo.wjoin(f), tmpname) + util.copyfile(repo.wjoin(f), tmpname, copystat=True) backups[f] = tmpname fp = cStringIO.StringIO() @@ -216,15 +215,12 @@ def dorecord(ui, repo, commitfunc, cmdsu # to be treated as unmodified dirstate.normallookup(realname) - util.copyfile(tmpname, repo.wjoin(realname)) - # Our calls to copystat() here and above are a - # hack to trick any editors that have f open that - # we haven't modified them. + # copystat=True here and above are a hack to trick any + # editors that have f open that we haven't modified them. # - # Also note that this racy as an editor could - # notice the file's mtime before we've finished - # writing it. - shutil.copystat(tmpname, repo.wjoin(realname)) + # Also note that this racy as an editor could notice the + # file's mtime before we've finished writing it. + util.copyfile(tmpname, repo.wjoin(realname), copystat=True) os.unlink(tmpname) if tobackup: os.rmdir(backupdir)