[Python-Dev] shutil.copy() and hard links (original) (raw)

Christian Heimes lists at cheimes.de
Wed Jan 11 10:49:46 CET 2012


Hello,

here is another fun fact about links, this time hard links and the shutil.copy() function.

The shutil.copy() functions behaves like the Unix cp(1) command. Both don't unlink the destination file if it already exists. As a consequence all hard links point to the updated file data. This behavior may surprise some users. Perhaps the docs should point out how shutil.copy() works when hard links join the party.

It might be worth to add a function that works similar to install(1). The install(1) command unlinks the destination first and opens it with exclusive create flags. This compensates for possible symlink attacks, too.

Christian

Shell session example of cp and install

$ echo "test1" > test1 $ echo "test2" > test2 $ ln test1 test_hardlink

now test_hardlink points to the same inodes as test1 $ cat test_hardlink test1

test_hardlink still points to the same inodes $ cp test2 test1 $ cat test_hardlink test2

reset $ echo "test1" > test1 $ cat test_hardlink test1

install unlinks the file first, test1 and test_hardlink point to different inodes $ install test2 test1 $ cat test_hardlink test1

strace of install test2 test1

stat("test1", {st_mode=S_IFREG|0755, st_size=6, ...}) = 0 stat("test2", {st_mode=S_IFREG|0664, st_size=6, ...}) = 0 lstat("test1", {st_mode=S_IFREG|0755, st_size=6, ...}) = 0 unlink("test1") = 0 open("test2", O_RDONLY) = 3 fstat(3, {st_mode=S_IFREG|0664, st_size=6, ...}) = 0 open("test1", O_WRONLY|O_CREAT|O_EXCL, 0664) = 4 fstat(4, {st_mode=S_IFREG|0664, st_size=0, ...}) = 0



More information about the Python-Dev mailing list