kernel32: Use define instead of hardcoded value.
[wine] / dlls / kernel32 / tests / volume.c
1 /*
2  * Unit test suite for volume functions
3  *
4  * Copyright 2006 Stefan Leichter
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #include "wine/test.h"
22 #include "winbase.h"
23 #include "winioctl.h"
24 #include <stdio.h>
25
26 static HINSTANCE hdll;
27 static BOOL (WINAPI * pGetVolumeNameForVolumeMountPointA)(LPCSTR, LPSTR, DWORD);
28 static BOOL (WINAPI * pGetVolumeNameForVolumeMountPointW)(LPCWSTR, LPWSTR, DWORD);
29 static HANDLE (WINAPI *pFindFirstVolumeA)(LPSTR,DWORD);
30 static BOOL (WINAPI *pFindNextVolumeA)(HANDLE,LPSTR,DWORD);
31 static BOOL (WINAPI *pFindVolumeClose)(HANDLE);
32 static UINT (WINAPI *pGetLogicalDriveStringsA)(UINT,LPSTR);
33 static UINT (WINAPI *pGetLogicalDriveStringsW)(UINT,LPWSTR);
34 static BOOL (WINAPI *pGetVolumeInformationA)(LPCSTR, LPSTR, DWORD, LPDWORD, LPDWORD, LPDWORD, LPSTR, DWORD);
35
36 /* ############################### */
37
38 static void test_query_dos_deviceA(void)
39 {
40     char drivestr[] = "a:";
41     char *p, *buffer, buffer2[2000];
42     DWORD ret, ret2, buflen=32768;
43     BOOL iswin9x, found = FALSE;
44
45     buffer = HeapAlloc( GetProcessHeap(), 0, buflen );
46     SetLastError(0xdeadbeef);
47     ret = QueryDosDeviceA( NULL, buffer, buflen );
48     iswin9x = !ret && (GetLastError() == ERROR_INVALID_PARAMETER /* win98 */
49                     || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED /* win95*/);
50     ok((ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER) || broken(iswin9x),
51         "QueryDosDeviceA failed to return list, last error %u\n", GetLastError());
52
53     if (ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
54         p = buffer;
55         for (;;) {
56             if (!strlen(p)) break;
57             ret2 = QueryDosDeviceA( p, buffer2, sizeof(buffer2) );
58             ok(ret2, "QueryDosDeviceA failed to return current mapping for %s, last error %u\n", p, GetLastError());
59             p += strlen(p) + 1;
60             if (ret <= (p-buffer)) break;
61         }
62     }
63
64     for (;drivestr[0] <= 'z'; drivestr[0]++) {
65         /* Older W2K fails with ERROR_INSUFFICIENT_BUFFER when buflen is > 32767 */
66         ret = QueryDosDeviceA( drivestr, buffer, buflen - 1);
67         /* fails for all drives in win9x */
68         ok(ret || GetLastError() == ERROR_FILE_NOT_FOUND || broken(!ret && iswin9x),
69             "QueryDosDeviceA failed to return current mapping for %s, last error %u\n", drivestr, GetLastError());
70         if(ret) {
71             for (p = buffer; *p; p++) *p = toupper(*p);
72             if (strstr(buffer, "HARDDISK") || strstr(buffer, "RAMDISK")) found = TRUE;
73         }
74     }
75     ok(found ^ iswin9x, "expected at least one devicename to contain HARDDISK or RAMDISK except on win9x\n");
76     HeapFree( GetProcessHeap(), 0, buffer );
77 }
78
79 static void test_FindFirstVolume(void)
80 {
81     char volume[51];
82     HANDLE handle;
83
84     /* not present before w2k */
85     if (!pFindFirstVolumeA) {
86         win_skip("FindFirstVolumeA not found\n");
87         return;
88     }
89
90     handle = pFindFirstVolumeA( volume, 0 );
91     ok( handle == INVALID_HANDLE_VALUE, "succeeded with short buffer\n" );
92     ok( GetLastError() == ERROR_MORE_DATA ||  /* XP */
93         GetLastError() == ERROR_FILENAME_EXCED_RANGE,  /* Vista */
94         "wrong error %u\n", GetLastError() );
95     handle = pFindFirstVolumeA( volume, 49 );
96     ok( handle == INVALID_HANDLE_VALUE, "succeeded with short buffer\n" );
97     ok( GetLastError() == ERROR_FILENAME_EXCED_RANGE, "wrong error %u\n", GetLastError() );
98     handle = pFindFirstVolumeA( volume, 51 );
99     ok( handle != INVALID_HANDLE_VALUE, "failed err %u\n", GetLastError() );
100     if (handle != INVALID_HANDLE_VALUE)
101     {
102         do
103         {
104             ok( strlen(volume) == 49, "bad volume name %s\n", volume );
105             ok( !memcmp( volume, "\\\\?\\Volume{", 11 ), "bad volume name %s\n", volume );
106             ok( !memcmp( volume + 47, "}\\", 2 ), "bad volume name %s\n", volume );
107         } while (pFindNextVolumeA( handle, volume, MAX_PATH ));
108         ok( GetLastError() == ERROR_NO_MORE_FILES, "wrong error %u\n", GetLastError() );
109         pFindVolumeClose( handle );
110     }
111 }
112
113 static void test_GetVolumeNameForVolumeMountPointA(void)
114 {
115     BOOL ret;
116     char volume[MAX_PATH], path[] = "c:\\";
117     DWORD len = sizeof(volume), reti;
118     char temp_path[MAX_PATH];
119
120     /* not present before w2k */
121     if (!pGetVolumeNameForVolumeMountPointA) {
122         win_skip("GetVolumeNameForVolumeMountPointA not found\n");
123         return;
124     }
125
126     reti = GetTempPathA(MAX_PATH, temp_path);
127     ok(reti != 0, "GetTempPathA error %d\n", GetLastError());
128     ok(reti < MAX_PATH, "temp path should fit into MAX_PATH\n");
129
130     ret = pGetVolumeNameForVolumeMountPointA(path, volume, 0);
131     ok(ret == FALSE, "GetVolumeNameForVolumeMountPointA succeeded\n");
132     ok(GetLastError() == ERROR_FILENAME_EXCED_RANGE ||
133         GetLastError() == ERROR_INVALID_PARAMETER, /* Vista */
134         "wrong error, last=%d\n", GetLastError());
135
136     if (0) { /* these crash on XP */
137     ret = pGetVolumeNameForVolumeMountPointA(path, NULL, len);
138     ok(ret == FALSE, "GetVolumeNameForVolumeMountPointA succeeded\n");
139
140     ret = pGetVolumeNameForVolumeMountPointA(NULL, volume, len);
141     ok(ret == FALSE, "GetVolumeNameForVolumeMountPointA succeeded\n");
142     }
143
144     ret = pGetVolumeNameForVolumeMountPointA(path, volume, len);
145     ok(ret == TRUE, "GetVolumeNameForVolumeMountPointA failed\n");
146     ok(!strncmp( volume, "\\\\?\\Volume{", 11),
147         "GetVolumeNameForVolumeMountPointA failed to return valid string <%s>\n",
148         volume);
149
150     /* test with too small buffer */
151     ret = pGetVolumeNameForVolumeMountPointA(path, volume, 10);
152     ok(ret == FALSE && GetLastError() == ERROR_FILENAME_EXCED_RANGE,
153             "GetVolumeNameForVolumeMountPointA failed, wrong error returned, was %d, should be ERROR_FILENAME_EXCED_RANGE\n",
154              GetLastError());
155
156     /* Try on a arbitrary directory */
157     /* On FAT filesystems it seems that GetLastError() is set to
158        ERROR_INVALID_FUNCTION. */
159     ret = pGetVolumeNameForVolumeMountPointA(temp_path, volume, len);
160     ok(ret == FALSE && (GetLastError() == ERROR_NOT_A_REPARSE_POINT ||
161         GetLastError() == ERROR_INVALID_FUNCTION),
162         "GetVolumeNameForVolumeMountPointA failed on %s, last=%d\n",
163         temp_path, GetLastError());
164
165     /* Try on a nonexistent dos drive */
166     path[2] = 0;
167     for (;path[0] <= 'z'; path[0]++) {
168         ret = QueryDosDeviceA( path, volume, len);
169         if(!ret) break;
170     }
171     if (path[0] <= 'z')
172     {
173         path[2] = '\\';
174         ret = pGetVolumeNameForVolumeMountPointA(path, volume, len);
175         ok(ret == FALSE && GetLastError() == ERROR_FILE_NOT_FOUND,
176             "GetVolumeNameForVolumeMountPointA failed on %s, last=%d\n",
177             path, GetLastError());
178
179         /* Try without trailing \ and on a nonexistent dos drive  */
180         path[2] = 0;
181         ret = pGetVolumeNameForVolumeMountPointA(path, volume, len);
182         ok(ret == FALSE && GetLastError() == ERROR_INVALID_NAME,
183             "GetVolumeNameForVolumeMountPointA failed on %s, last=%d\n",
184             path, GetLastError());
185     }
186 }
187
188 static void test_GetVolumeNameForVolumeMountPointW(void)
189 {
190     BOOL ret;
191     WCHAR volume[MAX_PATH], path[] = {'c',':','\\',0};
192     DWORD len = sizeof(volume) / sizeof(WCHAR);
193
194     /* not present before w2k */
195     if (!pGetVolumeNameForVolumeMountPointW) {
196         win_skip("GetVolumeNameForVolumeMountPointW not found\n");
197         return;
198     }
199
200     ret = pGetVolumeNameForVolumeMountPointW(path, volume, 0);
201     ok(ret == FALSE, "GetVolumeNameForVolumeMountPointA succeeded\n");
202     ok(GetLastError() == ERROR_FILENAME_EXCED_RANGE ||
203         GetLastError() == ERROR_INVALID_PARAMETER, /* Vista */
204         "wrong error, last=%d\n", GetLastError());
205
206     if (0) { /* these crash on XP */
207     ret = pGetVolumeNameForVolumeMountPointW(path, NULL, len);
208     ok(ret == FALSE, "GetVolumeNameForVolumeMountPointW succeeded\n");
209
210     ret = pGetVolumeNameForVolumeMountPointW(NULL, volume, len);
211     ok(ret == FALSE, "GetVolumeNameForVolumeMountPointW succeeded\n");
212     }
213
214     ret = pGetVolumeNameForVolumeMountPointW(path, volume, len);
215     ok(ret == TRUE, "GetVolumeNameForVolumeMountPointW failed\n");
216 }
217
218 static void test_GetLogicalDriveStringsA(void)
219 {
220     UINT size, size2;
221     char *buf, *ptr;
222
223     ok( pGetLogicalDriveStringsA != NULL, "GetLogicalDriveStringsA not available\n");
224     if(!pGetLogicalDriveStringsA) {
225         return;
226     }
227
228     size = pGetLogicalDriveStringsA(0, NULL);
229     ok(size%4 == 1, "size = %d\n", size);
230
231     buf = HeapAlloc(GetProcessHeap(), 0, size);
232
233     *buf = 0;
234     size2 = pGetLogicalDriveStringsA(2, buf);
235     ok(size2 == size, "size2 = %d\n", size2);
236     ok(!*buf, "buf changed\n");
237
238     size2 = pGetLogicalDriveStringsA(size, buf);
239     ok(size2 == size-1, "size2 = %d\n", size2);
240
241     for(ptr = buf; ptr < buf+size2; ptr += 4) {
242         ok(('A' <= *ptr && *ptr <= 'Z') ||
243            (broken('a' <= *ptr && *ptr <= 'z')), /* Win9x and WinMe */
244            "device name '%c' is not uppercase\n", *ptr);
245         ok(ptr[1] == ':', "ptr[1] = %c, expected ':'\n", ptr[1]);
246         ok(ptr[2] == '\\', "ptr[2] = %c expected '\\'\n", ptr[2]);
247         ok(!ptr[3], "ptr[3] = %c expected nullbyte\n", ptr[3]);
248     }
249     ok(!*ptr, "buf[size2] is not nullbyte\n");
250
251     HeapFree(GetProcessHeap(), 0, buf);
252 }
253
254 static void test_GetLogicalDriveStringsW(void)
255 {
256     UINT size, size2;
257     WCHAR *buf, *ptr;
258
259     ok( pGetLogicalDriveStringsW != NULL, "GetLogicalDriveStringsW not available\n");
260     if(!pGetLogicalDriveStringsW) {
261         return;
262     }
263
264     SetLastError(0xdeadbeef);
265     size = pGetLogicalDriveStringsW(0, NULL);
266     if (size == 0 && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) {
267         win_skip("GetLogicalDriveStringsW not implemented\n");
268         return;
269     }
270     ok(size%4 == 1, "size = %d\n", size);
271
272     buf = HeapAlloc(GetProcessHeap(), 0, size*sizeof(WCHAR));
273
274     *buf = 0;
275     size2 = pGetLogicalDriveStringsW(2, buf);
276     ok(size2 == size, "size2 = %d\n", size2);
277     ok(!*buf, "buf changed\n");
278
279     size2 = pGetLogicalDriveStringsW(size, buf);
280     ok(size2 == size-1, "size2 = %d\n", size2);
281
282     for(ptr = buf; ptr < buf+size2; ptr += 4) {
283         ok('A' <= *ptr && *ptr <= 'Z', "device name '%c' is not uppercase\n", *ptr);
284         ok(ptr[1] == ':', "ptr[1] = %c, expected ':'\n", ptr[1]);
285         ok(ptr[2] == '\\', "ptr[2] = %c expected '\\'\n", ptr[2]);
286         ok(!ptr[3], "ptr[3] = %c expected nullbyte\n", ptr[3]);
287     }
288     ok(!*ptr, "buf[size2] is not nullbyte\n");
289
290     HeapFree(GetProcessHeap(), 0, buf);
291 }
292
293 static void test_GetVolumeInformationA(void)
294 {
295     BOOL ret;
296     UINT result;
297     char Root_Colon[]="C:";
298     char Root_Slash[]="C:\\";
299     char Root_UNC[]="\\\\?\\C:\\";
300     char volume[MAX_PATH+1];
301     DWORD vol_name_size=MAX_PATH+1, vol_serial_num=-1, max_comp_len=0, fs_flags=0, fs_name_len=MAX_PATH+1;
302     char vol_name_buf[MAX_PATH+1], fs_name_buf[MAX_PATH+1];
303     char windowsdir[MAX_PATH+10];
304     char currentdir[MAX_PATH+1];
305
306     ok( pGetVolumeInformationA != NULL, "GetVolumeInformationA not found\n");
307     if(!pGetVolumeInformationA) {
308         return;
309     }
310
311     /* get windows drive letter and update strings for testing */
312     result = GetWindowsDirectory(windowsdir, sizeof(windowsdir));
313     ok(result < sizeof(windowsdir), "windowsdir is abnormally long!\n");
314     ok(result != 0, "GetWindowsDirectory: error %d\n", GetLastError());
315     Root_Colon[0] = windowsdir[0];
316     Root_Slash[0] = windowsdir[0];
317     Root_UNC[4] = windowsdir[0];
318
319     result = GetCurrentDirectory(MAX_PATH, currentdir);
320     ok(result, "GetCurrentDirectory: error %d\n", GetLastError());
321     /* Note that GetCurrentDir yields no trailing slash for subdirs */
322
323     /* check for NO error on no trailing \ when current dir is root dir */
324     ret = SetCurrentDirectory(Root_Slash);
325     ok(ret, "SetCurrentDirectory: error %d\n", GetLastError());
326     ret = pGetVolumeInformationA(Root_Colon, vol_name_buf, vol_name_size, NULL,
327             NULL, NULL, fs_name_buf, fs_name_len);
328     ok(ret, "GetVolumeInformationA root failed, last error %u\n", GetLastError());
329
330     /* check for error on no trailing \ when current dir is subdir (windows) of queried drive */
331     ret = SetCurrentDirectory(windowsdir);
332     ok(ret, "SetCurrentDirectory: error %d\n", GetLastError());
333     SetLastError(0xdeadbeef);
334     ret = pGetVolumeInformationA(Root_Colon, vol_name_buf, vol_name_size, NULL,
335             NULL, NULL, fs_name_buf, fs_name_len);
336     ok(!ret && (GetLastError() == ERROR_INVALID_NAME ||
337          broken(GetLastError() == ERROR_BAD_PATHNAME/* win9x */)),
338         "GetVolumeInformationA did%s fail, last error %u\n", ret ? " not":"", GetLastError());
339
340     /* reset current directory */
341     ret = SetCurrentDirectory(currentdir);
342     ok(ret, "SetCurrentDirectory: error %d\n", GetLastError());
343
344     if (toupper(currentdir[0]) == toupper(windowsdir[0])) {
345         skip("Please re-run from another device than %c:\n", windowsdir[0]);
346         /* FIXME: Use GetLogicalDrives to find another device to avoid this skip. */
347     } else {
348         char Root_Env[]="=C:"; /* where MS maintains the per volume directory */
349         Root_Env[1] = windowsdir[0];
350
351         /* C:\windows becomes the current directory on drive C: */
352         /* Note that paths to subdirs are stored without trailing slash, like what GetCurrentDir yields. */
353         ret = SetEnvironmentVariable(Root_Env, windowsdir);
354         ok(ret, "SetEnvironmentVariable %s failed\n", Root_Env);
355
356         ret = SetCurrentDirectory(windowsdir);
357         ok(ret, "SetCurrentDirectory: error %d\n", GetLastError());
358         ret = SetCurrentDirectory(currentdir);
359         ok(ret, "SetCurrentDirectory: error %d\n", GetLastError());
360
361         /* windows dir is current on the root drive, call fails */
362         SetLastError(0xdeadbeef);
363         ret = pGetVolumeInformationA(Root_Colon, vol_name_buf, vol_name_size, NULL,
364                 NULL, NULL, fs_name_buf, fs_name_len);
365         ok(!ret && (GetLastError() == ERROR_INVALID_NAME ||
366              broken(GetLastError() == ERROR_BAD_PATHNAME/* Win9x */)),
367            "GetVolumeInformationA did%s fail, last error %u\n", ret ? " not":"", GetLastError());
368
369         /* Try normal drive letter with trailing \ */
370         ret = pGetVolumeInformationA(Root_Slash, vol_name_buf, vol_name_size, NULL,
371                 NULL, NULL, fs_name_buf, fs_name_len);
372         ok(ret, "GetVolumeInformationA with \\ failed, last error %u\n", GetLastError());
373
374         ret = SetCurrentDirectory(Root_Slash);
375         ok(ret, "SetCurrentDirectory: error %d\n", GetLastError());
376         ret = SetCurrentDirectory(currentdir);
377         ok(ret, "SetCurrentDirectory: error %d\n", GetLastError());
378
379         /* windows dir is STILL CURRENT on root drive; the call fails as before,   */
380         /* proving that SetCurrentDir did not remember the other drive's directory */
381         SetLastError(0xdeadbeef);
382         ret = pGetVolumeInformationA(Root_Colon, vol_name_buf, vol_name_size, NULL,
383                 NULL, NULL, fs_name_buf, fs_name_len);
384         ok(!ret && (GetLastError() == ERROR_INVALID_NAME ||
385              broken(GetLastError() == ERROR_BAD_PATHNAME/* Win9x */)),
386            "GetVolumeInformationA did%s fail, last error %u\n", ret ? " not":"", GetLastError());
387
388         /* Now C:\ becomes the current directory on drive C: */
389         ret = SetEnvironmentVariable(Root_Env, Root_Slash); /* set =C:=C:\ */
390         ok(ret, "SetEnvironmentVariable %s failed\n", Root_Env);
391
392         /* \ is current on root drive, call succeeds */
393         ret = pGetVolumeInformationA(Root_Colon, vol_name_buf, vol_name_size, NULL,
394                 NULL, NULL, fs_name_buf, fs_name_len);
395         ok(ret, "GetVolumeInformationA failed, last error %u\n", GetLastError());
396
397         /* again, SetCurrentDirectory on another drive does not matter */
398         ret = SetCurrentDirectory(Root_Slash);
399         ok(ret, "SetCurrentDirectory: error %d\n", GetLastError());
400         ret = SetCurrentDirectory(currentdir);
401         ok(ret, "SetCurrentDirectory: error %d\n", GetLastError());
402
403         /* \ is current on root drive, call succeeds */
404         ret = pGetVolumeInformationA(Root_Colon, vol_name_buf, vol_name_size, NULL,
405                 NULL, NULL, fs_name_buf, fs_name_len);
406         ok(ret, "GetVolumeInformationA failed, last error %u\n", GetLastError());
407     }
408
409     /* try null root directory to return "root of the current directory"  */
410     ret = pGetVolumeInformationA(NULL, vol_name_buf, vol_name_size, NULL,
411             NULL, NULL, fs_name_buf, fs_name_len);
412     ok(ret, "GetVolumeInformationA failed on null root dir, last error %u\n", GetLastError());
413
414     /* Try normal drive letter with trailing \  */
415     ret = pGetVolumeInformationA(Root_Slash, vol_name_buf, vol_name_size,
416             &vol_serial_num, &max_comp_len, &fs_flags, fs_name_buf, fs_name_len);
417     ok(ret, "GetVolumeInformationA failed, root=%s, last error=%u\n", Root_Slash, GetLastError());
418
419     /* try again with drive letter and the "disable parsing" prefix */
420     SetLastError(0xdeadbeef);
421     ret = pGetVolumeInformationA(Root_UNC, vol_name_buf, vol_name_size,
422             &vol_serial_num, &max_comp_len, &fs_flags, fs_name_buf, fs_name_len);
423     ok(ret || broken(!ret /* win9x */ && GetLastError()==ERROR_BAD_NETPATH),
424         "GetVolumeInformationA did%s fail, root=%s, last error=%u\n", ret ? " not":"", Root_UNC, GetLastError());
425
426     /* try again with device name space  */
427     Root_UNC[2] = '.';
428     SetLastError(0xdeadbeef);
429     ret = pGetVolumeInformationA(Root_UNC, vol_name_buf, vol_name_size,
430             &vol_serial_num, &max_comp_len, &fs_flags, fs_name_buf, fs_name_len);
431     ok(ret || broken(!ret /* win9x */ && GetLastError()==ERROR_BAD_NETPATH),
432         "GetVolumeInformationA did%s fail, root=%s, last error=%u\n", ret ? " not":"", Root_UNC, GetLastError());
433
434     /* try again with a directory off the root - should generate error  */
435     if (windowsdir[strlen(windowsdir)-1] != '\\') strcat(windowsdir, "\\");
436     SetLastError(0xdeadbeef);
437     ret = pGetVolumeInformationA(windowsdir, vol_name_buf, vol_name_size,
438             &vol_serial_num, &max_comp_len, &fs_flags, fs_name_buf, fs_name_len);
439     ok(!ret && (GetLastError()==ERROR_DIR_NOT_ROOT ||
440          broken(GetLastError()==ERROR_BAD_PATHNAME/* win9x */)),
441           "GetVolumeInformationA did%s fail, root=%s, last error=%u\n", ret ? " not":"", windowsdir, GetLastError());
442     /* A subdir with trailing \ yields DIR_NOT_ROOT instead of INVALID_NAME */
443     if (windowsdir[strlen(windowsdir)-1] == '\\') windowsdir[strlen(windowsdir)-1] = 0;
444     SetLastError(0xdeadbeef);
445     ret = pGetVolumeInformationA(windowsdir, vol_name_buf, vol_name_size,
446             &vol_serial_num, &max_comp_len, &fs_flags, fs_name_buf, fs_name_len);
447     ok(!ret && (GetLastError()==ERROR_INVALID_NAME ||
448          broken(GetLastError()==ERROR_BAD_PATHNAME/* win9x */)),
449           "GetVolumeInformationA did%s fail, root=%s, last error=%u\n", ret ? " not":"", windowsdir, GetLastError());
450
451     if (!pGetVolumeNameForVolumeMountPointA) {
452         win_skip("GetVolumeNameForVolumeMountPointA not found\n");
453         return;
454     }
455     /* get the unique volume name for the windows drive  */
456     ret = pGetVolumeNameForVolumeMountPointA(Root_Slash, volume, MAX_PATH);
457     ok(ret == TRUE, "GetVolumeNameForVolumeMountPointA failed\n");
458
459     /* try again with unique volume name */
460     ret = pGetVolumeInformationA(volume, vol_name_buf, vol_name_size,
461             &vol_serial_num, &max_comp_len, &fs_flags, fs_name_buf, fs_name_len);
462     ok(ret, "GetVolumeInformationA failed, root=%s, last error=%u\n", volume, GetLastError());
463 }
464
465 /* Test to check that unique volume name from windows dir mount point  */
466 /* matches at least one of the unique volume names returned from the   */
467 /* FindFirstVolumeA/FindNextVolumeA list.                              */
468 static void test_enum_vols(void)
469 {
470     DWORD   ret;
471     HANDLE  hFind = INVALID_HANDLE_VALUE;
472     char    Volume_1[MAX_PATH] = {0};
473     char    Volume_2[MAX_PATH] = {0};
474     char    path[] = "c:\\";
475     BOOL    found = FALSE;
476     char    windowsdir[MAX_PATH];
477
478     if (!pGetVolumeNameForVolumeMountPointA) {
479         win_skip("GetVolumeNameForVolumeMountPointA not found\n");
480         return;
481     }
482
483     /*get windows drive letter and update strings for testing  */
484     ret = GetWindowsDirectory( windowsdir, sizeof(windowsdir) );
485     ok(ret < sizeof(windowsdir), "windowsdir is abnormally long!\n");
486     ok(ret != 0, "GetWindowsDirecory: error %d\n", GetLastError());
487     path[0] = windowsdir[0];
488
489     /* get the unique volume name for the windows drive  */
490     ret = pGetVolumeNameForVolumeMountPointA( path, Volume_1, MAX_PATH );
491     ok(ret == TRUE, "GetVolumeNameForVolumeMountPointA failed\n");
492     ok(strlen(Volume_1) == 49, "GetVolumeNameForVolumeMountPointA returned wrong length name %s\n", Volume_1);
493
494     /* get first unique volume name of list  */
495     hFind = pFindFirstVolumeA( Volume_2, MAX_PATH );
496     ok(hFind != INVALID_HANDLE_VALUE, "FindFirstVolume failed, err=%u\n",
497                 GetLastError());
498
499     do
500     {
501         /* validate correct length of unique volume name  */
502         ok(strlen(Volume_2) == 49, "Find[First/Next]Volume returned wrong length name %s\n", Volume_1);
503         if (memcmp(Volume_1, Volume_2, 49) == 0)
504         {
505             found = TRUE;
506             break;
507         }
508     } while (pFindNextVolumeA( hFind, Volume_2, MAX_PATH ));
509     ok(found, "volume name %s not found by Find[First/Next]Volume\n", Volume_1);
510     pFindVolumeClose( hFind );
511 }
512
513 static void test_disk_extents(void)
514 {
515     BOOL ret;
516     DWORD size;
517     HANDLE handle;
518     static DWORD data[16];
519
520     handle = CreateFileA( "\\\\.\\c:", GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0 );
521     if (handle == INVALID_HANDLE_VALUE)
522     {
523         win_skip("can't open c: drive %u\n", GetLastError());
524         return;
525     }
526     size = 0;
527     ret = DeviceIoControl( handle, IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS, &data,
528                            sizeof(data), &data, sizeof(data), &size, NULL );
529     if (!ret && GetLastError() == ERROR_INVALID_FUNCTION)
530     {
531         win_skip("IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS not supported\n");
532         CloseHandle( handle );
533         return;
534     }
535     ok(ret, "DeviceIoControl failed %u\n", GetLastError());
536     ok(size == 32, "expected 32, got %u\n", size);
537     CloseHandle( handle );
538 }
539
540 START_TEST(volume)
541 {
542     hdll = GetModuleHandleA("kernel32.dll");
543     pGetVolumeNameForVolumeMountPointA = (void *) GetProcAddress(hdll, "GetVolumeNameForVolumeMountPointA");
544     pGetVolumeNameForVolumeMountPointW = (void *) GetProcAddress(hdll, "GetVolumeNameForVolumeMountPointW");
545     pFindFirstVolumeA = (void *) GetProcAddress(hdll, "FindFirstVolumeA");
546     pFindNextVolumeA = (void *) GetProcAddress(hdll, "FindNextVolumeA");
547     pFindVolumeClose = (void *) GetProcAddress(hdll, "FindVolumeClose");
548     pGetLogicalDriveStringsA = (void *) GetProcAddress(hdll, "GetLogicalDriveStringsA");
549     pGetLogicalDriveStringsW = (void *) GetProcAddress(hdll, "GetLogicalDriveStringsW");
550     pGetVolumeInformationA = (void *) GetProcAddress(hdll, "GetVolumeInformationA");
551
552     test_query_dos_deviceA();
553     test_FindFirstVolume();
554     test_GetVolumeNameForVolumeMountPointA();
555     test_GetVolumeNameForVolumeMountPointW();
556     test_GetLogicalDriveStringsA();
557     test_GetLogicalDriveStringsW();
558     test_GetVolumeInformationA();
559     test_enum_vols();
560     test_disk_extents();
561 }