ntdll / kernel32: #42
Eric Pouech
pouech-eric at wanadoo.fr
Wed Feb 4 14:55:09 CST 2004
New volume management functions from NT
- implementation of Find{First|Next}Volume[AW], FindVolumeClose,
- partial implementation of DeleteVolumeMountPoint[AW],
GetVolumeNameForVolumeMountPoint[AW], SetVolumeMountPoint[AW]
(only works when mount point is at root)
- rewrite of QueryDosDevice, DefineDosDevice for new fs scheme
Note: DefineDosDevice is now broken (until patch 47)
-------------- next part --------------
diff -u -N -r -x '*~' -x '.#*' -x CVS dlls/kernel41/kernel32.spec dlls/kernel/kernel32.spec
--- dlls/kernel41/kernel32.spec 2004-02-01 13:25:28.000000000 +0100
+++ dlls/kernel/kernel32.spec 2004-02-01 14:10:48.000000000 +0100
@@ -227,6 +227,8 @@
@ stdcall DeleteCriticalSection(ptr) ntdll.RtlDeleteCriticalSection
@ stdcall DeleteFileA(str)
@ stdcall DeleteFileW(wstr)
+@ stdcall DeleteVolumeMountPointA(str)
+@ stdcall DeleteVolumeMountPointW(wstr)
@ stdcall DeviceIoControl(long long ptr long ptr long ptr ptr)
@ stdcall DisableThreadLibraryCalls(long)
@ stdcall DisconnectNamedPipe(long)
@@ -302,22 +304,22 @@
@ stdcall FindFirstChangeNotificationW(wstr long long)
@ stdcall FindFirstFileA(str ptr)
@ stdcall FindFirstFileW(wstr ptr)
-@ stub FindFirstVolumeA
-@ stub FindFirstVolumeW
+@ stdcall FindFirstVolumeA(ptr long)
+@ stdcall FindFirstVolumeW(ptr long)
@ stub FindFirstVolumeMountPointA
@ stub FindFirstVolumeMountPointW
@ stdcall FindNextChangeNotification(long)
@ stdcall FindNextFileA(long ptr)
@ stdcall FindNextFileW(long ptr)
-@ stub FindNextVolumeA
-@ stub FindNextVolumeW
+@ stdcall FindNextVolumeA(long ptr long)
+@ stdcall FindNextVolumeW(long ptr long)
@ stub FindNextVolumeMountPointA
@ stub FindNextVolumeMountPointW
@ stdcall FindResourceA(long str str)
@ stdcall FindResourceExA(long str str long)
@ stdcall FindResourceExW(long wstr wstr long)
@ stdcall FindResourceW(long wstr wstr)
-@ stub FindVolumeClose
+@ stdcall FindVolumeClose(long)
@ stub FindVolumeMountPointClose
@ stdcall FlushConsoleInputBuffer(long)
@ stdcall FlushFileBuffers(long)
@@ -512,8 +514,8 @@
@ stdcall GetVersionExW(ptr)
@ stdcall GetVolumeInformationA(str ptr long ptr ptr ptr ptr long)
@ stdcall GetVolumeInformationW(wstr ptr long ptr ptr ptr ptr long)
-@ stub GetVolumeNameForVolumeMountPointA
-@ stdcall GetVolumeNameForVolumeMountPointW(wstr long long)
+@ stdcall GetVolumeNameForVolumeMountPointA(str ptr long)
+@ stdcall GetVolumeNameForVolumeMountPointW(wstr ptr long)
@ stub GetVolumePathNameA
@ stub GetVolumePathNameW
@ stdcall GetWindowsDirectoryA(ptr long)
@@ -796,8 +798,8 @@
@ stdcall SetUserGeoID(long)
@ stdcall SetVolumeLabelA(str str)
@ stdcall SetVolumeLabelW(wstr wstr)
-@ stub SetVolumeMountPointA
-@ stub SetVolumeMountPointW
+@ stdcall SetVolumeMountPointA(str str)
+@ stdcall SetVolumeMountPointW(wstr wstr)
@ stdcall SetupComm(long long long)
@ stdcall SizeofResource(long long)
@ stdcall Sleep(long)
diff -u -N -r -x '*~' -x '.#*' -x CVS dlls/kernel41/kernel_private.h dlls/kernel/kernel_private.h
--- dlls/kernel41/kernel_private.h 2004-01-14 22:29:57.000000000 +0100
+++ dlls/kernel/kernel_private.h 2004-01-18 19:13:01.000000000 +0100
@@ -48,6 +48,7 @@
#define DOS_TABLE_SIZE 256
extern HANDLE dos_handles[DOS_TABLE_SIZE];
void FILE_ConvertOFMode( INT mode, DWORD *access, DWORD *sharing );
+void FILE_SetDosError(void);
extern void PTHREAD_Init(void);
extern BOOL WOWTHUNK_Init(void);
diff -u -N -r -x '*~' -x '.#*' -x CVS dlls/kernel41/Makefile.in dlls/kernel/Makefile.in
--- dlls/kernel41/Makefile.in 2004-02-01 13:25:28.000000000 +0100
+++ dlls/kernel/Makefile.in 2004-02-01 14:10:47.000000000 +0100
@@ -77,6 +77,7 @@
version.c \
virtual.c \
vxd.c \
+ volume.c \
win87em.c \
windebug.c \
wowthunk.c
diff -u -N -r -x '*~' -x '.#*' -x CVS dlls/kernel41/tests/drive.c dlls/kernel/tests/drive.c
--- dlls/kernel41/tests/drive.c 2004-01-23 22:19:47.000000000 +0100
+++ dlls/kernel/tests/drive.c 2004-01-23 22:21:08.000000000 +0100
@@ -173,11 +173,92 @@
}
}
+/* those function only appear starting at Win2k, so call them thru pointers */
+static HANDLE (WINAPI *pFindFirstVolumeA)(LPSTR,DWORD);
+static BOOL (WINAPI *pFindNextVolumeA)(HANDLE,LPSTR,DWORD);
+static BOOL (WINAPI *pFindVolumeClose)(HANDLE);
+static BOOL (WINAPI *pGetVolumeNameForVolumeMountPointA)(LPCSTR,LPSTR,DWORD);
+
+static void test_Volume(void)
+{
+ char buffer[MAX_PATH];
+ HANDLE h = pFindFirstVolumeA(buffer, sizeof(buffer));
+ char drv[] = "A:\\";
+ DWORD map = GetLogicalDrives();
+ char* ptr;
+ unsigned ret;
+
+ ok(h != INVALID_HANDLE_VALUE, "enum of volumes");
+ if (h != INVALID_HANDLE_VALUE)
+ {
+ do
+ {
+ trace("Got volume %s\n", buffer);
+ } while (pFindNextVolumeA(h, buffer, sizeof(buffer)));
+ pFindVolumeClose(h);
+ }
+ for (drv[0] = 'A'; drv[0] <= 'Z'; drv[0]++)
+ {
+ ret = pGetVolumeNameForVolumeMountPointA(drv, buffer, sizeof(buffer));
+ if (map & (1 << (drv[0] - 'A')))
+ {
+ ok(ret, "Couldn't get volume mount point (%lu)\n", GetLastError());
+ trace("%s => %s\n", drv, buffer);
+ }
+ else
+ ok(!ret, "Shouldn't get volume mount point\n");
+ }
+ ret = GetLogicalDriveStringsA(sizeof(buffer) - 1, buffer);
+ ok(ret > 0 && ret < sizeof(buffer),
+ "Cannot get drive strings (%lu)\n", GetLastError());
+ if (ret > 0 && ret < sizeof(buffer))
+ {
+ for (ptr = buffer; *ptr; ptr += strlen(ptr) + 1)
+ {
+ trace("\t%s\n", ptr);
+ ok(map & (1 << (toupper(*ptr) - 'A')), "Wrong bit set\n");
+ }
+ }
+}
+
+static void test_QueryDosDevice(void)
+{
+ char buffer[1024];
+ DWORD len;
+
+ struct {const char* dev; const char* result;} tests[] = {
+ {"com1", "\\device\\serial0"},
+ {"lpt1", "\\device\\parallel0"},
+ {"nul", "\\device\\null"},
+ {"aux", "\\dosdevices\\com1"},
+ {NULL, NULL}
+ }, *test;
+ for (test = tests; test->dev; test++)
+ {
+ len = QueryDosDevice(test->dev, buffer, sizeof(buffer));
+ ok(len, "QueryDosDevice failed on %s\n", test->dev);
+ if (len)
+ ok(strcmp(buffer, test->result) == 0, "Mismatch %s instead of %s\n", buffer, test->result);
+ }
+ ok(QueryDosDevice(NULL, buffer, sizeof(buffer)), "QueryDosDevice failed on <null>\n");
+}
+
START_TEST(drive)
{
+ HMODULE mod;
+
test_GetDriveTypeA();
test_GetDriveTypeW();
test_GetDiskFreeSpaceA();
test_GetDiskFreeSpaceW();
+
+ mod = GetModuleHandleA("kernel32.dll");
+ pFindFirstVolumeA = (void *)GetProcAddress(mod,"FindFirstVolumeA");
+ pFindNextVolumeA = (void *)GetProcAddress(mod,"FindNextVolumeA");
+ pFindVolumeClose = (void *)GetProcAddress(mod,"FindVolumeClose");
+ pGetVolumeNameForVolumeMountPointA = (void *)GetProcAddress(mod,"GetVolumeNameForVolumeMountPointA");
+
+ if (pFindFirstVolumeA) test_Volume();
+ test_QueryDosDevice();
}
diff -u -N -r -x '*~' -x '.#*' -x CVS dlls/kernel41/volume.c dlls/kernel/volume.c
--- dlls/kernel41/volume.c 1970-01-01 01:00:00.000000000 +0100
+++ dlls/kernel/volume.c 2004-02-01 21:13:30.000000000 +0100
@@ -0,0 +1,593 @@
+/*
+ * Volume file system functions
+ *
+ * Label & serial number read support.
+ * (c) 1999 Petr Tomasek <tomasek at etf.cuni.cz>
+ * (c) 2000 Andreas Mohr (changes)
+ *
+ * Copyright 1993 Erik Bos
+ * Copyright 1996 Alexandre Julliard
+ * Copyright 2003 Eric Pouech
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "config.h"
+#include "wine/port.h"
+
+#include <dirent.h>
+#include <stdarg.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#define NONAMELESSUNION
+#define NONAMELESSSTRUCT
+#include "windef.h"
+#include "winbase.h"
+#include "winnls.h"
+#include "winreg.h"
+#include "winternl.h"
+
+#include "wine/windef16.h"
+#include "kernel_private.h"
+
+#include "wine/unicode.h"
+#include "wine/library.h"
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(file);
+
+/******************************************************************
+ * get_volume
+ *
+ *
+ */
+static BOOL get_volume(char drive, char* dst, size_t size)
+{
+ char path[MAX_PATH], tmp[MAX_PATH];
+ LPCSTR beg, end;
+ struct stat st;
+ size_t len;
+
+ sprintf(path, "%s/dosdevices/%c:", wine_get_config_dir(), drive);
+ if (lstat(path, &st) == -1 || !S_ISLNK(st.st_mode))
+ {
+ SetLastError(ERROR_PATH_NOT_FOUND);
+ return FALSE;
+ }
+ len = readlink(path, tmp, sizeof(tmp));
+ if (len == -1)
+ {
+ FILE_SetDosError();
+ return FALSE;
+ }
+ if (len >= sizeof(tmp))
+ {
+ SetLastError(ERROR_INSUFFICIENT_BUFFER);
+ return FALSE;
+ }
+ tmp[len] = '\0';
+ /* FIXME: this is a bit harsh for parsing the volume name... */
+ if (!(beg = strstr(tmp, "/volume{")) || !(end = strchr(beg + 7, '}')))
+ {
+ FIXME("Internal error in string parsing (%s)\n", tmp);
+ return FALSE;
+ }
+ len = end - beg;
+ if (len + 1 > size)
+ {
+ SetLastError(ERROR_INSUFFICIENT_BUFFER);
+ return FALSE;
+ }
+ strncpy(dst, beg + 1, len);
+ dst[len] = '\0';
+ return TRUE;
+}
+
+struct volume_enum
+{
+ LPWSTR index;
+ WCHAR data[1];
+};
+
+/******************************************************************
+ * FindFirstVolumeA (KERNEL32.@)
+ */
+HANDLE WINAPI FindFirstVolumeA(LPSTR buffer, DWORD size)
+{
+ LPWSTR ptr = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR));
+ HANDLE h;
+
+ if (!ptr) return INVALID_HANDLE_VALUE;
+ if ((h = FindFirstVolumeW(ptr, size)) != INVALID_HANDLE_VALUE)
+ WideCharToMultiByte(CP_ACP, 0, ptr, -1, buffer, size, NULL, NULL);
+ HeapFree(GetProcessHeap(), 0, ptr);
+ return h;
+}
+
+/******************************************************************
+ * FindNextVolumeA (KERNEL32.@)
+ */
+BOOL WINAPI FindNextVolumeA(HANDLE h, LPSTR buffer, DWORD size)
+{
+ LPWSTR ptr = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR));
+ BOOL ret;
+
+ if (!ptr) return FALSE;
+ if ((ret = FindNextVolumeW(h, ptr, size)))
+ WideCharToMultiByte(CP_ACP, 0, ptr, -1, buffer, size, NULL, NULL);
+ HeapFree(GetProcessHeap(), 0, ptr);
+ return ret;
+}
+
+/******************************************************************
+ * FindFirstVolumeW (KERNEL32.@)
+ */
+HANDLE WINAPI FindFirstVolumeW(LPWSTR buffer, DWORD size)
+{
+ unsigned used = 0, len;
+ struct volume_enum* ve = HeapAlloc(GetProcessHeap(), 0, sizeof(*ve));
+ char path[MAX_PATH];
+ DIR* dir;
+ struct dirent* de;
+
+ if (!ve) return INVALID_HANDLE_VALUE;
+ sprintf(path, "%s/device/", wine_get_config_dir());
+
+ ve->index = ve->data;
+ dir = opendir(path);
+ if (dir)
+ {
+ while ((de = readdir(dir)))
+ {
+ if (strncmp(de->d_name, "volume{", 7)) continue;
+ len = MultiByteToWideChar(CP_UNIXCP, 0, de->d_name, -1, NULL, 0);
+ ve = HeapReAlloc(GetProcessHeap(), 0, ve,
+ sizeof(*ve) + (used + len) * sizeof(WCHAR));
+ if (!ve) return INVALID_HANDLE_VALUE;
+ MultiByteToWideChar(CP_UNIXCP, 0, de->d_name, -1, &ve->data[used], len);
+ used += len;
+ }
+ ve->data[used] = '\0';
+ }
+ closedir(dir);
+ if (!FindNextVolumeW((HANDLE)ve, buffer, size))
+ {
+ FindVolumeClose((HANDLE)ve);
+ return INVALID_HANDLE_VALUE;
+ }
+ return (HANDLE)ve;
+}
+
+/******************************************************************
+ * FindNextVolumeW (KERNEL32.@)
+ */
+BOOL WINAPI FindNextVolumeW(HANDLE h, LPWSTR buffer, DWORD size)
+{
+ struct volume_enum* ve = (void*)h;
+ size_t len;
+
+ if (h == INVALID_HANDLE_VALUE) return FALSE;
+ if (!*ve->index) return FALSE; /* last element, set last error ? */
+ len = strlenW(ve->index) + 1;
+ if (size < len)
+ {
+ SetLastError(ERROR_INSUFFICIENT_BUFFER);
+ return FALSE;
+ }
+ memcpy(buffer, ve->index, len * sizeof(WCHAR));
+ ve->index += len;
+ return TRUE;
+}
+
+/******************************************************************
+ * FindVolumeClose (KERNEL32.@)
+ */
+BOOL WINAPI FindVolumeClose(HANDLE h)
+{
+ return HeapFree(GetProcessHeap(), 0, (void*)h);
+}
+
+/***********************************************************************
+ * GetVolumeNameForVolumeMountPointA (KERNEL32.@)
+ */
+BOOL WINAPI GetVolumeNameForVolumeMountPointA(LPCSTR mount, LPSTR dst, DWORD size)
+{
+ LPWSTR mountW, dstW;
+ unsigned len;
+ BOOL ret;
+
+ len = MultiByteToWideChar(CP_ACP, 0, mount, -1, NULL, 0);
+ mountW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
+ if (!mountW) return FALSE;
+ MultiByteToWideChar(CP_ACP, 0, mount, -1, mountW, len);
+ dstW = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR));
+ if (!dstW)
+ {
+ HeapFree(GetProcessHeap(), 0, mountW);
+ return FALSE;
+ }
+ if ((ret = GetVolumeNameForVolumeMountPointW(mountW, dstW, size)))
+ WideCharToMultiByte(CP_ACP, 0, dstW, -1, dst, size, NULL, NULL);
+ HeapFree(GetProcessHeap(), 0, mountW);
+ HeapFree(GetProcessHeap(), 0, dstW);
+ return ret;
+}
+
+/***********************************************************************
+ * GetVolumeNameForVolumeMountPointW (KERNEL32.@)
+ */
+BOOL WINAPI GetVolumeNameForVolumeMountPointW(LPCWSTR mount, LPWSTR dst, DWORD size)
+{
+ char tmp[MAX_PATH];
+
+ TRACE("(%s, %p, %lx)\n", debugstr_w(mount), dst, size);
+
+ /* we only support setting mount points on root directory */
+ if (strlenW(mount) != 3 || mount[1] != ':' || mount[2] != '\\')
+ {
+ FIXME("Unsupported mount point %s\n", debugstr_w(mount));
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return FALSE;
+ }
+ if (!get_volume(tolowerW(mount[0]), tmp, sizeof(tmp))) return FALSE;
+
+ dst[0] = dst[1] = dst[3] = '\\'; dst[2] = '?';
+ MultiByteToWideChar(CP_UNIXCP, 0, tmp, -1, dst + 4, size - 4);
+ return TRUE;
+}
+
+
+/******************************************************************
+ * SetVolumeMountPointA (KERNEL32.@)
+ */
+BOOL WINAPI SetVolumeMountPointA(LPCSTR mount, LPCSTR volume)
+{
+ LPWSTR mountW, volumeW;
+ unsigned len;
+ BOOL ret;
+
+ len = MultiByteToWideChar(CP_ACP, 0, mount, -1, NULL, 0);
+ mountW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
+ if (!mountW) return FALSE;
+ MultiByteToWideChar(CP_ACP, 0, mount, -1, mountW, len);
+ len = MultiByteToWideChar(CP_ACP, 0, volume, -1, NULL, 0);
+ volumeW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
+ if (!volumeW)
+ {
+ HeapFree(GetProcessHeap(), 0, mountW);
+ return FALSE;
+ }
+ MultiByteToWideChar(CP_ACP, 0, volume, -1, volumeW, len);
+
+ ret = SetVolumeMountPointW(mountW, volumeW);
+ HeapFree(GetProcessHeap(), 0, mountW);
+ HeapFree(GetProcessHeap(), 0, volumeW);
+ return ret;
+}
+
+/******************************************************************
+ * SetVolumeMountPointW (KERNEL32.@)
+ */
+BOOL WINAPI SetVolumeMountPointW(LPCWSTR mount, LPCWSTR volumeW)
+{
+ char volume[MAX_PATH], dosmnt1[MAX_PATH], dosmnt2[MAX_PATH];
+ struct stat st;
+
+ if (strlenW(mount) < 3 || mount[1] != ':' || mount[2] != '\\')
+ {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return FALSE;
+ }
+ WideCharToMultiByte(CP_UNIXCP, 0, volumeW, -1, volume, sizeof(volume), NULL, NULL);
+
+ /* MS doc is ambiguous here... in some cases, it says it'll unmount the
+ * existing mount if any, in some other cases it says it won't delete it
+ * at root dir... doing the latest
+ */
+ sprintf(dosmnt2, "%s/device/%s/mount", wine_get_config_dir(), volume);
+
+ if (!wine_get_unix_file_name(mount, dosmnt1, sizeof(dosmnt1)))
+ {
+ SetLastError(ERROR_PATH_NOT_FOUND);
+ return FALSE;
+ }
+ if (stat(dosmnt1, &st) == -1 && !S_ISDIR(st.st_mode))
+ {
+ SetLastError(ERROR_FILE_NOT_FOUND);
+ return FALSE;
+ }
+ /* volume should exist and be mounted */
+ if (stat(dosmnt2, &st) == -1)
+ {
+ SetLastError(ERROR_PATH_NOT_FOUND);
+ return FALSE;
+ }
+ /* we fake the mount by:
+ * 1/ remove the dir
+ * 2/ symlink the dir to the volume mount point
+ */
+ if (rmdir(dosmnt1) == -1)
+ {
+ FILE_SetDosError();
+ return FALSE;
+ }
+ if (symlink(dosmnt1, dosmnt2) == -1)
+ {
+ FILE_SetDosError();
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/******************************************************************
+ * DeleteVolumeMountPointA (KERNEL32.@)
+ */
+BOOL WINAPI DeleteVolumeMountPointA(LPCSTR mount)
+{
+ UNICODE_STRING m;
+ BOOL ret;
+
+ if (!RtlCreateUnicodeStringFromAsciiz(&m, mount))
+ {
+ SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ return FALSE;
+ }
+ ret = DeleteVolumeMountPointW(m.Buffer);
+ RtlFreeUnicodeString(&m);
+ return ret;
+}
+
+/******************************************************************
+ * DeleteVolumeMountPointW (KERNEL32.@)
+ */
+BOOL WINAPI DeleteVolumeMountPointW(LPCWSTR mount)
+{
+ char buffer[MAX_PATH];
+ struct stat st;
+
+ if (!wine_get_unix_file_name(mount, buffer, sizeof(buffer)))
+ {
+ SetLastError(ERROR_PATH_NOT_FOUND);
+ return FALSE;
+ }
+ if (lstat(buffer, &st) != -1 && S_ISLNK(st.st_mode) &&
+ unlink(buffer) != -1 && mkdir(buffer, 0777) != -1)
+ return TRUE;
+ FILE_SetDosError();
+ return FALSE;
+}
+
+/***********************************************************************
+ * DefineDosDeviceA (KERNEL32.@)
+ */
+BOOL WINAPI DefineDosDeviceA(DWORD flags,LPCSTR devname,LPCSTR targetpath)
+{
+ UNICODE_STRING d, t;
+ BOOL ret;
+
+ if (!RtlCreateUnicodeStringFromAsciiz(&d, devname))
+ {
+ SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ return FALSE;
+ }
+ if (!RtlCreateUnicodeStringFromAsciiz(&t, targetpath))
+ {
+ RtlFreeUnicodeString(&d);
+ SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ return FALSE;
+ }
+ ret = DefineDosDeviceW(flags, d.Buffer, t.Buffer);
+ RtlFreeUnicodeString(&d);
+ RtlFreeUnicodeString(&t);
+ return ret;
+}
+
+
+/***********************************************************************
+ * DefineDosDeviceA (KERNEL32.@)
+ */
+BOOL WINAPI DefineDosDeviceW(DWORD flags, LPCWSTR devname, LPCWSTR targetpath)
+{
+ UNICODE_STRING ustr;
+ char volume[MAX_PATH], dosmnt1[MAX_PATH], dosmnt2[MAX_PATH],
+ device1[MAX_PATH], device2[MAX_PATH];
+ struct stat st;
+
+ /* FIXME: so far we only support drive as dos devices */
+ if (!(toupperW(devname[0]) >= 'A' && toupperW(devname[0]) <= 'Z') ||
+ devname[1] != ':' || devname[2] != 0)
+ {
+ FIXME("(0x%08lx,%s,%s),stub!\n", flags, debugstr_w(devname), debugstr_w(targetpath));
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return FALSE;
+ }
+ if (flags & DDD_RAW_TARGET_PATH)
+ {
+ RtlInitUnicodeString(&ustr, targetpath);
+ }
+ else if (!RtlDosPathNameToNtPathName_U(targetpath, &ustr, NULL, NULL))
+ {
+ SetLastError(ERROR_PATH_NOT_FOUND);
+ return FALSE;
+ }
+
+ WideCharToMultiByte(CP_UNIXCP, 0, ustr.Buffer, -1, volume, sizeof(volume), NULL, NULL);
+ if (!(flags & DDD_RAW_TARGET_PATH))
+ RtlFreeUnicodeString(&ustr);
+
+ /* FIXME: check it this is correct ? */
+ if (strncmp(volume, "\\\\?\\device\\", 12))
+ {
+ SetLastError(ERROR_PATH_NOT_FOUND);
+ return FALSE;
+ }
+ /* FIXME: we should check that no other drive is mapped to his very volume... */
+ sprintf(dosmnt1, "%s/dosdevices/%c:", wine_get_config_dir(), tolower(devname[0]));
+ sprintf(dosmnt2, "%s/device/%s/mount", wine_get_config_dir(), volume + 12);
+ sprintf(device1, "%s/device/%c:", wine_get_config_dir(), tolower(devname[0]));
+ sprintf(device2, "%s/device/%s", wine_get_config_dir(), volume + 12);
+
+ if (flags & DDD_REMOVE_DEFINITION)
+ {
+ if (unlink(dosmnt1) == -1 || unlink(device1) == -1)
+ {
+ FILE_SetDosError();
+ return FALSE;
+ }
+ return TRUE;
+ }
+
+ /* MS doc is ambiguous here... in some cases, it says it'll unmount the
+ * existing mount if any, in some other cases it says it won't delete it
+ * at root dir... doing the latest
+ */
+ /* symlink destination should exist */
+ if (stat(dosmnt2, &st) == -1 || stat(device2, &st) == -1)
+ {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return FALSE;
+ }
+ /* symlink source shouldn't exist */
+ if (stat(dosmnt1, &st) != -1 || stat(device1, &st) != -1)
+ {
+ SetLastError(ERROR_ALREADY_ASSIGNED);
+ return FALSE;
+ }
+ if (symlink(dosmnt2, dosmnt1) == -1)
+ {
+ FILE_SetDosError();
+ return FALSE;
+ }
+ if (symlink(device2, device1) == -1)
+ {
+ FILE_SetDosError();
+ remove(dosmnt2);
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/***********************************************************************
+ * QueryDosDeviceA (KERNEL32.@)
+ *
+ * returns array of strings terminated by \0, terminated by \0
+ */
+DWORD WINAPI QueryDosDeviceA(LPCSTR devname, LPSTR target, DWORD bufsize)
+{
+ DWORD ret = 0, retW;
+ LPWSTR targetW = (LPWSTR)HeapAlloc(GetProcessHeap(), 0,
+ bufsize * sizeof(WCHAR));
+ UNICODE_STRING devnameW;
+
+ if (devname) RtlCreateUnicodeStringFromAsciiz(&devnameW, devname);
+ else devnameW.Buffer = NULL;
+
+ retW = QueryDosDeviceW(devnameW.Buffer, targetW, bufsize);
+
+ ret = WideCharToMultiByte(CP_ACP, 0, targetW, retW, target,
+ bufsize, NULL, NULL);
+
+ RtlFreeUnicodeString(&devnameW);
+ if (targetW) HeapFree(GetProcessHeap(), 0, targetW);
+ return ret;
+}
+
+
+/***********************************************************************
+ * QueryDosDeviceW (KERNEL32.@)
+ *
+ * returns array of strings terminated by \0, terminated by \0
+ *
+ * FIXME
+ * - Win9x returns for all calls ERROR_INVALID_PARAMETER
+ */
+DWORD WINAPI QueryDosDeviceW(LPCWSTR devname, LPWSTR target, DWORD bufsize)
+{
+ int len;
+ DWORD cnt;
+ char buffer[MAX_PATH], dst[MAX_PATH];
+ LPSTR ptr;
+ struct stat st;
+
+ TRACE("(%s,%p,%lu)\n", debugstr_w(devname), target, bufsize);
+ SetLastError(0);
+ if (!devname)
+ {
+ DWORD ret = 0;
+ char path[MAX_PATH];
+ DIR* dir;
+ struct dirent* de;
+
+ len = sprintf(path, "%s/dosdevices/", wine_get_config_dir());
+
+ if ((dir = opendir(path)))
+ {
+ while ((de = readdir(dir)))
+ {
+ strcpy(path + len, de->d_name);
+ if (lstat(path, &st) != -1 && S_ISLNK(st.st_mode))
+ {
+ cnt = MultiByteToWideChar(CP_UNIXCP, 0, de->d_name, -1, NULL, 0);
+ if (target)
+ {
+ if (ret + cnt + 1 > bufsize)
+ {
+ /* in this case WinXP returns 0 */
+ FIXME("function return is wrong for WinXP!\n");
+ SetLastError(ERROR_INSUFFICIENT_BUFFER);
+ break;
+ }
+ MultiByteToWideChar(CP_UNIXCP, 0, de->d_name, -1,
+ target + ret, bufsize - ret);
+ }
+ ret += cnt;
+ }
+
+ }
+ closedir(dir);
+ }
+ if (target && bufsize > 0) target[ret++] = '\0';
+ return ret;
+ }
+ len = sprintf(buffer, "%s/dosdevices/", wine_get_config_dir());
+ WideCharToMultiByte(CP_UNIXCP, 0, devname, -1, buffer + len, sizeof(buffer) - len, NULL, NULL);
+ for (ptr = buffer + len; *ptr; ptr++) *ptr = tolower(*ptr);
+ if (lstat(buffer, &st) != -1 && S_ISLNK(st.st_mode))
+ {
+ len = readlink(buffer, dst, sizeof(dst));
+ if (len > 0 && len < sizeof(dst))
+ {
+ if (len >= 7 && !strncmp(dst + len - 7, "/device", 7)) len -= 7;
+ dst[len] = '\0';
+ for (cnt = 0, ptr = dst + len - 1; ptr >= dst; ptr--)
+ {
+ if (*ptr == '/')
+ {
+ *ptr = '\\';
+ if (cnt++ == 1)
+ return MultiByteToWideChar(CP_UNIXCP, 0, ptr, -1, target, bufsize);
+ }
+ }
+ ERR("Malformated device %s for %s\n", dst, buffer);
+ }
+ else ERR("Cannot read symlink for %s\n", buffer);
+ }
+ else FIXME("(%s) not detected as DOS device!\n", debugstr_w(devname));
+ /* Win9x set the error ERROR_INVALID_PARAMETER */
+ SetLastError(ERROR_FILE_NOT_FOUND);
+ return 0;
+}
diff -u -N -r -x '*~' -x '.#*' -x CVS dlls/ntdll41/path.c dlls/ntdll/path.c
--- dlls/ntdll41/path.c 2004-01-23 22:20:11.000000000 +0100
+++ dlls/ntdll/path.c 2004-01-23 22:21:24.000000000 +0100
@@ -168,7 +168,7 @@
* FIXME:
* + fill the cd structure
*/
-BOOLEAN WINAPI RtlDosPathNameToNtPathName_U(PWSTR dos_path,
+BOOLEAN WINAPI RtlDosPathNameToNtPathName_U(PCWSTR dos_path,
PUNICODE_STRING ntpath,
PWSTR* file_part,
CURDIR* cd)
diff -u -N -r -x '*~' -x '.#*' -x CVS files41/dos_fs.c files/dos_fs.c
--- files41/dos_fs.c 2004-01-23 22:19:48.000000000 +0100
+++ files/dos_fs.c 2004-01-23 22:21:09.000000000 +0100
@@ -1682,124 +1682,3 @@
}
-/***********************************************************************
- * QueryDosDeviceA (KERNEL32.@)
- *
- * returns array of strings terminated by \0, terminated by \0
- */
-DWORD WINAPI QueryDosDeviceA(LPCSTR devname,LPSTR target,DWORD bufsize)
-{
- DWORD ret = 0, retW;
- LPWSTR targetW = (LPWSTR)HeapAlloc(GetProcessHeap(),0,
- bufsize * sizeof(WCHAR));
- UNICODE_STRING devnameW;
-
- if(devname) RtlCreateUnicodeStringFromAsciiz(&devnameW, devname);
- else devnameW.Buffer = NULL;
-
- retW = QueryDosDeviceW(devnameW.Buffer, targetW, bufsize);
-
- ret = WideCharToMultiByte(CP_ACP, 0, targetW, retW, target,
- bufsize, NULL, NULL);
-
- RtlFreeUnicodeString(&devnameW);
- if (targetW) HeapFree(GetProcessHeap(),0,targetW);
- return ret;
-}
-
-
-/***********************************************************************
- * QueryDosDeviceW (KERNEL32.@)
- *
- * returns array of strings terminated by \0, terminated by \0
- *
- * FIXME
- * - Win9x returns for all calls ERROR_INVALID_PARAMETER
- * - the returned devices for devname == NULL is far from complete
- * - its not checked that the returned device exist
- */
-DWORD WINAPI QueryDosDeviceW(LPCWSTR devname,LPWSTR target,DWORD bufsize)
-{
- const WCHAR *pDev, *pName, *pNum = NULL;
- int numsiz=0;
- DWORD ret;
-
- TRACE("(%s,...)\n", debugstr_w(devname));
- if (!devname) {
- /* return known MSDOS devices */
- DWORD ret = 0;
- int i;
- static const WCHAR devices[][5] = {{'A','U','X',0},
- {'C','O','M','1',0},
- {'C','O','M','2',0},
- {'L','P','T','1',0},
- {'N','U','L',0,}};
- for(i=0; (i< (sizeof(devices)/sizeof(devices[0]))); i++) {
- DWORD len = strlenW(devices[i]);
- if(target && (bufsize >= ret + len + 2)) {
- strcpyW(target+ret, devices[i]);
- ret += len + 1;
- } else {
- /* in this case WinXP returns 0 */
- FIXME("function return is wrong for WinXP!\n");
- SetLastError(ERROR_INSUFFICIENT_BUFFER);
- break;
- }
- }
- /* append drives here */
- if(target && bufsize > 0) target[ret++] = 0;
- FIXME("Returned list is not complete\n");
- return ret;
- }
- /* In theory all that are possible and have been defined.
- * Now just those below, since mirc uses it to check for special files.
- *
- * (It is more complex, and supports netmounted stuff, and \\.\ stuff,
- * but currently we just ignore that.)
- */
- if (!strcmpiW(devname, auxW)) {
- pDev = dosW;
- pName = comW;
- numsiz = 1;
- pNum = oneW;
- } else if (!strcmpiW(devname, nulW)) {
- pDev = devW;
- pName = nullW;
- } else if (!strncmpiW(devname, comW, strlenW(comW))) {
- pDev = devW;
- pName = serW;
- pNum = devname + strlenW(comW);
- for(numsiz=0; isdigitW(*(pNum+numsiz)); numsiz++);
- if(*(pNum + numsiz)) {
- SetLastError(ERROR_FILE_NOT_FOUND);
- return 0;
- }
- } else if (!strncmpiW(devname, lptW, strlenW(lptW))) {
- pDev = devW;
- pName = parW;
- pNum = devname + strlenW(lptW);
- for(numsiz=0; isdigitW(*(pNum+numsiz)); numsiz++);
- if(*(pNum + numsiz)) {
- SetLastError(ERROR_FILE_NOT_FOUND);
- return 0;
- }
- } else {
- /* This might be a DOS device we do not handle yet ... */
- FIXME("(%s) not detected as DOS device!\n",debugstr_w(devname));
-
- /* Win9x set the error ERROR_INVALID_PARAMETER */
- SetLastError(ERROR_FILE_NOT_FOUND);
- return 0;
-}
- FIXME("device %s may not exist on this computer\n", debugstr_w(devname));
-
- ret = strlenW(pDev) + strlenW(pName) + numsiz + 2;
- if (ret > bufsize) ret = 0;
- if (target && ret) {
- strcpyW(target,pDev);
- strcatW(target,pName);
- if (pNum) strcatW(target,pNum);
- target[ret-1] = 0;
- }
- return ret;
-}
@@ -1317,90 +1317,6 @@
/***********************************************************************
- * DefineDosDeviceA (KERNEL32.@)
- */
-BOOL WINAPI DefineDosDeviceA(DWORD flags,LPCSTR devname,LPCSTR targetpath)
-{
- UNICODE_STRING d, t;
- BOOL ret;
-
- if (!RtlCreateUnicodeStringFromAsciiz(&d, devname))
- {
- SetLastError(ERROR_NOT_ENOUGH_MEMORY);
- return FALSE;
- }
- if (!RtlCreateUnicodeStringFromAsciiz(&t, targetpath))
- {
- RtlFreeUnicodeString(&d);
- SetLastError(ERROR_NOT_ENOUGH_MEMORY);
- return FALSE;
- }
- ret = DefineDosDeviceW(flags, d.Buffer, t.Buffer);
- RtlFreeUnicodeString(&d);
- RtlFreeUnicodeString(&t);
- return ret;
-}
-
-
-/***********************************************************************
- * DefineDosDeviceA (KERNEL32.@)
- */
-BOOL WINAPI DefineDosDeviceW(DWORD flags,LPCWSTR devname,LPCWSTR targetpath)
-{
- DOSDRIVE *old, *new;
-
- /* this is a temporary hack for int21 support. better implementation has to be done */
- if (flags != DDD_RAW_TARGET_PATH ||
- !(toupperW(devname[0]) >= 'A' && toupperW(devname[0]) <= 'Z') ||
- devname[1] != ':' || devname[2] != 0 ||
- !(toupperW(targetpath[0]) >= 'A' && toupperW(targetpath[0]) <= 'Z') ||
- targetpath[1] != ':' || targetpath[2] != '\\' || targetpath[3] != 0)
- {
- FIXME("(0x%08lx,%s,%s),stub!\n", flags, debugstr_w(devname), debugstr_w(targetpath));
- SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
- return FALSE;
- }
-
- old = DOSDrives + devname[0] - 'A';
- new = DOSDrives + targetpath[0] - 'A';
-
- if (!old->root)
- {
- SetLastError( ERROR_INVALID_DRIVE );
- return 0;
- }
-
- if ( new->root )
- {
- TRACE("Can't map drive %c: to already existing drive %c:\n",
- devname[0], targetpath[0] );
- /* it is already mapped there, so return success */
- if (!strcmp(old->root,new->root))
- return 1;
- return 0;
- }
-
- new->root = heap_strdup( old->root );
- new->dos_cwd = HeapAlloc(GetProcessHeap(), 0, (strlenW(old->dos_cwd) + 1) * sizeof(WCHAR));
- strcpyW(new->dos_cwd, old->dos_cwd);
- new->unix_cwd = heap_strdup( old->unix_cwd );
- new->device = heap_strdup( old->device );
- memcpy ( new->label_conf, old->label_conf, 12 );
- memcpy ( new->label_read, old->label_read, 12 );
- new->serial_conf = old->serial_conf;
- new->type = old->type;
- new->flags = old->flags;
- new->dev = old->dev;
- new->ino = old->ino;
-
- TRACE("Drive %c: is now equal to drive %c:\n",
- targetpath[0], devname[0] );
-
- return 1;
-}
-
-
-/***********************************************************************
* DRIVE_GetFreeSpace
*/
static int DRIVE_GetFreeSpace( int drive, PULARGE_INTEGER size,
@@ -2178,11 +2094,3 @@
return ret;
}
-/***********************************************************************
- * GetVolumeNameForVolumeMountPointW (KERNEL32.@)
- */
-BOOL WINAPI GetVolumeNameForVolumeMountPointW(LPCWSTR str, LPWSTR dst, DWORD size)
-{
- FIXME("(%s, %p, %lx): stub\n", debugstr_w(str), dst, size);
- return 0;
-}
diff -u -N -r -x '*~' -x '.#*' -x CVS include41/winbase.h include/winbase.h
--- include41/winbase.h 2004-01-17 08:10:18.000000000 +0100
+++ include/winbase.h 2004-01-18 19:06:32.000000000 +0100
@@ -1522,7 +1522,7 @@
BOOL WINAPI SetThreadToken(PHANDLE,HANDLE);
BOOL WINAPI SetTimeZoneInformation(const LPTIME_ZONE_INFORMATION);
BOOL WINAPI SetVolumeMountPointA(LPCSTR,LPCSTR);
-BOOL WINAPI SetVolumeMountPointW(LPCSTR,LPCSTR);
+BOOL WINAPI SetVolumeMountPointW(LPCWSTR,LPCWSTR);
#define SetVolumeMountPoint WINELIB_NAME_AW(SetVolumeMountPoint)
BOOL WINAPI SetWaitableTimer(HANDLE,const LARGE_INTEGER*,LONG,PTIMERAPCROUTINE,LPVOID,BOOL);
BOOL WINAPI SetupComm(HANDLE,DWORD,DWORD);
diff -u -N -r -x '*~' -x '.#*' -x CVS include41/winternl.h include/winternl.h
--- include41/winternl.h 2004-01-01 09:54:11.000000000 +0100
+++ include/winternl.h 2004-01-18 19:07:41.000000000 +0100
@@ -1108,7 +1108,7 @@
void WINAPI RtlDestroyProcessParameters(RTL_USER_PROCESS_PARAMETERS*);
DOS_PATHNAME_TYPE WINAPI RtlDetermineDosPathNameType_U(PCWSTR);
BOOLEAN WINAPI RtlDoesFileExists_U(LPCWSTR);
-BOOLEAN WINAPI RtlDosPathNameToNtPathName_U(LPWSTR,PUNICODE_STRING,PWSTR*,CURDIR*);
+BOOLEAN WINAPI RtlDosPathNameToNtPathName_U(LPCWSTR,PUNICODE_STRING,PWSTR*,CURDIR*);
ULONG WINAPI RtlDosSearchPath_U(LPCWSTR, LPCWSTR, LPCWSTR, ULONG, LPWSTR, LPWSTR*);
WCHAR WINAPI RtlDowncaseUnicodeChar(WCHAR);
NTSTATUS WINAPI RtlDowncaseUnicodeString(UNICODE_STRING*,const UNICODE_STRING*,BOOLEAN);
More information about the wine-patches
mailing list