mirror of
https://git.tartarus.org/simon/putty.git
synced 2025-01-09 09:27:59 +00:00
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.) [originally from svn r953]
This commit is contained in:
parent
1129d200e4
commit
b10bc57b03
71
psftp.c
71
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;
|
||||
}
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------
|
||||
|
Loading…
Reference in New Issue
Block a user