From 50d7e054c78fa501c82f66a351fa76b4896d2111 Mon Sep 17 00:00:00 2001 From: simon Date: Mon, 26 Feb 2001 16:39:15 +0000 Subject: [PATCH] Moderately evil workaround to compensate for a variation in behaviour of FXP_REALPATH. (Specifically, BSD and GNU realpath(3) disagree over whether to return success when computing the realpath for a putative new file to be created in a valid directory. There's no way we can tell from (say) the OpenSSH version string because OpenSSH might have been compiled to use the local realpath _or_ its own nonbroken one.) git-svn-id: svn://svn.tartarus.org/sgt/putty@953 cda61777-01e9-0310-a592-d414129be87e --- psftp.c | 71 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 69 insertions(+), 2 deletions(-) diff --git a/psftp.c b/psftp.c index 08c89e74..f4c254a5 100644 --- a/psftp.c +++ b/psftp.c @@ -94,8 +94,75 @@ char *canonify(char *name) { if (canonname) { sfree(fullname); return canonname; - } else - return fullname; + } else { + /* + * Attempt number 2. Some FXP_REALPATH implementations + * (glibc-based ones, in particular) require the _whole_ + * path to point to something that exists, whereas others + * (BSD-based) only require all but the last component to + * exist. So if the first call failed, we should strip off + * everything from the last slash onwards and try again, + * then put the final component back on. + * + * Special cases: + * + * - if the last component is "/." or "/..", then we don't + * bother trying this because there's no way it can work. + * + * - if the thing actually ends with a "/", we remove it + * before we start. Except if the string is "/" itself + * (although I can't see why we'd have got here if so, + * because surely "/" would have worked the first + * time?), in which case we don't bother. + * + * - if there's no slash in the string at all, give up in + * confusion (we expect at least one because of the way + * we constructed the string). + */ + + int i; + char *returnname; + + i = strlen(fullname); + if (i > 2 && fullname[i-1] == '/') + fullname[--i] = '\0'; /* strip trailing / unless at pos 0 */ + while (i > 0 && fullname[--i] != '/'); + + /* + * Give up on special cases. + */ + if (fullname[i] != '/' || /* no slash at all */ + !strcmp(fullname+i, "/.") || /* ends in /. */ + !strcmp(fullname+i, "/..") || /* ends in /.. */ + !strcmp(fullname, "/")) { + return fullname; + } + + /* + * Now i points at the slash. Deal with the final special + * case i==0 (ie the whole path was "/nonexistentfile"). + */ + fullname[i] = '\0'; /* separate the string */ + if (i == 0) { + canonname = fxp_realpath("/"); + } else { + canonname = fxp_realpath(fullname); + } + + if (!canonname) + return fullname; /* even that failed; give up */ + + /* + * We have a canonical name for all but the last path + * component. Concatenate the last component and return. + */ + returnname = dupcat(canonname, + canonname[strlen(canonname)-1] == '/' ? "" : "/", + fullname+i+1, NULL); + sfree(fullname); + sfree(canonname); + return returnname; + } } /* ---------------------------------------------------------------------- -- 2.11.0