2956e9fa8365d70401240fb1626b17ea670d7e4a galt Tue Nov 7 12:38:05 2017 -0800 Feedback from code review improvements. diff --git src/lib/filePath.c src/lib/filePath.c index 62b2030..7da8293 100644 --- src/lib/filePath.c +++ src/lib/filePath.c @@ -1,193 +1,215 @@ /* filePath - stuff to handle file name parsing. */ /* Copyright (C) 2011 The Regents of the University of California * See README in this or parent directory for licensing information. */ #include "common.h" #include "filePath.h" void undosPath(char *path) /* Convert '\' to '/' in path. */ { subChar(path, '\\', '/'); } void splitPath(char *path, char dir[PATH_LEN], char name[FILENAME_LEN], char extension[FILEEXT_LEN]) /* Split a full path into components. The dir component will include the * trailing / if any. The extension component will include the starting * . if any. Pass in NULL for dir, name, or extension if you don't care about * that part. */ { char *dirStart, *nameStart, *extStart, *extEnd; int dirSize, nameSize, extSize; undosPath(path); dirStart = path; nameStart = strrchr(path,'/'); if (nameStart == NULL) nameStart = path; else nameStart += 1; extStart = strrchr(nameStart, '.'); if (extStart == NULL) extStart = nameStart + strlen(nameStart); extEnd = extStart + strlen(extStart); if ((dirSize = (nameStart - dirStart)) >= PATH_LEN) errAbort("Directory too long in %s", path); if ((nameSize = (extStart - nameStart)) >= FILENAME_LEN) errAbort("Name too long in %s", path); if ((extSize = (extEnd - extStart)) >= FILEEXT_LEN) errAbort("Extension too long in %s", path); if (dir != NULL) { memcpy(dir, dirStart, dirSize); dir[dirSize] = 0; } if (name != NULL) { memcpy(name, nameStart, nameSize); name[nameSize] = 0; } if (extension != NULL) { memcpy(extension, extStart, extSize); extension[extSize] = 0; } } static char *findSlashBefore(char *start, char *e) /* Return first slash before s (but not before start) */ { while (--e >= start) { if (*e == '/') return e; } return start; } char *expandRelativePath(char *baseDir, char *relPath) /* Expand relative path to more absolute one. */ { if (relPath[0] == '/') // hey, it's absolute actually... return cloneString(relPath); char *e = baseDir + strlen(baseDir); int slashCount; char *rel = relPath; char *result; int size, baseSize; undosPath(baseDir); undosPath(relPath); slashCount = countChars(baseDir, '/'); if (baseDir[0] == 0) slashCount = -1; while (startsWith("../", rel)) { if (slashCount < 0) { warn("More ..'s in \"%s\" than directories in \"%s\"", relPath, baseDir); return NULL; } else if (slashCount == 0) e = baseDir; else e = findSlashBefore(baseDir, e); slashCount -= 1; rel += 3; } baseSize = e - baseDir; size = strlen(rel) + 1; if (baseSize > 0) size += baseSize + 1; if (baseSize > 0) { result = needMem(size); memcpy(result, baseDir, baseSize); result[baseSize] = '/'; strcpy(result + baseSize + 1, rel); } else result = cloneString(rel); return result; } +char *mustExpandRelativePath(char *dir, char* relPath) +/* Given a dir and relative path, expand path. + * Handy for processing symlinks. errAbort if expand fails. + * Result should be freeMem'd.*/ +{ +char *path = expandRelativePath(dir, relPath); +verbose(3, "dir=%s\nrelPath=%s\npath=%s\n", dir, relPath, path); +if (!path) + errAbort("Too many .. in path %s to make relative to submitDir %s\n", relPath, dir); +return path; +} + char *pathRelativeToFile(char *baseFile, char *relPath) /* Given a base file name and a path relative to that, return * relative path interpreted as if it were seen from the * same directory holding the baseFile. * An example of using this would be in processing include * files. In this case the baseFile would be the current * source file, and the relPath would be from the include * statement. The returned result could then be used to * open the include file. */ { char dir[PATH_LEN]; splitPath(baseFile, dir, NULL, NULL); int dirLen = strlen(dir); if (dirLen > 0 && dir[dirLen-1] == '/') dir[dirLen-1] = 0; return expandRelativePath(dir, relPath); } +char *mustPathRelativeToFile(char *baseFile, char *relPath) +/* Make Path Relative To File or Abort. */ +{ +char *path = pathRelativeToFile(baseFile, relPath); +verbose(3, "baseFile=%s\nrelPath=%s\npath=%s\n", baseFile, relPath, path); +if (!path) + errAbort("Too many .. in symlink path %s to make relative to %s\n", relPath, baseFile); +return path; +} + char *makeRelativePath(char *from, char *to) /* Calculate a relative path from one absolute directory/file to another. * Assumptions: both from and to are canonicalized absolute paths beginning * at "/" or "//". Filenames are okay, but all directory names must end with * a "/" to distinguish them from files. * e.g., /test/dir/ is a directory, but /test/dir is a file. */ { int i, j, toCount, fromCount; char fromDir[PATH_LEN]; char toDir[PATH_LEN], toFile[FILENAME_LEN], toExt[FILEEXT_LEN]; char relPath [PATH_LEN] = ""; char *fromDirList[PATH_LEN], *toDirList[PATH_LEN]; boolean fromStartsDoubleSlash = FALSE, toStartsDoubleSlash = FALSE; if (startsWith("//", from) && from[2] != '/') { fromStartsDoubleSlash = TRUE; from[1] = '_'; // prevent initial // from being misinterpreted } if (startsWith("//", to) && to[2] != '/') { toStartsDoubleSlash = TRUE; to[1] = '_'; // prevent initial // from being misinterpreted } splitPath(from, fromDir, NULL, NULL); splitPath(to, toDir, toFile, toExt); fromCount = chopByChar(fromDir, '/', fromDirList, ArraySize(fromDirList)); toCount = chopByChar(toDir, '/', toDirList, ArraySize(toDirList)); if (fromStartsDoubleSlash == TRUE) fromDirList[1][0] = '/'; if (toStartsDoubleSlash == TRUE) toDirList[1][0] = '/'; for (i=1; i < min(fromCount-1, toCount-1); i++) { if (!sameString(fromDirList[i], toDirList[i])) break; } for (j=i; j < fromCount-1; j++) { safecat(relPath, sizeof relPath, "../"); } for (j=i; j < toCount-1; j++) { safecat(relPath, sizeof relPath, toDirList[j]); safecat(relPath, sizeof relPath, "/"); } safecat(relPath, sizeof relPath, toFile); safecat(relPath, sizeof relPath, toExt); return cloneString(relPath); }