mfplat: Read queue subscriber within the critical section.
[wine/zf.git] / programs / winecfg / drive.c
bloba5fc3bfd73a9031f3ac32360dea3616bd233c8b7
1 /*
2 * Drive management code
4 * Copyright 2003 Mark Westcott
5 * Copyright 2003-2004 Mike Hearn
6 * Copyright 2004 Chris Morgan
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24 #include "config.h"
25 #include "wine/port.h"
27 #include <assert.h>
28 #include <stdarg.h>
29 #include <stdio.h>
30 #include <string.h>
32 #include <ntstatus.h>
33 #define WIN32_NO_STATUS
34 #include <windef.h>
35 #include <winbase.h>
36 #include <winternl.h>
37 #include <winioctl.h>
38 #include <winreg.h>
39 #include <wine/debug.h>
40 #include <shellapi.h>
41 #include <objbase.h>
42 #include <shlguid.h>
43 #include <shlwapi.h>
44 #include <shlobj.h>
45 #define WINE_MOUNTMGR_EXTENSIONS
46 #include <ddk/mountmgr.h>
48 #include "winecfg.h"
49 #include "resource.h"
52 WINE_DEFAULT_DEBUG_CHANNEL(winecfg);
54 struct drive drives[26]; /* one for each drive letter */
56 static inline int letter_to_index(char letter)
58 return (toupper(letter) - 'A');
61 /* This function produces a mask for each drive letter that isn't
62 * currently used. Each bit of the long result represents a letter,
63 * with A being the least significant bit, and Z being the most
64 * significant.
66 * To calculate this, we loop over each letter, and see if we can get
67 * a drive entry for it. If so, we set the appropriate bit. At the
68 * end, we flip each bit, to give the desired result.
70 * The letter parameter is always marked as being available. This is
71 * so the edit dialog can display the currently used drive letter
72 * alongside the available ones.
74 ULONG drive_available_mask(char letter)
76 ULONG result = 0;
77 int i;
79 WINE_TRACE("\n");
82 for(i = 0; i < 26; i++)
84 if (!drives[i].in_use) continue;
85 result |= (1 << (letter_to_index(drives[i].letter)));
88 result = ~result;
89 if (letter) result |= DRIVE_MASK_BIT(letter);
91 WINE_TRACE("finished drive letter loop with %x\n", result);
92 return result;
95 BOOL add_drive(char letter, const char *targetpath, const char *device, const WCHAR *label,
96 DWORD serial, DWORD type)
98 int driveIndex = letter_to_index(letter);
100 if(drives[driveIndex].in_use)
101 return FALSE;
103 WINE_TRACE("letter == '%c', unixpath == %s, device == %s, label == %s, serial == %08x, type == %d\n",
104 letter, wine_dbgstr_a(targetpath), wine_dbgstr_a(device),
105 wine_dbgstr_w(label), serial, type);
107 drives[driveIndex].letter = toupper(letter);
108 drives[driveIndex].unixpath = strdupA(targetpath);
109 drives[driveIndex].device = device ? strdupA(device) : NULL;
110 drives[driveIndex].label = label ? strdupW(label) : NULL;
111 drives[driveIndex].serial = serial;
112 drives[driveIndex].type = type;
113 drives[driveIndex].in_use = TRUE;
114 drives[driveIndex].modified = TRUE;
116 return TRUE;
119 /* deallocates the contents of the drive. does not free the drive itself */
120 void delete_drive(struct drive *d)
122 HeapFree(GetProcessHeap(), 0, d->unixpath);
123 d->unixpath = NULL;
124 HeapFree(GetProcessHeap(), 0, d->device);
125 d->device = NULL;
126 HeapFree(GetProcessHeap(), 0, d->label);
127 d->label = NULL;
128 d->serial = 0;
129 d->in_use = FALSE;
130 d->modified = TRUE;
133 static DWORD get_drive_type( char letter )
135 HKEY hKey;
136 char driveValue[4];
137 DWORD ret = DRIVE_UNKNOWN;
139 sprintf(driveValue, "%c:", letter);
141 if (RegOpenKeyA(HKEY_LOCAL_MACHINE, "Software\\Wine\\Drives", &hKey) != ERROR_SUCCESS)
142 WINE_TRACE(" Unable to open Software\\Wine\\Drives\n" );
143 else
145 char buffer[80];
146 DWORD size = sizeof(buffer);
148 if (!RegQueryValueExA( hKey, driveValue, NULL, NULL, (LPBYTE)buffer, &size ))
150 WINE_TRACE("Got type '%s' for %s\n", buffer, driveValue );
151 if (!lstrcmpiA( buffer, "hd" )) ret = DRIVE_FIXED;
152 else if (!lstrcmpiA( buffer, "network" )) ret = DRIVE_REMOTE;
153 else if (!lstrcmpiA( buffer, "floppy" )) ret = DRIVE_REMOVABLE;
154 else if (!lstrcmpiA( buffer, "cdrom" )) ret = DRIVE_CDROM;
156 RegCloseKey(hKey);
158 return ret;
162 static void set_drive_label( char letter, const WCHAR *label )
164 static const WCHAR emptyW[1];
165 WCHAR device[] = {'a',':','\\',0}; /* SetVolumeLabel() requires a trailing slash */
166 device[0] = letter;
168 if (!label) label = emptyW;
169 if(!SetVolumeLabelW(device, label))
171 WINE_WARN("unable to set volume label for devicename of %s, label of %s\n",
172 wine_dbgstr_w(device), wine_dbgstr_w(label));
173 PRINTERROR();
175 else
177 WINE_TRACE(" set volume label for devicename of %s, label of %s\n",
178 wine_dbgstr_w(device), wine_dbgstr_w(label));
182 /* set the drive serial number via a .windows-serial file */
183 static void set_drive_serial( WCHAR letter, DWORD serial )
185 WCHAR filename[] = {'a',':','\\','.','w','i','n','d','o','w','s','-','s','e','r','i','a','l',0};
186 HANDLE hFile;
188 filename[0] = letter;
189 WINE_TRACE("Putting serial number of %08X into file %s\n", serial, wine_dbgstr_w(filename));
190 hFile = CreateFileW(filename, GENERIC_WRITE, FILE_SHARE_READ, NULL,
191 CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
192 if (hFile != INVALID_HANDLE_VALUE)
194 DWORD w;
195 char buffer[16];
197 sprintf( buffer, "%X\n", serial );
198 WriteFile(hFile, buffer, strlen(buffer), &w, NULL);
199 CloseHandle(hFile);
203 #if 0
205 /* currently unused, but if users have this burning desire to be able to rename drives,
206 we can put it back in.
209 BOOL copyDrive(struct drive *pSrc, struct drive *pDst)
211 if(pDst->in_use)
213 WINE_TRACE("pDst already in use\n");
214 return FALSE;
217 if(!pSrc->unixpath) WINE_TRACE("!pSrc->unixpath\n");
218 if(!pSrc->label) WINE_TRACE("!pSrc->label\n");
219 if(!pSrc->serial) WINE_TRACE("!pSrc->serial\n");
221 pDst->unixpath = strdupA(pSrc->unixpath);
222 pDst->label = strdupA(pSrc->label);
223 pDst->serial = strdupA(pSrc->serial);
224 pDst->type = pSrc->type;
225 pDst->in_use = TRUE;
227 return TRUE;
230 BOOL moveDrive(struct drive *pSrc, struct drive *pDst)
232 WINE_TRACE("pSrc->letter == %c, pDst->letter == %c\n", pSrc->letter, pDst->letter);
234 if(!copyDrive(pSrc, pDst))
236 WINE_TRACE("copyDrive failed\n");
237 return FALSE;
240 delete_drive(pSrc);
241 return TRUE;
244 #endif
246 static HANDLE open_mountmgr(void)
248 HANDLE ret;
250 if ((ret = CreateFileW( MOUNTMGR_DOS_DEVICE_NAME, GENERIC_READ|GENERIC_WRITE,
251 FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
252 0, 0 )) == INVALID_HANDLE_VALUE)
253 WINE_ERR( "failed to open mount manager err %u\n", GetLastError() );
254 return ret;
257 /* Load currently defined drives into the drives array */
258 BOOL load_drives(void)
260 DWORD i, size = 1024;
261 HANDLE mgr;
262 WCHAR root[] = {'A',':','\\',0};
264 if ((mgr = open_mountmgr()) == INVALID_HANDLE_VALUE) return FALSE;
266 while (root[0] <= 'Z')
268 struct mountmgr_unix_drive input;
269 struct mountmgr_unix_drive *data;
271 if (!(data = HeapAlloc( GetProcessHeap(), 0, size ))) break;
273 memset( &input, 0, sizeof(input) );
274 input.letter = root[0];
276 if (DeviceIoControl( mgr, IOCTL_MOUNTMGR_QUERY_UNIX_DRIVE, &input, sizeof(input),
277 data, size, NULL, NULL ))
279 char *unixpath = NULL, *device = NULL;
280 WCHAR volname[MAX_PATH];
281 DWORD serial;
283 if (data->mount_point_offset) unixpath = (char *)data + data->mount_point_offset;
284 if (data->device_offset) device = (char *)data + data->device_offset;
286 if (!GetVolumeInformationW( root, volname, ARRAY_SIZE(volname),
287 &serial, NULL, NULL, NULL, 0 ))
289 volname[0] = 0;
290 serial = 0;
292 if (unixpath) /* FIXME: handle unmounted drives too */
293 add_drive( root[0], unixpath, device, volname, serial, get_drive_type(root[0]) );
294 root[0]++;
296 else
298 if (GetLastError() == ERROR_MORE_DATA) size = data->size;
299 else root[0]++; /* skip this drive */
301 HeapFree( GetProcessHeap(), 0, data );
304 /* reset modified flags */
305 for (i = 0; i < 26; i++) drives[i].modified = FALSE;
307 CloseHandle( mgr );
308 return TRUE;
311 /* some of this code appears to be broken by bugs in Wine: the label
312 * setting code has no effect, for instance */
313 void apply_drive_changes(void)
315 int i;
316 HANDLE mgr;
317 DWORD len;
318 struct mountmgr_unix_drive *ioctl;
320 WINE_TRACE("\n");
322 if ((mgr = open_mountmgr()) == INVALID_HANDLE_VALUE) return;
324 /* add each drive and remove as we go */
325 for(i = 0; i < 26; i++)
327 if (!drives[i].modified) continue;
328 drives[i].modified = FALSE;
330 len = sizeof(*ioctl);
331 if (drives[i].in_use)
333 len += strlen(drives[i].unixpath) + 1;
334 if (drives[i].device) len += strlen(drives[i].device) + 1;
336 if (!(ioctl = HeapAlloc( GetProcessHeap(), 0, len ))) continue;
337 ioctl->size = len;
338 ioctl->letter = 'a' + i;
339 ioctl->device_offset = 0;
340 if (drives[i].in_use)
342 char *ptr = (char *)(ioctl + 1);
344 ioctl->type = drives[i].type;
345 strcpy( ptr, drives[i].unixpath );
346 ioctl->mount_point_offset = ptr - (char *)ioctl;
347 if (drives[i].device)
349 ptr += strlen(ptr) + 1;
350 strcpy( ptr, drives[i].device );
351 ioctl->device_offset = ptr - (char *)ioctl;
354 else
356 ioctl->type = DRIVE_NO_ROOT_DIR;
357 ioctl->mount_point_offset = 0;
360 if (DeviceIoControl( mgr, IOCTL_MOUNTMGR_DEFINE_UNIX_DRIVE, ioctl, len, NULL, 0, NULL, NULL ))
362 set_drive_label( drives[i].letter, drives[i].label );
363 if (drives[i].in_use) set_drive_serial( drives[i].letter, drives[i].serial );
364 WINE_TRACE( "set drive %c: to %s type %u\n", 'a' + i,
365 wine_dbgstr_a(drives[i].unixpath), drives[i].type );
367 else WINE_WARN( "failed to set drive %c: to %s type %u err %u\n", 'a' + i,
368 wine_dbgstr_a(drives[i].unixpath), drives[i].type, GetLastError() );
369 HeapFree( GetProcessHeap(), 0, ioctl );
371 CloseHandle( mgr );