homepage

This issue tracker has been migrated to GitHub , and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

Author socketpair
Recipients Arfrever, barry, eric.araujo, eric.smith, exarkun, giampaolo.rodola, loewis, martin.panter, meatballhat, milko.krachounov, ncoghlan, neologix, olemis, pitrou, socketpair, tarek, vstinner
Date 2015年12月22日.18:41:08
SpamBayes Score -1.0
Marked as misclassified Yes
Message-id <1450809669.27.0.106825521484.issue8604@psf.upfronthosting.co.za>
In-reply-to
Content
You also forgot about two things:
1. set temporary file permissions before rename
2. fsync(open(os.dirname(temporaryfile)))
3. if original file name is symlink, replace will works wrong. os.realpath should be used.
So, here are real life function, that we use in production:
# TODO: save_mtime, save_selinux, extended attr, chattrs and so on...
# TODO: malicious user may replace directory with another while writing to file,
# so we should use open directory first, and then use openat() and renameat()
# with relative filename instead of specifying absolute path.
# also NameTemporaryFile should allow to specify dir=<dir_file_descriptor>
@contextmanager
def replace_file(path, save_perms=False, fsync=True, **kwargs):
 realpath = os.path.realpath(path)
 operating_dir = os.path.dirname(realpath)
 uid = None
 gid = None
 mode = None
 if save_perms:
 try:
 stinfo = os.lstat(realpath)
 uid = stinfo.st_uid
 gid = stinfo.st_gid
 mode = stinfo.st_mode
 except OSError as e:
 if e.errno != errno.ENOENT:
 raise
 with NamedTemporaryFile(dir=operating_dir, **kwargs) as fff:
 filedes = fff.fileno()
 if None not in (uid, gid, mode):
 os.fchown(filedes, uid, gid)
 os.fchmod(filedes, mode & 0o7777)
 yield fff
 # survive application crash
 fff.flush()
 if fsync:
 # survive power outage, is not required if that is temporary file
 os.fsync(filedes)
 os.rename(fff.name, realpath)
 # see http://bugs.python.org/issue21579
 fff._closer.delete = False
 if fsync:
 # Sync directory: http://stackoverflow.com/questions/3764822/how-to-durably-rename-a-file-in-posix
 dirfd = os.open(operating_dir, os.O_RDONLY | os.O_CLOEXEC | os.O_DIRECTORY)
 try:
 os.fsync(dirfd)
 finally:
 os.close(dirfd)
History
Date User Action Args
2015年12月22日 18:41:09socketpairsetrecipients: + socketpair, loewis, barry, exarkun, ncoghlan, pitrou, vstinner, eric.smith, giampaolo.rodola, tarek, eric.araujo, Arfrever, olemis, meatballhat, milko.krachounov, neologix, martin.panter
2015年12月22日 18:41:09socketpairsetmessageid: <1450809669.27.0.106825521484.issue8604@psf.upfronthosting.co.za>
2015年12月22日 18:41:09socketpairlinkissue8604 messages
2015年12月22日 18:41:08socketpaircreate

AltStyle によって変換されたページ (->オリジナル) /