hlink/tests: Sign compare fix.
[wine] / dlls / kernel32 / tests / volume.c
1 /*
2  * Unit test suite
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 <stdio.h>
24
25 static HINSTANCE hdll;
26 static BOOL (WINAPI * pGetVolumeNameForVolumeMountPointA)(LPCSTR, LPSTR, DWORD);
27 static BOOL (WINAPI * pGetVolumeNameForVolumeMountPointW)(LPCWSTR, LPWSTR, DWORD);
28 static HANDLE (WINAPI *pFindFirstVolumeA)(LPSTR,DWORD);
29 static BOOL (WINAPI *pFindNextVolumeA)(HANDLE,LPSTR,DWORD);
30 static BOOL (WINAPI *pFindVolumeClose)(HANDLE);
31 static UINT (WINAPI *pGetLogicalDriveStringsA)(UINT,LPSTR);
32 static UINT (WINAPI *pGetLogicalDriveStringsW)(UINT,LPWSTR);
33 static BOOL (WINAPI *pGetVolumeInformationA)(LPCSTR, LPSTR, DWORD, LPDWORD, LPDWORD, LPDWORD, LPSTR, DWORD);
34
35 /* ############################### */
36
37 static void test_query_dos_deviceA(void)
38 {
39     char drivestr[] = "a:";
40     char *p, *buffer, buffer2[2000];
41     DWORD ret, ret2, buflen=32768;
42     BOOL found = FALSE;
43
44     if (!pFindFirstVolumeA) {
45         win_skip("On win9x, HARDDISK and RAMDISK not present\n");
46         return;
47     }
48
49     buffer = HeapAlloc( GetProcessHeap(), 0, buflen );
50     ret = QueryDosDeviceA( NULL, buffer, buflen );
51     ok(ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER,
52         "QueryDosDevice buffer too small\n");
53     if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
54         HeapFree( GetProcessHeap(), 0, buffer );
55         return;
56     }
57     ok(ret, "QueryDosDeviceA failed to return list, last error %u\n", GetLastError());
58     if (ret) {
59         p = buffer;
60         for (;;) {
61             if (!strlen(p)) break;
62             ret2 = QueryDosDeviceA( p, buffer2, sizeof(buffer2) );
63             ok(ret2, "QueryDosDeviceA failed to return current mapping for %s, last error %u\n", p, GetLastError());
64             p += strlen(p) + 1;
65             if (ret <= (p-buffer)) break;
66         }
67     }
68
69     for (;drivestr[0] <= 'z'; drivestr[0]++) {
70         ret = QueryDosDeviceA( drivestr, buffer, buflen);
71         if(ret) {
72             for (p = buffer; *p; p++) *p = toupper(*p);
73             if (strstr(buffer, "HARDDISK") || strstr(buffer, "RAMDISK")) found = TRUE;
74         }
75     }
76     ok(found, "expected at least one devicename to contain HARDDISK or RAMDISK\n");
77     HeapFree( GetProcessHeap(), 0, buffer );
78 }
79
80 static void test_FindFirstVolume(void)
81 {
82     char volume[51];
83     HANDLE handle;
84
85     if (!pFindFirstVolumeA) {
86         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);
118
119     /* not present before w2k */
120     if (!pGetVolumeNameForVolumeMountPointA) {
121         skip("GetVolumeNameForVolumeMountPointA not found\n");
122         return;
123     }
124
125     ret = pGetVolumeNameForVolumeMountPointA(path, volume, 0);
126     ok(ret == FALSE, "GetVolumeNameForVolumeMountPointA succeeded\n");
127
128     if (0) { /* these crash on XP */
129     ret = pGetVolumeNameForVolumeMountPointA(path, NULL, len);
130     ok(ret == FALSE, "GetVolumeNameForVolumeMountPointA succeeded\n");
131
132     ret = pGetVolumeNameForVolumeMountPointA(NULL, volume, len);
133     ok(ret == FALSE, "GetVolumeNameForVolumeMountPointA succeeded\n");
134     }
135
136     ret = pGetVolumeNameForVolumeMountPointA(path, volume, len);
137     ok(ret == TRUE, "GetVolumeNameForVolumeMountPointA failed\n");
138 }
139
140 static void test_GetVolumeNameForVolumeMountPointW(void)
141 {
142     BOOL ret;
143     WCHAR volume[MAX_PATH], path[] = {'c',':','\\',0};
144     DWORD len = sizeof(volume) / sizeof(WCHAR);
145
146     /* not present before w2k */
147     if (!pGetVolumeNameForVolumeMountPointW) {
148         skip("GetVolumeNameForVolumeMountPointW not found\n");
149         return;
150     }
151
152     ret = pGetVolumeNameForVolumeMountPointW(path, volume, 0);
153     ok(ret == FALSE, "GetVolumeNameForVolumeMountPointA succeeded\n");
154
155     if (0) { /* these crash on XP */
156     ret = pGetVolumeNameForVolumeMountPointW(path, NULL, len);
157     ok(ret == FALSE, "GetVolumeNameForVolumeMountPointW succeeded\n");
158
159     ret = pGetVolumeNameForVolumeMountPointW(NULL, volume, len);
160     ok(ret == FALSE, "GetVolumeNameForVolumeMountPointW succeeded\n");
161     }
162
163     ret = pGetVolumeNameForVolumeMountPointW(path, volume, len);
164     ok(ret == TRUE, "GetVolumeNameForVolumeMountPointW failed\n");
165 }
166
167 static void test_GetLogicalDriveStringsA(void)
168 {
169     UINT size, size2;
170     char *buf, *ptr;
171
172     if(!pGetLogicalDriveStringsA) {
173         win_skip("GetLogicalDriveStringsA not available\n");
174         return;
175     }
176
177     size = pGetLogicalDriveStringsA(0, NULL);
178     ok(size%4 == 1, "size = %d\n", size);
179
180     buf = HeapAlloc(GetProcessHeap(), 0, size);
181
182     *buf = 0;
183     size2 = pGetLogicalDriveStringsA(2, buf);
184     ok(size2 == size, "size2 = %d\n", size2);
185     ok(!*buf, "buf changed\n");
186
187     size2 = pGetLogicalDriveStringsA(size, buf);
188     ok(size2 == size-1, "size2 = %d\n", size2);
189
190     for(ptr = buf; ptr < buf+size2; ptr += 4) {
191         ok(('A' <= *ptr && *ptr <= 'Z') ||
192            (broken('a' <= *ptr && *ptr <= 'z')), /* Win9x and WinMe */
193            "device name '%c' is not uppercase\n", *ptr);
194         ok(ptr[1] == ':', "ptr[1] = %c, expected ':'\n", ptr[1]);
195         ok(ptr[2] == '\\', "ptr[2] = %c expected '\\'\n", ptr[2]);
196         ok(!ptr[3], "ptr[3] = %c expected nullbyte\n", ptr[3]);
197     }
198     ok(!*ptr, "buf[size2] is not nullbyte\n");
199
200     HeapFree(GetProcessHeap(), 0, buf);
201 }
202
203 static void test_GetLogicalDriveStringsW(void)
204 {
205     UINT size, size2;
206     WCHAR *buf, *ptr;
207
208     if(!pGetLogicalDriveStringsW) {
209         win_skip("GetLogicalDriveStringsW not available\n");
210         return;
211     }
212
213     SetLastError(0xdeadbeef);
214     size = pGetLogicalDriveStringsW(0, NULL);
215     if (size == 0 && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) {
216         win_skip("GetLogicalDriveStringsW not implemented\n");
217         return;
218     }
219     ok(size%4 == 1, "size = %d\n", size);
220
221     buf = HeapAlloc(GetProcessHeap(), 0, size*sizeof(WCHAR));
222
223     *buf = 0;
224     size2 = pGetLogicalDriveStringsW(2, buf);
225     ok(size2 == size, "size2 = %d\n", size2);
226     ok(!*buf, "buf changed\n");
227
228     size2 = pGetLogicalDriveStringsW(size, buf);
229     ok(size2 == size-1, "size2 = %d\n", size2);
230
231     for(ptr = buf; ptr < buf+size2; ptr += 4) {
232         ok('A' <= *ptr && *ptr <= 'Z', "device name '%c' is not uppercase\n", *ptr);
233         ok(ptr[1] == ':', "ptr[1] = %c, expected ':'\n", ptr[1]);
234         ok(ptr[2] == '\\', "ptr[2] = %c expected '\\'\n", ptr[2]);
235         ok(!ptr[3], "ptr[3] = %c expected nullbyte\n", ptr[3]);
236     }
237     ok(!*ptr, "buf[size2] is not nullbyte\n");
238
239     HeapFree(GetProcessHeap(), 0, buf);
240 }
241
242 static void test_GetVolumeInformationA(void)
243 {
244     BOOL ret;
245     UINT result;
246     char Root_Dir0[]="C:";
247     char Root_Dir1[]="C:\\";
248     char Root_Dir2[]="\\\\?\\C:\\";
249     char volume[MAX_PATH+1];
250     DWORD vol_name_size=MAX_PATH+1, vol_serial_num=-1, max_comp_len=0, fs_flags=0, fs_name_len=MAX_PATH+1;
251     char vol_name_buf[MAX_PATH+1], fs_name_buf[MAX_PATH+1];
252     char windowsdir[MAX_PATH+10];
253
254     if (!pGetVolumeInformationA) {
255         win_skip("GetVolumeInformationA not found\n");
256         return;
257     }
258     if (!pGetVolumeNameForVolumeMountPointA) {
259         win_skip("GetVolumeNameForVolumeMountPointA not found\n");
260         return;
261     }
262
263     /* get windows drive letter and update strings for testing */
264     result = GetWindowsDirectory(windowsdir, sizeof(windowsdir));
265     ok(result < sizeof(windowsdir), "windowsdir is abnormally long!\n");
266     ok(result != 0, "GetWindowsDirectory: error %d\n", GetLastError());
267     Root_Dir0[0] = windowsdir[0];
268     Root_Dir1[0] = windowsdir[0];
269     Root_Dir2[4] = windowsdir[0];
270
271     /* get the unique volume name for the windows drive  */
272     ret = pGetVolumeNameForVolumeMountPointA(Root_Dir1, volume, MAX_PATH);
273     ok(ret == TRUE, "GetVolumeNameForVolumeMountPointA failed\n");
274
275     /*  ****  now start the tests       ****  */
276     /* check for error on no trailing \   */
277     ret = pGetVolumeInformationA(Root_Dir0, vol_name_buf, vol_name_size, NULL,
278             NULL, NULL, fs_name_buf, fs_name_len);
279     ok(!ret && GetLastError() == ERROR_INVALID_NAME,
280         "GetVolumeInformationA w/o '\\' did not fail, last error %u\n", GetLastError());
281
282     /* try null root directory to return "root of the current directory"  */
283     ret = pGetVolumeInformationA(NULL, vol_name_buf, vol_name_size, NULL,
284             NULL, NULL, fs_name_buf, fs_name_len);
285     ok(ret, "GetVolumeInformationA failed on null root dir, last error %u\n", GetLastError());
286
287     /* Try normal drive letter with trailing \  */
288     ret = pGetVolumeInformationA(Root_Dir1, vol_name_buf, vol_name_size,
289             &vol_serial_num, &max_comp_len, &fs_flags, fs_name_buf, fs_name_len);
290     ok(ret, "GetVolumeInformationA failed, root=%s, last error=%u\n", Root_Dir1, GetLastError());
291
292     /* try again with dirve letter and the "disable parsing" prefix */
293     ret = pGetVolumeInformationA(Root_Dir2, vol_name_buf, vol_name_size,
294             &vol_serial_num, &max_comp_len, &fs_flags, fs_name_buf, fs_name_len);
295     todo_wine ok(ret, "GetVolumeInformationA failed, root=%s, last error=%u\n", Root_Dir2, GetLastError());
296
297     /* try again with unique voluem name */
298     ret = pGetVolumeInformationA(volume, vol_name_buf, vol_name_size,
299             &vol_serial_num, &max_comp_len, &fs_flags, fs_name_buf, fs_name_len);
300     todo_wine ok(ret, "GetVolumeInformationA failed, root=%s, last error=%u\n", volume, GetLastError());
301
302     /* try again with device name space  */
303     Root_Dir2[2] = '.';
304     ret = pGetVolumeInformationA(Root_Dir2, vol_name_buf, vol_name_size,
305             &vol_serial_num, &max_comp_len, &fs_flags, fs_name_buf, fs_name_len);
306     todo_wine ok(ret, "GetVolumeInformationA failed, root=%s, last error=%u\n", Root_Dir2, GetLastError());
307
308     /* try again with a directory off the root - should generate error  */
309     if (windowsdir[strlen(windowsdir)-1] != '\\') strcat(windowsdir, "\\");
310     ret = pGetVolumeInformationA(windowsdir, vol_name_buf, vol_name_size,
311             &vol_serial_num, &max_comp_len, &fs_flags, fs_name_buf, fs_name_len);
312     todo_wine ok(!ret && GetLastError()==ERROR_DIR_NOT_ROOT,
313           "GetVolumeInformationA failed, root=%s, last error=%u\n", windowsdir, GetLastError());
314 }
315
316 /* Test to check that unique volume name from windows dir mount point  */
317 /* matches at least one of the unique volume names returned from the   */
318 /* FindFirstVolumeA/FindNextVolumeA list.                              */
319 static void test_enum_vols(void)
320 {
321     DWORD   ret;
322     HANDLE  hFind = INVALID_HANDLE_VALUE;
323     char    Volume_1[MAX_PATH] = {0};
324     char    Volume_2[MAX_PATH] = {0};
325     char    path[] = "c:\\";
326     BOOL    found = FALSE;
327     char    windowsdir[MAX_PATH];
328
329     if (!pGetVolumeNameForVolumeMountPointA) {
330         win_skip("GetVolumeNameForVolumeMountPointA not found\n");
331         return;
332     }
333
334     /*get windows drive letter and update strings for testing  */
335     ret = GetWindowsDirectory( windowsdir, sizeof(windowsdir) );
336     ok(ret < sizeof(windowsdir), "windowsdir is abnormally long!\n");
337     ok(ret != 0, "GetWindowsDirecory: error %d\n", GetLastError());
338     path[0] = windowsdir[0];
339
340     /* get the unique volume name for the windows drive  */
341     ret = pGetVolumeNameForVolumeMountPointA( path, Volume_1, MAX_PATH );
342     ok(ret == TRUE, "GetVolumeNameForVolumeMountPointA failed\n");
343 todo_wine
344     ok(strlen(Volume_1) == 49, "GetVolumeNameForVolumeMountPointA returned wrong length name %s\n", Volume_1);
345
346     /* get first unique volume name of list  */
347     hFind = pFindFirstVolumeA( Volume_2, MAX_PATH );
348     ok(hFind != INVALID_HANDLE_VALUE, "FindFirstVolume failed, err=%u\n",
349                 GetLastError());
350
351     do
352     {
353         /* validate correct length of unique volume name  */
354         ok(strlen(Volume_2) == 49, "Find[First/Next]Volume returned wrong length name %s\n", Volume_1);
355         if (memcmp(Volume_1, Volume_2, 49) == 0)
356         {
357             found = TRUE;
358             break;
359         }
360     } while (pFindNextVolumeA( hFind, Volume_2, MAX_PATH ));
361 todo_wine
362     ok(found, "volume name %s not found by Find[First/Next]Volume\n", Volume_1);
363     pFindVolumeClose( hFind );
364 }
365
366 START_TEST(volume)
367 {
368     hdll = GetModuleHandleA("kernel32.dll");
369     pGetVolumeNameForVolumeMountPointA = (void *) GetProcAddress(hdll, "GetVolumeNameForVolumeMountPointA");
370     pGetVolumeNameForVolumeMountPointW = (void *) GetProcAddress(hdll, "GetVolumeNameForVolumeMountPointW");
371     pFindFirstVolumeA = (void *) GetProcAddress(hdll, "FindFirstVolumeA");
372     pFindNextVolumeA = (void *) GetProcAddress(hdll, "FindNextVolumeA");
373     pFindVolumeClose = (void *) GetProcAddress(hdll, "FindVolumeClose");
374     pGetLogicalDriveStringsA = (void *) GetProcAddress(hdll, "GetLogicalDriveStringsA");
375     pGetLogicalDriveStringsW = (void *) GetProcAddress(hdll, "GetLogicalDriveStringsW");
376     pGetVolumeInformationA = (void *) GetProcAddress(hdll, "GetVolumeInformationA");
377
378     test_query_dos_deviceA();
379     test_FindFirstVolume();
380     test_GetVolumeNameForVolumeMountPointA();
381     test_GetVolumeNameForVolumeMountPointW();
382     test_GetLogicalDriveStringsA();
383     test_GetLogicalDriveStringsW();
384     test_GetVolumeInformationA();
385     test_enum_vols();
386 }