8315ec4c35d5e5edd52f82e7173f565777c92710
[reactos.git] / reactos / dll / win32 / kernel32 / client / file / volume.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS system libraries
4 * FILE: lib/kernel32/file/volume.c
5 * PURPOSE: File volume functions
6 * PROGRAMMER: Ariadne ( ariadne@xs4all.nl)
7 * Erik Bos, Alexandre Julliard :
8 * GetLogicalDriveStringsA,
9 * GetLogicalDriveStringsW, GetLogicalDrives
10 * UPDATE HISTORY:
11 * Created 01/11/98
12 */
13 //WINE copyright notice:
14 /*
15 * DOS drives handling functions
16 *
17 * Copyright 1993 Erik Bos
18 * Copyright 1996 Alexandre Julliard
19 */
20
21 #include <k32.h>
22 #define NDEBUG
23 #include <debug.h>
24 DEBUG_CHANNEL(kernel32file);
25
26 HANDLE
27 WINAPI
28 InternalOpenDirW(IN LPCWSTR DirName,
29 IN BOOLEAN Write)
30 {
31 UNICODE_STRING NtPathU;
32 OBJECT_ATTRIBUTES ObjectAttributes;
33 NTSTATUS errCode;
34 IO_STATUS_BLOCK IoStatusBlock;
35 HANDLE hFile;
36
37 if (!RtlDosPathNameToNtPathName_U(DirName, &NtPathU, NULL, NULL))
38 {
39 WARN("Invalid path\n");
40 SetLastError(ERROR_BAD_PATHNAME);
41 return INVALID_HANDLE_VALUE;
42 }
43
44 InitializeObjectAttributes(&ObjectAttributes,
45 &NtPathU,
46 OBJ_CASE_INSENSITIVE,
47 NULL,
48 NULL);
49
50 errCode = NtCreateFile(&hFile,
51 Write ? FILE_GENERIC_WRITE : FILE_GENERIC_READ,
52 &ObjectAttributes,
53 &IoStatusBlock,
54 NULL,
55 0,
56 FILE_SHARE_READ | FILE_SHARE_WRITE,
57 FILE_OPEN,
58 0,
59 NULL,
60 0);
61
62 RtlFreeHeap(RtlGetProcessHeap(), 0, NtPathU.Buffer);
63
64 if (!NT_SUCCESS(errCode))
65 {
66 BaseSetLastNTError(errCode);
67 return INVALID_HANDLE_VALUE;
68 }
69
70 return hFile;
71 }
72
73 /*
74 * @implemented
75 */
76 BOOL
77 WINAPI
78 GetVolumeInformationA(IN LPCSTR lpRootPathName,
79 IN LPSTR lpVolumeNameBuffer,
80 IN DWORD nVolumeNameSize,
81 OUT LPDWORD lpVolumeSerialNumber OPTIONAL,
82 OUT LPDWORD lpMaximumComponentLength OPTIONAL,
83 OUT LPDWORD lpFileSystemFlags OPTIONAL,
84 OUT LPSTR lpFileSystemNameBuffer OPTIONAL,
85 IN DWORD nFileSystemNameSize)
86 {
87 UNICODE_STRING FileSystemNameU;
88 UNICODE_STRING VolumeNameU = { 0, 0, NULL };
89 ANSI_STRING VolumeName;
90 ANSI_STRING FileSystemName;
91 PWCHAR RootPathNameW;
92 BOOL Result;
93
94 if (!(RootPathNameW = FilenameA2W(lpRootPathName, FALSE)))
95 return FALSE;
96
97 if (lpVolumeNameBuffer)
98 {
99 VolumeNameU.MaximumLength = (USHORT)nVolumeNameSize * sizeof(WCHAR);
100 VolumeNameU.Buffer = RtlAllocateHeap (RtlGetProcessHeap (),
101 0,
102 VolumeNameU.MaximumLength);
103 if (VolumeNameU.Buffer == NULL)
104 {
105 goto FailNoMem;
106 }
107 }
108
109 if (lpFileSystemNameBuffer)
110 {
111 FileSystemNameU.Length = 0;
112 FileSystemNameU.MaximumLength = (USHORT)nFileSystemNameSize * sizeof(WCHAR);
113 FileSystemNameU.Buffer = RtlAllocateHeap (RtlGetProcessHeap (),
114 0,
115 FileSystemNameU.MaximumLength);
116 if (FileSystemNameU.Buffer == NULL)
117 {
118 if (VolumeNameU.Buffer != NULL)
119 {
120 RtlFreeHeap(RtlGetProcessHeap(),
121 0,
122 VolumeNameU.Buffer);
123 }
124
125 FailNoMem:
126 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
127 return FALSE;
128 }
129 }
130
131 Result = GetVolumeInformationW (RootPathNameW,
132 lpVolumeNameBuffer ? VolumeNameU.Buffer : NULL,
133 nVolumeNameSize,
134 lpVolumeSerialNumber,
135 lpMaximumComponentLength,
136 lpFileSystemFlags,
137 lpFileSystemNameBuffer ? FileSystemNameU.Buffer : NULL,
138 nFileSystemNameSize);
139
140 if (Result)
141 {
142 if (lpVolumeNameBuffer)
143 {
144 VolumeNameU.Length = wcslen(VolumeNameU.Buffer) * sizeof(WCHAR);
145 VolumeName.Length = 0;
146 VolumeName.MaximumLength = (USHORT)nVolumeNameSize;
147 VolumeName.Buffer = lpVolumeNameBuffer;
148 }
149
150 if (lpFileSystemNameBuffer)
151 {
152 FileSystemNameU.Length = wcslen(FileSystemNameU.Buffer) * sizeof(WCHAR);
153 FileSystemName.Length = 0;
154 FileSystemName.MaximumLength = (USHORT)nFileSystemNameSize;
155 FileSystemName.Buffer = lpFileSystemNameBuffer;
156 }
157
158 /* convert unicode strings to ansi (or oem) */
159 if (bIsFileApiAnsi)
160 {
161 if (lpVolumeNameBuffer)
162 {
163 RtlUnicodeStringToAnsiString (&VolumeName,
164 &VolumeNameU,
165 FALSE);
166 }
167 if (lpFileSystemNameBuffer)
168 {
169 RtlUnicodeStringToAnsiString (&FileSystemName,
170 &FileSystemNameU,
171 FALSE);
172 }
173 }
174 else
175 {
176 if (lpVolumeNameBuffer)
177 {
178 RtlUnicodeStringToOemString (&VolumeName,
179 &VolumeNameU,
180 FALSE);
181 }
182 if (lpFileSystemNameBuffer)
183 {
184 RtlUnicodeStringToOemString (&FileSystemName,
185 &FileSystemNameU,
186 FALSE);
187 }
188 }
189 }
190
191 if (lpVolumeNameBuffer)
192 {
193 RtlFreeHeap (RtlGetProcessHeap (),
194 0,
195 VolumeNameU.Buffer);
196 }
197 if (lpFileSystemNameBuffer)
198 {
199 RtlFreeHeap (RtlGetProcessHeap (),
200 0,
201 FileSystemNameU.Buffer);
202 }
203
204 return Result;
205 }
206
207 #define FS_VOLUME_BUFFER_SIZE (MAX_PATH * sizeof(WCHAR) + sizeof(FILE_FS_VOLUME_INFORMATION))
208
209 #define FS_ATTRIBUTE_BUFFER_SIZE (MAX_PATH * sizeof(WCHAR) + sizeof(FILE_FS_ATTRIBUTE_INFORMATION))
210
211 /*
212 * @implemented
213 */
214 BOOL
215 WINAPI
216 GetVolumeInformationW(IN LPCWSTR lpRootPathName,
217 IN LPWSTR lpVolumeNameBuffer,
218 IN DWORD nVolumeNameSize,
219 OUT LPDWORD lpVolumeSerialNumber OPTIONAL,
220 OUT LPDWORD lpMaximumComponentLength OPTIONAL,
221 OUT LPDWORD lpFileSystemFlags OPTIONAL,
222 OUT LPWSTR lpFileSystemNameBuffer OPTIONAL,
223 IN DWORD nFileSystemNameSize)
224 {
225 PFILE_FS_VOLUME_INFORMATION FileFsVolume;
226 PFILE_FS_ATTRIBUTE_INFORMATION FileFsAttribute;
227 IO_STATUS_BLOCK IoStatusBlock;
228 WCHAR RootPathName[MAX_PATH];
229 UCHAR Buffer[max(FS_VOLUME_BUFFER_SIZE, FS_ATTRIBUTE_BUFFER_SIZE)];
230
231 HANDLE hFile;
232 NTSTATUS errCode;
233
234 FileFsVolume = (PFILE_FS_VOLUME_INFORMATION)Buffer;
235 FileFsAttribute = (PFILE_FS_ATTRIBUTE_INFORMATION)Buffer;
236
237 TRACE("FileFsVolume %p\n", FileFsVolume);
238 TRACE("FileFsAttribute %p\n", FileFsAttribute);
239
240 if (!lpRootPathName || !wcscmp(lpRootPathName, L""))
241 {
242 GetCurrentDirectoryW (MAX_PATH, RootPathName);
243 }
244 else
245 {
246 wcsncpy (RootPathName, lpRootPathName, 3);
247 }
248 RootPathName[3] = 0;
249
250 hFile = InternalOpenDirW(RootPathName, FALSE);
251 if (hFile == INVALID_HANDLE_VALUE)
252 {
253 return FALSE;
254 }
255
256 TRACE("hFile: %p\n", hFile);
257 errCode = NtQueryVolumeInformationFile(hFile,
258 &IoStatusBlock,
259 FileFsVolume,
260 FS_VOLUME_BUFFER_SIZE,
261 FileFsVolumeInformation);
262 if ( !NT_SUCCESS(errCode) )
263 {
264 WARN("Status: %x\n", errCode);
265 CloseHandle(hFile);
266 BaseSetLastNTError (errCode);
267 return FALSE;
268 }
269
270 if (lpVolumeSerialNumber)
271 *lpVolumeSerialNumber = FileFsVolume->VolumeSerialNumber;
272
273 if (lpVolumeNameBuffer)
274 {
275 if (nVolumeNameSize * sizeof(WCHAR) >= FileFsVolume->VolumeLabelLength + sizeof(WCHAR))
276 {
277 memcpy(lpVolumeNameBuffer,
278 FileFsVolume->VolumeLabel,
279 FileFsVolume->VolumeLabelLength);
280 lpVolumeNameBuffer[FileFsVolume->VolumeLabelLength / sizeof(WCHAR)] = 0;
281 }
282 else
283 {
284 CloseHandle(hFile);
285 SetLastError(ERROR_MORE_DATA);
286 return FALSE;
287 }
288 }
289
290 errCode = NtQueryVolumeInformationFile (hFile,
291 &IoStatusBlock,
292 FileFsAttribute,
293 FS_ATTRIBUTE_BUFFER_SIZE,
294 FileFsAttributeInformation);
295 CloseHandle(hFile);
296 if (!NT_SUCCESS(errCode))
297 {
298 WARN("Status: %x\n", errCode);
299 BaseSetLastNTError (errCode);
300 return FALSE;
301 }
302
303 if (lpFileSystemFlags)
304 *lpFileSystemFlags = FileFsAttribute->FileSystemAttributes;
305 if (lpMaximumComponentLength)
306 *lpMaximumComponentLength = FileFsAttribute->MaximumComponentNameLength;
307 if (lpFileSystemNameBuffer)
308 {
309 if (nFileSystemNameSize * sizeof(WCHAR) >= FileFsAttribute->FileSystemNameLength + sizeof(WCHAR))
310 {
311 memcpy(lpFileSystemNameBuffer,
312 FileFsAttribute->FileSystemName,
313 FileFsAttribute->FileSystemNameLength);
314 lpFileSystemNameBuffer[FileFsAttribute->FileSystemNameLength / sizeof(WCHAR)] = 0;
315 }
316 else
317 {
318 SetLastError(ERROR_MORE_DATA);
319 return FALSE;
320 }
321 }
322 return TRUE;
323 }
324
325 /*
326 * @implemented
327 */
328 BOOL
329 WINAPI
330 SetVolumeLabelA(IN LPCSTR lpRootPathName,
331 IN LPCSTR lpVolumeName OPTIONAL) /* NULL if deleting label */
332 {
333 PWCHAR RootPathNameW;
334 PWCHAR VolumeNameW = NULL;
335 BOOL Result;
336
337 if (!(RootPathNameW = FilenameA2W(lpRootPathName, FALSE)))
338 return FALSE;
339
340 if (lpVolumeName)
341 {
342 if (!(VolumeNameW = FilenameA2W(lpVolumeName, TRUE)))
343 return FALSE;
344 }
345
346 Result = SetVolumeLabelW (RootPathNameW,
347 VolumeNameW);
348
349 if (VolumeNameW)
350 {
351 RtlFreeHeap (RtlGetProcessHeap (),
352 0,
353 VolumeNameW );
354 }
355
356 return Result;
357 }
358
359 /*
360 * @implemented
361 */
362 BOOL
363 WINAPI
364 SetVolumeLabelW(IN LPCWSTR lpRootPathName,
365 IN LPCWSTR lpVolumeName OPTIONAL) /* NULL if deleting label */
366 {
367 PFILE_FS_LABEL_INFORMATION LabelInfo;
368 IO_STATUS_BLOCK IoStatusBlock;
369 ULONG LabelLength;
370 HANDLE hFile;
371 NTSTATUS Status;
372
373 LabelLength = wcslen(lpVolumeName) * sizeof(WCHAR);
374 LabelInfo = RtlAllocateHeap(RtlGetProcessHeap(),
375 0,
376 sizeof(FILE_FS_LABEL_INFORMATION) +
377 LabelLength);
378 if (LabelInfo == NULL)
379 {
380 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
381 return FALSE;
382 }
383 LabelInfo->VolumeLabelLength = LabelLength;
384 memcpy(LabelInfo->VolumeLabel,
385 lpVolumeName,
386 LabelLength);
387
388 hFile = InternalOpenDirW(lpRootPathName, TRUE);
389 if (INVALID_HANDLE_VALUE == hFile)
390 {
391 RtlFreeHeap(RtlGetProcessHeap(),
392 0,
393 LabelInfo);
394 return FALSE;
395 }
396
397 Status = NtSetVolumeInformationFile(hFile,
398 &IoStatusBlock,
399 LabelInfo,
400 sizeof(FILE_FS_LABEL_INFORMATION) +
401 LabelLength,
402 FileFsLabelInformation);
403
404 RtlFreeHeap(RtlGetProcessHeap(),
405 0,
406 LabelInfo);
407
408 if (!NT_SUCCESS(Status))
409 {
410 WARN("Status: %x\n", Status);
411 CloseHandle(hFile);
412 BaseSetLastNTError(Status);
413 return FALSE;
414 }
415
416 CloseHandle(hFile);
417 return TRUE;
418 }
419
420 /*
421 * @implemented (Wine 13 sep 2008)
422 */
423 HANDLE
424 WINAPI
425 FindFirstVolumeW(IN LPWSTR volume,
426 IN DWORD len)
427 {
428 DWORD size = 1024;
429 HANDLE mgr = CreateFileW( MOUNTMGR_DOS_DEVICE_NAME, 0, FILE_SHARE_READ|FILE_SHARE_WRITE,
430 NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, INVALID_HANDLE_VALUE );
431 if (mgr == INVALID_HANDLE_VALUE) return INVALID_HANDLE_VALUE;
432
433 for (;;)
434 {
435 MOUNTMGR_MOUNT_POINT input;
436 MOUNTMGR_MOUNT_POINTS *output;
437
438 if (!(output = RtlAllocateHeap( RtlGetProcessHeap(), 0, size )))
439 {
440 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
441 break;
442 }
443 memset( &input, 0, sizeof(input) );
444
445 if (!DeviceIoControl( mgr, IOCTL_MOUNTMGR_QUERY_POINTS, &input, sizeof(input),
446 output, size, NULL, NULL ))
447 {
448 if (GetLastError() != ERROR_MORE_DATA) break;
449 size = output->Size;
450 RtlFreeHeap( RtlGetProcessHeap(), 0, output );
451 continue;
452 }
453 CloseHandle( mgr );
454 /* abuse the Size field to store the current index */
455 output->Size = 0;
456 if (!FindNextVolumeW( output, volume, len ))
457 {
458 RtlFreeHeap( RtlGetProcessHeap(), 0, output );
459 return INVALID_HANDLE_VALUE;
460 }
461 return (HANDLE)output;
462 }
463 CloseHandle( mgr );
464 return INVALID_HANDLE_VALUE;
465 }
466
467 /*
468 * @implemented (Wine 13 sep 2008)
469 */
470 HANDLE
471 WINAPI
472 FindFirstVolumeA(IN LPSTR volume,
473 IN DWORD len)
474 {
475 WCHAR *buffer = NULL;
476 HANDLE handle;
477
478 buffer = RtlAllocateHeap( RtlGetProcessHeap(), 0, len * sizeof(WCHAR) );
479
480 if (!buffer)
481 {
482 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
483 return INVALID_HANDLE_VALUE;
484 }
485
486 handle = FindFirstVolumeW( buffer, len );
487
488 if (handle != INVALID_HANDLE_VALUE)
489 {
490 if (!WideCharToMultiByte( CP_ACP, 0, buffer, -1, volume, len, NULL, NULL ))
491 {
492 FindVolumeClose( handle );
493 handle = INVALID_HANDLE_VALUE;
494 }
495 }
496 RtlFreeHeap( RtlGetProcessHeap(), 0, buffer );
497 return handle;
498 }
499
500 /*
501 * @implemented (Wine 13 sep 2008)
502 */
503 BOOL
504 WINAPI
505 FindVolumeClose(IN HANDLE hFindVolume)
506 {
507 return RtlFreeHeap(RtlGetProcessHeap(), 0, hFindVolume);
508 }
509
510 /*
511 * @implemented
512 */
513 BOOL
514 WINAPI
515 GetVolumePathNameA(IN LPCSTR lpszFileName,
516 IN LPSTR lpszVolumePathName,
517 IN DWORD cchBufferLength)
518 {
519 PWCHAR FileNameW = NULL;
520 WCHAR VolumePathName[MAX_PATH];
521 BOOL Result;
522
523 if (lpszFileName)
524 {
525 if (!(FileNameW = FilenameA2W(lpszFileName, FALSE)))
526 return FALSE;
527 }
528
529 Result = GetVolumePathNameW(FileNameW, VolumePathName, cchBufferLength);
530
531 if (Result)
532 FilenameW2A_N(lpszVolumePathName, MAX_PATH, VolumePathName, -1);
533
534 return Result;
535 }
536
537 /*
538 * @implemented
539 */
540 BOOL
541 WINAPI
542 GetVolumePathNameW(IN LPCWSTR lpszFileName,
543 IN LPWSTR lpszVolumePathName,
544 IN DWORD cchBufferLength)
545 {
546 DWORD PathLength;
547 UNICODE_STRING UnicodeFilePath;
548 LPWSTR FilePart;
549 PWSTR FullFilePath, FilePathName;
550 ULONG PathSize;
551 WCHAR VolumeName[MAX_PATH];
552 DWORD ErrorCode;
553 BOOL Result = FALSE;
554
555 if (!lpszFileName || !lpszVolumePathName || !cchBufferLength)
556 {
557 SetLastError(ERROR_INVALID_PARAMETER);
558 return FALSE;
559 }
560
561 if (!(PathLength = GetFullPathNameW(lpszFileName, 0, NULL, NULL)))
562 {
563 return Result;
564 }
565 else
566 {
567 PathLength = PathLength + 10;
568 PathSize = PathLength * sizeof(WCHAR);
569
570 if (!(FullFilePath = RtlAllocateHeap(RtlGetProcessHeap(), 0, PathSize)))
571 {
572 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
573 return Result;
574 }
575
576 if (!GetFullPathNameW(lpszFileName, PathLength, FullFilePath, &FilePart))
577 {
578 RtlFreeHeap(RtlGetProcessHeap(), 0, FullFilePath);
579 return Result;
580 }
581
582 RtlInitUnicodeString(&UnicodeFilePath, FullFilePath);
583
584 if (UnicodeFilePath.Buffer[UnicodeFilePath.Length / sizeof(WCHAR) - 1] != '\\')
585 {
586 UnicodeFilePath.Length += sizeof(WCHAR);
587 UnicodeFilePath.Buffer[UnicodeFilePath.Length / sizeof(WCHAR) - 1] = '\\';
588 UnicodeFilePath.Buffer[UnicodeFilePath.Length / sizeof(WCHAR)] = '\0';
589 }
590
591 if (!(FilePathName = RtlAllocateHeap(RtlGetProcessHeap(), 0, PathSize)))
592 {
593 RtlFreeHeap(RtlGetProcessHeap(), 0, FullFilePath);
594 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
595 return Result;
596 }
597
598 while (!GetVolumeNameForVolumeMountPointW(UnicodeFilePath.Buffer,
599 VolumeName,
600 MAX_PATH))
601 {
602 if (((UnicodeFilePath.Length == 4) && (UnicodeFilePath.Buffer[0] == '\\') &&
603 (UnicodeFilePath.Buffer[1] == '\\')) || ((UnicodeFilePath.Length == 6) &&
604 (UnicodeFilePath.Buffer[1] == ':')))
605 {
606 break;
607 }
608
609 UnicodeFilePath.Length -= sizeof(WCHAR);
610 UnicodeFilePath.Buffer[UnicodeFilePath.Length / sizeof(WCHAR)] = '\0';
611
612 memcpy(FilePathName, UnicodeFilePath.Buffer, UnicodeFilePath.Length);
613 FilePathName[UnicodeFilePath.Length / sizeof(WCHAR)] = '\0';
614
615 if (!GetFullPathNameW(FilePathName, PathLength, FullFilePath, &FilePart))
616 {
617 goto Cleanup2;
618 }
619
620 if (!FilePart)
621 {
622 RtlInitUnicodeString(&UnicodeFilePath, FullFilePath);
623 UnicodeFilePath.Length += sizeof(WCHAR);
624 UnicodeFilePath.Buffer[UnicodeFilePath.Length / sizeof(WCHAR) - 1] = '\\';
625 UnicodeFilePath.Buffer[UnicodeFilePath.Length / sizeof(WCHAR)] = '\0';
626 break;
627 }
628
629 FilePart[0] = '\0';
630 RtlInitUnicodeString(&UnicodeFilePath, FullFilePath);
631 }
632 }
633
634 if (UnicodeFilePath.Length > (cchBufferLength * sizeof(WCHAR)) - sizeof(WCHAR))
635 {
636 ErrorCode = ERROR_FILENAME_EXCED_RANGE;
637 goto Cleanup1;
638 }
639
640 memcpy(lpszVolumePathName, UnicodeFilePath.Buffer, UnicodeFilePath.Length);
641 lpszVolumePathName[UnicodeFilePath.Length / sizeof(WCHAR)] = '\0';
642
643 Result = TRUE;
644 goto Cleanup2;
645
646 Cleanup1:
647 SetLastError(ErrorCode);
648 Cleanup2:
649 RtlFreeHeap(RtlGetProcessHeap(), 0, FullFilePath);
650 RtlFreeHeap(RtlGetProcessHeap(), 0, FilePathName);
651 return Result;
652 }
653
654 /*
655 * @implemented
656 */
657 BOOL
658 WINAPI
659 FindNextVolumeA(IN HANDLE handle,
660 IN LPSTR volume,
661 IN DWORD len)
662 {
663 WCHAR *buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, len * sizeof(WCHAR));
664 BOOL ret;
665
666 if (!buffer)
667 {
668 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
669 return FALSE;
670 }
671
672 if ((ret = FindNextVolumeW( handle, buffer, len )))
673 {
674 if (!WideCharToMultiByte( CP_ACP, 0, buffer, -1, volume, len, NULL, NULL )) ret = FALSE;
675 }
676
677 RtlFreeHeap(RtlGetProcessHeap(), 0, buffer);
678 return ret;
679 }
680
681 /*
682 * @implemented
683 */
684 BOOL
685 WINAPI
686 FindNextVolumeW(IN HANDLE handle,
687 IN LPWSTR volume,
688 IN DWORD len)
689 {
690 MOUNTMGR_MOUNT_POINTS *data = handle;
691
692 while (data->Size < data->NumberOfMountPoints)
693 {
694 static const WCHAR volumeW[] = {'\\','?','?','\\','V','o','l','u','m','e','{',};
695 WCHAR *link = (WCHAR *)((char *)data + data->MountPoints[data->Size].SymbolicLinkNameOffset);
696 DWORD size = data->MountPoints[data->Size].SymbolicLinkNameLength;
697 data->Size++;
698 /* skip non-volumes */
699 if (size < sizeof(volumeW) || memcmp( link, volumeW, sizeof(volumeW) )) continue;
700 if (size + sizeof(WCHAR) >= len * sizeof(WCHAR))
701 {
702 SetLastError( ERROR_FILENAME_EXCED_RANGE );
703 return FALSE;
704 }
705 memcpy( volume, link, size );
706 volume[1] = '\\'; /* map \??\ to \\?\ */
707 volume[size / sizeof(WCHAR)] = '\\'; /* Windows appends a backslash */
708 volume[size / sizeof(WCHAR) + 1] = 0;
709 DPRINT( "returning entry %u %s\n", data->Size - 1, volume );
710 return TRUE;
711 }
712 SetLastError( ERROR_NO_MORE_FILES );
713 return FALSE;
714 }
715
716 /*
717 * @unimplemented
718 */
719 BOOL
720 WINAPI
721 GetVolumePathNamesForVolumeNameA(IN LPCSTR lpszVolumeName,
722 IN LPSTR lpszVolumePathNames,
723 IN DWORD cchBufferLength,
724 OUT PDWORD lpcchReturnLength)
725 {
726 STUB;
727 return 0;
728 }
729
730
731 /*
732 * @unimplemented
733 */
734 BOOL
735 WINAPI
736 GetVolumePathNamesForVolumeNameW(IN LPCWSTR lpszVolumeName,
737 IN LPWSTR lpszVolumePathNames,
738 IN DWORD cchBufferLength,
739 OUT PDWORD lpcchReturnLength)
740 {
741 STUB;
742 return 0;
743 }
744
745 /* EOF */