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.

classification
Title: os.rename(src,dst) does nothing when src and dst files are hard-linked
Type: behavior Stage:
Components: Versions: Python 2.7
process
Status: open Resolution:
Dependencies: Superseder:
Assigned To: Nosy List: Aaron.Swan, Esa.Peuha, eryksun, r.david.murray, vstinner
Priority: normal Keywords:

Created on 2014-06-27 17:54 by Aaron.Swan, last changed 2022-04-11 14:58 by admin.

Messages (7)
msg221699 - (view) Author: Aaron Swan (Aaron.Swan) Date: 2014-06-27 17:54
On Linux Red Hat os.rename(src,dst) does nothing when src and dst files are hard-linked.

It seems like the expected behavior would be the removal of the src file. This would be in keeping with the documentation that states: "On Unix, if dst exists and is a file, it will be replaced silently if the user has permission. "
msg221707 - (view) Author: Esa Peuha (Esa.Peuha) Date: 2014-06-27 18:46
This looks like a documentation bug. Functions in module os are usually just thin wrappers around the underlying OS functions, and POSIX states that doing nothing is the correct thing to do here. (It is arguably a bug in early Unix implementations that got mistakenly codified as part of POSIX, and it is certainly inconsistent with the POSIX requirement that the mv command *must* remove the source file in this case, but there is nothing Python can do about that.)
msg221712 - (view) Author: Aaron Swan (Aaron.Swan) Date: 2014-06-27 19:22
Although using the mv command *does* remove the src file on red hat linux, I can accept that the POSIX requirement that the source *must* be removed might not apply if source is the same as the destination file.

It would be nice if the behavior was consistent, but I think the POSIX requirements are somewhat up for interpretation in this case.

The documentation should probably be updated at the least.
msg221796 - (view) Author: R. David Murray (r.david.murray) * (Python committer) Date: 2014-06-28 15:25
It may be a backward compatibility problem to change it, but although the os functions tend to be thin wrappers, we also try to be cross platform when possible and we tend to follow what the corresponding shell command does rather than what the posix API does when there is a conflict.

Clearly this case is a grey area, but it is worth thinking about at least.  Perhaps the change could be made in the newer and more cross-platform replace.
msg221967 - (view) Author: Aaron Swan (Aaron.Swan) Date: 2014-06-30 16:54
At any rate, it is a bit of a nuisance that files remain present when the intent was to move them.
msg406482 - (view) Author: STINNER Victor (vstinner) * (Python committer) Date: 2021-11-17 18:12
It's nice if os.rename() can be atomic. It can be atomic if it is implemented as a single syscall and the source and the destination are on the same filesystem.

If we modify the implement to check if src and/or dst is a hardlink, we will need more syscalls which cannot be atomic. What if another process replaces src or dst before or after the rename() syscall?

I suggest to document the issue. Or maybe we need a new flavor which keeps the current behavior.

"Atomic write" is an old topic and no one managed to implement it in a portable way. So maybe you can ignore the atomicity constraint.
msg406491 - (view) Author: Eryk Sun (eryksun) * (Python triager) Date: 2021-11-17 20:34
> It's nice if os.rename() can be atomic. 

How about fixing the behavior in shutil.move()? Currently it tries os.rename(src, dst) without checking for this case. For example:

    >>> os.path.samefile('src', 'dst')
    True
    >>> shutil.move('src', 'dst')
    'dst'
    >>> os.path.exists('src')
    True
    >>> os.stat('src').st_nlink
    2

---

Note that there's nothing to fix, and not much to document in Windows. It works as expected. A slight difference from the general case is that os.replace() is required only when replacing a different file, not a hard link for the same file.
History
Date User Action Args
2022-04-11 14:58:05adminsetgithub: 66075
2021-11-17 20:34:15eryksunsetnosy: + eryksun
messages: + msg406491
2021-11-17 18:12:35vstinnersetmessages: + msg406482
2021-10-25 22:02:27iritkatrielsetnosy: + vstinner
2014-06-30 16:54:50Aaron.Swansetmessages: + msg221967
2014-06-28 15:25:43r.david.murraysetnosy: + r.david.murray
messages: + msg221796
2014-06-27 19:22:23Aaron.Swansetmessages: + msg221712
2014-06-27 18:46:05Esa.Peuhasetnosy: + Esa.Peuha
messages: + msg221707
2014-06-27 17:54:35Aaron.Swancreate