Steve D'Aprano wrote: > On Mon, 30 Jan 2017 03:33 pm, Cameron Simpson wrote: > >> On 30Jan2017 13:49, Steve D'Aprano <steve+pyt...@pearwood.info> wrote: >>>This code contains a Time Of Check to Time Of Use bug: >>> >>> if os.path.exists(destination) >>> raise ValueError('destination already exists') >>> os.rename(oldname, destination) >>> >>> >>>In the microsecond between checking for the existence of the destination >>>and actually doing the rename, it is possible that another process may >>>create the destination, resulting in data loss. >>> >>>Apart from keeping my fingers crossed, how should I fix this TOCTOU bug? >> >> For files this is a problem at the Python level. At the UNIX level you >> can play neat games with open(2) and the various O_* modes. >> >> however, with directories things are more cut and dry. Do you have much >> freedom here? What's the wider context of the question? > > The wider context is that I'm taking from 1 to <arbitrarily huge number> > path names to existing files as arguments, and for each path name I > transfer the file name part (but not the directory part) and then rename > the file. For example: > > foo/bar/baz/spam.txt > > may be renamed to: > > foo/bar/baz/ham.txt > > but only provided ham.txt doesn't already exist.
Google finds http://stackoverflow.com/questions/3222341/how-to-rename-without-race-conditions and from a quick test it appears to work on Linux: $ echo foo > foo $ echo bar > bar $ python3 Python 3.4.3 (default, Nov 17 2016, 01:08:31) [GCC 4.8.4] on linux Type "help", "copyright", "credits" or "license" for more information. >>> import os >>> def rename(source, dest): ... os.link(source, dest) ... os.unlink(source) ... >>> rename("foo", "baz") >>> os.listdir() ['bar', 'baz'] >>> rename("bar", "baz") Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<stdin>", line 2, in rename FileExistsError: [Errno 17] File exists: 'bar' -> 'baz' -- https://mail.python.org/mailman/listinfo/python-list