Jinoh Kang (@iamahuman) commented about server/fd.c:
{ if (!fstat( fd->unix_fd, &st2 ) && st.st_ino == st2.st_ino && st.st_dev == st2.st_dev) { - if (create_link && !replace) set_error( STATUS_OBJECT_NAME_COLLISION ); + if (!create_link) + { + char src[PATH_MAX], dst[PATH_MAX]; + + /* if it's not the "same" file (by path), it means it's a hardlink, so remove the source */ + if (!realpath( fd->unix_name, src ) || !realpath( name, dst ) || (strcmp( src, dst ) && unlink( src )))
Instead of resolving the full realpath, we can check if: 1. their dirnames resolve to different dev/ino, which means they belong to a different directory, or 2. they have different basenames (even if they belong to the same directory). Granted, there might be an edge case regarding symlinks and/or mount points, but I suspect the existing code isn't fully correct in this regard either, so I guess it's fine. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/6855#note_88541