#ifdef HAVE_DOS_PATHS #define IS_ABSOLUTE(n) (n[0] && n[1] == ':' || IS_PATHSEP(n[0]) && IS_PATHSEP(n[1])) #define ROOT_LEN 3 #else #define IS_ABSOLUTE(n) (n[0] == '/') #define ROOT_LEN 1 #endif /* Return the absolute name of file NAME which does not contain any `.', `..' components nor any repeated path separators ('/'). */ static char * abspath (const char *name, char *apath) { char *dest; const char *start, *end, *apath_limit; unsigned long root_len = ROOT_LEN; if (name[0] == '\0' || apath == NULL) return NULL; apath_limit = apath + GET_PATH_MAX; if (!IS_ABSOLUTE(name)) { /* It is unlikely we would make it until here but just to make sure. */ if (!starting_directory) return NULL; strcpy (apath, starting_directory); #ifdef HAVE_DOS_PATHS if (IS_PATHSEP(name[0])) { /* We have /foo, an absolute file name except for the drive letter. Assume the missing drive letter is the current drive, which we can get if we remove from starting_directory everything past the root directory. */ apath[root_len] = '\0'; } #endif dest = strchr (apath, '\0'); } else { strncpy (apath, name, root_len); apath[root_len] = '\0'; dest = apath + root_len; /* Get past the root, since we already copied it. */ name += root_len; #ifdef HAVE_DOS_PATHS if (IS_PATHSEP(apath[0])) { /* Convert \\foo into //foo and decrease root_len. */ apath[0] = '/'; apath[1] = '/'; dest--; root_len--; /* strncpy above copied one character too many. */ name--; } else { if (!IS_PATHSEP(apath[2])) { /* Convert d:foo into d:./foo and increase root_len. */ apath[2] = '.'; apath[3] = '/'; dest++; root_len++; /* strncpy above copied one character too many. */ name--; } else apath[2] = '/'; /* make sure it's a forward slash */ } #endif } for (start = end = name; *start != '\0'; start = end) { unsigned long len; /* Skip sequence of multiple path-separators. */ while (IS_PATHSEP(*start)) ++start; /* Find end of path component. */ for (end = start; *end != '\0' && !IS_PATHSEP(*end); ++end) ; len = end - start; if (len == 0) break; else if (len == 1 && start[0] == '.') /* nothing */; else if (len == 2 && start[0] == '.' && start[1] == '.') { /* Back up to previous component, ignore if at root already. */ if (dest > apath + root_len) for (--dest; !IS_PATHSEP(dest[-1]); --dest); } else { if (!IS_PATHSEP(dest[-1])) *dest++ = '/'; if (dest + len >= apath_limit) return NULL; dest = memcpy (dest, start, len); dest += len; *dest = '\0'; } } /* Unless it is root strip trailing separator. */ if (dest > apath + root_len && IS_PATHSEP(dest[-1])) --dest; *dest = '\0'; return apath; }