ReactOS  0.4.10-dev-19-g39281f0
volume.c
Go to the documentation of this file.
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 
26 
27 /*
28  * @implemented
29  */
30 BOOL
31 WINAPI
33  IN LPSTR lpVolumeNameBuffer,
34  IN DWORD nVolumeNameSize,
35  OUT LPDWORD lpVolumeSerialNumber OPTIONAL,
36  OUT LPDWORD lpMaximumComponentLength OPTIONAL,
37  OUT LPDWORD lpFileSystemFlags OPTIONAL,
38  OUT LPSTR lpFileSystemNameBuffer OPTIONAL,
39  IN DWORD nFileSystemNameSize)
40 {
41  BOOL Ret;
43  PUNICODE_STRING RootPathNameU;
44  ANSI_STRING VolumeName, FileSystemName;
45  UNICODE_STRING VolumeNameU, FileSystemNameU;
46 
47  /* If no root path provided, default to \ */
48  if (lpRootPathName == NULL)
49  {
50  lpRootPathName = "\\";
51  }
52 
53  /* Convert root path to unicode */
54  RootPathNameU = Basep8BitStringToStaticUnicodeString(lpRootPathName);
55  if (RootPathNameU == NULL)
56  {
57  return FALSE;
58  }
59 
60  /* Init all our STRINGS (U/A) */
61  VolumeNameU.Buffer = NULL;
62  VolumeNameU.MaximumLength = 0;
63  FileSystemNameU.Buffer = NULL;
64  FileSystemNameU.MaximumLength = 0;
65 
66  VolumeName.Buffer = lpVolumeNameBuffer;
67  VolumeName.MaximumLength = nVolumeNameSize + 1;
68  FileSystemName.Buffer = lpFileSystemNameBuffer;
69  FileSystemName.MaximumLength = nFileSystemNameSize + 1;
70 
71  /* Assume failure for now */
72  Ret = FALSE;
73 
74  /* If caller wants volume name, allocate a buffer to receive it */
75  if (lpVolumeNameBuffer != NULL)
76  {
77  VolumeNameU.MaximumLength = sizeof(WCHAR) * (nVolumeNameSize + 1);
78  VolumeNameU.Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0,
79  VolumeNameU.MaximumLength);
80  if (VolumeNameU.Buffer == NULL)
81  {
83  goto CleanAndQuit;
84  }
85  }
86 
87  /* If caller wants file system name, allocate a buffer to receive it */
88  if (lpFileSystemNameBuffer != NULL)
89  {
90  FileSystemNameU.MaximumLength = sizeof(WCHAR) * (nFileSystemNameSize + 1);
91  FileSystemNameU.Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0,
92  FileSystemNameU.MaximumLength);
93  if (FileSystemNameU.Buffer == NULL)
94  {
96  goto CleanAndQuit;
97  }
98  }
99 
100  /* Call W */
101  Ret = GetVolumeInformationW(RootPathNameU->Buffer, VolumeNameU.Buffer,
102  nVolumeNameSize, lpVolumeSerialNumber,
103  lpMaximumComponentLength, lpFileSystemFlags,
104  FileSystemNameU.Buffer, nFileSystemNameSize);
105  /* If it succeed, convert back to ANSI */
106  if (Ret)
107  {
108  if (lpVolumeNameBuffer != NULL)
109  {
110  RtlInitUnicodeString(&VolumeNameU, VolumeNameU.Buffer);
111  Status = RtlUnicodeStringToAnsiString(&VolumeName, &VolumeNameU, FALSE);
112  if (!NT_SUCCESS(Status))
113  {
114  BaseSetLastNTError(Status);
115  Ret = FALSE;
116 
117  goto CleanAndQuit;
118  }
119  }
120 
121  if (lpFileSystemNameBuffer != NULL)
122  {
123  RtlInitUnicodeString(&FileSystemNameU, FileSystemNameU.Buffer);
124  Status = RtlUnicodeStringToAnsiString(&FileSystemName, &FileSystemNameU, FALSE);
125  if (!NT_SUCCESS(Status))
126  {
127  BaseSetLastNTError(Status);
128  Ret = FALSE;
129 
130  goto CleanAndQuit;
131  }
132  }
133  }
134 
135  /* Clean and quit */
136 CleanAndQuit:
137  if (VolumeNameU.Buffer != NULL)
138  {
139  RtlFreeHeap(RtlGetProcessHeap(), 0, VolumeNameU.Buffer);
140  }
141 
142  if (FileSystemNameU.Buffer != NULL)
143  {
144  RtlFreeHeap(RtlGetProcessHeap(), 0, FileSystemNameU.Buffer);
145  }
146 
147  return Ret;
148 }
149 
150 /*
151  * @implemented
152  */
153 BOOL
155  IN PUNICODE_STRING NtPathName)
156 {
159  struct
160  {
163  } FileNameInfo;
164 
165  /* If we have a handle, query the name */
166  if (VolumeHandle)
167  {
168  Status = NtQueryInformationFile(VolumeHandle, &IoStatusBlock, &FileNameInfo, sizeof(FileNameInfo), FileNameInformation);
169  if (!NT_SUCCESS(Status))
170  {
171  return FALSE;
172  }
173 
174  /* Check we properly end with a \ */
175  if (FileNameInfo.FileName[FileNameInfo.FileNameLength / sizeof(WCHAR) - 1] != L'\\')
176  {
177  return FALSE;
178  }
179  }
180 
181  /* If we have a path */
182  if (NtPathName != NULL)
183  {
184  HANDLE LinkHandle;
185  WCHAR Buffer[512];
189 
190  NtPathName->Length -= sizeof(WCHAR);
191 
192  InitializeObjectAttributes(&ObjectAttributes, NtPathName,
194  NULL, NULL);
195 
196  /* Try to see whether that's a symbolic name */
197  Status = NtOpenSymbolicLinkObject(&LinkHandle, SYMBOLIC_LINK_QUERY, &ObjectAttributes);
198  NtPathName->Length += sizeof(WCHAR);
199  if (!NT_SUCCESS(Status))
200  {
201  return FALSE;
202  }
203 
204  /* If so, query the target */
205  LinkTarget.Buffer = Buffer;
206  LinkTarget.Length = 0;
207  LinkTarget.MaximumLength = sizeof(Buffer);
208 
209  Status = NtQuerySymbolicLinkObject(LinkHandle, &LinkTarget, &ReturnedLength);
210  NtClose(LinkHandle);
211  /* A root directory (NtName) is a symbolic link */
212  if (!NT_SUCCESS(Status))
213  {
214  return FALSE;
215  }
216  }
217 
218  return TRUE;
219 }
220 
221 /*
222  * @implemented
223  */
224 BOOL
225 WINAPI
227  IN LPWSTR lpVolumeNameBuffer,
228  IN DWORD nVolumeNameSize,
229  OUT LPDWORD lpVolumeSerialNumber OPTIONAL,
230  OUT LPDWORD lpMaximumComponentLength OPTIONAL,
231  OUT LPDWORD lpFileSystemFlags OPTIONAL,
232  OUT LPWSTR lpFileSystemNameBuffer OPTIONAL,
233  IN DWORD nFileSystemNameSize)
234 {
235  BOOL Ret;
238  LPCWSTR RootPathName;
239  UNICODE_STRING NtPathName;
244  ULONG OldMode, VolumeInfoSize, VolumeAttrSize;
245 
246  /* If no root path provided, default to \ */
247  if (lpRootPathName == NULL)
248  {
249  RootPathName = L"\\";
250  }
251  else
252  {
253  RootPathName = lpRootPathName;
254  }
255 
256  /* Convert length to bytes */
257  nVolumeNameSize *= sizeof(WCHAR);
258  nFileSystemNameSize *= sizeof(WCHAR);
259 
260  /* Convert to NT name */
261  if (!RtlDosPathNameToNtPathName_U(RootPathName, &NtPathName, NULL, NULL))
262  {
264  return FALSE;
265  }
266 
267  /* Check we really end with a backslash */
268  if (NtPathName.Buffer[(NtPathName.Length / sizeof(WCHAR)) - 1] != L'\\')
269  {
270  RtlFreeHeap(RtlGetProcessHeap(), 0, NtPathName.Buffer);
272  return FALSE;
273  }
274 
275  /* Try to open the received path */
276  InitializeObjectAttributes(&ObjectAttributes, &NtPathName,
278  NULL, NULL);
279 
280  /* No errors to the user */
282  Status = NtOpenFile(&VolumeHandle, SYNCHRONIZE, &ObjectAttributes, &IoStatusBlock, 0, FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT);
283  RtlSetThreadErrorMode(OldMode, NULL);
284  if (!NT_SUCCESS(Status))
285  {
286  RtlFreeHeap(RtlGetProcessHeap(), 0, NtPathName.Buffer);
287  BaseSetLastNTError(Status);
288  return FALSE;
289  }
290 
291  /* Check whether that's a root directory */
292  if (!IsThisARootDirectory(VolumeHandle, &NtPathName))
293  {
294  RtlFreeHeap(RtlGetProcessHeap(), 0, NtPathName.Buffer);
295  NtClose(VolumeHandle);
297  return FALSE;
298  }
299 
300  RtlFreeHeap(RtlGetProcessHeap(), 0, NtPathName.Buffer);
301 
302  /* Assume we don't need to query FileFsVolumeInformation */
303  VolumeInfo = NULL;
304  /* If user wants volume name, allocate a buffer to query it */
305  if (lpVolumeNameBuffer != NULL)
306  {
307  VolumeInfoSize = nVolumeNameSize + sizeof(FILE_FS_VOLUME_INFORMATION);
308  }
309  /* If user just wants the serial number, allocate a dummy buffer */
310  else if (lpVolumeSerialNumber != NULL)
311  {
312  VolumeInfoSize = MAX_PATH * sizeof(WCHAR) + sizeof(FILE_FS_VOLUME_INFORMATION);
313  }
314  /* Otherwise, nothing to query */
315  else
316  {
317  VolumeInfoSize = 0;
318  }
319 
320  /* If we're to query, allocate a big enough buffer */
321  if (VolumeInfoSize != 0)
322  {
323  VolumeInfo = RtlAllocateHeap(RtlGetProcessHeap(), 0, VolumeInfoSize);
324  if (VolumeInfo == NULL)
325  {
326  NtClose(VolumeHandle);
328  return FALSE;
329  }
330  }
331 
332  /* Assume we don't need to query FileFsAttributeInformation */
333  VolumeAttr = NULL;
334  /* If user wants filesystem name, allocate a buffer to query it */
335  if (lpFileSystemNameBuffer != NULL)
336  {
337  VolumeAttrSize = nFileSystemNameSize + sizeof(FILE_FS_ATTRIBUTE_INFORMATION);
338  }
339  /* If user just wants max compo len or flags, allocate a dummy buffer */
340  else if (lpMaximumComponentLength != NULL || lpFileSystemFlags != NULL)
341  {
342  VolumeAttrSize = MAX_PATH * sizeof(WCHAR) + sizeof(FILE_FS_ATTRIBUTE_INFORMATION);
343  }
344  else
345  {
346  VolumeAttrSize = 0;
347  }
348 
349  /* If we're to query, allocate a big enough buffer */
350  if (VolumeAttrSize != 0)
351  {
352  VolumeAttr = RtlAllocateHeap(RtlGetProcessHeap(), 0, VolumeAttrSize);
353  if (VolumeAttr == NULL)
354  {
355  if (VolumeInfo != NULL)
356  {
357  RtlFreeHeap(RtlGetProcessHeap(), 0, VolumeInfo);
358  }
359 
360  NtClose(VolumeHandle);
362  return FALSE;
363  }
364  }
365 
366  /* Assume we'll fail */
367  Ret = FALSE;
368 
369  /* If we're to query FileFsVolumeInformation, do it now! */
370  if (VolumeInfo != NULL)
371  {
372  Status = NtQueryVolumeInformationFile(VolumeHandle, &IoStatusBlock, VolumeInfo, VolumeInfoSize, FileFsVolumeInformation);
373  if (!NT_SUCCESS(Status))
374  {
375  BaseSetLastNTError(Status);
376  goto CleanAndQuit;
377  }
378  }
379 
380  /* If we're to query FileFsAttributeInformation, do it now! */
381  if (VolumeAttr != NULL)
382  {
383  Status = NtQueryVolumeInformationFile(VolumeHandle, &IoStatusBlock, VolumeAttr, VolumeAttrSize, FileFsAttributeInformation);
384  if (!NT_SUCCESS(Status))
385  {
386  BaseSetLastNTError(Status);
387  goto CleanAndQuit;
388  }
389  }
390 
391  /* If user wants volume name */
392  if (lpVolumeNameBuffer != NULL)
393  {
394  /* Check its buffer can hold it (+ 0) */
395  if (VolumeInfo->VolumeLabelLength >= nVolumeNameSize)
396  {
398  goto CleanAndQuit;
399  }
400 
401  /* Copy and zero */
402  RtlCopyMemory(lpVolumeNameBuffer, VolumeInfo->VolumeLabel, VolumeInfo->VolumeLabelLength);
403  lpVolumeNameBuffer[VolumeInfo->VolumeLabelLength / sizeof(WCHAR)] = UNICODE_NULL;
404  }
405 
406  /* If user wants wants serial number, return it */
407  if (lpVolumeSerialNumber != NULL)
408  {
409  *lpVolumeSerialNumber = VolumeInfo->VolumeSerialNumber;
410  }
411 
412  /* If user wants filesystem name */
413  if (lpFileSystemNameBuffer != NULL)
414  {
415  /* Check its buffer can hold it (+ 0) */
416  if (VolumeAttr->FileSystemNameLength >= nFileSystemNameSize)
417  {
419  goto CleanAndQuit;
420  }
421 
422  /* Copy and zero */
423  RtlCopyMemory(lpFileSystemNameBuffer, VolumeAttr->FileSystemName, VolumeAttr->FileSystemNameLength);
424  lpFileSystemNameBuffer[VolumeAttr->FileSystemNameLength / sizeof(WCHAR)] = UNICODE_NULL;
425  }
426 
427  /* If user wants wants max compo len, return it */
428  if (lpMaximumComponentLength != NULL)
429  {
430  *lpMaximumComponentLength = VolumeAttr->MaximumComponentNameLength;
431  }
432 
433  /* If user wants wants FS flags, return them */
434  if (lpFileSystemFlags != NULL)
435  {
436  *lpFileSystemFlags = VolumeAttr->FileSystemAttributes;
437  }
438 
439  /* We did it! */
440  Ret = TRUE;
441 
442 CleanAndQuit:
443  NtClose(VolumeHandle);
444 
445  if (VolumeInfo != NULL)
446  {
447  RtlFreeHeap(RtlGetProcessHeap(), 0, VolumeInfo);
448  }
449 
450  if (VolumeAttr != NULL)
451  {
452  RtlFreeHeap(RtlGetProcessHeap(), 0, VolumeAttr);
453  }
454 
455  return Ret;
456 }
457 
458 /*
459  * @implemented
460  */
461 BOOL
462 WINAPI
463 SetVolumeLabelA(IN LPCSTR lpRootPathName,
464  IN LPCSTR lpVolumeName OPTIONAL) /* NULL if deleting label */
465 {
466  BOOL Ret;
467  UNICODE_STRING VolumeNameU;
468  PUNICODE_STRING RootPathNameU;
469 
470  if (lpRootPathName == NULL)
471  {
472  lpRootPathName = "\\";
473  }
474 
475  RootPathNameU = Basep8BitStringToStaticUnicodeString(lpRootPathName);
476  if (RootPathNameU == NULL)
477  {
478  return FALSE;
479  }
480 
481  if (lpVolumeName != NULL)
482  {
483  if (!Basep8BitStringToDynamicUnicodeString(&VolumeNameU, lpVolumeName))
484  {
485  return FALSE;
486  }
487  }
488  else
489  {
490  VolumeNameU.Buffer = NULL;
491  }
492 
493  Ret = SetVolumeLabelW(RootPathNameU->Buffer, VolumeNameU.Buffer);
494  RtlFreeUnicodeString(&VolumeNameU);
495  return Ret;
496 }
497 
498 /*
499  * @implemented
500  */
501 BOOL
502 WINAPI
503 SetVolumeLabelW(IN LPCWSTR lpRootPathName,
504  IN LPCWSTR lpVolumeName OPTIONAL) /* NULL if deleting label */
505 {
506  BOOL Ret;
508  PWSTR VolumeRoot;
510  WCHAR VolumeGuid[MAX_PATH];
513  PFILE_FS_LABEL_INFORMATION FsLabelInfo;
514  UNICODE_STRING VolumeName, NtVolumeName;
515 
516  /* If no root path provided, default to \ */
517  VolumeRoot = L"\\";
518 
519  /* If user wants to set a label, make it a string */
520  if (lpVolumeName != NULL)
521  {
522  RtlInitUnicodeString(&VolumeName, lpVolumeName);
523  }
524  else
525  {
526  VolumeName.Length = 0;
527  VolumeName.MaximumLength = 0;
528  VolumeName.Buffer = NULL;
529  }
530 
531  /* If we received a volume, try to get its GUID name */
532  if (lpRootPathName != NULL)
533  {
534  Ret = GetVolumeNameForVolumeMountPointW(lpRootPathName, VolumeGuid, MAX_PATH);
535  }
536  else
537  {
538  Ret = FALSE;
539  }
540 
541  /* If we got the GUID name, use it */
542  if (Ret)
543  {
544  VolumeRoot = VolumeGuid;
545  }
546  else
547  {
548  /* Otherwise, use the name provided by the caller */
549  if (lpRootPathName != NULL)
550  {
551  VolumeRoot = (PWSTR)lpRootPathName;
552  }
553  }
554 
555  /* Convert to a NT path */
556  if (!RtlDosPathNameToNtPathName_U(VolumeRoot, &NtVolumeName, NULL, NULL))
557  {
559  return FALSE;
560  }
561 
562 
563  /* Check we really end with a backslash */
564  if (NtVolumeName.Buffer[(NtVolumeName.Length / sizeof(WCHAR)) - 1] != L'\\')
565  {
566  RtlFreeHeap(RtlGetProcessHeap(), 0, NtVolumeName.Buffer);
568  return FALSE;
569  }
570 
571  /* Try to open the root directory */
572  InitializeObjectAttributes(&ObjectAttributes, &NtVolumeName,
574 
575  Status = NtOpenFile(&VolumeHandle, SYNCHRONIZE | FILE_WRITE_DATA,
576  &ObjectAttributes, &IoStatusBlock,
579  if (!NT_SUCCESS(Status))
580  {
581  RtlFreeHeap(RtlGetProcessHeap(), 0, NtVolumeName.Buffer);
582  BaseSetLastNTError(Status);
583  return FALSE;
584  }
585 
586  /* Validate it's really a root path */
587  if (!IsThisARootDirectory(VolumeHandle, NULL))
588  {
589  RtlFreeHeap(RtlGetProcessHeap(), 0, NtVolumeName.Buffer);
590  NtClose(VolumeHandle);
592  return FALSE;
593  }
594 
595  /* Done */
596  NtClose(VolumeHandle);
597 
598  /* Now, open the volume to perform the label change */
599  NtVolumeName.Length -= sizeof(WCHAR);
600  InitializeObjectAttributes(&ObjectAttributes, &NtVolumeName,
602 
603  Status = NtOpenFile(&VolumeHandle, SYNCHRONIZE | FILE_WRITE_DATA,
604  &ObjectAttributes, &IoStatusBlock,
607 
608  RtlFreeHeap(RtlGetProcessHeap(), 0, NtVolumeName.Buffer);
609 
610  if (!NT_SUCCESS(Status))
611  {
612  BaseSetLastNTError(Status);
613  return FALSE;
614  }
615 
616  /* Assume success */
617  Ret = TRUE;
618 
619  /* Allocate a buffer that can hold new label and its size */
620  FsLabelInfo = RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(FILE_FS_LABEL_INFORMATION) + VolumeName.Length);
621  if (FsLabelInfo != NULL)
622  {
623  /* Copy name and set its size */
624  RtlCopyMemory(FsLabelInfo->VolumeLabel, VolumeName.Buffer, VolumeName.Length);
625  FsLabelInfo->VolumeLabelLength = VolumeName.Length;
626 
627  /* And finally, set new label */
628  Status = NtSetVolumeInformationFile(VolumeHandle, &IoStatusBlock, FsLabelInfo, sizeof(FILE_FS_LABEL_INFORMATION) + VolumeName.Length, FileFsLabelInformation);
629  }
630  else
631  {
632  /* Allocation failed */
633  Status = STATUS_NO_MEMORY;
634  }
635 
636  /* In case of failure, set status and mark failure */
637  if (!NT_SUCCESS(Status))
638  {
639  BaseSetLastNTError(Status);
640  Ret = FALSE;
641  }
642 
643  /* We're done */
644  NtClose(VolumeHandle);
645 
646  /* Free buffer if required */
647  if (FsLabelInfo != NULL)
648  {
649  RtlFreeHeap(RtlGetProcessHeap(), 0, FsLabelInfo);
650  }
651 
652  return Ret;
653 }
654 
655 /*
656  * @implemented (Wine 13 sep 2008)
657  */
658 HANDLE
659 WINAPI
661  IN DWORD len)
662 {
663  DWORD size = 1024;
664  DWORD br;
667  if (mgr == INVALID_HANDLE_VALUE) return INVALID_HANDLE_VALUE;
668 
669  for (;;)
670  {
673 
674  if (!(output = RtlAllocateHeap( RtlGetProcessHeap(), 0, size )))
675  {
677  break;
678  }
679  memset( &input, 0, sizeof(input) );
680 
681  if (!DeviceIoControl( mgr, IOCTL_MOUNTMGR_QUERY_POINTS, &input, sizeof(input),
682  output, size, &br, NULL ))
683  {
684  if (GetLastError() != ERROR_MORE_DATA) break;
685  size = output->Size;
686  RtlFreeHeap( RtlGetProcessHeap(), 0, output );
687  continue;
688  }
689  CloseHandle( mgr );
690  /* abuse the Size field to store the current index */
691  output->Size = 0;
692  if (!FindNextVolumeW( output, volume, len ))
693  {
694  RtlFreeHeap( RtlGetProcessHeap(), 0, output );
695  return INVALID_HANDLE_VALUE;
696  }
697  return (HANDLE)output;
698  }
699  CloseHandle( mgr );
700  return INVALID_HANDLE_VALUE;
701 }
702 
703 /*
704  * @implemented (Wine 13 sep 2008)
705  */
706 HANDLE
707 WINAPI
709  IN DWORD len)
710 {
711  WCHAR *buffer = NULL;
712  HANDLE handle;
713 
714  buffer = RtlAllocateHeap( RtlGetProcessHeap(), 0, len * sizeof(WCHAR) );
715 
716  if (!buffer)
717  {
719  return INVALID_HANDLE_VALUE;
720  }
721 
722  handle = FindFirstVolumeW( buffer, len );
723 
724  if (handle != INVALID_HANDLE_VALUE)
725  {
726  if (!WideCharToMultiByte( CP_ACP, 0, buffer, -1, volume, len, NULL, NULL ))
727  {
728  FindVolumeClose( handle );
729  handle = INVALID_HANDLE_VALUE;
730  }
731  }
732  RtlFreeHeap( RtlGetProcessHeap(), 0, buffer );
733  return handle;
734 }
735 
736 /*
737  * @implemented (Wine 13 sep 2008)
738  */
739 BOOL
740 WINAPI
742 {
743  return RtlFreeHeap(RtlGetProcessHeap(), 0, hFindVolume);
744 }
745 
746 /*
747  * @implemented
748  */
749 BOOL
750 WINAPI
752  IN LPSTR lpszVolumePathName,
753  IN DWORD cchBufferLength)
754 {
755  BOOL Ret;
756  PUNICODE_STRING FileNameU;
757  ANSI_STRING VolumePathName;
758  UNICODE_STRING VolumePathNameU;
759 
760  /* Convert file name to unicode */
761  FileNameU = Basep8BitStringToStaticUnicodeString(lpszFileName);
762  if (FileNameU == NULL)
763  {
764  return FALSE;
765  }
766 
767  /* Initialize all the strings we'll need */
768  VolumePathName.Buffer = lpszVolumePathName;
769  VolumePathName.Length = 0;
770  VolumePathName.MaximumLength = cchBufferLength - 1;
771 
772  VolumePathNameU.Length = 0;
773  VolumePathNameU.MaximumLength = (cchBufferLength - 1) * sizeof(WCHAR) + sizeof(UNICODE_NULL);
774  /* Allocate a buffer for calling the -W */
775  VolumePathNameU.Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, VolumePathNameU.MaximumLength);
776  if (VolumePathNameU.Buffer == NULL)
777  {
779  return FALSE;
780  }
781 
782  /* Call the -W implementation */
783  Ret = GetVolumePathNameW(FileNameU->Buffer, VolumePathNameU.Buffer, cchBufferLength);
784  /* If it succeed */
785  if (Ret)
786  {
788 
789  /* Convert back to ANSI */
790  RtlInitUnicodeString(&VolumePathNameU, VolumePathNameU.Buffer);
791  Status = RtlUnicodeStringToAnsiString(&VolumePathName, &VolumePathNameU, FALSE);
792  /* If conversion failed, just set error code and fail the rest */
793  if (!NT_SUCCESS(Status))
794  {
795  BaseSetLastNTError(Status);
796  Ret = FALSE;
797  }
798  /* Otherwise, null terminate the string (it's OK, we computed -1) */
799  else
800  {
801  VolumePathName.Buffer[VolumePathName.Length] = ANSI_NULL;
802  }
803  }
804 
805  /* Free the buffer allocated for -W call */
806  RtlFreeHeap(RtlGetProcessHeap(), 0, VolumePathNameU.Buffer);
807  return Ret;
808 }
809 
810 /*
811  * @implemented
812  */
813 BOOL
814 WINAPI
816  IN LPWSTR lpszVolumePathName,
817  IN DWORD cchBufferLength)
818 {
819  BOOL MountPoint;
820  DWORD FullPathLen;
821  WCHAR OldFilePart;
822  UNICODE_STRING FullPath;
823  PWSTR FullPathBuf, FilePart, VolumeNameBuf;
824 
825  /* Probe for full path len */
826  FullPathLen = GetFullPathNameW(lpszFileName, 0, NULL, NULL);
827  if (FullPathLen == 0)
828  {
829  return FALSE;
830  }
831 
832  /* Allocate a big enough buffer to receive it */
833  FullPathBuf = RtlAllocateHeap(RtlGetProcessHeap(), 0, (FullPathLen + 10) * sizeof(WCHAR));
834  if (FullPathBuf == NULL)
835  {
837  return FALSE;
838  }
839 
840  /* And get full path name */
841  if (GetFullPathNameW(lpszFileName, FullPathLen + 10, FullPathBuf, &FilePart) == 0)
842  {
843  RtlFreeHeap(RtlGetProcessHeap(), 0, FullPathBuf);
844  return FALSE;
845  }
846 
847  /* Make a string out of it */
848  RtlInitUnicodeString(&FullPath, FullPathBuf);
849  /* We will finish our string with '\', for ease of the parsing after */
850  if (FullPath.Buffer[(FullPath.Length / sizeof(WCHAR)) - 1] != L'\\')
851  {
852  FullPath.Length += sizeof(WCHAR);
853  FullPath.Buffer[(FullPath.Length / sizeof(WCHAR)) - 1] = L'\\';
854  FullPath.Buffer[FullPath.Length / sizeof(WCHAR)] = UNICODE_NULL;
855  }
856 
857  /* Allocate a buffer big enough to receive our volume name */
858  VolumeNameBuf = RtlAllocateHeap(RtlGetProcessHeap(), 0, 0x2000 * sizeof(WCHAR));
859  if (VolumeNameBuf == NULL)
860  {
861  RtlFreeHeap(RtlGetProcessHeap(), 0, FullPathBuf);
863  return FALSE;
864  }
865 
866  /* We don't care about file part: we added an extra backslash, so there's no
867  * file, we're back at the dir level.
868  * We'll recompute file part afterwards
869  */
870  FilePart = NULL;
871  /* Keep track of the letter we could drop to shorten the string */
872  OldFilePart = UNICODE_NULL;
873  /* As long as querying volume name fails, keep looping */
874  while (!BasepGetVolumeNameForVolumeMountPoint(FullPath.Buffer, VolumeNameBuf, 0x2000u, &MountPoint))
875  {
876  USHORT LastSlash;
877 
878  /* Not a mount point, but opening returning access denied? Assume it's one, just not
879  * a reparse backed one (classic mount point, a device)!
880  */
881  if (!MountPoint && GetLastError() == ERROR_ACCESS_DENIED)
882  {
883  MountPoint = TRUE;
884  }
885 
886  /* BasepGetVolumeNameForVolumeMountPoint failed, but returned a volume name.
887  * This can happen when we are given a reparse point where MountMgr could find associated
888  * volume name which is not a valid DOS volume
889  * A valid DOS name always starts with \\
890  */
891  if (VolumeNameBuf[0] != UNICODE_NULL && (FullPath.Buffer[0] != L'\\' || FullPath.Buffer[1] != L'\\'))
892  {
893  CHAR RootPathName[4];
894 
895  /* Construct a simple <letter>:\ string to get drive type */
896  RootPathName[0] = FullPath.Buffer[0];
897  RootPathName[1] = ':';
898  RootPathName[2] = '\\';
899  RootPathName[3] = ANSI_NULL;
900 
901  /* If we weren't given a drive letter actually, or if that's not a remote drive
902  * Note: in this code path, we're recursive and stop fail loop
903  */
904  if (FullPath.Buffer[1] != L':' || GetDriveTypeA(RootPathName) != DRIVE_REMOTE)
905  {
906  BOOL Ret;
907 
908  /* We won't need the full path, we'll now work with the returned volume name */
909  RtlFreeHeap(RtlGetProcessHeap(), 0, FullPathBuf);
910  /* If it wasn't an NT name which was returned */
911  if ((VolumeNameBuf[0] != L'\\') || (VolumeNameBuf[1] != L'?') ||
912  (VolumeNameBuf[2] != L'?') || (VolumeNameBuf[3] != L'\\'))
913  {
914  PWSTR GlobalPath;
915  UNICODE_STRING GlobalRoot;
916 
917  /* Create a new name in the NT namespace (from Win32) */
918  RtlInitUnicodeString(&FullPath, VolumeNameBuf);
919  RtlInitUnicodeString(&GlobalRoot, L"\\\\?\\GLOBALROOT");
920 
921  /* We allocate a buffer than can contain both the namespace and the volume name */
922  GlobalPath = RtlAllocateHeap(RtlGetProcessHeap(), 0, FullPath.Length + GlobalRoot.Length);
923  if (GlobalPath == NULL)
924  {
925  RtlFreeHeap(RtlGetProcessHeap(), 0, VolumeNameBuf);
927  return FALSE;
928  }
929 
930  /* Fill in the new query name */
931  RtlCopyMemory(GlobalPath, GlobalRoot.Buffer, GlobalRoot.Length);
932  RtlCopyMemory((PVOID)((ULONG_PTR)GlobalPath + GlobalRoot.Length), FullPath.Buffer, FullPath.Length);
933  GlobalPath[(FullPath.Length + GlobalRoot.Length) / sizeof(WCHAR)] = UNICODE_NULL;
934 
935  /* Give it another try */
936  Ret = GetVolumePathNameW(GlobalPath, lpszVolumePathName, cchBufferLength);
937 
938  RtlFreeHeap(RtlGetProcessHeap(), 0, GlobalPath);
939  }
940  else
941  {
942  /* If we don't have a drive letter in the Win32 name space \\.<letter>: */
943  if ((VolumeNameBuf[4] != UNICODE_NULL) && (VolumeNameBuf[5] != L':'))
944  {
945  /* Shit our starting \\ */
946  RtlInitUnicodeString(&FullPath, VolumeNameBuf);
947  RtlMoveMemory(VolumeNameBuf, (PVOID)((ULONG_PTR)VolumeNameBuf + (2 * sizeof(WCHAR))), FullPath.Length - (3 * sizeof(WCHAR)));
948  }
949  /* Otherwise, just make sure we're double \ at the being to query again with the
950  * proper namespace
951  */
952  else
953  {
954  VolumeNameBuf[1] = L'\\';
955  }
956 
957  /* Give it another try */
958  Ret = GetVolumePathNameW(VolumeNameBuf, lpszVolumePathName, cchBufferLength);
959  }
960 
961  /* And done! */
962  RtlFreeHeap(RtlGetProcessHeap(), 0, VolumeNameBuf);
963  return Ret;
964  }
965  }
966 
967  /* No mount point but with a file part? Restore filepart and exit */
968  if (!MountPoint && FilePart != NULL)
969  {
970  FilePart[0] = OldFilePart;
971  RtlInitUnicodeString(&FullPath, FullPathBuf);
972  break;
973  }
974 
975  /* We cannot go down the path any longer, too small */
976  if (FullPath.Length <= sizeof(WCHAR))
977  {
978  break;
979  }
980 
981  /* Prepare the next split */
982  LastSlash = (FullPath.Length / sizeof(WCHAR)) - 2;
983  if (FullPath.Length / sizeof(WCHAR) != 2)
984  {
985  do
986  {
987  if (FullPath.Buffer[LastSlash] == L'\\')
988  {
989  break;
990  }
991 
992  --LastSlash;
993  } while (LastSlash != 0);
994  }
995 
996  /* We couldn't split path, quit */
997  if (LastSlash == 0)
998  {
999  break;
1000  }
1001 
1002  /* If that's a mount point, keep track of the directory name */
1003  if (MountPoint)
1004  {
1005  FilePart = &FullPath.Buffer[LastSlash + 1];
1006  OldFilePart = FilePart[0];
1007  /* And null terminate the string */
1008  FilePart[0] = UNICODE_NULL;
1009  }
1010  /* Otherwise, just null terminate the string */
1011  else
1012  {
1013  FullPath.Buffer[LastSlash + 1] = UNICODE_NULL;
1014  }
1015 
1016  /* We went down a bit in the path, fix the string and retry */
1017  RtlInitUnicodeString(&FullPath, FullPathBuf);
1018  }
1019 
1020  /* Once here, we'll return something from the full path buffer, so release
1021  * output buffer
1022  */
1023  RtlFreeHeap(RtlGetProcessHeap(), 0, VolumeNameBuf);
1024 
1025  /* Not a mount point, bail out */
1026  if (!MountPoint && FilePart == NULL)
1027  {
1028  RtlFreeHeap(RtlGetProcessHeap(), 0, FullPathBuf);
1029  return FALSE;
1030  }
1031 
1032  /* Make sure we have enough room to copy our volume */
1033  if ((cchBufferLength * sizeof(WCHAR)) < FullPath.Length + sizeof(UNICODE_NULL))
1034  {
1035  RtlFreeHeap(RtlGetProcessHeap(), 0, FullPathBuf);
1037  return FALSE;
1038  }
1039 
1040  /* Copy and null terminate */
1041  RtlCopyMemory(lpszVolumePathName, FullPath.Buffer, FullPath.Length);
1042  lpszVolumePathName[FullPath.Length / sizeof(WCHAR)] = UNICODE_NULL;
1043 
1044  RtlFreeHeap(RtlGetProcessHeap(), 0, FullPathBuf);
1045 
1046  /* Done! */
1047  return TRUE;
1048 }
1049 
1050 /*
1051  * @implemented
1052  */
1053 BOOL
1054 WINAPI
1056  IN LPSTR volume,
1057  IN DWORD len)
1058 {
1059  WCHAR *buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, len * sizeof(WCHAR));
1060  BOOL ret;
1061 
1062  if (!buffer)
1063  {
1065  return FALSE;
1066  }
1067 
1068  if ((ret = FindNextVolumeW( handle, buffer, len )))
1069  {
1070  if (!WideCharToMultiByte( CP_ACP, 0, buffer, -1, volume, len, NULL, NULL )) ret = FALSE;
1071  }
1072 
1073  RtlFreeHeap(RtlGetProcessHeap(), 0, buffer);
1074  return ret;
1075 }
1076 
1077 /*
1078  * @implemented
1079  */
1080 BOOL
1081 WINAPI
1083  IN LPWSTR volume,
1084  IN DWORD len)
1085 {
1087 
1088  while (data->Size < data->NumberOfMountPoints)
1089  {
1090  static const WCHAR volumeW[] = {'\\','?','?','\\','V','o','l','u','m','e','{',};
1091  WCHAR *link = (WCHAR *)((char *)data + data->MountPoints[data->Size].SymbolicLinkNameOffset);
1093  data->Size++;
1094  /* skip non-volumes */
1095  if (size < sizeof(volumeW) || memcmp( link, volumeW, sizeof(volumeW) )) continue;
1096  if (size + sizeof(WCHAR) >= len * sizeof(WCHAR))
1097  {
1099  return FALSE;
1100  }
1101  memcpy( volume, link, size );
1102  volume[1] = '\\'; /* map \??\ to \\?\ */
1103  volume[size / sizeof(WCHAR)] = '\\'; /* Windows appends a backslash */
1104  volume[size / sizeof(WCHAR) + 1] = 0;
1105  DPRINT( "returning entry %u %s\n", data->Size - 1, volume );
1106  return TRUE;
1107  }
1109  return FALSE;
1110 }
1111 
1112 /*
1113  * @implemented
1114  */
1115 BOOL
1116 WINAPI
1118  IN LPSTR lpszVolumePathNames,
1119  IN DWORD cchBufferLength,
1120  OUT PDWORD lpcchReturnLength)
1121 {
1122  BOOL Ret;
1123  NTSTATUS Status;
1124  DWORD cchReturnLength;
1125  ANSI_STRING VolumePathName;
1126  PUNICODE_STRING VolumeNameU;
1127  UNICODE_STRING VolumePathNamesU;
1128 
1129  /* Convert volume name to unicode */
1130  VolumeNameU = Basep8BitStringToStaticUnicodeString(lpszVolumeName);
1131  if (VolumeNameU == NULL)
1132  {
1133  return FALSE;
1134  }
1135 
1136  /* Initialize the strings we'll use later on */
1137  VolumePathName.Length = 0;
1138  VolumePathName.MaximumLength = cchBufferLength;
1139  VolumePathName.Buffer = lpszVolumePathNames;
1140 
1141  VolumePathNamesU.Length = 0;
1142  VolumePathNamesU.MaximumLength = sizeof(WCHAR) * cchBufferLength;
1143  /* If caller provided a non 0 sized string, allocate a buffer for our unicode string */
1144  if (VolumePathNamesU.MaximumLength != 0)
1145  {
1146  VolumePathNamesU.Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, VolumePathNamesU.MaximumLength);
1147  if (VolumePathNamesU.Buffer == NULL)
1148  {
1150  return FALSE;
1151  }
1152  }
1153  else
1154  {
1155  VolumePathNamesU.Buffer = NULL;
1156  }
1157 
1158  /* Call the -W implementation */
1159  Ret = GetVolumePathNamesForVolumeNameW(VolumeNameU->Buffer, VolumePathNamesU.Buffer,
1160  cchBufferLength, &cchReturnLength);
1161  /* Call succeed, we'll return the total length */
1162  if (Ret)
1163  {
1164  VolumePathNamesU.Length = sizeof(WCHAR) * cchReturnLength;
1165  }
1166  else
1167  {
1168  /* Else, if we fail for anything else than too small buffer, quit */
1169  if (GetLastError() != ERROR_MORE_DATA)
1170  {
1171  if (VolumePathNamesU.Buffer != NULL)
1172  {
1173  RtlFreeHeap(RtlGetProcessHeap(), 0, VolumePathNamesU.Buffer);
1174  }
1175 
1176  return FALSE;
1177  }
1178 
1179  /* Otherwise, we'll just copy as much as we can */
1180  VolumePathNamesU.Length = sizeof(WCHAR) * cchBufferLength;
1181  }
1182 
1183  /* Convert our output string back to ANSI */
1184  Status = RtlUnicodeStringToAnsiString(&VolumePathName, &VolumePathNamesU, FALSE);
1185  if (!NT_SUCCESS(Status))
1186  {
1187  BaseSetLastNTError(Status);
1188 
1189  if (VolumePathNamesU.Buffer != NULL)
1190  {
1191  RtlFreeHeap(RtlGetProcessHeap(), 0, VolumePathNamesU.Buffer);
1192  }
1193 
1194  return FALSE;
1195  }
1196 
1197  /* If caller wants return length, two cases... */
1198  if (lpcchReturnLength != NULL)
1199  {
1200  /* We succeed: return the copied length */
1201  if (Ret)
1202  {
1203  *lpcchReturnLength = VolumePathName.Length;
1204  }
1205  /* We failed, return the size we would have loved having! */
1206  else
1207  {
1208  *lpcchReturnLength = sizeof(WCHAR) * cchReturnLength;
1209  }
1210  }
1211 
1212  /* Release our buffer if allocated */
1213  if (VolumePathNamesU.Buffer != NULL)
1214  {
1215  RtlFreeHeap(RtlGetProcessHeap(), 0, VolumePathNamesU.Buffer);
1216  }
1217 
1218  return Ret;
1219 }
1220 
1221 
1222 /*
1223  * @implemented
1224  */
1225 BOOL
1226 WINAPI
1228  IN LPWSTR lpszVolumePathNames,
1229  IN DWORD cchBufferLength,
1230  OUT PDWORD lpcchReturnLength)
1231 {
1232  BOOL Ret;
1233  PWSTR MultiSz;
1235  HANDLE MountMgrHandle;
1238  PMOUNTMGR_VOLUME_PATHS VolumePaths;
1239  ULONG BufferSize, CharsInMgr, CharsInOutput, Paths;
1240 
1241  /* First look that our volume name looks somehow correct */
1242  RtlInitUnicodeString(&VolumeName, lpszVolumeName);
1243  if (VolumeName.Buffer[(VolumeName.Length / sizeof(WCHAR)) - 1] != L'\\')
1244  {
1246  return FALSE;
1247  }
1248 
1249  /* Validate it's a DOS volume name finishing with a backslash */
1250  if (!MOUNTMGR_IS_DOS_VOLUME_NAME_WB(&VolumeName))
1251  {
1253  return FALSE;
1254  }
1255 
1256  /* Allocate an input MOUNTMGR_TARGET_NAME */
1257  TargetName = RtlAllocateHeap(RtlGetProcessHeap(), 0, MAX_PATH * sizeof(WCHAR) + sizeof(USHORT));
1258  if (TargetName == NULL)
1259  {
1261  return FALSE;
1262  }
1263 
1264  /* And fill it */
1265  RtlZeroMemory(TargetName, MAX_PATH * sizeof(WCHAR) + sizeof(USHORT));
1266  TargetName->DeviceNameLength = VolumeName.Length - sizeof(WCHAR);
1267  RtlCopyMemory(TargetName->DeviceName, VolumeName.Buffer, TargetName->DeviceNameLength);
1268  TargetName->DeviceName[1] = L'?';
1269 
1270  /* Open the mount manager */
1271  MountMgrHandle = CreateFileW(MOUNTMGR_DOS_DEVICE_NAME, 0,
1275  if (MountMgrHandle == INVALID_HANDLE_VALUE)
1276  {
1277  RtlFreeHeap(RtlGetProcessHeap(), 0, TargetName);
1278  return FALSE;
1279  }
1280 
1281  /* Allocate an initial output buffer, just to get length */
1282  VolumePaths = RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(MOUNTMGR_VOLUME_PATHS));
1283  if (VolumePaths == NULL)
1284  {
1285  CloseHandle(MountMgrHandle);
1286  RtlFreeHeap(RtlGetProcessHeap(), 0, TargetName);
1288  return FALSE;
1289  }
1290 
1291  /* Query the paths */
1293  TargetName, MAX_PATH * sizeof(WCHAR) + sizeof(USHORT),
1294  VolumePaths, sizeof(MOUNTMGR_VOLUME_PATHS), &BytesReturned,
1295  NULL);
1296  /* Loop until we can query everything */
1297  while (!Ret)
1298  {
1299  /* If failed for another reason than too small buffer, fail */
1300  if (GetLastError() != ERROR_MORE_DATA)
1301  {
1302  CloseHandle(MountMgrHandle);
1303  RtlFreeHeap(RtlGetProcessHeap(), 0, TargetName);
1304  RtlFreeHeap(RtlGetProcessHeap(), 0, VolumePaths);
1305  return FALSE;
1306  }
1307 
1308  /* Get the required length */
1309  BufferSize = VolumePaths->MultiSzLength + sizeof(MOUNTMGR_VOLUME_PATHS);
1310 
1311  /* And reallocate our output buffer (big enough this time) */
1312  RtlFreeHeap(RtlGetProcessHeap(), 0, VolumePaths);
1313  VolumePaths = RtlAllocateHeap(RtlGetProcessHeap(), 0, BufferSize);
1314  if (VolumePaths == NULL)
1315  {
1316  CloseHandle(MountMgrHandle);
1317  RtlFreeHeap(RtlGetProcessHeap(), 0, TargetName);
1319  return FALSE;
1320  }
1321 
1322  /* Query again the mount mgr */
1324  TargetName, MAX_PATH * sizeof(WCHAR) + sizeof(USHORT),
1325  VolumePaths, BufferSize, &BytesReturned, NULL);
1326  }
1327 
1328  /* We're done, no need for input nor mount mgr any longer */
1329  CloseHandle(MountMgrHandle);
1330  RtlFreeHeap(RtlGetProcessHeap(), 0, TargetName);
1331 
1332  /* Initialize:
1333  - Number of paths we saw (useful to count extra \)
1334  - Progress in mount mgr output
1335  - Progress in output buffer
1336  - Direct buffer to returned MultiSz
1337  */
1338  Paths = 0;
1339  CharsInMgr = 0;
1340  CharsInOutput = 0;
1341  MultiSz = VolumePaths->MultiSz;
1342 
1343  /* If we have an output buffer */
1344  if (cchBufferLength != 0)
1345  {
1346  /* Loop on the output to recopy it back to the caller
1347  * Note that we loop until -1 not to handle last 0 (will be done later on)
1348  */
1349  for (; (CharsInMgr < VolumePaths->MultiSzLength / sizeof(WCHAR) - 1) && (CharsInOutput < cchBufferLength);
1350  ++CharsInMgr, ++CharsInOutput)
1351  {
1352  /* When we reach the end of a path */
1353  if (MultiSz[CharsInMgr] == UNICODE_NULL)
1354  {
1355  /* On path done (count), add an extra \ at the end */
1356  ++Paths;
1357  lpszVolumePathNames[CharsInOutput] = L'\\';
1358  ++CharsInOutput;
1359  /* Make sure we don't overflow */
1360  if (CharsInOutput == cchBufferLength)
1361  {
1362  break;
1363  }
1364  }
1365 
1366  /* Copy the char to the caller
1367  * So, in case we're in the end of a path, we wrote two chars to
1368  * the output buffer: \\ and \0
1369  */
1370  lpszVolumePathNames[CharsInOutput] = MultiSz[CharsInMgr];
1371  }
1372  }
1373 
1374  /* If output buffer was too small (ie, we couldn't parse all the input buffer) */
1375  if (CharsInMgr < VolumePaths->MultiSzLength / sizeof(WCHAR) - 1)
1376  {
1377  /* Keep looping on it, to count the number of extra \ that will be required
1378  * So that on the next call, caller can allocate enough space
1379  */
1380  for (; CharsInMgr < VolumePaths->MultiSzLength / sizeof(WCHAR) - 1; ++CharsInMgr)
1381  {
1382  if (MultiSz[CharsInMgr] == UNICODE_NULL)
1383  {
1384  ++Paths;
1385  }
1386  }
1387  }
1388 
1389  /* If we couldn't write as much as we wanted to the output buffer
1390  * This handles the case where we could write everything excepted the
1391  * terminating \0 for multi SZ
1392  */
1393  if (CharsInOutput >= cchBufferLength)
1394  {
1395  /* Fail and set appropriate error code */
1396  Ret = FALSE;
1398  /* If caller wants to know how many chars to allocate, return it */
1399  if (lpcchReturnLength != NULL)
1400  {
1401  /* It's amount of extra \ + number of chars in MultiSz (including double \0) */
1402  *lpcchReturnLength = Paths + (VolumePaths->MultiSzLength / sizeof(WCHAR));
1403  }
1404  }
1405  else
1406  {
1407  /* It succeed so terminate the multi SZ (second \0) */
1408  lpszVolumePathNames[CharsInOutput] = UNICODE_NULL;
1409  Ret = TRUE;
1410 
1411  /* If caller wants the amount of chars written, return it */
1412  if (lpcchReturnLength != NULL)
1413  {
1414  /* Including the terminating \0 we just added */
1415  *lpcchReturnLength = CharsInOutput + 1;
1416  }
1417  }
1418 
1419  /* Free last bits */
1420  RtlFreeHeap(RtlGetProcessHeap(), 0, VolumePaths);
1421 
1422  /* And return */
1423  return Ret;
1424 }
1425 
1426 /* EOF */
DWORD *typedef PVOID
Definition: winlogon.h:52
#define ERROR_INVALID_PARAMETER
Definition: compat.h:91
IN PUNICODE_STRING IN POBJECT_ATTRIBUTES ObjectAttributes
Definition: conport.c:35
BOOL BasepGetVolumeNameForVolumeMountPoint(IN LPCWSTR lpszMountPoint, OUT LPWSTR lpszVolumeName, IN DWORD cchBufferLength, OUT LPBOOL IsAMountPoint)
Definition: mntpoint.c:398
#define IN
Definition: typedefs.h:38
WCHAR DeviceName[1]
Definition: imports.h:155
PUNICODE_STRING WINAPI Basep8BitStringToStaticUnicodeString(IN LPCSTR String)
Definition: utils.c:188
namespace GUID const ADDRINFOEXW ADDRINFOEXW struct timeval OVERLAPPED LPLOOKUPSERVICE_COMPLETION_ROUTINE HANDLE * handle
Definition: sock.c:82
#define TRUE
Definition: types.h:120
NTSYSAPI VOID NTAPI RtlCopyMemory(VOID UNALIGNED *Destination, CONST VOID UNALIGNED *Source, ULONG Length)
static UCHAR ULONG UCHAR ULONG UCHAR * output
Definition: bcrypt.c:29
#define CloseHandle
Definition: compat.h:398
UINT WINAPI GetDriveTypeA(IN LPCSTR lpRootPathName)
Definition: disk.c:469
int memcmp(void *Buffer1, void *Buffer2, ACPI_SIZE Count)
Definition: utclib.c:112
#define WideCharToMultiByte
Definition: compat.h:101
USHORT MaximumLength
Definition: env_spec_w32.h:370
Definition: bidi.c:85
struct _FILE_NAME_INFORMATION FILE_NAME_INFORMATION
#define ERROR_BAD_LENGTH
Definition: winerror.h:127
__wchar_t WCHAR
Definition: xmlstorage.h:180
#define FILE_DIRECTORY_FILE
Definition: constants.h:491
#define CP_ACP
Definition: compat.h:99
BOOL WINAPI GetVolumePathNamesForVolumeNameW(IN LPCWSTR lpszVolumeName, IN LPWSTR lpszVolumePathNames, IN DWORD cchBufferLength, OUT PDWORD lpcchReturnLength)
Definition: volume.c:1227
char CHAR
Definition: xmlstorage.h:175
BOOLEAN NTAPI RtlFreeHeap(IN PVOID HeapHandle, IN ULONG Flags, IN PVOID HeapBase)
Definition: heap.c:603
PVOID *typedef PWSTR
Definition: winlogon.h:57
const WCHAR * LPCWSTR
Definition: xmlstorage.h:185
#define ERROR_NOT_ENOUGH_MEMORY
Definition: dderror.h:7
#define INVALID_HANDLE_VALUE
Definition: compat.h:391
DWORD WINAPI GetLastError(VOID)
Definition: except.c:1056
DWORD WINAPI GetFullPathNameW(IN LPCWSTR lpFileName, IN DWORD nBufferLength, OUT LPWSTR lpBuffer, OUT LPWSTR *lpFilePart)
Definition: path.c:1105
GLuint buffer
Definition: glext.h:5915
BOOL WINAPI GetVolumePathNameW(IN LPCWSTR lpszFileName, IN LPWSTR lpszVolumePathName, IN DWORD cchBufferLength)
Definition: volume.c:815
HANDLE WINAPI FindFirstVolumeW(IN LPWSTR volume, IN DWORD len)
Definition: volume.c:660
#define FILE_SHARE_WRITE
Definition: nt_native.h:681
BOOL WINAPI GetVolumeInformationA(IN LPCSTR lpRootPathName, IN LPSTR lpVolumeNameBuffer, IN DWORD nVolumeNameSize, OUT LPDWORD lpVolumeSerialNumber OPTIONAL, OUT LPDWORD lpMaximumComponentLength OPTIONAL, OUT LPDWORD lpFileSystemFlags OPTIONAL, OUT LPSTR lpFileSystemNameBuffer OPTIONAL, IN DWORD nFileSystemNameSize)
Definition: volume.c:32
char * LPSTR
Definition: xmlstorage.h:182
struct _FILE_FS_ATTRIBUTE_INFORMATION FILE_FS_ATTRIBUTE_INFORMATION
#define WCHAR
Definition: msvc.h:43
#define BufferSize
Definition: acefiex.h:377
DWORD DWORD
Definition: winlogon.h:75
#define FILE_SHARE_READ
Definition: compat.h:125
#define RtlMoveMemory(Destination, Source, Length)
Definition: typedefs.h:263
uint32_t ULONG_PTR
Definition: typedefs.h:63
_Inout_ PUNICODE_STRING LinkTarget
Definition: zwfuncs.h:292
BOOL WINAPI GetVolumePathNamesForVolumeNameA(IN LPCSTR lpszVolumeName, IN LPSTR lpszVolumePathNames, IN DWORD cchBufferLength, OUT PDWORD lpcchReturnLength)
Definition: volume.c:1117
#define IOCTL_MOUNTMGR_QUERY_POINTS
Definition: mountmgr.h:30
BOOL WINAPI FindNextVolumeW(IN HANDLE handle, IN LPWSTR volume, IN DWORD len)
Definition: volume.c:1082
#define DRIVE_REMOTE
Definition: winbase.h:250
#define IOCTL_MOUNTMGR_QUERY_DOS_VOLUME_PATHS
Definition: mountmgr.h:129
BOOLEAN WINAPI Basep8BitStringToDynamicUnicodeString(OUT PUNICODE_STRING UnicodeString, IN LPCSTR String)
Definition: utils.c:225
#define FALSE
Definition: types.h:117
#define UNICODE_NULL
#define ANSI_NULL
#define ERROR_ACCESS_DENIED
Definition: compat.h:87
HANDLE WINAPI FindFirstVolumeA(IN LPSTR volume, IN DWORD len)
Definition: volume.c:708
smooth NULL
Definition: ftsmooth.c:416
#define MOUNTMGR_DOS_DEVICE_NAME
Definition: mountmgr.h:11
#define ERROR_DIR_NOT_ROOT
Definition: winerror.h:216
NTSTATUS NTAPI NtQueryVolumeInformationFile(IN HANDLE FileHandle, OUT PIO_STATUS_BLOCK IoStatusBlock, OUT PVOID FsInformation, IN ULONG Length, IN FS_INFORMATION_CLASS FsInformationClass)
Definition: iofunc.c:3833
void DPRINT(...)
Definition: polytest.cpp:61
Definition: bufpool.h:45
DWORD BaseSetLastNTError(IN NTSTATUS Status)
Definition: reactos.cpp:166
NTSYSAPI NTSTATUS NTAPI RtlUnicodeStringToAnsiString(PANSI_STRING DestinationString, PUNICODE_STRING SourceString, BOOLEAN AllocateDestinationString)
const char * LPCSTR
Definition: xmlstorage.h:183
#define ERROR_NO_MORE_FILES
Definition: winerror.h:121
#define FILE_WRITE_DATA
Definition: nt_native.h:631
#define OPEN_EXISTING
Definition: compat.h:426
PVOID NTAPI RtlAllocateHeap(IN PVOID HeapHandle, IN ULONG Flags, IN SIZE_T Size)
Definition: heap.c:585
USHORT MaximumLength
Definition: env_spec_w32.h:377
NTSYSAPI NTSTATUS NTAPI NtOpenFile(OUT PHANDLE phFile, IN ACCESS_MASK DesiredAccess, IN POBJECT_ATTRIBUTES ObjectAttributes, OUT PIO_STATUS_BLOCK pIoStatusBlock, IN ULONG ShareMode, IN ULONG OpenMode)
Definition: file.c:3508
unsigned int BOOL
Definition: ntddk_ex.h:94
GLsizeiptr size
Definition: glext.h:5919
LONG NTSTATUS
Definition: precomp.h:26
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:24
BOOL WINAPI SetVolumeLabelW(IN LPCWSTR lpRootPathName, IN LPCWSTR lpVolumeName OPTIONAL)
Definition: volume.c:503
#define MAX_PATH
Definition: compat.h:26
BOOL WINAPI GetVolumePathNameA(IN LPCSTR lpszFileName, IN LPSTR lpszVolumePathName, IN DWORD cchBufferLength)
Definition: volume.c:751
_Must_inspect_result_ _Out_ PHANDLE VolumeHandle
Definition: fltkernel.h:2284
NTSYSAPI VOID NTAPI RtlFreeUnicodeString(PUNICODE_STRING UnicodeString)
#define SetLastError(x)
Definition: compat.h:409
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: gl.h:1950
UINTN VOID * Buffer
Definition: acefiex.h:370
#define RTL_SEM_FAILCRITICALERRORS
Definition: rtltypes.h:74
NTSTATUS NTAPI NtClose(IN HANDLE Handle)
Definition: obhandle.c:3392
#define OBJ_CASE_INSENSITIVE
Definition: winternl.h:228
BOOL IsThisARootDirectory(IN HANDLE VolumeHandle, IN PUNICODE_STRING NtPathName)
Definition: volume.c:154
int ret
#define FILE_ATTRIBUTE_NORMAL
Definition: compat.h:126
_In_ ULONG _In_ BATTERY_QUERY_INFORMATION_LEVEL _In_ LONG _In_ ULONG _Out_ PULONG ReturnedLength
Definition: batclass.h:187
#define memcpy(s1, s2, n)
Definition: mkisofs.h:878
GLenum GLsizei len
Definition: glext.h:6722
WCHAR TargetName[256]
Definition: arping.c:27
#define MOUNTMGR_IS_DOS_VOLUME_NAME_WB(s)
Definition: mountmgr.h:134
NTSTATUS NTAPI NtQueryInformationFile(HANDLE hFile, PIO_STATUS_BLOCK io, PVOID ptr, ULONG len, FILE_INFORMATION_CLASS FileInformationClass)
#define SYNCHRONIZE
Definition: nt_native.h:61
#define ERROR_MORE_DATA
Definition: dderror.h:13
#define WINAPI
Definition: msvc.h:20
Status
Definition: gdiplustypes.h:24
MOUNTMGR_MOUNT_POINT MountPoints[1]
Definition: imports.h:177
BOOL WINAPI GetVolumeInformationW(IN LPCWSTR lpRootPathName, IN LPWSTR lpVolumeNameBuffer, IN DWORD nVolumeNameSize, OUT LPDWORD lpVolumeSerialNumber OPTIONAL, OUT LPDWORD lpMaximumComponentLength OPTIONAL, OUT LPDWORD lpFileSystemFlags OPTIONAL, OUT LPWSTR lpFileSystemNameBuffer OPTIONAL, IN DWORD nFileSystemNameSize)
Definition: volume.c:226
USHORT DeviceNameLength
Definition: imports.h:154
DWORD *typedef HANDLE
Definition: winlogon.h:52
BOOL WINAPI DeviceIoControl(IN HANDLE hDevice, IN DWORD dwIoControlCode, IN LPVOID lpInBuffer OPTIONAL, IN DWORD nInBufferSize OPTIONAL, OUT LPVOID lpOutBuffer OPTIONAL, IN DWORD nOutBufferSize OPTIONAL, OUT LPDWORD lpBytesReturned OPTIONAL, IN LPOVERLAPPED lpOverlapped OPTIONAL)
Definition: deviceio.c:136
GLenum GLenum GLenum input
Definition: glext.h:9031
unsigned short USHORT
Definition: pedump.c:61
#define STATUS_NO_MEMORY
Definition: ntstatus.h:246
#define FILE_OPEN_FOR_BACKUP_INTENT
Definition: from_kernel.h:42
#define STATUS_OBJECT_NAME_INVALID
Definition: udferr_usr.h:148
_In_ FILTER_INFORMATION_CLASS _In_ ULONG _Out_ PULONG BytesReturned
Definition: fltkernel.h:1716
static OUT PIO_STATUS_BLOCK IoStatusBlock
Definition: pipe.c:75
DWORD * PDWORD
Definition: pedump.c:68
struct _MOUNTMGR_VOLUME_PATHS MOUNTMGR_VOLUME_PATHS
#define CreateFileW
Definition: compat.h:400
#define FILE_SYNCHRONOUS_IO_NONALERT
Definition: from_kernel.h:31
_Must_inspect_result_ _Inout_opt_ PUNICODE_STRING VolumeName
Definition: fltkernel.h:1117
NTSTATUS NTAPI NtSetVolumeInformationFile(IN HANDLE FileHandle, OUT PIO_STATUS_BLOCK IoStatusBlock, IN PVOID FsInformation, IN ULONG Length, IN FS_INFORMATION_CLASS FsInformationClass)
Definition: iofunc.c:3999
struct _FILE_FS_VOLUME_INFORMATION FILE_FS_VOLUME_INFORMATION
#define OUT
Definition: typedefs.h:39
ULONG SymbolicLinkNameOffset
Definition: imports.h:166
uint32_t * LPDWORD
Definition: typedefs.h:57
unsigned int ULONG
Definition: retypes.h:1
#define SYMBOLIC_LINK_QUERY
Definition: nt_native.h:1265
USHORT SymbolicLinkNameLength
Definition: imports.h:167
NTSYSAPI VOID NTAPI RtlInitUnicodeString(PUNICODE_STRING DestinationString, PCWSTR SourceString)
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:261
#define InitializeObjectAttributes(p, n, a, r, s)
Definition: reg.c:106
const WCHAR * link
Definition: db.cpp:926
#define ERROR_PATH_NOT_FOUND
Definition: winerror.h:106
BOOL WINAPI GetVolumeNameForVolumeMountPointW(IN LPCWSTR VolumeMountPoint, OUT LPWSTR VolumeName, IN DWORD VolumeNameLength)
Definition: mntpoint.c:496
BOOL WINAPI SetVolumeLabelA(IN LPCSTR lpRootPathName, IN LPCSTR lpVolumeName OPTIONAL)
Definition: volume.c:463
BOOL WINAPI FindNextVolumeA(IN HANDLE handle, IN LPSTR volume, IN DWORD len)
Definition: volume.c:1055
NTSYSAPI NTSTATUS WINAPI RtlSetThreadErrorMode(DWORD, LPDWORD)
BOOL WINAPI FindVolumeClose(IN HANDLE hFindVolume)
Definition: volume.c:741
#define memset(x, y, z)
Definition: compat.h:39
WCHAR * LPWSTR
Definition: xmlstorage.h:184
IN HDEVINFO IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL
Definition: devinst.c:44
NTSYSAPI BOOLEAN NTAPI RtlDosPathNameToNtPathName_U(_In_opt_z_ PCWSTR DosPathName, _Out_ PUNICODE_STRING NtPathName, _Out_opt_ PCWSTR *NtFileNamePart, _Out_opt_ PRTL_RELATIVE_NAME_U DirectoryInfo)
#define ERROR_FILENAME_EXCED_RANGE
Definition: winerror.h:263