diff options
Diffstat (limited to 'Src')
-rw-r--r-- | Src/Modules/files.c | 18 | ||||
-rw-r--r-- | Src/compat.c | 48 |
2 files changed, 35 insertions, 31 deletions
diff --git a/Src/Modules/files.c b/Src/Modules/files.c index ac775c75a..d01a59b03 100644 --- a/Src/Modules/files.c +++ b/Src/Modules/files.c @@ -71,7 +71,6 @@ bin_mkdir(char *nam, char **args, char *ops, int func) mode_t oumask = umask(0); mode_t mode = 0777 & ~oumask; int err = 0; - char *head; umask(oumask); if(ops['m']) { @@ -92,19 +91,8 @@ bin_mkdir(char *nam, char **args, char *ops, int func) while(ptr > *args + (**args == '/') && *--ptr == '/') *ptr = 0; - -/* Drop the tail so that pathconf receives a potentially valid pathname */ - head = (char *) ztrdup(*args); - if ((ptr = strrchr(head, '/'))) - *ptr = 0; - else { -/* Relative to current directory */ - *head = '.'; - *(head + 1) = '\0'; - } - - if(zpathmax(unmeta(head)) < 0) { - zwarnnam(nam, "%s: %e", head, errno); + if(zpathmax(unmeta(*args)) < 0) { + zwarnnam(nam, "%s: %e", *args, errno); err = 1; continue; } @@ -133,8 +121,6 @@ bin_mkdir(char *nam, char **args, char *ops, int func) } } else err |= domkdir(nam, *args, mode, 0); - - free(head); } return err; } diff --git a/Src/compat.c b/Src/compat.c index 27c9c740c..f639c8b8a 100644 --- a/Src/compat.c +++ b/Src/compat.c @@ -118,21 +118,52 @@ strerror(int errnum) * some other flag value) in order to determine that the resource is * * unlimited. What use is leaving errno unchanged? Instead, define * * a wrapper that resets errno to 0 and returns 0 for "the system * - * does not have a limit." * + * does not have a limit," so that -1 always means a real error. * * * - * This is replaced by a macro from system.h if not HAVE_PATHCONF. */ + * This is replaced by a macro from system.h if not HAVE_PATHCONF. * + * + * Note that the length of a relative path is compared without first * + * prepending the current directory, if pathconf() does not return * + * an error. This is for consistency with the macro and with older * + * zsh behavior; it may be problematic in the ENOENT/ENOTDIR cases. */ /**/ mod_export long zpathmax(char *dir) { long pathmax; + + if (!dir || !*dir) + dir = "."; errno = 0; if ((pathmax = pathconf(dir, _PC_PATH_MAX)) >= 0) { + /* This code is redundant if pathconf works correctly, but * + * some versions of glibc pathconf return a hardwired value. */ if (strlen(dir) < pathmax) return pathmax; else errno = ENAMETOOLONG; + } else if (errno == ENOENT || errno == ENOTDIR) { + /* Work backward to find a directory, until we run out of path. */ + char *tail = strrchr(dir, '/'); + while (tail > dir && tail[-1] == '/') + --tail; + if (tail > dir) { + *tail = 0; + pathmax = zpathmax(dir); + *tail = '/'; + if (pathmax > 0) { + if (strlen(dir) < pathmax) + return pathmax; + else + errno = ENAMETOOLONG; + } + } + /* else * + * Either we're at the root (tail == dir) or we're on the first * + * component of a relative path (tail == NULL). Either way we * + * have nothing to do here, the error from pathconf() is real. * + * Perhaps our current working directory has been removed? */ } if (errno) return -1; @@ -141,19 +172,6 @@ zpathmax(char *dir) } #endif -/**/ -mod_export char * -zrealpath(const char *path, char *resolved_path) -{ -#ifdef HAVE_REALPATH - return realpath(path, resolved_path); -#else /* the following block should be replaced with a realpath() equiv. */ - long pathmax; - - if ((pathmax = zpathmax(path)) > 0) - return strncpy(resolved_path, path, pathmax); -#endif -} /**/ mod_export char * |