From bd2e2279d2b8f491ff9a56f6bd9000b0215778f8 Mon Sep 17 00:00:00 2001 From: Rob Landley Date: Tue, 20 Nov 2012 09:21:52 -0600 Subject: [PATCH] Update readlink so -f works. Add -menq while there. --- lib/lib.c | 63 ++++++++++++++++++++------------------------------- lib/lib.h | 2 +- toys/other/readlink.c | 34 +++++++++++++++------------ 3 files changed, 45 insertions(+), 54 deletions(-) diff --git a/lib/lib.c b/lib/lib.c index 49f2be5..83b9bb2 100644 --- a/lib/lib.c +++ b/lib/lib.c @@ -323,52 +323,37 @@ void xstat(char *path, struct stat *st) if(stat(path, st)) perror_exit("Can't stat %s", path); } -// Cannonicalizes path by removing ".", "..", and "//" elements. This is not -// the same as realpath(), where "dir/.." could wind up somewhere else by -// following symlinks. -char *xabspath(char *path) +// Cannonicalize path, even to file with one or more missing components at end +char *xabspath(char *path, unsigned missing) { - char *from, *to; + char *apath, *temp, *slash; + int i=0; // If this isn't an absolute path, make it one with cwd. if (path[0]!='/') { - char *cwd=xgetcwd(); - path = xmsprintf("%s/%s", cwd, path); - free(cwd); - } else path = xstrdup(path); - - // Loop through path elements - from = to = path; - while (*from) { - - // Continue any current path component. - if (*from!='/') { - *(to++) = *(from++); - continue; - } + char *temp=xgetcwd(); + apath = xmsprintf("%s/%s", temp, path); + free(temp); + } else apath = path; + slash = apath+strlen(apath); - // Skip duplicate slashes. - while (*from=='/') from++; - - // Start of a new filename. Handle . and .. - while (*from=='.') { - // Skip . - if (from[1]=='/') from += 2; - else if (!from[1]) from++; - // Back up for .. - else if (from[1]=='.') { - if (from[2]=='/') from +=3; - else if(!from[2]) from+=2; - else break; - while (to>path && *(--to)!='/'); - } else break; - } - // Add directory separator slash. - *(to++) = '/'; + for (;;) { + temp = realpath(apath, NULL); + if (i) *slash = '/'; + if (temp || ++i > missing) break; + while (slash>apath) if (*--slash == '/') break; + *slash=0; + free(temp); + } + + if (i && temp) { + slash = xmsprintf("%s%s", temp, slash); + free(temp); + temp = slash; } - *to = 0; - return path; + if (path != apath) free(apath); + return temp; } // Resolve all symlinks, returning malloc() memory. diff --git a/lib/lib.h b/lib/lib.h index 5e5cbdf..34ded00 100644 --- a/lib/lib.h +++ b/lib/lib.h @@ -116,7 +116,7 @@ char *readfile(char *name); char *xreadfile(char *name); char *xgetcwd(void); void xstat(char *path, struct stat *st); -char *xabspath(char *path); +char *xabspath(char *path, unsigned missing); char *xrealpath(char *path); void xchdir(char *path); void xmkpath(char *path, int mode); diff --git a/toys/other/readlink.c b/toys/other/readlink.c index b7f77f9..b237a51 100644 --- a/toys/other/readlink.c +++ b/toys/other/readlink.c @@ -2,27 +2,26 @@ * * Copyright 2007 Rob Landley -USE_READLINK(NEWTOY(readlink, "<1f", TOYFLAG_BIN)) +USE_READLINK(NEWTOY(readlink, "<1>1femnq[-fem]", TOYFLAG_BIN)) config READLINK bool "readlink" default n help - usage: readlink + usage: readlink FILE - Show what a symbolic link points to. + With no options, show what symlink points to, return error if not symlink. -config READLINK_F - bool "readlink -f" - default n - depends on READLINK - help - usage: readlink [-f] + Options for producing cannonical paths (all symlinks/./.. resolved): - -f Show full cannonical path, with no symlinks in it. Returns - nonzero if nothing could currently exist at this location. + -e cannonical path to existing file (fail if does not exist) + -f cannonical path to creatable file (fail if directory does not exist) + -m cannonical path + -n no trailing newline + -q quiet (no output, just error code) */ +#define FOR_readlink #include "toys.h" void readlink_main(void) @@ -31,11 +30,18 @@ void readlink_main(void) // Calculating full cannonical path? - if (CFG_READLINK_F && toys.optflags) s = xrealpath(*toys.optargs); - else s = xreadlink(*toys.optargs); + if (toys.optflags & (FLAG_f|FLAG_e|FLAG_m)) { + unsigned u = 0; + + if (toys.optflags & FLAG_f) u++; + if (toys.optflags & FLAG_m) u=999999999; + + s = xabspath(*toys.optargs, u); + } else s = xreadlink(*toys.optargs); if (s) { - xputs(s); + if (!(toys.optflags & FLAG_q)) + xprintf((toys.optflags & FLAG_n) ? "%s" : "%s\n", s); if (CFG_TOYBOX_FREE) free(s); } else toys.exitval = 1; } -- 2.7.4