/* Like getcwd(), except bsize is ignored if buf is 0 (PATH_MAX is used) */ char * ksh_get_wd(char *buf, int bsize) { char *b; char *ret; /* Note: we could just use plain getcwd(), but then we'd had to * inject possibly allocated space into the ATEMP area. */ /* Assume getcwd() available */ if (!buf) { bsize = MAXPATHLEN; b = alloc(MAXPATHLEN + 1, ATEMP); } else b = buf; ret = getcwd(b, bsize); if (!buf) { if (ret) ret = aresize(b, strlen(b) + 1, ATEMP); else afree(b, ATEMP); } return ret; }
/* called from expand.h:XcheckN() to grow buffer */ char * Xcheck_grow_(XString *xsp, char *xp, int more) { char *old_beg = xsp->beg; xsp->len += more > xsp->len ? more : xsp->len; xsp->beg = aresize(xsp->beg, xsp->len + 8, xsp->areap); xsp->end = xsp->beg + xsp->len; return xsp->beg + (xp - old_beg); }
/* called from XcheckN() to grow buffer */ char * Xcheck_grow(XString *xsp, const char *xp, size_t more) { const char *old_beg = xsp->beg; if (more < xsp->len) more = xsp->len; /* (xsp->len + X_EXTRA) never overflows */ checkoktoadd(more, xsp->len + X_EXTRA); xsp->beg = aresize(xsp->beg, (xsp->len += more) + X_EXTRA, xsp->areap); xsp->end = xsp->beg + xsp->len; return (xsp->beg + (xp - old_beg)); }
void set_current_wd(char *path) { int len; char *p = path; if (!p && !(p = ksh_get_wd((char *) 0, 0))) p = null; len = strlen(p) + 1; if (len > current_wd_size) current_wd = aresize(current_wd, current_wd_size = len, APERM); memcpy(current_wd, p, len); if (p != path && p != null) afree(p, ATEMP); }
/* Like getcwd(), except bsize is ignored if buf is 0 (PATH_MAX is used) */ char * ksh_get_wd(size_t *dlen) { char *ret, *b; size_t len = 1; #ifdef NO_PATH_MAX if ((b = get_current_dir_name())) { len = strlen(b) + 1; strndupx(ret, b, len - 1, ATEMP); free(b); } else ret = NULL; #else if ((ret = getcwd((b = alloc(PATH_MAX + 1, ATEMP)), PATH_MAX))) ret = aresize(b, len = (strlen(b) + 1), ATEMP); else afree(b, ATEMP); #endif if (dlen) *dlen = len; return (ret); }
char * do_realpath(const char *upath) { char *xp, *ip, *tp, *ipath, *ldest = NULL; XString xs; size_t pos, len; int llen; struct stat sb; #ifdef MKSH__NO_PATH_MAX size_t ldestlen = 0; #define pathlen sb.st_size #define pathcnd (ldestlen < (pathlen + 1)) #else #define pathlen PATH_MAX #define pathcnd (!ldest) #endif /* max. recursion depth */ int symlinks = 32; if (mksh_abspath(upath)) { /* upath is an absolute pathname */ strdupx(ipath, upath, ATEMP); } else { /* upath is a relative pathname, prepend cwd */ if ((tp = ksh_get_wd()) == NULL || !mksh_abspath(tp)) return (NULL); ipath = shf_smprintf("%s%s%s", tp, "/", upath); afree(tp, ATEMP); } /* ipath and upath are in memory at the same time -> unchecked */ Xinit(xs, xp, strlen(ip = ipath) + 1, ATEMP); /* now jump into the deep of the loop */ goto beginning_of_a_pathname; while (*ip) { /* skip slashes in input */ while (*ip == '/') ++ip; if (!*ip) break; /* get next pathname component from input */ tp = ip; while (*ip && *ip != '/') ++ip; len = ip - tp; /* check input for "." and ".." */ if (tp[0] == '.') { if (len == 1) /* just continue with the next one */ continue; else if (len == 2 && tp[1] == '.') { /* strip off last pathname component */ while (xp > Xstring(xs, xp)) if (*--xp == '/') break; /* then continue with the next one */ continue; } } /* store output position away, then append slash to output */ pos = Xsavepos(xs, xp); /* 1 for the '/' and len + 1 for tp and the NUL from below */ XcheckN(xs, xp, 1 + len + 1); Xput(xs, xp, '/'); /* append next pathname component to output */ memcpy(xp, tp, len); xp += len; *xp = '\0'; /* lstat the current output, see if it's a symlink */ if (mksh_lstat(Xstring(xs, xp), &sb)) { /* lstat failed */ if (errno == ENOENT) { /* because the pathname does not exist */ while (*ip == '/') /* skip any trailing slashes */ ++ip; /* no more components left? */ if (!*ip) /* we can still return successfully */ break; /* more components left? fall through */ } /* not ENOENT or not at the end of ipath */ goto notfound; } /* check if we encountered a symlink? */ if (S_ISLNK(sb.st_mode)) { #ifndef MKSH__NO_SYMLINK /* reached maximum recursion depth? */ if (!symlinks--) { /* yep, prevent infinite loops */ errno = ELOOP; goto notfound; } /* get symlink(7) target */ if (pathcnd) { #ifdef MKSH__NO_PATH_MAX if (notoktoadd(pathlen, 1)) { errno = ENAMETOOLONG; goto notfound; } #endif ldest = aresize(ldest, pathlen + 1, ATEMP); } llen = readlink(Xstring(xs, xp), ldest, pathlen); if (llen < 0) /* oops... */ goto notfound; ldest[llen] = '\0'; /* * restart if symlink target is an absolute path, * otherwise continue with currently resolved prefix */ /* append rest of current input path to link target */ tp = shf_smprintf("%s%s%s", ldest, *ip ? "/" : "", ip); afree(ipath, ATEMP); ip = ipath = tp; if (!mksh_abspath(ldest)) { /* symlink target is a relative path */ xp = Xrestpos(xs, xp, pos); } else #endif { /* symlink target is an absolute path */ xp = Xstring(xs, xp); beginning_of_a_pathname: /* assert: (ip == ipath)[0] == '/' */ /* assert: xp == xs.beg => start of path */ /* exactly two leading slashes? (SUSv4 3.266) */ if (ip[1] == '/' && ip[2] != '/') { /* keep them, e.g. for UNC pathnames */ Xput(xs, xp, '/'); } } } /* otherwise (no symlink) merely go on */ } /* * either found the target and successfully resolved it, * or found its parent directory and may create it */ if (Xlength(xs, xp) == 0) /* * if the resolved pathname is "", make it "/", * otherwise do not add a trailing slash */ Xput(xs, xp, '/'); Xput(xs, xp, '\0'); /* * if source path had a trailing slash, check if target path * is not a non-directory existing file */ if (ip > ipath && ip[-1] == '/') { if (stat(Xstring(xs, xp), &sb)) { if (errno != ENOENT) goto notfound; } else if (!S_ISDIR(sb.st_mode)) { errno = ENOTDIR; goto notfound; } /* target now either does not exist or is a directory */ } /* return target path */ if (ldest != NULL) afree(ldest, ATEMP); afree(ipath, ATEMP); return (Xclose(xs, xp)); notfound: /* save; freeing memory might trash it */ llen = errno; if (ldest != NULL) afree(ldest, ATEMP); afree(ipath, ATEMP); Xfree(xs, xp); errno = llen; return (NULL); #undef pathlen #undef pathcnd }
/* Like getcwd(), except bsize is ignored if buf is 0 (MAXPATHLEN is used) */ char * ksh_get_wd(char *buf, int bsize) { #ifdef HAVE_GETCWD char *b; char *ret; /* Before memory allocated */ HPUX_GETWD_BUG_CODE /* Assume getcwd() available */ if (!buf) { bsize = MAXPATHLEN; b = alloc(MAXPATHLEN + 1, ATEMP); } else b = buf; ret = getcwd(b, bsize); if (!buf) { if (ret) ret = aresize(b, strlen(b) + 1, ATEMP); else afree(b, ATEMP); } return ret; #else /* HAVE_GETCWD */ extern char *getwd(char *); char *b; int len; /* Before memory allocated */ HPUX_GETWD_BUG_CODE if (buf && bsize > MAXPATHLEN) b = buf; else b = alloc(MAXPATHLEN + 1, ATEMP); if (!getwd(b)) { errno = EACCES; if (b != buf) afree(b, ATEMP); return (char *) 0; } len = strlen(b) + 1; if (!buf) b = aresize(b, len, ATEMP); else if (buf != b) { if (len > bsize) { errno = ERANGE; return (char *) 0; } memcpy(buf, b, len); afree(b, ATEMP); b = buf; } return b; #endif /* HAVE_GETCWD */ }