Copy a file, but don't overwrite, without TOCTTOU issues in Python

kuzzooroo picture kuzzooroo · May 26, 2015 · Viewed 7.2k times · Source

I know that if I want to copy a file in Python but not overwrite the destination I can use code like this:

if os.path.exists(dest):
    raise Exception("Destination file exists!")
else:
    shutil.copy2(src, dest)

But the state of the world could change between the time I call os.path.exists and the time I call copy2. Is there a more preferred way to copy without overwriting, presumably wherein the copy operation will raise an exception if the destination already exists?

Answer

user554538 picture user554538 · May 26, 2015

You can use the lower-level os.open and then os.fdopen to copy the file:

import os
import shutil

# Open the file and raise an exception if it exists
fd = os.open(filename, os.O_CREAT | os.O_EXCL | os.O_WRONLY)

# Copy the file and automatically close files at the end
with os.fdopen(fd) as f:
    with open(src_filename) as sf:
        shutil.copyfileobj(sf, f)