From 60efa4e546a8f2e8e23f2de5ccd77c8c30240162 Mon Sep 17 00:00:00 2001 From: Brian Dessent Date: Tue, 11 Mar 2008 17:20:02 +0000 Subject: [PATCH] * cygcheck.cc (dirname): New static function. (find_app_on_path): Use SYMLINK_MAX. Resolve symlink relative to link's location. Adjust to the fact that cygpath already normalizes its return value. * path.cc (rel_vconcat): Add cwd parameter, and use it instead of calling GetCurrentDirectory() if possible. Rename throughout. (vcygpath): Rename from cygpath and accept cwd and va_list. Pass cwd on to rel_vconcat(). (cygpath_rel): New front end for vcygpath. (cygpath): Ditto. * path.h (cygpath_rel): Declare. (SYMLINK_MAX): Define to 4095. --- winsup/utils/ChangeLog | 15 +++++++++ winsup/utils/cygcheck.cc | 41 ++++++++++++++++------ winsup/utils/path.cc | 73 ++++++++++++++++++++++++++++------------ winsup/utils/path.h | 2 ++ 4 files changed, 100 insertions(+), 31 deletions(-) diff --git a/winsup/utils/ChangeLog b/winsup/utils/ChangeLog index 18f70518a..288beafd0 100644 --- a/winsup/utils/ChangeLog +++ b/winsup/utils/ChangeLog @@ -1,3 +1,18 @@ +2008-03-11 Brian Dessent + + * cygcheck.cc (dirname): New static function. + (find_app_on_path): Use SYMLINK_MAX. Resolve symlink relative + to link's location. Adjust to the fact that cygpath already + normalizes its return value. + * path.cc (rel_vconcat): Add cwd parameter, and use it instead + of calling GetCurrentDirectory() if possible. Rename throughout. + (vcygpath): Rename from cygpath and accept cwd and va_list. Pass + cwd on to rel_vconcat(). + (cygpath_rel): New front end for vcygpath. + (cygpath): Ditto. + * path.h (cygpath_rel): Declare. + (SYMLINK_MAX): Define to 4095. + 2008-03-09 Brian Dessent * Makefile.in (install): Don't install the testsuite. diff --git a/winsup/utils/cygcheck.cc b/winsup/utils/cygcheck.cc index 5e9713e03..e23a6858e 100644 --- a/winsup/utils/cygcheck.cc +++ b/winsup/utils/cygcheck.cc @@ -807,6 +807,28 @@ ls (char *f) display_error ("ls: CloseHandle()"); } +/* Remove filename from 's' and return directory name without trailing + backslash, or NULL if 's' doesn't seem to have a dirname. */ +static char * +dirname (const char *s) +{ + static char buf[MAX_PATH]; + + if (!s) + return NULL; + + strncpy (buf, s, MAX_PATH); + buf[MAX_PATH - 1] = '\0'; // in case strlen(s) > MAX_PATH + char *lastsep = strrchr (buf, '\\'); + if (!lastsep) + return NULL; // no backslash -> no dirname + else if (lastsep - buf <= 2 && buf[1] == ':') + lastsep[1] = '\0'; // can't remove backslash of "x:\" + else + *lastsep = '\0'; + return buf; +} + // Find a real application on the path (possibly following symlinks) static const char * find_app_on_path (const char *app, bool showall = false) @@ -821,26 +843,25 @@ find_app_on_path (const char *app, bool showall = false) if (is_symlink (fh)) { - static char tmp[4000] = ""; - char *ptr; - if (!readlink (fh, tmp, 3999)) + static char tmp[SYMLINK_MAX]; + if (!readlink (fh, tmp, SYMLINK_MAX)) display_error("readlink failed"); - ptr = cygpath (tmp, NULL); - for (char *p = ptr; (p = strchr (p, '/')); p++) - *p = '\\'; + + /* Resolve the linkname relative to the directory of the link. */ + char *ptr = cygpath_rel (dirname (papp), tmp, NULL); printf (" -> %s\n", ptr); if (!strchr (ptr, '\\')) { char *lastsep; - strncpy (tmp, cygpath (papp, NULL), 3999); - for (char *p = tmp; (p = strchr (p, '/')); p++) - *p = '\\'; + strncpy (tmp, cygpath (papp, NULL), SYMLINK_MAX - 1); lastsep = strrchr (tmp, '\\'); - strncpy (lastsep+1, ptr, 3999-(lastsep-tmp)); + strncpy (lastsep+1, ptr, SYMLINK_MAX - 1 - (lastsep-tmp)); ptr = tmp; } if (!CloseHandle (fh)) display_error ("find_app_on_path: CloseHandle()"); + /* FIXME: We leak the ptr returned by cygpath() here which is a + malloc()d string. */ return find_app_on_path (ptr, showall); } diff --git a/winsup/utils/path.cc b/winsup/utils/path.cc index 569196344..4a29d14e9 100644 --- a/winsup/utils/path.cc +++ b/winsup/utils/path.cc @@ -486,26 +486,35 @@ unconvert_slashes (char* name) *name++ = '\\'; } +/* This is a helper function for when vcygpath is passed what appears + to be a relative POSIX path. We take a Win32 CWD (either as specified + in 'cwd' or as retrieved with GetCurrentDirectory() if 'cwd' is NULL) + and find the mount table entry with the longest match. We replace the + matching portion with the corresponding POSIX prefix, and to that append + 's' and anything in 'v'. The returned result is a mostly-POSIX + absolute path -- 'mostly' because the portions of CWD that didn't + match the mount prefix will still have '\\' separators. */ static char * -rel_vconcat (const char *s, va_list v) +rel_vconcat (const char *cwd, const char *s, va_list v) { - char path[MAX_PATH + 1]; - if (!GetCurrentDirectory (MAX_PATH, path)) - return NULL; + char pathbuf[MAX_PATH]; + if (!cwd || *cwd == '\0') + { + if (!GetCurrentDirectory (MAX_PATH, pathbuf)) + return NULL; + cwd = pathbuf; + } int max_len = -1; struct mnt *m, *match = NULL; - if (s[0] == '.' && isslash (s[1])) - s += 2; - - for (m = mount_table; m->posix ; m++) + for (m = mount_table; m->posix; m++) { if (m->flags & MOUNT_CYGDRIVE) continue; int n = strlen (m->native); - if (n < max_len || !path_prefix_p (m->native, path, n)) + if (n < max_len || !path_prefix_p (m->native, cwd, n)) continue; max_len = n; match = m; @@ -514,34 +523,36 @@ rel_vconcat (const char *s, va_list v) char *temppath; if (!match) // No prefix matched - best effort to return meaningful value. - temppath = concat (path, "/", s, NULL); + temppath = concat (cwd, "/", s, NULL); else if (strcmp (match->posix, "/") != 0) // Matched on non-root. Copy matching prefix + remaining 'path'. - temppath = concat (match->posix, path + max_len, "/", s, NULL); - else if (path[max_len] == '\0') + temppath = concat (match->posix, cwd + max_len, "/", s, NULL); + else if (cwd[max_len] == '\0') // Matched on root and there's no remaining 'path'. temppath = concat ("/", s, NULL); - else if (isslash (path[max_len])) + else if (isslash (cwd[max_len])) // Matched on root but remaining 'path' starts with a slash anyway. - temppath = concat (path + max_len, "/", s, NULL); + temppath = concat (cwd + max_len, "/", s, NULL); else - temppath = concat ("/", path + max_len, "/", s, NULL); + temppath = concat ("/", cwd + max_len, "/", s, NULL); char *res = vconcat (temppath, v); free (temppath); return res; } -char * -cygpath (const char *s, ...) +/* Convert a POSIX path in 's' to an absolute Win32 path, and append + anything in 'v' to the end, returning the result. If 's' is a + relative path then 'cwd' is used as the working directory to make + it absolute. Pass NULL in 'cwd' to use GetCurrentDirectory. */ +static char * +vcygpath (const char *cwd, const char *s, va_list v) { - va_list v; int max_len = -1; struct mnt *m, *match = NULL; if (!mount_table[0].posix) read_mounts (); - va_start (v, s); char *path; if (s[0] == '.' && isslash (s[1])) s += 2; @@ -549,7 +560,7 @@ cygpath (const char *s, ...) if (s[0] == '/' || s[1] == ':') /* FIXME: too crude? */ path = vconcat (s, v); else - path = rel_vconcat (s, v); + path = rel_vconcat (cwd, s, v); if (!path) return NULL; @@ -557,7 +568,7 @@ cygpath (const char *s, ...) if (strncmp (path, "/./", 3) == 0) memmove (path + 1, path + 3, strlen (path + 3) + 1); - for (m = mount_table; m->posix ; m++) + for (m = mount_table; m->posix; m++) { if (m->flags & MOUNT_CYGDRIVE) continue; @@ -586,6 +597,26 @@ cygpath (const char *s, ...) return native; } +char * +cygpath_rel (const char *cwd, const char *s, ...) +{ + va_list v; + + va_start (v, s); + + return vcygpath (cwd, s, v); +} + +char * +cygpath (const char *s, ...) +{ + va_list v; + + va_start (v, s); + + return vcygpath (NULL, s, v); +} + static mnt *m = NULL; extern "C" FILE * diff --git a/winsup/utils/path.h b/winsup/utils/path.h index 134235e38..48739df74 100644 --- a/winsup/utils/path.h +++ b/winsup/utils/path.h @@ -9,9 +9,11 @@ Cygwin license. Please consult the file "CYGWIN_LICENSE" for details. */ char *cygpath (const char *s, ...); +char *cygpath_rel (const char *cwd, const char *s, ...); bool is_exe (HANDLE); bool is_symlink (HANDLE); bool readlink (HANDLE, char *, int); int get_word (HANDLE, int); int get_dword (HANDLE, int); +#define SYMLINK_MAX 4095 /* PATH_MAX - 1 */