Welcome to mirror list, hosted at ThFree Co, Russian Federation.

cygwin.com/git/newlib-cygwin.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCorinna Vinschen <corinna@vinschen.de>2006-08-02 13:48:18 +0400
committerCorinna Vinschen <corinna@vinschen.de>2006-08-02 13:48:18 +0400
commit2dba45f4aab6206025bb2f09c6e6a68d20386628 (patch)
tree88ff1d3191d02562f91039e3f172a25326c88337 /winsup/utils/cygpath.cc
parent2ebf115df97ff9ad5d72fe7723f934e0104b0e08 (diff)
* 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.
Diffstat (limited to 'winsup/utils/cygpath.cc')
-rw-r--r--winsup/utils/cygpath.cc160
1 files changed, 160 insertions, 0 deletions
diff --git a/winsup/utils/cygpath.cc b/winsup/utils/cygpath.cc
index 96738b186..9d0f80d01 100644
--- a/winsup/utils/cygpath.cc
+++ b/winsup/utils/cygpath.cc
@@ -21,6 +21,9 @@ details. */
#include <sys/cygwin.h>
#include <ctype.h>
#include <errno.h>
+#include <ddk/ntddk.h>
+#include <ddk/winddk.h>
+#include <ddk/ntifs.h>
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)