Jinoh Kang (@iamahuman) commented about server/fd.c:
- if (!is_dir)
- {
/* we can't just do rename(2) here; renaming a file to its hardlink is no-op */
if (linkat( dirfd, tmpname, dirfd, dstname, 0 ) && errno != EEXIST)
{
if (errno == EPERM || errno == EOPNOTSUPP)
{
/* FIXME: filesystem doesn't support hardlinks, entire operation might be a no-op on casefold dirs */
if (renameat( dirfd, tmpname, dirfd, dstname ))
file_set_error();
goto ret;
}
file_set_error();
/* revert the temporary rename */
renameat( dirfd, tmpname, dirfd, srcname );
Let's make this a common logic for all cases (hardlink, no hardlink, & dir).
Something like this (untested):
```c int undo_tmp_rename = 0;
(...)
undo_tmp_rename = 1;
/* directories can't have hardlinks */ if (!is_dir) { /* we can't just do rename(2) here; renaming a file to its hardlink is no-op */ if (linkat( dirfd, tmpname, dirfd, dstname, 0 ) && errno != EEXIST) { if (errno != EPERM && errno != EOPNOTSUPP) { file_set_error(); goto ret; }
/* Filesystem doesn't support hardlinks, fall back to renaming */ } else { undo_tmp_rename = 0;
if (unlinkat( dirfd, tmpname, 0 )) file_set_error();
goto ret; /* We're done */ } }
/* Renaming a directory, or filesystem doesn't support hardlinks */ if (renameat( dirfd, tmpname, dirfd, dstname )) file_set_error(); else undo_tmp_rename = 0;
ret: if (undo_tmp_rename) { /* revert the temporary rename */ renameat( dirfd, tmpname, dirfd, srcname ); } ```