diff options
-rw-r--r-- | Doc/Zsh/builtins.yo | 7 | ||||
-rw-r--r-- | Src/builtin.c | 24 |
2 files changed, 28 insertions, 3 deletions
diff --git a/Doc/Zsh/builtins.yo b/Doc/Zsh/builtins.yo index 328e7db80..fb1d63569 100644 --- a/Doc/Zsh/builtins.yo +++ b/Doc/Zsh/builtins.yo @@ -682,7 +682,12 @@ item(tt(pwd) [ tt(-rLP) ])( Print the absolute pathname of the current working directory. If the tt(-r) or the tt(-P) flag is specified, or the tt(CHASE_LINKS) option is set and the tt(-L) flag is not given, the printed path will not -contain symbolic links. +contain symbolic links. Otherwise, the shell will print the stored +directory, i.e. the value to which tt($PWD) was last set. In this case, it +will check that the current tt($PWD) is still valid; if it is, or if it is +unable to find a valid path because the current directory no longer exists, +it will print that, and if it is not, it will print the full path without +symbolic links and update tt($PWD) accordingly. ) alias(r)(fc -e -) findex(read) diff --git a/Src/builtin.c b/Src/builtin.c index ae608cc39..e159c1e85 100644 --- a/Src/builtin.c +++ b/Src/builtin.c @@ -572,8 +572,28 @@ bin_pwd(char *name, char **argv, char *ops, int func) if (ops['r'] || ops['P'] || (isset(CHASELINKS) && !ops['L'])) printf("%s\n", zgetcwd()); else { - zputs(pwd, stdout); - putchar('\n'); + struct stat stdot, stpwd; + char *tmppwd; + /* + * We could print nothing and return status 1 if we can't + * stat ., but that's incompatible with both ksh and what + * we used to do. + */ + if (stat(".", &stdot) < 0 || + stat(pwd, &stpwd) >= 0 && stpwd.st_ino == stdot.st_ino) { + zputs(pwd, stdout); + putchar('\n'); + } else { + /* + * The directory has changed without us noticing it. We + * need to change pwd, since directory changing commands + * are liable to fail otherwise. + */ + zsfree(pwd); + printf("%s\n", tmppwd = zgetcwd()); + pwd = metafy(tmppwd, -1, META_DUP); + set_pwd_env(); + } } return 0; } |