- register char *sp;
- register char *p1, *p2; /* general purpose */
- bool slash;
-
- if (*cp != '/')
- abort();
- while (*p) { /* for each component */
- sp = p; /* save slash address */
- while (*++p == '/') /* flush extra slashes */
- ;
- if (p != ++sp)
- for (p1 = sp, p2 = p; *p1++ = *p2++;)
- ;
- p = sp; /* save start of component */
- slash = 0;
- while (*++p) /* find next slash or end of path */
- if (*p == '/') {
- slash = 1;
- *p = 0;
- break;
- }
- if (*sp == '\0') /* if component is null */
- if (--sp == cp) /* if path is one char (i.e. /) */
- break;
- else
- *sp = '\0';
- else if (sp[0] == '.' && sp[1] == 0) {
- if (slash) {
- for (p1 = sp, p2 = p + 1; *p1++ = *p2++;)
- ;
- p = --sp;
- } else if (--sp != cp)
- *sp = '\0';
- } else if (sp[0] == '.' && sp[1] == '.' && sp[2] == 0) {
- char link[MAXPATHLEN];
- int cc;
- char *newcp;
-
- /*
- * We have something like "yyy/xxx/..", where "yyy"
- * can be null or a path starting at /, and "xxx"
- * is a single component.
- * Before compressing "xxx/..", we want to expand
- * "yyy/xxx", if it is a symbolic link.
- */
- *--sp = 0; /* form the pathname for readlink */
- if (sp != cp &&
- (cc = readlink(cp, link, sizeof link)) >= 0) {
- link[cc] = '\0';
- if (slash)
- *p = '/';
- /*
- * Point p to the '/' in "/..", and restore
- * the '/'.
- */
- *(p = sp) = '/';
- /*
- * find length of p
- */
- for (p1 = p; *p1++;)
- ;
- if (*link != '/') {
- /*
- * Relative path, expand it between
- * the "yyy/" and the "/..".
- * First, back sp up to the character
- * past "yyy/".
- */
- while (*--sp != '/')
- ;
- sp++;
- *sp = 0;
- /*
- * New length is
- * "yyy/" + link + "/.." and rest
- */
- p1 = newcp = xalloc((unsigned)
- ((sp - cp) + cc + (p1 - p)));
- /*
- * Copy new path into newcp
- */
- for (p2 = cp; *p1++ = *p2++;)
- ;
- for (p1--, p2 = link; *p1++ = *p2++;)
- ;
- for (p1--, p2 = p; *p1++ = *p2++;)
- ;
- /*
- * Restart canonicalization at
- * expanded "/xxx".
- */
- p = sp - cp - 1 + newcp;
- } else {
- /*
- * New length is link + "/.." and rest
- */
- p1 = newcp = xalloc((unsigned)
- (cc + (p1 - p)));
- /*
- * Copy new path into newcp
- */
- for (p2 = link; *p1++ = *p2++;)
- ;
- for (p1--, p2 = p; *p1++ = *p2++;)
- ;
- /*
- * Restart canonicalization at beginning
- */
- p = newcp;
- }
- xfree(cp);
- cp = newcp;
- continue; /* canonicalize the link */
- }
- *sp = '/';
- if (sp != cp)
- while (*--sp != '/')
- ;
- if (slash) {
- for (p1 = sp + 1, p2 = p + 1; *p1++ = *p2++;)
- ;
- p = sp;
- } else if (cp == sp)
- *++sp = '\0';
- else
- *sp = '\0';
- } else if (slash)
- *p = '/';
+ register Char *sp;
+ register Char *p1, *p2; /* general purpose */
+ bool slash;
+
+ Char link[MAXPATHLEN];
+ char tlink[MAXPATHLEN];
+ int cc;
+ Char *newcp;
+
+ /*
+ * christos: if the path given does not start with a slash prepend cwd. If
+ * cwd does not start with a path or the result would be too long abort().
+ */
+ if (*cp != '/') {
+ Char tmpdir[MAXPATHLEN];
+
+ p1 = value(STRcwd);
+ if (p1 == NULL || *p1 != '/')
+ abort();
+ if (Strlen(p1) + Strlen(cp) + 1 >= MAXPATHLEN)
+ abort();
+ (void) Strcpy(tmpdir, p1);
+ (void) Strcat(tmpdir, STRslash);
+ (void) Strcat(tmpdir, cp);
+ xfree((ptr_t) cp);
+ cp = p = Strsave(tmpdir);
+ }
+
+ while (*p) { /* for each component */
+ sp = p; /* save slash address */
+ while (*++p == '/') /* flush extra slashes */
+ ;
+ if (p != ++sp)
+ for (p1 = sp, p2 = p; *p1++ = *p2++;);
+ p = sp; /* save start of component */
+ slash = 0;
+ while (*++p) /* find next slash or end of path */
+ if (*p == '/') {
+ slash = 1;
+ *p = 0;
+ break;
+ }
+
+ if (*sp == '\0') /* if component is null */
+ if (--sp == cp) /* if path is one char (i.e. /) */
+ break;
+ else
+ *sp = '\0';
+ else if (sp[0] == '.' && sp[1] == 0) {
+ if (slash) {
+ for (p1 = sp, p2 = p + 1; *p1++ = *p2++;);
+ p = --sp;
+ }
+ else if (--sp != cp)
+ *sp = '\0';
+ }
+ else if (sp[0] == '.' && sp[1] == '.' && sp[2] == 0) {
+ /*
+ * We have something like "yyy/xxx/..", where "yyy" can be null or
+ * a path starting at /, and "xxx" is a single component. Before
+ * compressing "xxx/..", we want to expand "yyy/xxx", if it is a
+ * symbolic link.
+ */
+ *--sp = 0; /* form the pathname for readlink */
+ if (sp != cp && !adrof(STRignore_symlinks) &&
+ (cc = readlink(short2str(cp), tlink,
+ sizeof tlink)) >= 0) {
+ (void) Strcpy(link, str2short(tlink));
+ link[cc] = '\0';
+
+ if (slash)
+ *p = '/';
+ /*
+ * Point p to the '/' in "/..", and restore the '/'.
+ */
+ *(p = sp) = '/';
+ /*
+ * find length of p
+ */
+ for (p1 = p; *p1++;);
+ if (*link != '/') {
+ /*
+ * Relative path, expand it between the "yyy/" and the
+ * "/..". First, back sp up to the character past "yyy/".
+ */
+ while (*--sp != '/');
+ sp++;
+ *sp = 0;
+ /*
+ * New length is "yyy/" + link + "/.." and rest
+ */
+ p1 = newcp = (Char *) xmalloc((size_t)
+ (((sp - cp) + cc + (p1 - p)) *
+ sizeof(Char)));
+ /*
+ * Copy new path into newcp
+ */
+ for (p2 = cp; *p1++ = *p2++;);
+ for (p1--, p2 = link; *p1++ = *p2++;);
+ for (p1--, p2 = p; *p1++ = *p2++;);
+ /*
+ * Restart canonicalization at expanded "/xxx".
+ */
+ p = sp - cp - 1 + newcp;
+ }
+ else {
+ /*
+ * New length is link + "/.." and rest
+ */
+ p1 = newcp = (Char *) xmalloc((size_t)
+ ((cc + (p1 - p)) * sizeof(Char)));
+ /*
+ * Copy new path into newcp
+ */
+ for (p2 = link; *p1++ = *p2++;);
+ for (p1--, p2 = p; *p1++ = *p2++;);
+ /*
+ * Restart canonicalization at beginning
+ */
+ p = newcp;
+ }
+ xfree((ptr_t) cp);
+ cp = newcp;
+ continue; /* canonicalize the link */
+ }
+ *sp = '/';
+ if (sp != cp)
+ while (*--sp != '/');
+ if (slash) {
+ for (p1 = sp + 1, p2 = p + 1; *p1++ = *p2++;);
+ p = sp;
+ }
+ else if (cp == sp)
+ *++sp = '\0';
+ else
+ *sp = '\0';
+ }
+ else { /* normal dir name (not . or .. or nothing) */
+
+ if (sp != cp && adrof(STRchase_symlinks) &&
+ !adrof(STRignore_symlinks) &&
+ (cc = readlink(short2str(cp), tlink,
+ sizeof tlink)) >= 0) {
+ (void) Strcpy(link, str2short(tlink));
+ link[cc] = '\0';
+
+ /*
+ * restore the '/'.
+ */
+ if (slash)
+ *p = '/';
+
+ /*
+ * point sp to p (rather than backing up).
+ */
+ sp = p;
+
+ /*
+ * find length of p
+ */
+ for (p1 = p; *p1++;);
+ if (*link != '/') {
+ /*
+ * Relative path, expand it between the "yyy/" and the
+ * remainder. First, back sp up to the character past
+ * "yyy/".
+ */
+ while (*--sp != '/');
+ sp++;
+ *sp = 0;
+ /*
+ * New length is "yyy/" + link + "/.." and rest
+ */
+ p1 = newcp = (Char *) xmalloc((size_t)
+ (((sp - cp) + cc + (p1 - p))
+ * sizeof(Char)));
+ /*
+ * Copy new path into newcp
+ */
+ for (p2 = cp; *p1++ = *p2++;);
+ for (p1--, p2 = link; *p1++ = *p2++;);
+ for (p1--, p2 = p; *p1++ = *p2++;);
+ /*
+ * Restart canonicalization at expanded "/xxx".
+ */
+ p = sp - cp - 1 + newcp;
+ }
+ else {
+ /*
+ * New length is link + the rest
+ */
+ p1 = newcp = (Char *) xmalloc((size_t)
+ ((cc + (p1 - p)) * sizeof(Char)));
+ /*
+ * Copy new path into newcp
+ */
+ for (p2 = link; *p1++ = *p2++;);
+ for (p1--, p2 = p; *p1++ = *p2++;);
+ /*
+ * Restart canonicalization at beginning
+ */
+ p = newcp;
+ }
+ xfree((ptr_t) cp);
+ cp = newcp;
+ continue; /* canonicalize the link */
+ }
+ if (slash)
+ *p = '/';
+ }
+ }
+
+ /*
+ * fix home...
+ */
+ p1 = value(STRhome);
+ cc = Strlen(p1);
+ /*
+ * See if we're not in a subdir of STRhome
+ */
+ if (p1 && *p1 &&
+ (Strncmp(p1, cp, cc) != 0 || (cp[cc] != '/' && cp[cc] != '\0'))) {
+ static ino_t home_ino = -1;
+ static dev_t home_dev = -1;
+ static Char *home_ptr = NULL;
+ struct stat statbuf;
+
+ /*
+ * Get dev and ino of STRhome
+ */
+ if (home_ptr != p1 &&
+ stat(short2str(p1), &statbuf) != -1) {
+ home_dev = statbuf.st_dev;
+ home_ino = statbuf.st_ino;
+ home_ptr = p1;