From 8e2bfd7c4b9d5ffa5afe7499a87cd9f6f1b594f9 Mon Sep 17 00:00:00 2001 From: Miklos Szeredi Date: Mon, 17 Oct 2005 16:01:45 +0000 Subject: fix --- ChangeLog | 3 +++ sshfs.c | 46 +++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 48 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 0439a59..0e8db4c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -2,6 +2,9 @@ * Add one more missing lock. + * Add workaround for failure to rename to an existing file. Based + on patch by Michael Best + 2005-10-15 Miklos Szeredi * Protect request ID allocation with mutex. Bug report by Tvrtko diff --git a/sshfs.c b/sshfs.c index d69c5f0..957112a 100644 --- a/sshfs.c +++ b/sshfs.c @@ -85,6 +85,10 @@ #define MAX_REPLY_LEN (1 << 17) +#define RENAME_TEMP_CHARS 8 + +static unsigned int randseed; + static int infd; static int outfd; static int connver; @@ -93,6 +97,7 @@ static int debug = 0; static int reconnect = 0; static int sync_write = 0; static int sync_read = 0; +static int rename_workaround = 0; static char *base_path; static char *host; static unsigned blksize = 4096; @@ -200,6 +205,7 @@ enum { SOPT_MAX_READ, SOPT_DEBUG, SOPT_RECONNECT, + SOPT_RENAME_FIX, SOPT_LAST /* Last entry in this list! */ }; @@ -211,6 +217,7 @@ static struct opt sshfs_opts[] = { [SOPT_MAX_READ] = { .optname = "max_read" }, [SOPT_DEBUG] = { .optname = "sshfs_debug" }, [SOPT_RECONNECT] = { .optname = "reconnect" }, + [SOPT_RENAME_FIX] = { .optname = "rename_workaround" }, [SOPT_LAST] = { .optname = NULL } }; @@ -1196,7 +1203,7 @@ static int sshfs_rmdir(const char *path) return err; } -static int sshfs_rename(const char *from, const char *to) +static int sshfs_do_rename(const char *from, const char *to) { int err; struct buffer buf; @@ -1208,6 +1215,38 @@ static int sshfs_rename(const char *from, const char *to) return err; } +static void random_string(char *str, int length) +{ + int i; + for (i = 0; i < length; i++) + *str++ = (char)('0' + rand_r(&randseed) % 10); + *str = '\0'; +} + +static int sshfs_rename(const char *from, const char *to) +{ + int err; + err = sshfs_do_rename(from, to); + if (err == -EPERM && 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); + } + } + } + return err; +} + static int sshfs_chmod(const char *path, mode_t mode) { int err; @@ -1692,6 +1731,7 @@ static void usage(const char *progname) " -o cache=YESNO enable caching {yes,no} (default: yes)\n" " -o cache_timeout=N sets timeout for caches in seconds (default: 20)\n" " -o cache_X_timeout=N sets timeout for {stat,dir,link} cache\n" +" -o rename_workaround work around problem renaming to existing file" " -o ssh_command=CMD execute CMD instead of 'ssh'\n" " -o directport=PORT directly connect to PORT bypassing ssh\n" " -o SSHOPT=VAL ssh options (see man ssh_config)\n" @@ -1777,6 +1817,8 @@ int main(int argc, char *argv[]) sync_read = 1; if (sshfs_opts[SOPT_DEBUG].present) debug = 1; + if (sshfs_opts[SOPT_RENAME_FIX].present) + rename_workaround = 1; if (sshfs_opts[SOPT_RECONNECT].present) reconnect = 1; if (sshfs_opts[SOPT_MAX_READ].present) { @@ -1808,6 +1850,8 @@ int main(int argc, char *argv[]) if (res == -1) exit(1); + randseed = time(0); + newargv[newargc++] = g_strdup_printf("-omax_read=%u", max_read); newargv[newargc++] = g_strdup_printf("-ofsname=sshfs#%s", fsname); g_free(fsname); -- cgit v1.2.3