* fhandler_process.cc (dos_drive_mappings): Partially rewrite to

handle volumes mounted into juntion points correctly.
This commit is contained in:
Corinna Vinschen 2011-12-12 21:38:08 +00:00
parent 1e10d23a56
commit 01ba99e8cd
2 changed files with 91 additions and 74 deletions

View File

@ -1,3 +1,8 @@
2011-12-12 Corinna Vinschen <vinschen@redhat.com>
* fhandler_process.cc (dos_drive_mappings): Partially rewrite to
handle volumes mounted into juntion points correctly.
2011-12-12 Corinna Vinschen <vinschen@redhat.com> 2011-12-12 Corinna Vinschen <vinschen@redhat.com>
* fhandler_process.cc (dos_drive_mappings::dos_drive_mappings): Fully * fhandler_process.cc (dos_drive_mappings::dos_drive_mappings): Fully

View File

@ -549,84 +549,88 @@ struct dos_drive_mappings
struct mapping struct mapping
{ {
mapping *next; mapping *next;
int len; size_t doslen;
wchar_t drive_letter; size_t ntlen;
wchar_t mapping[1]; wchar_t *dospath;
wchar_t *ntdevpath;
}; };
mapping *mappings; mapping *mappings;
dos_drive_mappings () dos_drive_mappings ()
: mappings(0) : mappings(0)
{ {
/* The logical drive strings buffer holds a list of (at most 26) tmp_pathbuf tp;
drive names separated by nulls and terminated by a double-null: wchar_t vol[64]; /* Long enough for Volume GUID string */
wchar_t *devpath = tp.w_get ();
wchar_t *mounts = tp.w_get ();
"a:\\\0b:\\\0...z:\\\0" /* Iterate over all volumes, fetch the first path from the list of
DOS paths the volume is mounted to, or use the GUID volume path
The annoying part is, QueryDosDeviceW wants only "x:" rather otherwise. */
than the "x:\" we get back from GetLogicalDriveStringsW, so HANDLE sh = FindFirstVolumeW (vol, 64);
we'll have to strip out the trailing slash for each mapping. if (sh == INVALID_HANDLE_VALUE)
debug_printf ("FindFirstVolumeW, %E");
The returned mapping a native NT pathname (\Device\...) which
we can use to fix up the output of GetMappedFileNameW
*/
static unsigned const DBUFLEN = 26 * 4;
wchar_t dbuf[DBUFLEN + 1];
wchar_t pbuf[NT_MAX_PATH];
wchar_t drive[] = {L'x', L':', 0};
unsigned result = GetLogicalDriveStringsW (DBUFLEN * sizeof (wchar_t),
dbuf);
if (!result)
debug_printf ("Failed to get logical DOS drive names: %lu",
GetLastError ());
else if (result > DBUFLEN)
debug_printf ("Too many mapped drive letters: %u", result);
else else
for (wchar_t *cur = dbuf; (*drive = *cur); cur = wcschr (cur, L'\0')+1) do
if (QueryDosDeviceW (drive, pbuf, NT_MAX_PATH)) {
{ DWORD len;
/* The DOS drive mapping can be another symbolic link. The result /* Skip drives which are not mounted. */
is that the mapping won't work since the section name is the if (!GetVolumePathNamesForVolumeNameW (vol, mounts, NT_MAX_PATH, &len)
name after resolving all symbolic links. So we have to resolve || mounts[0] == L'\0')
symbolic links here, too. */ continue;
for (int syml_cnt = 0; syml_cnt < SYMLOOP_MAX; ++syml_cnt) *wcsrchr (vol, L'\\') = L'\0';
{ if (QueryDosDeviceW (vol + 4, devpath, NT_MAX_PATH))
UNICODE_STRING upath; {
OBJECT_ATTRIBUTES attr; /* The DOS drive mapping can be another symbolic link. If so,
NTSTATUS status; the mapping won't work since the section name is the name
HANDLE h; after resolving all symlinks. Resolve symlinks here, too. */
for (int syml_cnt = 0; syml_cnt < SYMLOOP_MAX; ++syml_cnt)
{
UNICODE_STRING upath;
OBJECT_ATTRIBUTES attr;
NTSTATUS status;
HANDLE h;
RtlInitUnicodeString (&upath, pbuf); RtlInitUnicodeString (&upath, devpath);
InitializeObjectAttributes (&attr, &upath, OBJ_CASE_INSENSITIVE, InitializeObjectAttributes (&attr, &upath,
NULL, NULL); OBJ_CASE_INSENSITIVE, NULL, NULL);
status = NtOpenSymbolicLinkObject (&h, SYMBOLIC_LINK_QUERY, status = NtOpenSymbolicLinkObject (&h, SYMBOLIC_LINK_QUERY,
&attr); &attr);
if (!NT_SUCCESS (status)) if (!NT_SUCCESS (status))
break; break;
RtlInitEmptyUnicodeString (&upath, pbuf, RtlInitEmptyUnicodeString (&upath, devpath, (NT_MAX_PATH - 1)
(NT_MAX_PATH - 1) * sizeof (WCHAR)); * sizeof (WCHAR));
status = NtQuerySymbolicLinkObject (h, &upath, NULL); status = NtQuerySymbolicLinkObject (h, &upath, NULL);
NtClose (h); NtClose (h);
if (!NT_SUCCESS (status)) if (!NT_SUCCESS (status))
break; break;
pbuf[upath.Length / sizeof (WCHAR)] = L'\0'; devpath[upath.Length / sizeof (WCHAR)] = L'\0';
} }
size_t plen = wcslen (pbuf); mapping *m = new mapping ();
size_t psize = plen * sizeof (wchar_t); if (m)
debug_printf ("DOS drive %ls maps to %ls", drive, pbuf); {
mapping *m = (mapping*) malloc (sizeof (mapping) + psize); m->dospath = wcsdup (mounts);
if (m) m->ntdevpath = wcsdup (devpath);
{ if (!m->dospath || !m->ntdevpath)
m->next = mappings; {
m->len = plen; free (m->dospath);
m->drive_letter = *drive; free (m->ntdevpath);
memcpy (m->mapping, pbuf, psize + sizeof (wchar_t)); delete m;
mappings = m; continue;
} }
} m->doslen = wcslen (m->dospath);
else m->dospath[--m->doslen] = L'\0'; /* Drop trailing backslash */
debug_printf ("Unable to determine the native mapping for %ls " m->ntlen = wcslen (m->ntdevpath);
"(error %lu)", drive, GetLastError ()); m->next = mappings;
mappings = m;
}
}
else
debug_printf ("Unable to determine the native mapping for %ls "
"(error %lu)", vol, GetLastError ());
}
while (FindNextVolumeW (sh, vol, 64));
FindVolumeClose (sh);
} }
wchar_t *fixup_if_match (wchar_t *path) wchar_t *fixup_if_match (wchar_t *path)
@ -640,11 +644,17 @@ struct dos_drive_mappings
} }
/* Then test local drives. */ /* Then test local drives. */
for (mapping *m = mappings; m; m = m->next) for (mapping *m = mappings; m; m = m->next)
if (!wcsncmp (m->mapping, path, m->len)) if (!wcsncmp (m->ntdevpath, path, m->ntlen))
{ {
path += m->len - 2; wchar_t *tmppath;
path[0] = m->drive_letter;
path[1] = L':'; if (m->ntlen > m->doslen)
wcsncpy (path += m->ntlen - m->doslen, m->dospath, m->doslen);
else if ((tmppath = wcsdup (path + m->ntlen)) != NULL)
{
wcpcpy (wcpcpy (path, m->dospath), tmppath);
free (tmppath);
}
break; break;
} }
return path; return path;
@ -656,7 +666,9 @@ struct dos_drive_mappings
for (mapping *m = mappings; m; m = n) for (mapping *m = mappings; m; m = n)
{ {
n = m->next; n = m->next;
free (m); free (m->dospath);
free (m->ntdevpath);
delete m;
} }
} }
}; };