* 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.
This commit is contained in:
Brian Dessent 2008-03-11 17:20:02 +00:00
parent 0c4cb56009
commit 60efa4e546
4 changed files with 100 additions and 31 deletions

View File

@ -1,3 +1,18 @@
2008-03-11 Brian Dessent <brian@dessent.net>
* 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 <brian@dessent.net> 2008-03-09 Brian Dessent <brian@dessent.net>
* Makefile.in (install): Don't install the testsuite. * Makefile.in (install): Don't install the testsuite.

View File

@ -807,6 +807,28 @@ ls (char *f)
display_error ("ls: CloseHandle()"); 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) // Find a real application on the path (possibly following symlinks)
static const char * static const char *
find_app_on_path (const char *app, bool showall = false) 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)) if (is_symlink (fh))
{ {
static char tmp[4000] = ""; static char tmp[SYMLINK_MAX];
char *ptr; if (!readlink (fh, tmp, SYMLINK_MAX))
if (!readlink (fh, tmp, 3999))
display_error("readlink failed"); display_error("readlink failed");
ptr = cygpath (tmp, NULL);
for (char *p = ptr; (p = strchr (p, '/')); p++) /* Resolve the linkname relative to the directory of the link. */
*p = '\\'; char *ptr = cygpath_rel (dirname (papp), tmp, NULL);
printf (" -> %s\n", ptr); printf (" -> %s\n", ptr);
if (!strchr (ptr, '\\')) if (!strchr (ptr, '\\'))
{ {
char *lastsep; char *lastsep;
strncpy (tmp, cygpath (papp, NULL), 3999); strncpy (tmp, cygpath (papp, NULL), SYMLINK_MAX - 1);
for (char *p = tmp; (p = strchr (p, '/')); p++)
*p = '\\';
lastsep = strrchr (tmp, '\\'); lastsep = strrchr (tmp, '\\');
strncpy (lastsep+1, ptr, 3999-(lastsep-tmp)); strncpy (lastsep+1, ptr, SYMLINK_MAX - 1 - (lastsep-tmp));
ptr = tmp; ptr = tmp;
} }
if (!CloseHandle (fh)) if (!CloseHandle (fh))
display_error ("find_app_on_path: CloseHandle()"); 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); return find_app_on_path (ptr, showall);
} }

View File

@ -486,26 +486,35 @@ unconvert_slashes (char* name)
*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 * 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]; char pathbuf[MAX_PATH];
if (!GetCurrentDirectory (MAX_PATH, path)) if (!cwd || *cwd == '\0')
return NULL; {
if (!GetCurrentDirectory (MAX_PATH, pathbuf))
return NULL;
cwd = pathbuf;
}
int max_len = -1; int max_len = -1;
struct mnt *m, *match = NULL; struct mnt *m, *match = NULL;
if (s[0] == '.' && isslash (s[1])) for (m = mount_table; m->posix; m++)
s += 2;
for (m = mount_table; m->posix ; m++)
{ {
if (m->flags & MOUNT_CYGDRIVE) if (m->flags & MOUNT_CYGDRIVE)
continue; continue;
int n = strlen (m->native); 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; continue;
max_len = n; max_len = n;
match = m; match = m;
@ -514,34 +523,36 @@ rel_vconcat (const char *s, va_list v)
char *temppath; char *temppath;
if (!match) if (!match)
// No prefix matched - best effort to return meaningful value. // 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) else if (strcmp (match->posix, "/") != 0)
// Matched on non-root. Copy matching prefix + remaining 'path'. // Matched on non-root. Copy matching prefix + remaining 'path'.
temppath = concat (match->posix, path + max_len, "/", s, NULL); temppath = concat (match->posix, cwd + max_len, "/", s, NULL);
else if (path[max_len] == '\0') else if (cwd[max_len] == '\0')
// Matched on root and there's no remaining 'path'. // Matched on root and there's no remaining 'path'.
temppath = concat ("/", s, NULL); 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. // 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 else
temppath = concat ("/", path + max_len, "/", s, NULL); temppath = concat ("/", cwd + max_len, "/", s, NULL);
char *res = vconcat (temppath, v); char *res = vconcat (temppath, v);
free (temppath); free (temppath);
return res; return res;
} }
char * /* Convert a POSIX path in 's' to an absolute Win32 path, and append
cygpath (const char *s, ...) 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; int max_len = -1;
struct mnt *m, *match = NULL; struct mnt *m, *match = NULL;
if (!mount_table[0].posix) if (!mount_table[0].posix)
read_mounts (); read_mounts ();
va_start (v, s);
char *path; char *path;
if (s[0] == '.' && isslash (s[1])) if (s[0] == '.' && isslash (s[1]))
s += 2; s += 2;
@ -549,7 +560,7 @@ cygpath (const char *s, ...)
if (s[0] == '/' || s[1] == ':') /* FIXME: too crude? */ if (s[0] == '/' || s[1] == ':') /* FIXME: too crude? */
path = vconcat (s, v); path = vconcat (s, v);
else else
path = rel_vconcat (s, v); path = rel_vconcat (cwd, s, v);
if (!path) if (!path)
return NULL; return NULL;
@ -557,7 +568,7 @@ cygpath (const char *s, ...)
if (strncmp (path, "/./", 3) == 0) if (strncmp (path, "/./", 3) == 0)
memmove (path + 1, path + 3, strlen (path + 3) + 1); 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) if (m->flags & MOUNT_CYGDRIVE)
continue; continue;
@ -586,6 +597,26 @@ cygpath (const char *s, ...)
return native; 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; static mnt *m = NULL;
extern "C" FILE * extern "C" FILE *

View File

@ -9,9 +9,11 @@ Cygwin license. Please consult the file "CYGWIN_LICENSE" for
details. */ details. */
char *cygpath (const char *s, ...); char *cygpath (const char *s, ...);
char *cygpath_rel (const char *cwd, const char *s, ...);
bool is_exe (HANDLE); bool is_exe (HANDLE);
bool is_symlink (HANDLE); bool is_symlink (HANDLE);
bool readlink (HANDLE, char *, int); bool readlink (HANDLE, char *, int);
int get_word (HANDLE, int); int get_word (HANDLE, int);
int get_dword (HANDLE, int); int get_dword (HANDLE, int);
#define SYMLINK_MAX 4095 /* PATH_MAX - 1 */