sshfs uses the SSH File Transfer Protocol (SFTP). The workaround that you have enabled is working around the semantics of a rename() operation over that protocol when the "new" name already exists.
The POSIX behavior for rename() in this case is to remove the existing file and complete the rename.
In the SFTP protocol, you can rename a file with the SSH_FXP_RENAME operation; however, its behavior when the target name already exists seems to depend on the version of the protocol you are using and what flags you pass. The wikipedia page for the SFTP protocol has links to various draft RFCs for various versions of the protocol. In Draft 00 the behavior is listed as:
It is an error if there already exists a file with the name
specified by newpath.
In Draft 13, the behavior is listed as
If flags does not include SSH_FXP_RENAME_OVERWRITE, and there already
exists a file with the name specified by newpath, the server MUST
respond with SSH_FX_FILE_ALREADY_EXISTS.
If flags includes SSH_FXP_RENAME_ATOMIC, and the destination file
already exists, it is replaced in an atomic fashion. I.e., there is
no observable instant in time where the name does not refer to either
the old or the new file. SSH_FXP_RENAME_ATOMIC implies
SSH_FXP_RENAME_OVERWRITE.
To deal with the possible failure of a rename() operation when the target name exists, sshfs provides the following workaround (if enabled):
if (err == -EPERM && sshfs.rename_workaround) {
size_t tolen = strlen(to);
if (tolen + RENAME_TEMP_CHARS < PATH_MAX) {
int tmperr;
char totmp[PATH_MAX];
strcpy(totmp, to);
random_string(totmp + tolen, RENAME_TEMP_CHARS);
tmperr = sshfs_do_rename(to, totmp);
if (!tmperr) {
err = sshfs_do_rename(from, to);
if (!err)
err = sshfs_unlink(totmp);
else
sshfs_do_rename(totmp, to);
}
}
}
In this code "from" is the existing name of the file we want to rename and "to" is the new name we want. Putting some path length and error bookkeeping aside, this work around
- Renames "to" to "totmp"
- Renames "from" to "to"
- Unlinks (deletes) "totmp"
This avoids the "file already exists" conflict, but also changes the semantics of the rename() operations, which is why you wouldn't want to do it by default.