[KERNEL32]
[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: dll/win32/kernel32/client/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 * Pierre Schweitzer (pierre@reactos.org)
11 * UPDATE HISTORY:
12 * Created 01/11/98
13 */
14 //WINE copyright notice:
15 /*
16 * DOS drives handling functions
17 *
18 * Copyright 1993 Erik Bos
19 * Copyright 1996 Alexandre Julliard
20 */
21
22 #include <k32.h>
23 #define NDEBUG
24 #include <debug.h>
25 DEBUG_CHANNEL(kernel32file);
26
27 HANDLE
28 WINAPI
29 InternalOpenDirW(IN LPCWSTR DirName,
30 IN BOOLEAN Write)
31 {
32 UNICODE_STRING NtPathU;
33 OBJECT_ATTRIBUTES ObjectAttributes;
34 NTSTATUS errCode;
35 IO_STATUS_BLOCK IoStatusBlock;
36 HANDLE hFile;
37
38 if (!RtlDosPathNameToNtPathName_U(DirName, &NtPathU, NULL, NULL))
39 {
40 WARN("Invalid path\n");
41 SetLastError(ERROR_BAD_PATHNAME);
42 return INVALID_HANDLE_VALUE;
43 }
44
45 InitializeObjectAttributes(&ObjectAttributes,
46 &NtPathU,
47 OBJ_CASE_INSENSITIVE,
48 NULL,
49 NULL);
50
51 errCode = NtCreateFile(&hFile,
52 Write ? FILE_GENERIC_WRITE : FILE_GENERIC_READ,
53 &ObjectAttributes,
54 &IoStatusBlock,
55 NULL,
56 0,
57 FILE_SHARE_READ | FILE_SHARE_WRITE,
58 FILE_OPEN,
59 0,
60 NULL,
61 0);
62
63 RtlFreeHeap(RtlGetProcessHeap(), 0, NtPathU.Buffer);
64
65 if (!NT_SUCCESS(errCode))
66 {
67 BaseSetLastNTError(errCode);
68 return INVALID_HANDLE_VALUE;
69 }
70
71 return hFile;
72 }
73
74 /*
75 * @implemented
76 */
77 BOOL
78 WINAPI
79 GetVolumeInformationA(IN LPCSTR lpRootPathName,
80 IN LPSTR lpVolumeNameBuffer,
81 IN DWORD nVolumeNameSize,
82 OUT LPDWORD lpVolumeSerialNumber OPTIONAL,
83 OUT LPDWORD lpMaximumComponentLength OPTIONAL,
84 OUT LPDWORD lpFileSystemFlags OPTIONAL,
85 OUT LPSTR lpFileSystemNameBuffer OPTIONAL,
86 IN DWORD nFileSystemNameSize)
87 {
88 UNICODE_STRING FileSystemNameU;
89 UNICODE_STRING VolumeNameU = { 0, 0, NULL };
90 ANSI_STRING VolumeName;
91 ANSI_STRING FileSystemName;
92 PWCHAR RootPathNameW;
93 BOOL Result;
94
95 if (!(RootPathNameW = FilenameA2W(lpRootPathName, FALSE)))
96 return FALSE;
97
98 if (lpVolumeNameBuffer)
99 {
100 VolumeNameU.MaximumLength = (USHORT)nVolumeNameSize * sizeof(WCHAR);
101 VolumeNameU.Buffer = RtlAllocateHeap (RtlGetProcessHeap (),
102 0,
103 VolumeNameU.MaximumLength);
104 if (VolumeNameU.Buffer == NULL)
105 {
106 goto FailNoMem;
107 }
108 }
109
110 if (lpFileSystemNameBuffer)
111 {
112 FileSystemNameU.Length = 0;
113 FileSystemNameU.MaximumLength = (USHORT)nFileSystemNameSize * sizeof(WCHAR);
114 FileSystemNameU.Buffer = RtlAllocateHeap (RtlGetProcessHeap (),
115 0,
116 FileSystemNameU.MaximumLength);
117 if (FileSystemNameU.Buffer == NULL)
118 {
119 if (VolumeNameU.Buffer != NULL)
120 {
121 RtlFreeHeap(RtlGetProcessHeap(),
122 0,
123 VolumeNameU.Buffer);
124 }
125
126 FailNoMem:
127 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
128 return FALSE;
129 }
130 }
131
132 Result = GetVolumeInformationW (RootPathNameW,
133 lpVolumeNameBuffer ? VolumeNameU.Buffer : NULL,
134 nVolumeNameSize,
135 lpVolumeSerialNumber,
136 lpMaximumComponentLength,
137 lpFileSystemFlags,
138 lpFileSystemNameBuffer ? FileSystemNameU.Buffer : NULL,
139 nFileSystemNameSize);
140
141 if (Result)
142 {
143 if (lpVolumeNameBuffer)
144 {
145 VolumeNameU.Length = wcslen(VolumeNameU.Buffer) * sizeof(WCHAR);
146 VolumeName.Length = 0;
147 VolumeName.MaximumLength = (USHORT)nVolumeNameSize;
148 VolumeName.Buffer = lpVolumeNameBuffer;
149 }
150
151 if (lpFileSystemNameBuffer)
152 {
153 FileSystemNameU.Length = wcslen(FileSystemNameU.Buffer) * sizeof(WCHAR);
154 FileSystemName.Length = 0;
155 FileSystemName.MaximumLength = (USHORT)nFileSystemNameSize;
156 FileSystemName.Buffer = lpFileSystemNameBuffer;
157 }
158
159 /* convert unicode strings to ansi (or oem) */
160 if (bIsFileApiAnsi)
161 {
162 if (lpVolumeNameBuffer)
163 {
164 RtlUnicodeStringToAnsiString (&VolumeName,
165 &VolumeNameU,
166 FALSE);
167 }
168 if (lpFileSystemNameBuffer)
169 {
170 RtlUnicodeStringToAnsiString (&FileSystemName,
171 &FileSystemNameU,
172 FALSE);
173 }
174 }
175 else
176 {
177 if (lpVolumeNameBuffer)
178 {
179 RtlUnicodeStringToOemString (&VolumeName,
180 &VolumeNameU,
181 FALSE);
182 }
183 if (lpFileSystemNameBuffer)
184 {
185 RtlUnicodeStringToOemString (&FileSystemName,
186 &FileSystemNameU,
187 FALSE);
188 }
189 }
190 }
191
192 if (lpVolumeNameBuffer)
193 {
194 RtlFreeHeap (RtlGetProcessHeap (),
195 0,
196 VolumeNameU.Buffer);
197 }
198 if (lpFileSystemNameBuffer)
199 {
200 RtlFreeHeap (RtlGetProcessHeap (),
201 0,
202 FileSystemNameU.Buffer);
203 }
204
205 return Result;
206 }
207
208 /*
209 * @implemented
210 */
211 static BOOL
212 IsThisARootDirectory(IN HANDLE VolumeHandle,
213 IN PUNICODE_STRING NtPathName)
214 {
215 NTSTATUS Status;
216 IO_STATUS_BLOCK IoStatusBlock;
217 struct
218 {
219 FILE_NAME_INFORMATION;
220 WCHAR Buffer[MAX_PATH];
221 } FileNameInfo;
222
223 /* If we have a handle, query the name */
224 if (VolumeHandle)
225 {
226 Status = NtQueryInformationFile(VolumeHandle, &IoStatusBlock, &FileNameInfo, sizeof(FileNameInfo), FileNameInformation);
227 if (!NT_SUCCESS(Status))
228 {
229 return FALSE;
230 }
231
232 /* Check we properly end with a \ */
233 if (FileNameInfo.FileName[FileNameInfo.FileNameLength / sizeof(WCHAR) - 1] != L'\\')
234 {
235 return FALSE;
236 }
237 }
238
239 /* If we have a path */
240 if (NtPathName != NULL)
241 {
242 HANDLE LinkHandle;
243 WCHAR Buffer[512];
244 ULONG ReturnedLength;
245 UNICODE_STRING LinkTarget;
246 OBJECT_ATTRIBUTES ObjectAttributes;
247
248 NtPathName->Length -= sizeof(WCHAR);
249
250 InitializeObjectAttributes(&ObjectAttributes, NtPathName,
251 OBJ_CASE_INSENSITIVE,
252 NULL, NULL);
253
254 /* Try to see whether that's a symbolic name */
255 Status = NtOpenSymbolicLinkObject(&LinkHandle, SYMBOLIC_LINK_QUERY, &ObjectAttributes);
256 NtPathName->Length += sizeof(WCHAR);
257 if (!NT_SUCCESS(Status))
258 {
259 return FALSE;
260 }
261
262 /* If so, query the target */
263 LinkTarget.Buffer = Buffer;
264 LinkTarget.Length = 0;
265 LinkTarget.MaximumLength = sizeof(Buffer);
266
267 Status = NtQuerySymbolicLinkObject(LinkHandle, &LinkTarget, &ReturnedLength);
268 NtClose(LinkHandle);
269 /* A root directory (NtName) is a symbolic link */
270 if (!NT_SUCCESS(Status))
271 {
272 return FALSE;
273 }
274 }
275
276 return TRUE;
277 }
278
279 /*
280 * @implemented
281 */
282 BOOL
283 WINAPI
284 GetVolumeInformationW(IN LPCWSTR lpRootPathName,
285 IN LPWSTR lpVolumeNameBuffer,
286 IN DWORD nVolumeNameSize,
287 OUT LPDWORD lpVolumeSerialNumber OPTIONAL,
288 OUT LPDWORD lpMaximumComponentLength OPTIONAL,
289 OUT LPDWORD lpFileSystemFlags OPTIONAL,
290 OUT LPWSTR lpFileSystemNameBuffer OPTIONAL,
291 IN DWORD nFileSystemNameSize)
292 {
293 BOOL Ret;
294 NTSTATUS Status;
295 HANDLE VolumeHandle;
296 LPCWSTR RootPathName;
297 UNICODE_STRING NtPathName;
298 IO_STATUS_BLOCK IoStatusBlock;
299 OBJECT_ATTRIBUTES ObjectAttributes;
300 PFILE_FS_VOLUME_INFORMATION VolumeInfo;
301 PFILE_FS_ATTRIBUTE_INFORMATION VolumeAttr;
302 ULONG OldMode, VolumeInfoSize, VolumeAttrSize;
303
304 /* If no root path provided, default to \ */
305 if (lpRootPathName == NULL)
306 {
307 RootPathName = L"\\";
308 }
309 else
310 {
311 RootPathName = lpRootPathName;
312 }
313
314 /* Convert to NT name */
315 if (!RtlDosPathNameToNtPathName_U(RootPathName, &NtPathName, NULL, NULL))
316 {
317 SetLastError(ERROR_PATH_NOT_FOUND);
318 return FALSE;
319 }
320
321 /* Check we really end with a backslash */
322 if (NtPathName.Buffer[(NtPathName.Length / sizeof(WCHAR)) - 1] != L'\\')
323 {
324 RtlFreeHeap(RtlGetProcessHeap(), 0, NtPathName.Buffer);
325 BaseSetLastNTError(STATUS_OBJECT_NAME_INVALID);
326 return FALSE;
327 }
328
329 /* Try to open the received path */
330 InitializeObjectAttributes(&ObjectAttributes, &NtPathName,
331 OBJ_CASE_INSENSITIVE,
332 NULL, NULL);
333
334 /* No errors to the user */
335 RtlSetThreadErrorMode(RTL_SEM_FAILCRITICALERRORS, &OldMode);
336 Status = NtOpenFile(&VolumeHandle, SYNCHRONIZE, &ObjectAttributes, &IoStatusBlock, 0, FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT);
337 RtlSetThreadErrorMode(OldMode, NULL);
338 if (!NT_SUCCESS(Status))
339 {
340 RtlFreeHeap(RtlGetProcessHeap(), 0, NtPathName.Buffer);
341 BaseSetLastNTError(Status);
342 return FALSE;
343 }
344
345 /* Check whether that's a root directory */
346 if (!IsThisARootDirectory(VolumeHandle, &NtPathName))
347 {
348 RtlFreeHeap(RtlGetProcessHeap(), 0, NtPathName.Buffer);
349 NtClose(VolumeHandle);
350 SetLastError(ERROR_DIR_NOT_ROOT);
351 return FALSE;
352 }
353
354 RtlFreeHeap(RtlGetProcessHeap(), 0, NtPathName.Buffer);
355
356 /* Assume we don't need to query FileFsVolumeInformation */
357 VolumeInfo = NULL;
358 /* If user wants volume name, allocate a buffer to query it */
359 if (lpVolumeNameBuffer != NULL)
360 {
361 VolumeInfoSize = nVolumeNameSize + sizeof(FILE_FS_VOLUME_INFORMATION);
362 }
363 /* If user just wants the serial number, allocate a dummy buffer */
364 else if (lpVolumeSerialNumber != NULL)
365 {
366 VolumeInfoSize = MAX_PATH * sizeof(WCHAR) + sizeof(FILE_FS_VOLUME_INFORMATION);
367 }
368 /* Otherwise, nothing to query */
369 else
370 {
371 VolumeInfoSize = 0;
372 }
373
374 /* If we're to query, allocate a big enough buffer */
375 if (VolumeInfoSize != 0)
376 {
377 VolumeInfo = RtlAllocateHeap(RtlGetProcessHeap(), 0, VolumeInfoSize);
378 if (VolumeInfo == NULL)
379 {
380 NtClose(VolumeHandle);
381 BaseSetLastNTError(STATUS_NO_MEMORY);
382 return FALSE;
383 }
384 }
385
386 /* Assume we don't need to query FileFsAttributeInformation */
387 VolumeAttr = NULL;
388 /* If user wants filesystem name, allocate a buffer to query it */
389 if (lpFileSystemNameBuffer != NULL)
390 {
391 VolumeAttrSize = nFileSystemNameSize + sizeof(FILE_FS_ATTRIBUTE_INFORMATION);
392 }
393 /* If user just wants max compo len or flags, allocate a dummy buffer */
394 else if (lpMaximumComponentLength != NULL || lpFileSystemFlags != NULL)
395 {
396 VolumeAttrSize = MAX_PATH * sizeof(WCHAR) + sizeof(FILE_FS_ATTRIBUTE_INFORMATION);
397 }
398 else
399 {
400 VolumeAttrSize = 0;
401 }
402
403 /* If we're to query, allocate a big enough buffer */
404 if (VolumeAttrSize != 0)
405 {
406 VolumeAttr = RtlAllocateHeap(RtlGetProcessHeap(), 0, VolumeAttrSize);
407 if (VolumeAttr == NULL)
408 {
409 if (VolumeInfo != NULL)
410 {
411 RtlFreeHeap(RtlGetProcessHeap(), 0, VolumeInfo);
412 }
413
414 NtClose(VolumeHandle);
415 BaseSetLastNTError(STATUS_NO_MEMORY);
416 return FALSE;
417 }
418 }
419
420 /* Assume we'll fail */
421 Ret = FALSE;
422
423 /* If we're to query FileFsVolumeInformation, do it now! */
424 if (VolumeInfo != NULL)
425 {
426 Status = NtQueryVolumeInformationFile(VolumeHandle, &IoStatusBlock, VolumeInfo, VolumeInfoSize, FileFsVolumeInformation);
427 if (!NT_SUCCESS(Status))
428 {
429 BaseSetLastNTError(Status);
430 goto CleanAndQuit;
431 }
432 }
433
434 /* If we're to query FileFsAttributeInformation, do it now! */
435 if (VolumeAttr != NULL)
436 {
437 Status = NtQueryVolumeInformationFile(VolumeHandle, &IoStatusBlock, VolumeAttr, VolumeAttrSize, FileFsAttributeInformation);
438 if (!NT_SUCCESS(Status))
439 {
440 BaseSetLastNTError(Status);
441 goto CleanAndQuit;
442 }
443 }
444
445 /* If user wants volume name */
446 if (lpVolumeNameBuffer != NULL)
447 {
448 /* Check its buffer can hold it (+ 0) */
449 if (VolumeInfo->VolumeLabelLength >= nVolumeNameSize)
450 {
451 SetLastError(ERROR_BAD_LENGTH);
452 goto CleanAndQuit;
453 }
454
455 /* Copy and zero */
456 RtlCopyMemory(lpVolumeNameBuffer, VolumeInfo->VolumeLabel, VolumeInfo->VolumeLabelLength);
457 lpVolumeNameBuffer[VolumeInfo->VolumeLabelLength / sizeof(WCHAR)] = UNICODE_NULL;
458 }
459
460 /* If user wants wants serial number, return it */
461 if (lpVolumeSerialNumber != NULL)
462 {
463 *lpVolumeSerialNumber = VolumeInfo->VolumeSerialNumber;
464 }
465
466 /* If user wants filesystem name */
467 if (lpFileSystemNameBuffer != NULL)
468 {
469 /* Check its buffer can hold it (+ 0) */
470 if (VolumeAttr->FileSystemNameLength >= nFileSystemNameSize)
471 {
472 SetLastError(ERROR_BAD_LENGTH);
473 goto CleanAndQuit;
474 }
475
476 /* Copy and zero */
477 RtlCopyMemory(lpFileSystemNameBuffer, VolumeAttr->FileSystemName, VolumeAttr->FileSystemNameLength);
478 lpFileSystemNameBuffer[VolumeAttr->FileSystemNameLength / sizeof(WCHAR)] = UNICODE_NULL;
479 }
480
481 /* If user wants wants max compo len, return it */
482 if (lpMaximumComponentLength != NULL)
483 {
484 *lpMaximumComponentLength = VolumeAttr->MaximumComponentNameLength;
485 }
486
487 /* If user wants wants FS flags, return them */
488 if (lpFileSystemFlags != NULL)
489 {
490 *lpFileSystemFlags = VolumeAttr->FileSystemAttributes;
491 }
492
493 /* We did it! */
494 Ret = TRUE;
495
496 CleanAndQuit:
497 NtClose(VolumeHandle);
498
499 if (VolumeInfo != NULL)
500 {
501 RtlFreeHeap(RtlGetProcessHeap(), 0, VolumeInfo);
502 }
503
504 if (VolumeAttr != NULL)
505 {
506 RtlFreeHeap(RtlGetProcessHeap(), 0, VolumeAttr);
507 }
508
509 return Ret;
510 }
511
512 /*
513 * @implemented
514 */
515 BOOL
516 WINAPI
517 SetVolumeLabelA(IN LPCSTR lpRootPathName,
518 IN LPCSTR lpVolumeName OPTIONAL) /* NULL if deleting label */
519 {
520 PWCHAR RootPathNameW;
521 PWCHAR VolumeNameW = NULL;
522 BOOL Result;
523
524 if (!(RootPathNameW = FilenameA2W(lpRootPathName, FALSE)))
525 return FALSE;
526
527 if (lpVolumeName)
528 {
529 if (!(VolumeNameW = FilenameA2W(lpVolumeName, TRUE)))
530 return FALSE;
531 }
532
533 Result = SetVolumeLabelW (RootPathNameW,
534 VolumeNameW);
535
536 if (VolumeNameW)
537 {
538 RtlFreeHeap (RtlGetProcessHeap (),
539 0,
540 VolumeNameW );
541 }
542
543 return Result;
544 }
545
546 /*
547 * @implemented
548 */
549 BOOL
550 WINAPI
551 SetVolumeLabelW(IN LPCWSTR lpRootPathName,
552 IN LPCWSTR lpVolumeName OPTIONAL) /* NULL if deleting label */
553 {
554 PFILE_FS_LABEL_INFORMATION LabelInfo;
555 IO_STATUS_BLOCK IoStatusBlock;
556 ULONG LabelLength;
557 HANDLE hFile;
558 NTSTATUS Status;
559
560 LabelLength = wcslen(lpVolumeName) * sizeof(WCHAR);
561 LabelInfo = RtlAllocateHeap(RtlGetProcessHeap(),
562 0,
563 sizeof(FILE_FS_LABEL_INFORMATION) +
564 LabelLength);
565 if (LabelInfo == NULL)
566 {
567 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
568 return FALSE;
569 }
570 LabelInfo->VolumeLabelLength = LabelLength;
571 memcpy(LabelInfo->VolumeLabel,
572 lpVolumeName,
573 LabelLength);
574
575 hFile = InternalOpenDirW(lpRootPathName, TRUE);
576 if (INVALID_HANDLE_VALUE == hFile)
577 {
578 RtlFreeHeap(RtlGetProcessHeap(),
579 0,
580 LabelInfo);
581 return FALSE;
582 }
583
584 Status = NtSetVolumeInformationFile(hFile,
585 &IoStatusBlock,
586 LabelInfo,
587 sizeof(FILE_FS_LABEL_INFORMATION) +
588 LabelLength,
589 FileFsLabelInformation);
590
591 RtlFreeHeap(RtlGetProcessHeap(),
592 0,
593 LabelInfo);
594
595 if (!NT_SUCCESS(Status))
596 {
597 WARN("Status: %x\n", Status);
598 CloseHandle(hFile);
599 BaseSetLastNTError(Status);
600 return FALSE;
601 }
602
603 CloseHandle(hFile);
604 return TRUE;
605 }
606
607 /*
608 * @implemented (Wine 13 sep 2008)
609 */
610 HANDLE
611 WINAPI
612 FindFirstVolumeW(IN LPWSTR volume,
613 IN DWORD len)
614 {
615 DWORD size = 1024;
616 DWORD br;
617 HANDLE mgr = CreateFileW( MOUNTMGR_DOS_DEVICE_NAME, 0, FILE_SHARE_READ|FILE_SHARE_WRITE,
618 NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, INVALID_HANDLE_VALUE );
619 if (mgr == INVALID_HANDLE_VALUE) return INVALID_HANDLE_VALUE;
620
621 for (;;)
622 {
623 MOUNTMGR_MOUNT_POINT input;
624 MOUNTMGR_MOUNT_POINTS *output;
625
626 if (!(output = RtlAllocateHeap( RtlGetProcessHeap(), 0, size )))
627 {
628 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
629 break;
630 }
631 memset( &input, 0, sizeof(input) );
632
633 if (!DeviceIoControl( mgr, IOCTL_MOUNTMGR_QUERY_POINTS, &input, sizeof(input),
634 output, size, &br, NULL ))
635 {
636 if (GetLastError() != ERROR_MORE_DATA) break;
637 size = output->Size;
638 RtlFreeHeap( RtlGetProcessHeap(), 0, output );
639 continue;
640 }
641 CloseHandle( mgr );
642 /* abuse the Size field to store the current index */
643 output->Size = 0;
644 if (!FindNextVolumeW( output, volume, len ))
645 {
646 RtlFreeHeap( RtlGetProcessHeap(), 0, output );
647 return INVALID_HANDLE_VALUE;
648 }
649 return (HANDLE)output;
650 }
651 CloseHandle( mgr );
652 return INVALID_HANDLE_VALUE;
653 }
654
655 /*
656 * @implemented (Wine 13 sep 2008)
657 */
658 HANDLE
659 WINAPI
660 FindFirstVolumeA(IN LPSTR volume,
661 IN DWORD len)
662 {
663 WCHAR *buffer = NULL;
664 HANDLE handle;
665
666 buffer = RtlAllocateHeap( RtlGetProcessHeap(), 0, len * sizeof(WCHAR) );
667
668 if (!buffer)
669 {
670 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
671 return INVALID_HANDLE_VALUE;
672 }
673
674 handle = FindFirstVolumeW( buffer, len );
675
676 if (handle != INVALID_HANDLE_VALUE)
677 {
678 if (!WideCharToMultiByte( CP_ACP, 0, buffer, -1, volume, len, NULL, NULL ))
679 {
680 FindVolumeClose( handle );
681 handle = INVALID_HANDLE_VALUE;
682 }
683 }
684 RtlFreeHeap( RtlGetProcessHeap(), 0, buffer );
685 return handle;
686 }
687
688 /*
689 * @implemented (Wine 13 sep 2008)
690 */
691 BOOL
692 WINAPI
693 FindVolumeClose(IN HANDLE hFindVolume)
694 {
695 return RtlFreeHeap(RtlGetProcessHeap(), 0, hFindVolume);
696 }
697
698 /*
699 * @implemented
700 */
701 BOOL
702 WINAPI
703 GetVolumePathNameA(IN LPCSTR lpszFileName,
704 IN LPSTR lpszVolumePathName,
705 IN DWORD cchBufferLength)
706 {
707 PWCHAR FileNameW = NULL;
708 WCHAR VolumePathName[MAX_PATH];
709 BOOL Result;
710
711 if (lpszFileName)
712 {
713 if (!(FileNameW = FilenameA2W(lpszFileName, FALSE)))
714 return FALSE;
715 }
716
717 Result = GetVolumePathNameW(FileNameW, VolumePathName, cchBufferLength);
718
719 if (Result)
720 FilenameW2A_N(lpszVolumePathName, MAX_PATH, VolumePathName, -1);
721
722 return Result;
723 }
724
725 /*
726 * @implemented
727 */
728 BOOL
729 WINAPI
730 GetVolumePathNameW(IN LPCWSTR lpszFileName,
731 IN LPWSTR lpszVolumePathName,
732 IN DWORD cchBufferLength)
733 {
734 DWORD PathLength;
735 UNICODE_STRING UnicodeFilePath;
736 LPWSTR FilePart;
737 PWSTR FullFilePath, FilePathName;
738 ULONG PathSize;
739 WCHAR VolumeName[MAX_PATH];
740 DWORD ErrorCode;
741 BOOL Result = FALSE;
742
743 if (!lpszFileName || !lpszVolumePathName || !cchBufferLength)
744 {
745 SetLastError(ERROR_INVALID_PARAMETER);
746 return FALSE;
747 }
748
749 if (!(PathLength = GetFullPathNameW(lpszFileName, 0, NULL, NULL)))
750 {
751 return Result;
752 }
753 else
754 {
755 PathLength = PathLength + 10;
756 PathSize = PathLength * sizeof(WCHAR);
757
758 if (!(FullFilePath = RtlAllocateHeap(RtlGetProcessHeap(), 0, PathSize)))
759 {
760 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
761 return Result;
762 }
763
764 if (!GetFullPathNameW(lpszFileName, PathLength, FullFilePath, &FilePart))
765 {
766 RtlFreeHeap(RtlGetProcessHeap(), 0, FullFilePath);
767 return Result;
768 }
769
770 RtlInitUnicodeString(&UnicodeFilePath, FullFilePath);
771
772 if (UnicodeFilePath.Buffer[UnicodeFilePath.Length / sizeof(WCHAR) - 1] != '\\')
773 {
774 UnicodeFilePath.Length += sizeof(WCHAR);
775 UnicodeFilePath.Buffer[UnicodeFilePath.Length / sizeof(WCHAR) - 1] = '\\';
776 UnicodeFilePath.Buffer[UnicodeFilePath.Length / sizeof(WCHAR)] = '\0';
777 }
778
779 if (!(FilePathName = RtlAllocateHeap(RtlGetProcessHeap(), 0, PathSize)))
780 {
781 RtlFreeHeap(RtlGetProcessHeap(), 0, FullFilePath);
782 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
783 return Result;
784 }
785
786 while (!GetVolumeNameForVolumeMountPointW(UnicodeFilePath.Buffer,
787 VolumeName,
788 MAX_PATH))
789 {
790 if (((UnicodeFilePath.Length == 4) && (UnicodeFilePath.Buffer[0] == '\\') &&
791 (UnicodeFilePath.Buffer[1] == '\\')) || ((UnicodeFilePath.Length == 6) &&
792 (UnicodeFilePath.Buffer[1] == ':')))
793 {
794 break;
795 }
796
797 UnicodeFilePath.Length -= sizeof(WCHAR);
798 UnicodeFilePath.Buffer[UnicodeFilePath.Length / sizeof(WCHAR)] = '\0';
799
800 memcpy(FilePathName, UnicodeFilePath.Buffer, UnicodeFilePath.Length);
801 FilePathName[UnicodeFilePath.Length / sizeof(WCHAR)] = '\0';
802
803 if (!GetFullPathNameW(FilePathName, PathLength, FullFilePath, &FilePart))
804 {
805 goto Cleanup2;
806 }
807
808 if (!FilePart)
809 {
810 RtlInitUnicodeString(&UnicodeFilePath, FullFilePath);
811 UnicodeFilePath.Length += sizeof(WCHAR);
812 UnicodeFilePath.Buffer[UnicodeFilePath.Length / sizeof(WCHAR) - 1] = '\\';
813 UnicodeFilePath.Buffer[UnicodeFilePath.Length / sizeof(WCHAR)] = '\0';
814 break;
815 }
816
817 FilePart[0] = '\0';
818 RtlInitUnicodeString(&UnicodeFilePath, FullFilePath);
819 }
820 }
821
822 if (UnicodeFilePath.Length > (cchBufferLength * sizeof(WCHAR)) - sizeof(WCHAR))
823 {
824 ErrorCode = ERROR_FILENAME_EXCED_RANGE;
825 goto Cleanup1;
826 }
827
828 memcpy(lpszVolumePathName, UnicodeFilePath.Buffer, UnicodeFilePath.Length);
829 lpszVolumePathName[UnicodeFilePath.Length / sizeof(WCHAR)] = '\0';
830
831 Result = TRUE;
832 goto Cleanup2;
833
834 Cleanup1:
835 SetLastError(ErrorCode);
836 Cleanup2:
837 RtlFreeHeap(RtlGetProcessHeap(), 0, FullFilePath);
838 RtlFreeHeap(RtlGetProcessHeap(), 0, FilePathName);
839 return Result;
840 }
841
842 /*
843 * @implemented
844 */
845 BOOL
846 WINAPI
847 FindNextVolumeA(IN HANDLE handle,
848 IN LPSTR volume,
849 IN DWORD len)
850 {
851 WCHAR *buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, len * sizeof(WCHAR));
852 BOOL ret;
853
854 if (!buffer)
855 {
856 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
857 return FALSE;
858 }
859
860 if ((ret = FindNextVolumeW( handle, buffer, len )))
861 {
862 if (!WideCharToMultiByte( CP_ACP, 0, buffer, -1, volume, len, NULL, NULL )) ret = FALSE;
863 }
864
865 RtlFreeHeap(RtlGetProcessHeap(), 0, buffer);
866 return ret;
867 }
868
869 /*
870 * @implemented
871 */
872 BOOL
873 WINAPI
874 FindNextVolumeW(IN HANDLE handle,
875 IN LPWSTR volume,
876 IN DWORD len)
877 {
878 MOUNTMGR_MOUNT_POINTS *data = handle;
879
880 while (data->Size < data->NumberOfMountPoints)
881 {
882 static const WCHAR volumeW[] = {'\\','?','?','\\','V','o','l','u','m','e','{',};
883 WCHAR *link = (WCHAR *)((char *)data + data->MountPoints[data->Size].SymbolicLinkNameOffset);
884 DWORD size = data->MountPoints[data->Size].SymbolicLinkNameLength;
885 data->Size++;
886 /* skip non-volumes */
887 if (size < sizeof(volumeW) || memcmp( link, volumeW, sizeof(volumeW) )) continue;
888 if (size + sizeof(WCHAR) >= len * sizeof(WCHAR))
889 {
890 SetLastError( ERROR_FILENAME_EXCED_RANGE );
891 return FALSE;
892 }
893 memcpy( volume, link, size );
894 volume[1] = '\\'; /* map \??\ to \\?\ */
895 volume[size / sizeof(WCHAR)] = '\\'; /* Windows appends a backslash */
896 volume[size / sizeof(WCHAR) + 1] = 0;
897 DPRINT( "returning entry %u %s\n", data->Size - 1, volume );
898 return TRUE;
899 }
900 SetLastError( ERROR_NO_MORE_FILES );
901 return FALSE;
902 }
903
904 /*
905 * @unimplemented
906 */
907 BOOL
908 WINAPI
909 GetVolumePathNamesForVolumeNameA(IN LPCSTR lpszVolumeName,
910 IN LPSTR lpszVolumePathNames,
911 IN DWORD cchBufferLength,
912 OUT PDWORD lpcchReturnLength)
913 {
914 STUB;
915 return 0;
916 }
917
918
919 /*
920 * @unimplemented
921 */
922 BOOL
923 WINAPI
924 GetVolumePathNamesForVolumeNameW(IN LPCWSTR lpszVolumeName,
925 IN LPWSTR lpszVolumePathNames,
926 IN DWORD cchBufferLength,
927 OUT PDWORD lpcchReturnLength)
928 {
929 STUB;
930 return 0;
931 }
932
933 /* EOF */