From: corinna Date: Wed, 2 Aug 2006 09:48:17 +0000 (+0000) Subject: * Makefile.in (cygpath.exe): Add rule to link cygpath against ntdll.dll. X-Git-Url: http://git.osdn.net/view?a=commitdiff_plain;h=d00a27f757a5ed9b6069e8205ffeff06d64f86dd;p=pf3gnuchains%2Fsourceware.git * Makefile.in (cygpath.exe): Add rule to link cygpath against ntdll.dll. * cygpath.cc: Include DDK headers. (RtlAllocateUnicodeString): New static inline function. (get_device_name): New static function to evaluate DOS path from native NT path. (get_device_paths): New function to do the same for path lists. (doit): Call get_device_paths/get_device_name where appropriate. --- diff --git a/winsup/utils/ChangeLog b/winsup/utils/ChangeLog index c818a03d9a..8e1afeccc6 100644 --- a/winsup/utils/ChangeLog +++ b/winsup/utils/ChangeLog @@ -1,3 +1,13 @@ +2006-08-02 Corinna Vinschen + + * Makefile.in (cygpath.exe): Add rule to link cygpath against ntdll.dll. + * cygpath.cc: Include DDK headers. + (RtlAllocateUnicodeString): New static inline function. + (get_device_name): New static function to evaluate DOS path from + native NT path. + (get_device_paths): New function to do the same for path lists. + (doit): Call get_device_paths/get_device_name where appropriate. + 2006-07-30 Ilya Bobir * cygpath.cc (get_long_name): Fallback to get_long_path_name_w32impl. diff --git a/winsup/utils/Makefile.in b/winsup/utils/Makefile.in index daa8e5fd14..a14a18f67c 100644 --- a/winsup/utils/Makefile.in +++ b/winsup/utils/Makefile.in @@ -208,6 +208,14 @@ else $(CXX) -o $@ ${wordlist 1,3,$^} -B$(cygwin_build)/ $(DUMPER_LDFLAGS) endif +cygpath.exe: cygpath.o $(ALL_DEP_LDLIBS) +ifdef VERBOSE + $(CXX) -o $@ ${firstword $^} -B$(cygwin_build)/ $(ALL_LDFLAGS) -lntdll +else + @echo $(CXX) -o $@ ${firstword $^} ${filter-out -B%, $(ALL_LDFLAGS) -ntdll};\ + $(CXX) -o $@ ${firstword $^} -B$(cygwin_build)/ $(ALL_LDFLAGS) -ntdll +endif + %.exe: %.o $(ALL_DEP_LDLIBS) ifdef VERBOSE $(CXX) -o $@ ${firstword $^} -B$(cygwin_build)/ $(ALL_LDFLAGS) diff --git a/winsup/utils/cygpath.cc b/winsup/utils/cygpath.cc index 96738b1862..9d0f80d012 100644 --- a/winsup/utils/cygpath.cc +++ b/winsup/utils/cygpath.cc @@ -21,6 +21,9 @@ details. */ #include #include #include +#include +#include +#include static const char version[] = "$Revision$"; @@ -109,6 +112,161 @@ Other options:\n\ exit (ignore_flag ? 0 : status); } +static inline BOOLEAN +RtlAllocateUnicodeString (PUNICODE_STRING uni, ULONG size) +{ + uni->Length = 0; + uni->MaximumLength = 512; + uni->Buffer = (WCHAR *) malloc (size); + return uni->Buffer != NULL; +} + +static char * +get_device_name (char *path) +{ + UNICODE_STRING ntdev, tgtdev, ntdevdir; + ANSI_STRING ans; + OBJECT_ATTRIBUTES ntobj; + NTSTATUS status; + HANDLE lnk, dir; + char *ret = strdup (path); + PDIRECTORY_BASIC_INFORMATION odi = (PDIRECTORY_BASIC_INFORMATION) + alloca (4096); + BOOLEAN restart; + ULONG cont; + + if (strncasecmp (path, "\\Device\\", 8)) + return ret; + + if (!RtlAllocateUnicodeString (&ntdev, MAX_PATH * 2)) + return ret; + if (!RtlAllocateUnicodeString (&tgtdev, MAX_PATH * 2)) + return ret; + RtlInitAnsiString (&ans, path); + RtlAnsiStringToUnicodeString (&ntdev, &ans, FALSE); + + /* First check if the given device name is a symbolic link itself. If so, + query it and use the new name as actual device name to search for in the + DOS device name directory. If not, just use the incoming device name. */ + InitializeObjectAttributes (&ntobj, &ntdev, OBJ_CASE_INSENSITIVE, NULL, NULL); + status = ZwOpenSymbolicLinkObject (&lnk, SYMBOLIC_LINK_QUERY, &ntobj); + if (NT_SUCCESS (status)) + { + status = ZwQuerySymbolicLinkObject (lnk, &tgtdev, NULL); + ZwClose (lnk); + if (!NT_SUCCESS (status)) + goto out; + RtlCopyUnicodeString (&ntdev, &tgtdev); + } + else if (status != STATUS_OBJECT_TYPE_MISMATCH) + goto out; + + for (int i = 0; i < 2; ++i) + { + /* There are two DOS device directories, the local and the global dir. + Try both, local first. */ + RtlInitUnicodeString (&ntdevdir, i ? L"\\GLOBAL??" : L"\\??"); + + /* Open the directory... */ + InitializeObjectAttributes (&ntobj, &ntdevdir, OBJ_CASE_INSENSITIVE, + NULL, NULL); + status = ZwOpenDirectoryObject (&dir, DIRECTORY_QUERY, &ntobj); + if (!NT_SUCCESS (status)) + break; + + /* ...and scan it. */ + for (restart = TRUE, cont = 0; + NT_SUCCESS (ZwQueryDirectoryObject (dir, odi, 4096, TRUE, + restart, &cont, NULL)); + restart = FALSE) + { + /* For each entry check if it's a symbolic link. */ + InitializeObjectAttributes (&ntobj, &odi->ObjectName, + OBJ_CASE_INSENSITIVE, dir, NULL); + status = ZwOpenSymbolicLinkObject (&lnk, SYMBOLIC_LINK_QUERY, &ntobj); + if (!NT_SUCCESS (status)) + continue; + tgtdev.Length = 0; + tgtdev.MaximumLength = 512; + /* If so, query it and compare the target of the symlink with the + incoming device name. */ + status = ZwQuerySymbolicLinkObject (lnk, &tgtdev, NULL); + ZwClose (lnk); + if (!NT_SUCCESS (status)) + continue; + if (RtlEqualUnicodeString (&ntdev, &tgtdev, TRUE)) + { + /* If the comparison succeeds, the name of the directory entry is + a valid DOS device name, if prepended with "\\.\". Return that + valid DOS path. */ + ULONG len = RtlUnicodeStringToAnsiSize (&odi->ObjectName); + ret = (char *) malloc (len + 4); + strcpy (ret, "\\\\.\\"); + ans.Length = 0; + ans.MaximumLength = len; + ans.Buffer = ret + 4; + RtlUnicodeStringToAnsiString (&ans, &odi->ObjectName, FALSE); + ZwClose (dir); + goto out; + } + } + ZwClose (dir); + } + +out: + free (tgtdev.Buffer); + free (ntdev.Buffer); + return ret; +} + +static char * +get_device_paths (char *path) +{ + char *sbuf; + char *ptr; + int n = 1; + + ptr = path; + while ((ptr = strchr (ptr, ';'))) + { + ptr++; + n++; + } + + char *paths[n]; + DWORD acc = 0; + int i; + if (!n) + return strdup (""); + + for (i = 0, ptr = path; ptr; i++) + { + char *next = ptr; + ptr = strchr (ptr, ';'); + if (ptr) + *ptr++ = 0; + paths[i] = get_device_name (next); + acc += strlen (paths[i]) + 1; + } + + sbuf = (char *) malloc (acc + 1); + if (sbuf == NULL) + { + fprintf (stderr, "%s: out of memory\n", prog_name); + exit (1); + } + + sbuf[0] = '\0'; + for (i = 0; i < n; i++) + { + strcat (strcat (sbuf, paths[i]), ";"); + free (paths[i]); + } + + strchr (sbuf, '\0')[-1] = '\0'; + return sbuf; +} + static char * get_short_paths (char *path) { @@ -487,6 +645,7 @@ doit (char *filename) err = cygwin_posix_to_win32_path_list (filename, buf); if (err) /* oops */; + buf = get_device_paths (buf); if (shortname_flag) buf = get_short_paths (buf); if (longname_flag) @@ -518,6 +677,7 @@ doit (char *filename) } if (!unix_flag) { + buf = get_device_name (buf); if (shortname_flag) buf = get_short_name (buf); if (longname_flag)