diff --git a/winsup/utils/ChangeLog b/winsup/utils/ChangeLog index fc839a4b7..7a0c80d53 100644 --- a/winsup/utils/ChangeLog +++ b/winsup/utils/ChangeLog @@ -1,3 +1,35 @@ +2007-06-03 Christopher Faylor + + * cygcheck.cc (pathlike): New class. + (paths): Redefine as type pathlike. + (display_error): Declare a few different ways to allow more flexible + usage throughout. + (display_error_fmt): New function for those cases where C++ just isn't + enough. + (add_path): Rewrite to allocate pathlike paths. Always tack on a + trailing slash since that's what everyone who uses it wants. NULL + terminate the path list. Register "it's a system path" field. + (init_path): Call add_path with info regarding whether path is a system + path or not. + (pathlike::check_existence): Move into pathlike class. Accept file and + extension arguments to build up path on the fly. Modify other + arguments. + (find_on_path): Constify return value and appropriate arguments. + Eliminate short-circuit for fully-qualified paths. Simplify loop which + iterates over path. + (already_did): Constify argument. + (track_down): Ditto. Regularize some error messages. + (find_app_on_path): Ditto. + (cygcheck): Constify argument. Use 20th century string handling + functions. + (dump_sysinfo): Remove odd inclusion of '\\bin' "Just in case". + Accommodate change of paths to pathlike. + * path.cc (isslash): Rename from SLASH_P and use throughout. + (rel_vconcat): Front-end to vconcat which prepends cwd to path before + passing along for conversion to native windows. + (cygpath): Remove "./" test. Call rel_vconcat if filename appears to + be relative. + 2007-05-29 Pedro Alves * dumper.cc (dumper::prepare_core_dump): Record a phdr for each section. diff --git a/winsup/utils/cygcheck.cc b/winsup/utils/cygcheck.cc index 94498aa4e..b75f38f26 100644 --- a/winsup/utils/cygcheck.cc +++ b/winsup/utils/cygcheck.cc @@ -38,6 +38,8 @@ int find_package = 0; int list_package = 0; int grep_packages = 0; +static char emptystr[] = ""; + /* This is global because it's used in both internet_display_error as well as package_grep. */ BOOL (WINAPI *pInternetCloseHandle) (HINTERNET); @@ -114,7 +116,16 @@ static common_apps[] = { }; static int num_paths, max_paths; -static char **paths; +struct pathlike +{ + char *dir; + bool issys; + void pathlike::check_existence (const char *fn, int showall, int verbose, + char* first, const char *ext1 = "", + const char *ext2 = ""); +}; + +pathlike *paths; int first_nonsys_path; void @@ -130,17 +141,43 @@ eprintf (const char *format, ...) * display_error() is used to report failure modes */ static int -display_error (const char *name, bool show_error = true, bool print_failed = true) +display_error (const char *name, bool show_error, bool print_failed) { + fprintf (stderr, "cygcheck: %s", name); if (show_error) - fprintf (stderr, "cygcheck: %s%s: %lu\n", name, + fprintf (stderr, "%s: %lu\n", print_failed ? " failed" : "", GetLastError ()); else - fprintf (stderr, "cygcheck: %s%s\n", name, + fprintf (stderr, "%s\n", print_failed ? " failed" : ""); return 1; } +static int +display_error (const char *name) +{ + return display_error (name, true, true); +} + +static int +display_error (const char *fmt, const char *x) +{ + char buf[4000]; + sprintf (buf, fmt, x); + return display_error (buf, false, false); +} + +static int +display_error_fmt (const char *fmt, ...) +{ + char buf[4000]; + va_list va; + + va_start (va, fmt); + vsprintf (buf, fmt, va); + return display_error (buf, false, false); +} + /* Display a WinInet error message, and close a variable number of handles. (Passed a list of handles terminated by NULL.) */ static int @@ -156,12 +193,12 @@ display_internet_error (const char *message, ...) if (err) { if (FormatMessage (FORMAT_MESSAGE_FROM_HMODULE, - GetModuleHandle ("wininet.dll"), err, 0, err_buf, - sizeof (err_buf), NULL) == 0) - strcpy (err_buf, "(Unknown error)"); + GetModuleHandle ("wininet.dll"), err, 0, err_buf, + sizeof (err_buf), NULL) == 0) + strcpy (err_buf, "(Unknown error)"); fprintf (stderr, "cygcheck: %s: %s (win32 error %d)\n", message, - err_buf, err); + err_buf, err); } else fprintf (stderr, "cygcheck: %s\n", message); @@ -175,33 +212,37 @@ display_internet_error (const char *message, ...) } static void -add_path (char *s, int maxlen) +add_path (char *s, int maxlen, bool issys) { if (num_paths >= max_paths) { max_paths += 10; - if (paths) - paths = (char **) realloc (paths, max_paths * sizeof (char *)); - else - paths = (char **) malloc (max_paths * sizeof (char *)); + /* Extend path array */ + paths = (pathlike *) realloc (paths, (1 + max_paths) * sizeof (paths[0])); } - paths[num_paths] = (char *) malloc (maxlen + 1); - if (paths[num_paths] == NULL) + + pathlike *pth = paths + num_paths; + + /* Allocate space for directory in path list */ + char *dir = (char *) calloc (maxlen + 2, sizeof (char)); + if (dir == NULL) { - display_error ("add_path: malloc()"); + display_error ("add_path: calloc() failed"); return; } - memcpy (paths[num_paths], s, maxlen); - paths[num_paths][maxlen] = 0; - char *e = paths[num_paths] + strlen (paths[num_paths]); - if (e[-1] == '\\' && e[-2] != ':') - *--e = 0; - for (int i = 1; i < num_paths; i++) - if (strcasecmp (paths[num_paths], paths[i]) == 0) - { - free (paths[num_paths]); - return; - } + + /* Copy input directory to path list */ + memcpy (dir, s, maxlen); + + /* Add a trailing slash by default */ + char *e = strchr (dir, '\0'); + if (e != dir && e[-1] != '\\') + strcpy (e, "\\"); + + /* Fill out this element */ + pth->dir = dir; + pth->issys = issys; + pth[1].dir = NULL; num_paths++; } @@ -209,39 +250,39 @@ static void init_paths () { char tmp[4000], *sl; - add_path ((char *) ".", 1); /* to be replaced later */ + add_path ((char *) ".", 1, true); /* to be replaced later */ if (GetCurrentDirectory (4000, tmp)) - add_path (tmp, strlen (tmp)); + add_path (tmp, strlen (tmp), true); else display_error ("init_paths: GetCurrentDirectory()"); if (GetSystemDirectory (tmp, 4000)) - add_path (tmp, strlen (tmp)); + add_path (tmp, strlen (tmp), true); else display_error ("init_paths: GetSystemDirectory()"); sl = strrchr (tmp, '\\'); if (sl) { strcpy (sl, "\\SYSTEM"); - add_path (tmp, strlen (tmp)); + add_path (tmp, strlen (tmp), true); } GetWindowsDirectory (tmp, 4000); - add_path (tmp, strlen (tmp)); - first_nonsys_path = num_paths; + add_path (tmp, strlen (tmp), true); char *wpath = getenv ("PATH"); if (!wpath) - fprintf (stderr, "WARNING: PATH is not set at all!\n"); + display_error ("WARNING: PATH is not set\n", ""); else { char *b, *e; b = wpath; while (1) { - for (e = b; *e && *e != ';'; e++); - if (strncmp(b, ".", 1) && strncmp(b, ".\\", 2)) - add_path (b, e - b); + for (e = b; *e && *e != ';'; e++) + continue; /* loop terminates at first ';' or EOS */ + if (strncmp(b, ".\\", 2) != 0) + add_path (b, e - b, false); if (!*e) break; b = e + 1; @@ -251,9 +292,16 @@ init_paths () #define LINK_EXTENSION ".lnk" -static bool -check_existence (char *file, int showall, int foundone, char *first) +void +pathlike::check_existence (const char *fn, int showall, int verbose, + char* first, const char *ext1, const char *ext2) { + char file[4000]; + strcpy (file, dir); + strcat (file, fn); + strcat (file, ext1); + strcat (file, ext2); + if (GetFileAttributes (file) != (DWORD) - 1) { char *lastdot = strrchr (file, '.'); @@ -263,7 +311,7 @@ check_existence (char *file, int showall, int foundone, char *first) *lastdot = '\0'; if (showall) printf ("Found: %s\n", file); - if (foundone) + if (verbose && *first != '\0' && strcasecmp (first, file) != 0) { char *flastdot = strrchr (first, '.'); bool f_is_link = flastdot && !strcmp (flastdot, LINK_EXTENSION); @@ -276,84 +324,81 @@ check_existence (char *file, int showall, int foundone, char *first) } if (is_link) *lastdot = '.'; - return true; + if (!*first) + strcpy (first, file); } - return false; } -static char * -find_on_path (char *file, char *default_extension, - int showall = 0, int search_sysdirs = 0, int checklinks = 0) +static const char * +find_on_path (const char *in_file, const char *ext, bool showall = false, + bool search_sys = false, bool checklinks = false) { static char rv[4000]; - char tmp[4000], *ptr = rv; + + /* Sort of a kludge but we've already tested this once, so don't try it again */ + if (in_file == rv) + return in_file; + + static pathlike abspath[2] = + { + {emptystr, 0}, + {NULL, 0} + }; + + *rv = '\0'; + if (!in_file) + { + display_error ("internal error find_on_path: NULL pointer for file", false, false); + return 0; + } + + if (!ext) + { + display_error ("internal error find_on_path: NULL pointer for default_extension", false, false); + return 0; + } + + const char *file; + pathlike *search_paths; + if (!strpbrk (in_file, ":/\\")) + { + file = in_file; + search_paths = paths; + } + else + { + file = cygpath (in_file, NULL); + search_paths = abspath; + showall = false; + } if (!file) { - display_error ("find_on_path: NULL pointer for file", false, false); + display_error ("internal error find_on_path: cygpath conversion failed for %s\n", in_file); return 0; } - if (default_extension == NULL) - { - display_error ("find_on_path: NULL pointer for default_extension", false, false); - return 0; - } + char *hasext = strrchr (file, '.'); + if (hasext && !strpbrk (hasext, "/\\")) + ext = ""; - if (strchr (file, ':') || strchr (file, '\\') || strchr (file, '/')) - { - // FIXME: this will find "foo" before "foo.exe" -- contrary to Windows - char *fn = cygpath (file, NULL); - if (access (fn, F_OK) == 0) - return fn; - strcpy (rv, fn); - strcat (rv, default_extension); - if (access (rv, F_OK) == 0) - return rv; - if (!checklinks) - return fn; - strcat (rv, LINK_EXTENSION); - if (access (rv, F_OK) == 0) - return rv; - strcpy (rv, fn); - strcat (rv, LINK_EXTENSION); - return access (rv, F_OK) == 0 ? strdup (rv) : fn; - } + for (pathlike *pth = search_paths; pth->dir; pth++) + if (!pth->issys || search_sys) + { + pth->check_existence (file, showall, verbose, rv, ext); - if (strchr (file, '.')) - default_extension = (char *) ""; + if (checklinks) + pth->check_existence (file, showall, verbose, rv, ext, LINK_EXTENSION); - for (int i = search_sysdirs ? 0 : first_nonsys_path; i < num_paths; i++) - { - if (i == 0 || !search_sysdirs || strcasecmp (paths[i], paths[0])) - { - sprintf (ptr, "%s\\%s%s", paths[i], file, default_extension); - if (check_existence (ptr, showall, ptr == tmp && verbose, rv)) - ptr = tmp; + if (!*ext) + continue; - if (!checklinks) - continue; + pth->check_existence (file, showall, verbose, rv); + if (checklinks) + pth->check_existence (file, showall, verbose, rv, LINK_EXTENSION); + } - sprintf (ptr, "%s\\%s%s%s", paths[i], file, default_extension, LINK_EXTENSION); - if (check_existence (ptr, showall, ptr == tmp && verbose, rv)) - ptr = tmp; - - if (!*default_extension) - continue; - - sprintf (ptr, "%s\\%s", paths[i], file); - if (check_existence (ptr, showall, ptr == tmp && verbose, rv)) - ptr = tmp; - sprintf (ptr, "%s\\%s%s", paths[i], file, LINK_EXTENSION); - if (check_existence (ptr, showall, ptr == tmp && verbose, rv)) - ptr = tmp; - } - } - - if (ptr == tmp) - return rv; - - return 0; + return *rv ? rv : NULL; } #define DID_NEW 1 @@ -369,7 +414,7 @@ struct Did static Did *did = 0; static Did * -already_did (char *file) +already_did (const char *file) { Did *d; for (d = did; d; d = d->next) @@ -440,8 +485,7 @@ struct ImpDirectory unsigned iat_rva; }; - -static bool track_down (char *file, char *suffix, int lvl); +static bool track_down (const char *file, const char *suffix, int lvl); #define CYGPREFIX (sizeof ("%%% Cygwin ") - 1) static void @@ -647,7 +691,7 @@ dll_info (const char *path, HANDLE fh, int lvl, int recurse) // Return true on success, false if error printed static bool -track_down (char *file, char *suffix, int lvl) +track_down (const char *file, const char *suffix, int lvl) { if (file == NULL) { @@ -661,10 +705,10 @@ track_down (char *file, char *suffix, int lvl) return false; } - char *path = find_on_path (file, suffix, 0, 1); + const char *path = find_on_path (file, suffix, false, true); if (!path) { - printf ("Error: could not find %s\n", file); + display_error ("track_down: could not find %s\n", file); return false; } @@ -700,7 +744,7 @@ track_down (char *file, char *suffix, int lvl) if (!path) { - printf ("%s not found\n", file); + display_error ("file not found - '%s'\n", file); return false; } @@ -711,7 +755,7 @@ track_down (char *file, char *suffix, int lvl) NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (fh == INVALID_HANDLE_VALUE) { - printf (" - Cannot open\n"); + display_error ("cannot open - '%s'\n", path); return false; } @@ -720,15 +764,15 @@ track_down (char *file, char *suffix, int lvl) if (is_exe (fh)) dll_info (path, fh, lvl, 1); else if (is_symlink (fh)) - printf (" - Found a symlink instead of a DLL\n"); + display_error ("%s is a symlink instead of a DLL\n", path); else { int magic = get_word (fh, 0x0); if (magic == -1) - display_error ("get_word"); + display_error ("get_word"); magic &= 0x00FFFFFF; - printf (" - Not a DLL: magic number %x (%d) '%s'\n", - magic, magic, (char *)&magic); + display_error_fmt ("%s is not a DLL: magic number %x (%d) '%s'\n", + path, magic, magic, (char *)&magic); } d->state = DID_INACTIVE; @@ -760,19 +804,16 @@ ls (char *f) } // Find a real application on the path (possibly following symlinks) -static char * -find_app_on_path (char *app, int showall = 0) +static const char * +find_app_on_path (const char *app, bool showall = false) { - char *papp = find_on_path (app, (char *) ".exe", showall, 0, 1); + const char *papp = find_on_path (app, ".exe", showall, false, true); HANDLE fh = CreateFile (papp, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (fh == INVALID_HANDLE_VALUE) - { - printf (" - Cannot open\n"); - return NULL; - } + return NULL; if (is_symlink (fh)) { @@ -806,28 +847,33 @@ find_app_on_path (char *app, int showall = 0) // Return true on success, false if error printed static bool -cygcheck (char *app) +cygcheck (const char *app) { - char *papp = find_app_on_path (app, 1); + const char *papp = find_app_on_path (app, 1); if (!papp) { - printf ("Error: could not find %s\n", app); + display_error ("could not find '%s'\n", app); return false; } - char *s = strdup (papp); - char *sl = 0, *t; - for (t = s; *t; t++) - if (*t == '/' || *t == '\\' || *t == ':') - sl = t; - if (sl == 0) - paths[0] = (char *) "."; + + char *s; + char *sep = strpbrk (papp, ":/\\"); + if (!sep) + { + static char dot[] = "."; + s = dot; + } else { - *sl = 0; - paths[0] = s; + int n = sep - papp; + s = (char *) malloc (n + 2); + memcpy ((char *) s, papp, n); + strcpy (s + n, "\\"); } - did = 0; - return track_down (papp, (char *) ".exe", 0); + + paths[0].dir = s; + did = NULL; + return track_down (papp, ".exe", 0); } @@ -1192,15 +1238,15 @@ dump_sysinfo () else if (osversion.dwMinorVersion == 1) { if (GetSystemMetrics (SM_MEDIACENTER)) - osname = "XP Media Center Edition"; + osname = "XP Media Center Edition"; else if (GetSystemMetrics (SM_TABLETPC)) - osname = "XP Tablet PC Edition"; + osname = "XP Tablet PC Edition"; else if (!more_info) osname = "XP"; else if (osversionex.wSuiteMask & VER_SUITE_PERSONAL) - osname = "XP Home Edition"; + osname = "XP Home Edition"; else - osname = "XP Professional"; + osname = "XP Professional"; } else if (osversion.dwMinorVersion == 2) { @@ -1238,12 +1284,12 @@ dump_sysinfo () if (wow64_func && wow64_func (GetCurrentProcess (), &is_wow64) && is_wow64) { void (WINAPI *nativinfo) (LPSYSTEM_INFO) = (void (WINAPI *) - (LPSYSTEM_INFO)) GetProcAddress (k32, "GetNativeSystemInfo"); + (LPSYSTEM_INFO)) GetProcAddress (k32, "GetNativeSystemInfo"); SYSTEM_INFO natinfo; nativinfo (&natinfo); fputs ("\nRunning under WOW64 on ", stdout); switch (natinfo.wProcessorArchitecture) - { + { case PROCESSOR_ARCHITECTURE_IA64: puts ("IA64"); break; @@ -1522,8 +1568,6 @@ dump_sysinfo () } printf ("\n"); - add_path ((char *) "\\bin", 4); /* just in case */ - if (givehelp) printf ("Looking to see where common programs can be found, if at all...\n"); @@ -1540,10 +1584,10 @@ dump_sysinfo () if (givehelp) printf ("Looking for various Cygwin DLLs... (-v gives version info)\n"); int cygwin_dll_count = 0; - for (i = 1; i < num_paths; i++) + for (pathlike *pth = paths; pth->dir; pth++) { WIN32_FIND_DATA ffinfo; - sprintf (tmp, "%s/*.*", paths[i]); + sprintf (tmp, "%s*.*", pth->dir); HANDLE ff = FindFirstFile (tmp, &ffinfo); int found = (ff != INVALID_HANDLE_VALUE); found_cygwin_dll = NULL; @@ -1554,7 +1598,7 @@ dump_sysinfo () { if (strncasecmp (f, "cyg", 3) == 0) { - sprintf (tmp, "%s\\%s", paths[i], f); + sprintf (tmp, "%s%s", pth->dir, f); if (strcasecmp (f, "cygwin1.dll") == 0) { cygwin_dll_count++; @@ -1672,7 +1716,7 @@ static const char safe_chars[] = "$-_.+!*'(),"; /* the URL to query. */ static const char base_url[] = - "http://cygwin.com/cgi-bin2/package-grep.cgi?text=1&grep="; + "http://cygwin.com/cgi-bin2/package-grep.cgi?text=1&grep="; /* Queries Cygwin web site for packages containing files matching a regexp. Return value is 1 if there was a problem, otherwise 0. */ @@ -1687,7 +1731,7 @@ package_grep (char *search) if (!(hWinInet = LoadLibrary ("wininet.dll"))) { fputs ("Unable to locate WININET.DLL. This feature requires Microsoft " - "Internet Explorer v3 or later to function.\n", stderr); + "Internet Explorer v3 or later to function.\n", stderr); return 1; } @@ -1696,25 +1740,25 @@ package_grep (char *search) and call GetProcAddress for each of them with the following macro. */ pInternetCloseHandle = (BOOL (WINAPI *) (HINTERNET)) - GetProcAddress (hWinInet, "InternetCloseHandle"); + GetProcAddress (hWinInet, "InternetCloseHandle"); #define make_func_pointer(name, ret, args) ret (WINAPI * p##name) args = \ - (ret (WINAPI *) args) GetProcAddress (hWinInet, #name); + (ret (WINAPI *) args) GetProcAddress (hWinInet, #name); make_func_pointer (InternetAttemptConnect, DWORD, (DWORD)); - make_func_pointer (InternetOpenA, HINTERNET, (LPCSTR, DWORD, LPCSTR, LPCSTR, - DWORD)); - make_func_pointer (InternetOpenUrlA, HINTERNET, (HINTERNET, LPCSTR, LPCSTR, - DWORD, DWORD, DWORD)); + make_func_pointer (InternetOpenA, HINTERNET, (LPCSTR, DWORD, LPCSTR, LPCSTR, + DWORD)); + make_func_pointer (InternetOpenUrlA, HINTERNET, (HINTERNET, LPCSTR, LPCSTR, + DWORD, DWORD, DWORD)); make_func_pointer (InternetReadFile, BOOL, (HINTERNET, PVOID, DWORD, PDWORD)); make_func_pointer (HttpQueryInfoA, BOOL, (HINTERNET, DWORD, PVOID, PDWORD, - PDWORD)); + PDWORD)); #undef make_func_pointer if(!pInternetCloseHandle || !pInternetAttemptConnect || !pInternetOpenA || !pInternetOpenUrlA || !pInternetReadFile || !pHttpQueryInfoA) { fputs ("Unable to load one or more functions from WININET.DLL. This " - "feature requires Microsoft Internet Explorer v3 or later to " - "function.\n", stderr); + "feature requires Microsoft Internet Explorer v3 or later to " + "function.\n", stderr); return 1; } @@ -1726,16 +1770,16 @@ package_grep (char *search) for (dest = &url[sizeof (base_url) - 1]; *search; search++) { if (isalnum (*search) - || memchr (safe_chars, *search, sizeof (safe_chars) - 1)) - { - *dest++ = *search; - } + || memchr (safe_chars, *search, sizeof (safe_chars) - 1)) + { + *dest++ = *search; + } else - { - *dest++ = '%'; - sprintf (dest, "%02x", (unsigned char) *search); - dest += 2; - } + { + *dest++ = '%'; + sprintf (dest, "%02x", (unsigned char) *search); + dest += 2; + } } *dest = 0; @@ -1753,18 +1797,18 @@ package_grep (char *search) if (!(hurl = pInternetOpenUrlA (hi, url, NULL, 0, 0, 0))) return display_internet_error ("unable to contact cygwin.com site, " - "InternetOpenUrl() failed", hi, NULL); + "InternetOpenUrl() failed", hi, NULL); /* Check the HTTP response code. */ DWORD rc = 0, rc_s = sizeof (DWORD); if (!pHttpQueryInfoA (hurl, HTTP_QUERY_STATUS_CODE | HTTP_QUERY_FLAG_NUMBER, - (void *) &rc, &rc_s, NULL)) + (void *) &rc, &rc_s, NULL)) return display_internet_error ("HttpQueryInfo() failed", hurl, hi, NULL); if (rc != HTTP_STATUS_OK) { sprintf (buf, "error retrieving results from cygwin.com site, " - "HTTP status code %lu", rc); + "HTTP status code %lu", rc); return display_internet_error (buf, hurl, hi, NULL); } @@ -1773,9 +1817,9 @@ package_grep (char *search) do { if (!pInternetReadFile (hurl, (void *) buf, sizeof (buf), &numread)) - return display_internet_error ("InternetReadFile failed", hurl, hi, NULL); + return display_internet_error ("InternetReadFile failed", hurl, hi, NULL); if (numread) - fwrite ((void *) buf, (size_t) numread, 1, stdout); + fwrite ((void *) buf, (size_t) numread, 1, stdout); } while (numread); @@ -1955,8 +1999,8 @@ main (int argc, char **argv) list_package = 1; break; case 'p': - grep_packages = 1; - break; + grep_packages = 1; + break; case 'h': givehelp = 1; break; diff --git a/winsup/utils/path.cc b/winsup/utils/path.cc index 356a60f01..75590282c 100644 --- a/winsup/utils/path.cc +++ b/winsup/utils/path.cc @@ -1,6 +1,6 @@ /* path.cc - Copyright 2001, 2002, 2003, 2005 Red Hat, Inc. + Copyright 2001, 2002, 2003, 2005, 2006, 2007 Red Hat, Inc. This file is part of Cygwin. @@ -24,7 +24,7 @@ details. */ #include "cygwin/include/mntent.h" /* Used when treating / and \ as equivalent. */ -#define SLASH_P(ch) \ +#define isslash(ch) \ ({ \ char __c = (ch); \ ((__c) == '/' || (__c) == '\\'); \ @@ -150,7 +150,7 @@ is_symlink (HANDLE fh) if (got != size || !cmp_shortcut_header ((win_shortcut_hdr *) buf)) return false; /* Not a Cygwin symlink. */ /* TODO: check for invalid path contents - (see symlink_info::check() in ../cygwin/path.cc) */ + (see symlink_info::check() in ../cygwin/path.cc) */ } else /* magic == SYMLINK_MAGIC */ { @@ -161,7 +161,7 @@ is_symlink (HANDLE fh) if (!ReadFile (fh, buf, sizeof (buf), &got, 0)) return false; if (got != sizeof (buf) || - memcmp (buf, SYMLINK_COOKIE, sizeof (buf)) != 0) + memcmp (buf, SYMLINK_COOKIE, sizeof (buf)) != 0) return false; /* Not a Cygwin symlink. */ } return true; @@ -184,11 +184,11 @@ readlink (HANDLE fh, char *path, int maxlen) return false; } if (SetFilePointer (fh, 0x4c + offset + 4, 0, FILE_BEGIN) == - INVALID_SET_FILE_POINTER && GetLastError () != NO_ERROR) - return false; + INVALID_SET_FILE_POINTER && GetLastError () != NO_ERROR) + return false; if (!ReadFile (fh, path, slen, (DWORD *) &got, 0)) - return false; + return false; else if (got < slen) { SetLastError (ERROR_READ_FAULT); @@ -203,15 +203,15 @@ readlink (HANDLE fh, char *path, int maxlen) if (SetFilePointer (fh, 0, 0, FILE_BEGIN) == INVALID_SET_FILE_POINTER && GetLastError () != NO_ERROR) - return false; + return false; if (!ReadFile (fh, cookie_buf, sizeof (cookie_buf), (DWORD *) &got, 0)) - return false; + return false; else if (got == sizeof (cookie_buf) && memcmp (cookie_buf, SYMLINK_COOKIE, sizeof (cookie_buf)) == 0) { if (!ReadFile (fh, path, maxlen, (DWORD *) &got, 0)) - return false; + return false; else if (got >= maxlen) { SetLastError (ERROR_FILENAME_EXCED_RANGE); @@ -378,16 +378,16 @@ static int path_prefix_p (const char *path1, const char *path2, int len1) { /* Handle case where PATH1 has trailing '/' and when it doesn't. */ - if (len1 > 0 && SLASH_P (path1[len1 - 1])) + if (len1 > 0 && isslash (path1[len1 - 1])) len1--; if (len1 == 0) - return SLASH_P (path2[0]) && !SLASH_P (path2[1]); + return isslash (path2[0]) && !isslash (path2[1]); if (strncasecmp (path1, path2, len1) != 0) return 0; - return SLASH_P (path2[len1]) || path2[len1] == 0 || path1[len1 - 1] == ':'; + return isslash (path2[len1]) || path2[len1] == 0 || path1[len1 - 1] == ':'; } static char * @@ -403,7 +403,7 @@ vconcat (const char *s, va_list v) len = strlen (s); - unc = SLASH_P (*s) && SLASH_P (s[1]); + unc = isslash (*s) && isslash (s[1]); while (1) { @@ -462,6 +462,43 @@ concat (const char *s, ...) return vconcat (s, v); } +static char * +rel_vconcat (const char *s, va_list v) +{ + char path[MAX_PATH + 1]; + if (!GetCurrentDirectory (MAX_PATH, path)) + return NULL; + + int max_len = -1; + struct mnt *m, *match = NULL; + + if (s[0] == '.' && isslash (s[1])) + s += 2; + + 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)) + continue; + max_len = n; + match = m; + } + + if (match) + strcpy (path, match->posix); + + if (!isslash (strchr (path, '\0')[-1])) + strcat (path, "/"); + + char *temppath = concat (path, s, NULL); + char *res = vconcat (temppath, v); + free (temppath); + return res; +} + char * cygpath (const char *s, ...) { @@ -472,9 +509,15 @@ cygpath (const char *s, ...) if (!mount_table[0].posix) read_mounts (); va_start (v, s); - char *path = vconcat (s, v); - if (strncmp (path, "./", 2) == 0) - memmove (path, path + 2, strlen (path + 2) + 1); + char *path; + if (s[0] == '/' || s[1] == ':') /* FIXME: too crude? */ + path = vconcat (s, v); + else + path = rel_vconcat (s, v); + + if (!path) + return NULL; + if (strncmp (path, "/./", 3) == 0) memmove (path + 1, path + 3, strlen (path + 3) + 1); @@ -542,7 +585,7 @@ getmntent (FILE *) strcat (mnt.mnt_opts, (char *) ",noexec"); if (m->flags & MOUNT_ENC) strcat (mnt.mnt_opts, ",managed"); - if ((m->flags & MOUNT_CYGDRIVE)) /* cygdrive */ + if ((m->flags & MOUNT_CYGDRIVE)) /* cygdrive */ strcat (mnt.mnt_opts, (char *) ",cygdrive"); mnt.mnt_freq = 1; mnt.mnt_passno = 1;