ReactOS  r76032
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) * (nVolumeNameSize + 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 static 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 to NT name */
257  if (!RtlDosPathNameToNtPathName_U(RootPathName, &NtPathName, NULL, NULL))
258  {
260  return FALSE;
261  }
262 
263  /* Check we really end with a backslash */
264  if (NtPathName.Buffer[(NtPathName.Length / sizeof(WCHAR)) - 1] != L'\\')
265  {
266  RtlFreeHeap(RtlGetProcessHeap(), 0, NtPathName.Buffer);
268  return FALSE;
269  }
270 
271  /* Try to open the received path */
272  InitializeObjectAttributes(&ObjectAttributes, &NtPathName,
274  NULL, NULL);
275 
276  /* No errors to the user */
278  Status = NtOpenFile(&VolumeHandle, SYNCHRONIZE, &ObjectAttributes, &IoStatusBlock, 0, FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT);
279  RtlSetThreadErrorMode(OldMode, NULL);
280  if (!NT_SUCCESS(Status))
281  {
282  RtlFreeHeap(RtlGetProcessHeap(), 0, NtPathName.Buffer);
283  BaseSetLastNTError(Status);
284  return FALSE;
285  }
286 
287  /* Check whether that's a root directory */
288  if (!IsThisARootDirectory(VolumeHandle, &NtPathName))
289  {
290  RtlFreeHeap(RtlGetProcessHeap(), 0, NtPathName.Buffer);
291  NtClose(VolumeHandle);
293  return FALSE;
294  }
295 
296  RtlFreeHeap(RtlGetProcessHeap(), 0, NtPathName.Buffer);
297 
298  /* Assume we don't need to query FileFsVolumeInformation */
299  VolumeInfo = NULL;
300  /* If user wants volume name, allocate a buffer to query it */
301  if (lpVolumeNameBuffer != NULL)
302  {
303  VolumeInfoSize = nVolumeNameSize + sizeof(FILE_FS_VOLUME_INFORMATION);
304  }
305  /* If user just wants the serial number, allocate a dummy buffer */
306  else if (lpVolumeSerialNumber != NULL)
307  {
308  VolumeInfoSize = MAX_PATH * sizeof(WCHAR) + sizeof(FILE_FS_VOLUME_INFORMATION);
309  }
310  /* Otherwise, nothing to query */
311  else
312  {
313  VolumeInfoSize = 0;
314  }
315 
316  /* If we're to query, allocate a big enough buffer */
317  if (VolumeInfoSize != 0)
318  {
319  VolumeInfo = RtlAllocateHeap(RtlGetProcessHeap(), 0, VolumeInfoSize);
320  if (VolumeInfo == NULL)
321  {
322  NtClose(VolumeHandle);
324  return FALSE;
325  }
326  }
327 
328  /* Assume we don't need to query FileFsAttributeInformation */
329  VolumeAttr = NULL;
330  /* If user wants filesystem name, allocate a buffer to query it */
331  if (lpFileSystemNameBuffer != NULL)
332  {
333  VolumeAttrSize = nFileSystemNameSize + sizeof(FILE_FS_ATTRIBUTE_INFORMATION);
334  }
335  /* If user just wants max compo len or flags, allocate a dummy buffer */
336  else if (lpMaximumComponentLength != NULL || lpFileSystemFlags != NULL)
337  {
338  VolumeAttrSize = MAX_PATH * sizeof(WCHAR) + sizeof(FILE_FS_ATTRIBUTE_INFORMATION);
339  }
340  else
341  {
342  VolumeAttrSize = 0;
343  }
344 
345  /* If we're to query, allocate a big enough buffer */
346  if (VolumeAttrSize != 0)
347  {
348  VolumeAttr = RtlAllocateHeap(RtlGetProcessHeap(), 0, VolumeAttrSize);
349  if (VolumeAttr == NULL)
350  {
351  if (VolumeInfo != NULL)
352  {
353  RtlFreeHeap(RtlGetProcessHeap(), 0, VolumeInfo);
354  }
355 
356  NtClose(VolumeHandle);
358  return FALSE;
359  }
360  }
361 
362  /* Assume we'll fail */
363  Ret = FALSE;
364 
365  /* If we're to query FileFsVolumeInformation, do it now! */
366  if (VolumeInfo != NULL)
367  {
368  Status = NtQueryVolumeInformationFile(VolumeHandle, &IoStatusBlock, VolumeInfo, VolumeInfoSize, FileFsVolumeInformation);
369  if (!NT_SUCCESS(Status))
370  {
371  BaseSetLastNTError(Status);
372  goto CleanAndQuit;
373  }
374  }
375 
376  /* If we're to query FileFsAttributeInformation, do it now! */
377  if (VolumeAttr != NULL)
378  {
379  Status = NtQueryVolumeInformationFile(VolumeHandle, &IoStatusBlock, VolumeAttr, VolumeAttrSize, FileFsAttributeInformation);
380  if (!NT_SUCCESS(Status))
381  {
382  BaseSetLastNTError(Status);
383  goto CleanAndQuit;
384  }
385  }
386 
387  /* If user wants volume name */
388  if (lpVolumeNameBuffer != NULL)
389  {
390  /* Check its buffer can hold it (+ 0) */
391  if (VolumeInfo->VolumeLabelLength >= nVolumeNameSize)
392  {
394  goto CleanAndQuit;
395  }
396 
397  /* Copy and zero */
398  RtlCopyMemory(lpVolumeNameBuffer, VolumeInfo->VolumeLabel, VolumeInfo->VolumeLabelLength);
399  lpVolumeNameBuffer[VolumeInfo->VolumeLabelLength / sizeof(WCHAR)] = UNICODE_NULL;
400  }
401 
402  /* If user wants wants serial number, return it */
403  if (lpVolumeSerialNumber != NULL)
404  {
405  *lpVolumeSerialNumber = VolumeInfo->VolumeSerialNumber;
406  }
407 
408  /* If user wants filesystem name */
409  if (lpFileSystemNameBuffer != NULL)
410  {
411  /* Check its buffer can hold it (+ 0) */
412  if (VolumeAttr->FileSystemNameLength >= nFileSystemNameSize)
413  {
415  goto CleanAndQuit;
416  }
417 
418  /* Copy and zero */
419  RtlCopyMemory(lpFileSystemNameBuffer, VolumeAttr->FileSystemName, VolumeAttr->FileSystemNameLength);
420  lpFileSystemNameBuffer[VolumeAttr->FileSystemNameLength / sizeof(WCHAR)] = UNICODE_NULL;
421  }
422 
423  /* If user wants wants max compo len, return it */
424  if (lpMaximumComponentLength != NULL)
425  {
426  *lpMaximumComponentLength = VolumeAttr->MaximumComponentNameLength;
427  }
428 
429  /* If user wants wants FS flags, return them */
430  if (lpFileSystemFlags != NULL)
431  {
432  *lpFileSystemFlags = VolumeAttr->FileSystemAttributes;
433  }
434 
435  /* We did it! */
436  Ret = TRUE;
437 
438 CleanAndQuit:
439  NtClose(VolumeHandle);
440 
441  if (VolumeInfo != NULL)
442  {
443  RtlFreeHeap(RtlGetProcessHeap(), 0, VolumeInfo);
444  }
445 
446  if (VolumeAttr != NULL)
447  {
448  RtlFreeHeap(RtlGetProcessHeap(), 0, VolumeAttr);
449  }
450 
451  return Ret;
452 }
453 
454 /*
455  * @implemented
456  */
457 BOOL
458 WINAPI
459 SetVolumeLabelA(IN LPCSTR lpRootPathName,
460  IN LPCSTR lpVolumeName OPTIONAL) /* NULL if deleting label */
461 {
462  BOOL Ret;
463  UNICODE_STRING VolumeNameU;
464  PUNICODE_STRING RootPathNameU;
465 
466  if (lpRootPathName == NULL)
467  {
468  lpRootPathName = "\\";
469  }
470 
471  RootPathNameU = Basep8BitStringToStaticUnicodeString(lpRootPathName);
472  if (RootPathNameU == NULL)
473  {
474  return FALSE;
475  }
476 
477  if (lpVolumeName != NULL)
478  {
479  if (!Basep8BitStringToDynamicUnicodeString(&VolumeNameU, lpVolumeName))
480  {
481  return FALSE;
482  }
483  }
484  else
485  {
486  VolumeNameU.Buffer = NULL;
487  }
488 
489  Ret = SetVolumeLabelW(RootPathNameU->Buffer, VolumeNameU.Buffer);
490  RtlFreeUnicodeString(&VolumeNameU);
491  return Ret;
492 }
493 
494 /*
495  * @implemented
496  */
497 BOOL
498 WINAPI
499 SetVolumeLabelW(IN LPCWSTR lpRootPathName,
500  IN LPCWSTR lpVolumeName OPTIONAL) /* NULL if deleting label */
501 {
502  BOOL Ret;
504  PWSTR VolumeRoot;
506  WCHAR VolumeGuid[MAX_PATH];
509  PFILE_FS_LABEL_INFORMATION FsLabelInfo;
510  UNICODE_STRING VolumeName, NtVolumeName;
511 
512  /* If no root path provided, default to \ */
513  VolumeRoot = L"\\";
514 
515  /* If user wants to set a label, make it a string */
516  if (lpVolumeName != NULL)
517  {
518  RtlInitUnicodeString(&VolumeName, lpVolumeName);
519  }
520  else
521  {
522  VolumeName.Length = 0;
523  VolumeName.MaximumLength = 0;
524  VolumeName.Buffer = NULL;
525  }
526 
527  /* If we received a volume, try to get its GUID name */
528  if (lpRootPathName != NULL)
529  {
530  Ret = GetVolumeNameForVolumeMountPointW(lpRootPathName, VolumeGuid, MAX_PATH);
531  }
532  else
533  {
534  Ret = FALSE;
535  }
536 
537  /* If we got the GUID name, use it */
538  if (Ret)
539  {
540  VolumeRoot = VolumeGuid;
541  }
542  else
543  {
544  /* Otherwise, use the name provided by the caller */
545  if (lpRootPathName != NULL)
546  {
547  VolumeRoot = (PWSTR)lpRootPathName;
548  }
549  }
550 
551  /* Convert to a NT path */
552  if (!RtlDosPathNameToNtPathName_U(VolumeRoot, &NtVolumeName, NULL, NULL))
553  {
555  return FALSE;
556  }
557 
558 
559  /* Check we really end with a backslash */
560  if (NtVolumeName.Buffer[(NtVolumeName.Length / sizeof(WCHAR)) - 1] != L'\\')
561  {
562  RtlFreeHeap(RtlGetProcessHeap(), 0, NtVolumeName.Buffer);
564  return FALSE;
565  }
566 
567  /* Try to open the root directory */
568  InitializeObjectAttributes(&ObjectAttributes, &NtVolumeName,
570 
571  Status = NtOpenFile(&VolumeHandle, SYNCHRONIZE | FILE_WRITE_DATA,
572  &ObjectAttributes, &IoStatusBlock,
575  if (!NT_SUCCESS(Status))
576  {
577  RtlFreeHeap(RtlGetProcessHeap(), 0, NtVolumeName.Buffer);
578  BaseSetLastNTError(Status);
579  return FALSE;
580  }
581 
582  /* Validate it's really a root path */
583  if (!IsThisARootDirectory(VolumeHandle, NULL))
584  {
585  RtlFreeHeap(RtlGetProcessHeap(), 0, NtVolumeName.Buffer);
586  NtClose(VolumeHandle);
588  return FALSE;
589  }
590 
591  /* Done */
592  NtClose(VolumeHandle);
593 
594  /* Now, open the volume to perform the label change */
595  NtVolumeName.Length -= sizeof(WCHAR);
596  InitializeObjectAttributes(&ObjectAttributes, &NtVolumeName,
598 
599  Status = NtOpenFile(&VolumeHandle, SYNCHRONIZE | FILE_WRITE_DATA,
600  &ObjectAttributes, &IoStatusBlock,
603 
604  RtlFreeHeap(RtlGetProcessHeap(), 0, NtVolumeName.Buffer);
605 
606  if (!NT_SUCCESS(Status))
607  {
608  BaseSetLastNTError(Status);
609  return FALSE;
610  }
611 
612  /* Assume success */
613  Ret = TRUE;
614 
615  /* Allocate a buffer that can hold new label and its size */
616  FsLabelInfo = RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(FILE_FS_LABEL_INFORMATION) + VolumeName.Length);
617  if (FsLabelInfo != NULL)
618  {
619  /* Copy name and set its size */
620  RtlCopyMemory(FsLabelInfo->VolumeLabel, VolumeName.Buffer, VolumeName.Length);
621  FsLabelInfo->VolumeLabelLength = VolumeName.Length;
622 
623  /* And finally, set new label */
624  Status = NtSetVolumeInformationFile(VolumeHandle, &IoStatusBlock, FsLabelInfo, sizeof(FILE_FS_LABEL_INFORMATION) + VolumeName.Length, FileFsLabelInformation);
625  }
626  else
627  {
628  /* Allocation failed */
629  Status = STATUS_NO_MEMORY;
630  }
631 
632  /* In case of failure, set status and mark failure */
633  if (!NT_SUCCESS(Status))
634  {
635  BaseSetLastNTError(Status);
636  Ret = FALSE;
637  }
638 
639  /* We're done */
640  NtClose(VolumeHandle);
641 
642  /* Free buffer if required */
643  if (FsLabelInfo != NULL)
644  {
645  RtlFreeHeap(RtlGetProcessHeap(), 0, FsLabelInfo);
646  }
647 
648  return Ret;
649 }
650 
651 /*
652  * @implemented (Wine 13 sep 2008)
653  */
654 HANDLE
655 WINAPI
657  IN DWORD len)
658 {
659  DWORD size = 1024;
660  DWORD br;
663  if (mgr == INVALID_HANDLE_VALUE) return INVALID_HANDLE_VALUE;
664 
665  for (;;)
666  {
669 
670  if (!(output = RtlAllocateHeap( RtlGetProcessHeap(), 0, size )))
671  {
673  break;
674  }
675  memset( &input, 0, sizeof(input) );
676 
677  if (!DeviceIoControl( mgr, IOCTL_MOUNTMGR_QUERY_POINTS, &input, sizeof(input),
678  output, size, &br, NULL ))
679  {
680  if (GetLastError() != ERROR_MORE_DATA) break;
681  size = output->Size;
682  RtlFreeHeap( RtlGetProcessHeap(), 0, output );
683  continue;
684  }
685  CloseHandle( mgr );
686  /* abuse the Size field to store the current index */
687  output->Size = 0;
688  if (!FindNextVolumeW( output, volume, len ))
689  {
690  RtlFreeHeap( RtlGetProcessHeap(), 0, output );
691  return INVALID_HANDLE_VALUE;
692  }
693  return (HANDLE)output;
694  }
695  CloseHandle( mgr );
696  return INVALID_HANDLE_VALUE;
697 }
698 
699 /*
700  * @implemented (Wine 13 sep 2008)
701  */
702 HANDLE
703 WINAPI
705  IN DWORD len)
706 {
707  WCHAR *buffer = NULL;
708  HANDLE handle;
709 
710  buffer = RtlAllocateHeap( RtlGetProcessHeap(), 0, len * sizeof(WCHAR) );
711 
712  if (!buffer)
713  {
715  return INVALID_HANDLE_VALUE;
716  }
717 
718  handle = FindFirstVolumeW( buffer, len );
719 
720  if (handle != INVALID_HANDLE_VALUE)
721  {
722  if (!WideCharToMultiByte( CP_ACP, 0, buffer, -1, volume, len, NULL, NULL ))
723  {
724  FindVolumeClose( handle );
725  handle = INVALID_HANDLE_VALUE;
726  }
727  }
728  RtlFreeHeap( RtlGetProcessHeap(), 0, buffer );
729  return handle;
730 }
731 
732 /*
733  * @implemented (Wine 13 sep 2008)
734  */
735 BOOL
736 WINAPI
738 {
739  return RtlFreeHeap(RtlGetProcessHeap(), 0, hFindVolume);
740 }
741 
742 /*
743  * @implemented
744  */
745 BOOL
746 WINAPI
748  IN LPSTR lpszVolumePathName,
749  IN DWORD cchBufferLength)
750 {
751  BOOL Ret;
752  PUNICODE_STRING FileNameU;
753  ANSI_STRING VolumePathName;
754  UNICODE_STRING VolumePathNameU;
755 
756  /* Convert file name to unicode */
757  FileNameU = Basep8BitStringToStaticUnicodeString(lpszFileName);
758  if (FileNameU == NULL)
759  {
760  return FALSE;
761  }
762 
763  /* Initialize all the strings we'll need */
764  VolumePathName.Buffer = lpszVolumePathName;
765  VolumePathName.Length = 0;
766  VolumePathName.MaximumLength = cchBufferLength - 1;
767 
768  VolumePathNameU.Length = 0;
769  VolumePathNameU.MaximumLength = (cchBufferLength - 1) * sizeof(WCHAR) + sizeof(UNICODE_NULL);
770  /* Allocate a buffer for calling the -W */
771  VolumePathNameU.Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, VolumePathNameU.MaximumLength);
772  if (VolumePathNameU.Buffer == NULL)
773  {
775  return FALSE;
776  }
777 
778  /* Call the -W implementation */
779  Ret = GetVolumePathNameW(FileNameU->Buffer, VolumePathNameU.Buffer, cchBufferLength);
780  /* If it succeed */
781  if (Ret)
782  {
784 
785  /* Convert back to ANSI */
786  RtlInitUnicodeString(&VolumePathNameU, VolumePathNameU.Buffer);
787  Status = RtlUnicodeStringToAnsiString(&VolumePathName, &VolumePathNameU, FALSE);
788  /* If conversion failed, just set error code and fail the rest */
789  if (!NT_SUCCESS(Status))
790  {
791  BaseSetLastNTError(Status);
792  Ret = FALSE;
793  }
794  /* Otherwise, null terminate the string (it's OK, we computed -1) */
795  else
796  {
797  VolumePathName.Buffer[VolumePathName.Length] = ANSI_NULL;
798  }
799  }
800 
801  /* Free the buffer allocated for -W call */
802  RtlFreeHeap(RtlGetProcessHeap(), 0, VolumePathNameU.Buffer);
803  return Ret;
804 }
805 
806 /*
807  * @implemented
808  */
809 BOOL
810 WINAPI
812  IN LPWSTR lpszVolumePathName,
813  IN DWORD cchBufferLength)
814 {
815  BOOL MountPoint;
816  DWORD FullPathLen;
817  WCHAR OldFilePart;
818  UNICODE_STRING FullPath;
819  PWSTR FullPathBuf, FilePart, VolumeNameBuf;
820 
821  /* Probe for full path len */
822  FullPathLen = GetFullPathNameW(lpszFileName, 0, NULL, NULL);
823  if (FullPathLen == 0)
824  {
825  return FALSE;
826  }
827 
828  /* Allocate a big enough buffer to receive it */
829  FullPathBuf = RtlAllocateHeap(RtlGetProcessHeap(), 0, (FullPathLen + 10) * sizeof(WCHAR));
830  if (FullPathBuf == NULL)
831  {
833  return FALSE;
834  }
835 
836  /* And get full path name */
837  if (GetFullPathNameW(lpszFileName, FullPathLen + 10, FullPathBuf, &FilePart) == 0)
838  {
839  RtlFreeHeap(RtlGetProcessHeap(), 0, FullPathBuf);
840  return FALSE;
841  }
842 
843  /* Make a string out of it */
844  RtlInitUnicodeString(&FullPath, FullPathBuf);
845  /* We will finish our string with '\', for ease of the parsing after */
846  if (FullPath.Buffer[(FullPath.Length / sizeof(WCHAR)) - 1] != L'\\')
847  {
848  FullPath.Length += sizeof(WCHAR);
849  FullPath.Buffer[(FullPath.Length / sizeof(WCHAR)) - 1] = L'\\';
850  FullPath.Buffer[FullPath.Length / sizeof(WCHAR)] = UNICODE_NULL;
851  }
852 
853  /* Allocate a buffer big enough to receive our volume name */
854  VolumeNameBuf = RtlAllocateHeap(RtlGetProcessHeap(), 0, 0x2000 * sizeof(WCHAR));
855  if (VolumeNameBuf == NULL)
856  {
857  RtlFreeHeap(RtlGetProcessHeap(), 0, FullPathBuf);
859  return FALSE;
860  }
861 
862  /* We don't care about file part: we added an extra backslash, so there's no
863  * file, we're back at the dir level.
864  * We'll recompute file part afterwards
865  */
866  FilePart = NULL;
867  /* Keep track of the letter we could drop to shorten the string */
868  OldFilePart = UNICODE_NULL;
869  /* As long as querying volume name fails, keep looping */
870  while (!BasepGetVolumeNameForVolumeMountPoint(FullPath.Buffer, VolumeNameBuf, 0x2000u, &MountPoint))
871  {
872  USHORT LastSlash;
873 
874  /* Not a mount point, but opening returning access denied? Assume it's one, just not
875  * a reparse backed one (classic mount point, a device)!
876  */
877  if (!MountPoint && GetLastError() == ERROR_ACCESS_DENIED)
878  {
879  MountPoint = TRUE;
880  }
881 
882  /* BasepGetVolumeNameForVolumeMountPoint failed, but returned a volume name.
883  * This can happen when we are given a reparse point where MountMgr could find associated
884  * volume name which is not a valid DOS volume
885  * A valid DOS name always starts with \\
886  */
887  if (VolumeNameBuf[0] != UNICODE_NULL && (FullPath.Buffer[0] != L'\\' || FullPath.Buffer[1] != L'\\'))
888  {
889  CHAR RootPathName[4];
890 
891  /* Construct a simple <letter>:\ string to get drive type */
892  RootPathName[0] = FullPath.Buffer[0];
893  RootPathName[1] = ':';
894  RootPathName[2] = '\\';
895  RootPathName[3] = ANSI_NULL;
896 
897  /* If we weren't given a drive letter actually, or if that's not a remote drive
898  * Note: in this code path, we're recursive and stop fail loop
899  */
900  if (FullPath.Buffer[1] != L':' || GetDriveTypeA(RootPathName) != DRIVE_REMOTE)
901  {
902  BOOL Ret;
903 
904  /* We won't need the full path, we'll now work with the returned volume name */
905  RtlFreeHeap(RtlGetProcessHeap(), 0, FullPathBuf);
906  /* If it wasn't an NT name which was returned */
907  if ((VolumeNameBuf[0] != L'\\') || (VolumeNameBuf[1] != L'?') ||
908  (VolumeNameBuf[2] != L'?') || (VolumeNameBuf[3] != L'\\'))
909  {
910  PWSTR GlobalPath;
911  UNICODE_STRING GlobalRoot;
912 
913  /* Create a new name in the NT namespace (from Win32) */
914  RtlInitUnicodeString(&FullPath, VolumeNameBuf);
915  RtlInitUnicodeString(&GlobalRoot, L"\\\\?\\GLOBALROOT");
916 
917  /* We allocate a buffer than can contain both the namespace and the volume name */
918  GlobalPath = RtlAllocateHeap(RtlGetProcessHeap(), 0, FullPath.Length + GlobalRoot.Length);
919  if (GlobalPath == NULL)
920  {
921  RtlFreeHeap(RtlGetProcessHeap(), 0, VolumeNameBuf);
923  return FALSE;
924  }
925 
926  /* Fill in the new query name */
927  RtlCopyMemory(GlobalPath, GlobalRoot.Buffer, GlobalRoot.Length);
928  RtlCopyMemory((PVOID)((ULONG_PTR)GlobalPath + GlobalRoot.Length), FullPath.Buffer, FullPath.Length);
929  GlobalPath[(FullPath.Length + GlobalRoot.Length) / sizeof(WCHAR)] = UNICODE_NULL;
930 
931  /* Give it another try */
932  Ret = GetVolumePathNameW(GlobalPath, lpszVolumePathName, cchBufferLength);
933 
934  RtlFreeHeap(RtlGetProcessHeap(), 0, GlobalPath);
935  }
936  else
937  {
938  /* If we don't have a drive letter in the Win32 name space \\.<letter>: */
939  if ((VolumeNameBuf[4] != UNICODE_NULL) && (VolumeNameBuf[5] != L':'))
940  {
941  /* Shit our starting \\ */
942  RtlInitUnicodeString(&FullPath, VolumeNameBuf);
943  RtlMoveMemory(VolumeNameBuf, (PVOID)((ULONG_PTR)VolumeNameBuf + (2 * sizeof(WCHAR))), FullPath.Length - (3 * sizeof(WCHAR)));
944  }
945  /* Otherwise, just make sure we're double \ at the being to query again with the
946  * proper namespace
947  */
948  else
949  {
950  VolumeNameBuf[1] = L'\\';
951  }
952 
953  /* Give it another try */
954  Ret = GetVolumePathNameW(VolumeNameBuf, lpszVolumePathName, cchBufferLength);
955  }
956 
957  /* And done! */
958  RtlFreeHeap(RtlGetProcessHeap(), 0, VolumeNameBuf);
959  return Ret;
960  }
961  }
962 
963  /* No mount point but with a file part? Restore filepart and exit */
964  if (!MountPoint && FilePart != NULL)
965  {
966  FilePart[0] = OldFilePart;
967  RtlInitUnicodeString(&FullPath, FullPathBuf);
968  break;
969  }
970 
971  /* We cannot go down the path any longer, too small */
972  if (FullPath.Length <= sizeof(WCHAR))
973  {
974  break;
975  }
976 
977  /* Prepare the next split */
978  LastSlash = (FullPath.Length / sizeof(WCHAR)) - 2;
979  if (FullPath.Length / sizeof(WCHAR) != 2)
980  {
981  do
982  {
983  if (FullPath.Buffer[LastSlash] == L'\\')
984  {
985  break;
986  }
987 
988  --LastSlash;
989  } while (LastSlash != 0);
990  }
991 
992  /* We couldn't split path, quit */
993  if (LastSlash == 0)
994  {
995  break;
996  }
997 
998  /* If that's a mount point, keep track of the directory name */
999  if (MountPoint)
1000  {
1001  FilePart = &FullPath.Buffer[LastSlash + 1];
1002  OldFilePart = FilePart[0];
1003  /* And null terminate the string */
1004  FilePart[0] = UNICODE_NULL;
1005  }
1006  /* Otherwise, just null terminate the string */
1007  else
1008  {
1009  FullPath.Buffer[LastSlash + 1] = UNICODE_NULL;
1010  }
1011 
1012  /* We went down a bit in the path, fix the string and retry */
1013  RtlInitUnicodeString(&FullPath, FullPathBuf);
1014  }
1015 
1016  /* Once here, we'll return something from the full path buffer, so release
1017  * output buffer
1018  */
1019  RtlFreeHeap(RtlGetProcessHeap(), 0, VolumeNameBuf);
1020 
1021  /* Not a mount point, bail out */
1022  if (!MountPoint && FilePart == NULL)
1023  {
1024  RtlFreeHeap(RtlGetProcessHeap(), 0, FullPathBuf);
1025  return FALSE;
1026  }
1027 
1028  /* Make sure we have enough room to copy our volume */
1029  if ((cchBufferLength * sizeof(WCHAR)) < FullPath.Length + sizeof(UNICODE_NULL))
1030  {
1031  RtlFreeHeap(RtlGetProcessHeap(), 0, FullPathBuf);
1033  return FALSE;
1034  }
1035 
1036  /* Copy and null terminate */
1037  RtlCopyMemory(lpszVolumePathName, FullPath.Buffer, FullPath.Length);
1038  lpszVolumePathName[FullPath.Length / sizeof(WCHAR)] = UNICODE_NULL;
1039 
1040  RtlFreeHeap(RtlGetProcessHeap(), 0, FullPathBuf);
1041 
1042  /* Done! */
1043  return TRUE;
1044 }
1045 
1046 /*
1047  * @implemented
1048  */
1049 BOOL
1050 WINAPI
1052  IN LPSTR volume,
1053  IN DWORD len)
1054 {
1055  WCHAR *buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, len * sizeof(WCHAR));
1056  BOOL ret;
1057 
1058  if (!buffer)
1059  {
1061  return FALSE;
1062  }
1063 
1064  if ((ret = FindNextVolumeW( handle, buffer, len )))
1065  {
1066  if (!WideCharToMultiByte( CP_ACP, 0, buffer, -1, volume, len, NULL, NULL )) ret = FALSE;
1067  }
1068 
1069  RtlFreeHeap(RtlGetProcessHeap(), 0, buffer);
1070  return ret;
1071 }
1072 
1073 /*
1074  * @implemented
1075  */
1076 BOOL
1077 WINAPI
1079  IN LPWSTR volume,
1080  IN DWORD len)
1081 {
1083 
1084  while (data->Size < data->NumberOfMountPoints)
1085  {
1086  static const WCHAR volumeW[] = {'\\','?','?','\\','V','o','l','u','m','e','{',};
1087  WCHAR *link = (WCHAR *)((char *)data + data->MountPoints[data->Size].SymbolicLinkNameOffset);
1089  data->Size++;
1090  /* skip non-volumes */
1091  if (size < sizeof(volumeW) || memcmp( link, volumeW, sizeof(volumeW) )) continue;
1092  if (size + sizeof(WCHAR) >= len * sizeof(WCHAR))
1093  {
1095  return FALSE;
1096  }
1097  memcpy( volume, link, size );
1098  volume[1] = '\\'; /* map \??\ to \\?\ */
1099  volume[size / sizeof(WCHAR)] = '\\'; /* Windows appends a backslash */
1100  volume[size / sizeof(WCHAR) + 1] = 0;
1101  DPRINT( "returning entry %u %s\n", data->Size - 1, volume );
1102  return TRUE;
1103  }
1105  return FALSE;
1106 }
1107 
1108 /*
1109  * @implemented
1110  */
1111 BOOL
1112 WINAPI
1114  IN LPSTR lpszVolumePathNames,
1115  IN DWORD cchBufferLength,
1116  OUT PDWORD lpcchReturnLength)
1117 {
1118  BOOL Ret;
1119  NTSTATUS Status;
1120  DWORD cchReturnLength;
1121  ANSI_STRING VolumePathName;
1122  PUNICODE_STRING VolumeNameU;
1123  UNICODE_STRING VolumePathNamesU;
1124 
1125  /* Convert volume name to unicode */
1126  VolumeNameU = Basep8BitStringToStaticUnicodeString(lpszVolumeName);
1127  if (VolumeNameU == NULL)
1128  {
1129  return FALSE;
1130  }
1131 
1132  /* Initialize the strings we'll use later on */
1133  VolumePathName.Length = 0;
1134  VolumePathName.MaximumLength = cchBufferLength;
1135  VolumePathName.Buffer = lpszVolumePathNames;
1136 
1137  VolumePathNamesU.Length = 0;
1138  VolumePathNamesU.MaximumLength = sizeof(WCHAR) * cchBufferLength;
1139  /* If caller provided a non 0 sized string, allocate a buffer for our unicode string */
1140  if (VolumePathNamesU.MaximumLength != 0)
1141  {
1142  VolumePathNamesU.Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, VolumePathNamesU.MaximumLength);
1143  if (VolumePathNamesU.Buffer == NULL)
1144  {
1146  return FALSE;
1147  }
1148  }
1149  else
1150  {
1151  VolumePathNamesU.Buffer = NULL;
1152  }
1153 
1154  /* Call the -W implementation */
1155  Ret = GetVolumePathNamesForVolumeNameW(VolumeNameU->Buffer, VolumePathNamesU.Buffer,
1156  cchBufferLength, &cchReturnLength);
1157  /* Call succeed, we'll return the total length */
1158  if (Ret)
1159  {
1160  VolumePathNamesU.Length = sizeof(WCHAR) * cchReturnLength;
1161  }
1162  else
1163  {
1164  /* Else, if we fail for anything else than too small buffer, quit */
1165  if (GetLastError() != ERROR_MORE_DATA)
1166  {
1167  if (VolumePathNamesU.Buffer != NULL)
1168  {
1169  RtlFreeHeap(RtlGetProcessHeap(), 0, VolumePathNamesU.Buffer);
1170  }
1171 
1172  return FALSE;
1173  }
1174 
1175  /* Otherwise, we'll just copy as much as we can */
1176  VolumePathNamesU.Length = sizeof(WCHAR) * cchBufferLength;
1177  }
1178 
1179  /* Convert our output string back to ANSI */
1180  Status = RtlUnicodeStringToAnsiString(&VolumePathName, &VolumePathNamesU, FALSE);
1181  if (!NT_SUCCESS(Status))
1182  {
1183  BaseSetLastNTError(Status);
1184 
1185  if (VolumePathNamesU.Buffer != NULL)
1186  {
1187  RtlFreeHeap(RtlGetProcessHeap(), 0, VolumePathNamesU.Buffer);
1188  }
1189 
1190  return FALSE;
1191  }
1192 
1193  /* If caller wants return length, two cases... */
1194  if (lpcchReturnLength != NULL)
1195  {
1196  /* We succeed: return the copied length */
1197  if (Ret)
1198  {
1199  *lpcchReturnLength = VolumePathName.Length;
1200  }
1201  /* We failed, return the size we would have loved having! */
1202  else
1203  {
1204  *lpcchReturnLength = sizeof(WCHAR) * cchReturnLength;
1205  }
1206  }
1207 
1208  /* Release our buffer if allocated */
1209  if (VolumePathNamesU.Buffer != NULL)
1210  {
1211  RtlFreeHeap(RtlGetProcessHeap(), 0, VolumePathNamesU.Buffer);
1212  }
1213 
1214  return Ret;
1215 }
1216 
1217 
1218 /*
1219  * @implemented
1220  */
1221 BOOL
1222 WINAPI
1224  IN LPWSTR lpszVolumePathNames,
1225  IN DWORD cchBufferLength,
1226  OUT PDWORD lpcchReturnLength)
1227 {
1228  BOOL Ret;
1229  PWSTR MultiSz;
1231  HANDLE MountMgrHandle;
1234  PMOUNTMGR_VOLUME_PATHS VolumePaths;
1235  ULONG BufferSize, CharsInMgr, CharsInOutput, Paths;
1236 
1237  /* First look that our volume name looks somehow correct */
1238  RtlInitUnicodeString(&VolumeName, lpszVolumeName);
1239  if (VolumeName.Buffer[(VolumeName.Length / sizeof(WCHAR)) - 1] != L'\\')
1240  {
1242  return FALSE;
1243  }
1244 
1245  /* Validate it's a DOS volume name finishing with a backslash */
1246  if (!MOUNTMGR_IS_DOS_VOLUME_NAME_WB(&VolumeName))
1247  {
1249  return FALSE;
1250  }
1251 
1252  /* Allocate an input MOUNTMGR_TARGET_NAME */
1253  TargetName = RtlAllocateHeap(RtlGetProcessHeap(), 0, MAX_PATH * sizeof(WCHAR) + sizeof(USHORT));
1254  if (TargetName == NULL)
1255  {
1257  return FALSE;
1258  }
1259 
1260  /* And fill it */
1261  RtlZeroMemory(TargetName, MAX_PATH * sizeof(WCHAR) + sizeof(USHORT));
1262  TargetName->DeviceNameLength = VolumeName.Length - sizeof(WCHAR);
1263  RtlCopyMemory(TargetName->DeviceName, VolumeName.Buffer, TargetName->DeviceNameLength);
1264  TargetName->DeviceName[1] = L'?';
1265 
1266  /* Open the mount manager */
1267  MountMgrHandle = CreateFileW(MOUNTMGR_DOS_DEVICE_NAME, 0,
1271  if (MountMgrHandle == INVALID_HANDLE_VALUE)
1272  {
1273  RtlFreeHeap(RtlGetProcessHeap(), 0, TargetName);
1274  return FALSE;
1275  }
1276 
1277  /* Allocate an initial output buffer, just to get length */
1278  VolumePaths = RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(MOUNTMGR_VOLUME_PATHS));
1279  if (VolumePaths == NULL)
1280  {
1281  CloseHandle(MountMgrHandle);
1282  RtlFreeHeap(RtlGetProcessHeap(), 0, TargetName);
1284  return FALSE;
1285  }
1286 
1287  /* Query the paths */
1289  TargetName, MAX_PATH * sizeof(WCHAR) + sizeof(USHORT),
1290  VolumePaths, sizeof(MOUNTMGR_VOLUME_PATHS), &BytesReturned,
1291  NULL);
1292  /* Loop until we can query everything */
1293  while (!Ret)
1294  {
1295  /* If failed for another reason than too small buffer, fail */
1296  if (GetLastError() != ERROR_MORE_DATA)
1297  {
1298  CloseHandle(MountMgrHandle);
1299  RtlFreeHeap(RtlGetProcessHeap(), 0, TargetName);
1300  RtlFreeHeap(RtlGetProcessHeap(), 0, VolumePaths);
1301  return FALSE;
1302  }
1303 
1304  /* Get the required length */
1305  BufferSize = VolumePaths->MultiSzLength + sizeof(MOUNTMGR_VOLUME_PATHS);
1306 
1307  /* And reallocate our output buffer (big enough this time) */
1308  RtlFreeHeap(RtlGetProcessHeap(), 0, VolumePaths);
1309  VolumePaths = RtlAllocateHeap(RtlGetProcessHeap(), 0, BufferSize);
1310  if (VolumePaths == NULL)
1311  {
1312  CloseHandle(MountMgrHandle);
1313  RtlFreeHeap(RtlGetProcessHeap(), 0, TargetName);
1315  return FALSE;
1316  }
1317 
1318  /* Query again the mount mgr */
1320  TargetName, MAX_PATH * sizeof(WCHAR) + sizeof(USHORT),
1321  VolumePaths, BufferSize, &BytesReturned, NULL);
1322  }
1323 
1324  /* We're done, no need for input nor mount mgr any longer */
1325  CloseHandle(MountMgrHandle);
1326  RtlFreeHeap(RtlGetProcessHeap(), 0, TargetName);
1327 
1328  /* Initialize:
1329  - Number of paths we saw (useful to count extra \)
1330  - Progress in mount mgr output
1331  - Progress in output buffer
1332  - Direct buffer to returned MultiSz
1333  */
1334  Paths = 0;
1335  CharsInMgr = 0;
1336  CharsInOutput = 0;
1337  MultiSz = VolumePaths->MultiSz;
1338 
1339  /* If we have an output buffer */
1340  if (cchBufferLength != 0)
1341  {
1342  /* Loop on the output to recopy it back to the caller
1343  * Note that we loop until -1 not to handle last 0 (will be done later on)
1344  */
1345  for (; (CharsInMgr < VolumePaths->MultiSzLength / sizeof(WCHAR) - 1) && (CharsInOutput < cchBufferLength);
1346  ++CharsInMgr, ++CharsInOutput)
1347  {
1348  /* When we reach the end of a path */
1349  if (MultiSz[CharsInMgr] == UNICODE_NULL)
1350  {
1351  /* On path done (count), add an extra \ at the end */
1352  ++Paths;
1353  lpszVolumePathNames[CharsInOutput] = L'\\';
1354  ++CharsInOutput;
1355  /* Make sure we don't overflow */
1356  if (CharsInOutput == cchBufferLength)
1357  {
1358  break;
1359  }
1360  }
1361 
1362  /* Copy the char to the caller
1363  * So, in case we're in the end of a path, we wrote two chars to
1364  * the output buffer: \\ and \0
1365  */
1366  lpszVolumePathNames[CharsInOutput] = MultiSz[CharsInMgr];
1367  }
1368  }
1369 
1370  /* If output buffer was too small (ie, we couldn't parse all the input buffer) */
1371  if (CharsInMgr < VolumePaths->MultiSzLength / sizeof(WCHAR) - 1)
1372  {
1373  /* Keep looping on it, to count the number of extra \ that will be required
1374  * So that on the next call, caller can allocate enough space
1375  */
1376  for (; CharsInMgr < VolumePaths->MultiSzLength / sizeof(WCHAR) - 1; ++CharsInMgr)
1377  {
1378  if (MultiSz[CharsInMgr] == UNICODE_NULL)
1379  {
1380  ++Paths;
1381  }
1382  }
1383  }
1384 
1385  /* If we couldn't write as much as we wanted to the output buffer
1386  * This handles the case where we could write everything excepted the
1387  * terminating \0 for multi SZ
1388  */
1389  if (CharsInOutput >= cchBufferLength)
1390  {
1391  /* Fail and set appropriate error code */
1392  Ret = FALSE;
1394  /* If caller wants to know how many chars to allocate, return it */
1395  if (lpcchReturnLength != NULL)
1396  {
1397  /* It's amount of extra \ + number of chars in MultiSz (including double \0) */
1398  *lpcchReturnLength = Paths + (VolumePaths->MultiSzLength / sizeof(WCHAR));
1399  }
1400  }
1401  else
1402  {
1403  /* It succeed so terminate the multi SZ (second \0) */
1404  lpszVolumePathNames[CharsInOutput] = UNICODE_NULL;
1405  Ret = TRUE;
1406 
1407  /* If caller wants the amount of chars written, return it */
1408  if (lpcchReturnLength != NULL)
1409  {
1410  /* Including the terminating \0 we just added */
1411  *lpcchReturnLength = CharsInOutput + 1;
1412  }
1413  }
1414 
1415  /* Free last bits */
1416  RtlFreeHeap(RtlGetProcessHeap(), 0, VolumePaths);
1417 
1418  /* And return */
1419  return Ret;
1420 }
1421 
1422 /* 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
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:79
#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:407
int memcmp(void *Buffer1, void *Buffer2, ACPI_SIZE Count)
Definition: utclib.c:112
#define WideCharToMultiByte
Definition: compat.h:101
static BOOL IsThisARootDirectory(IN HANDLE VolumeHandle, IN PUNICODE_STRING NtPathName)
Definition: volume.c:154
USHORT MaximumLength
Definition: env_spec_w32.h:370
Definition: bidi.c:75
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:1223
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:811
HANDLE WINAPI FindFirstVolumeW(IN LPWSTR volume, IN DWORD len)
Definition: volume.c:656
#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:1113
#define IOCTL_MOUNTMGR_QUERY_POINTS
Definition: mountmgr.h:30
BOOL WINAPI FindNextVolumeW(IN HANDLE handle, IN LPWSTR volume, IN DWORD len)
Definition: volume.c:1078
#define DRIVE_REMOTE
Definition: winbase.h:248
#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:704
smooth NULL
Definition: ftsmooth.c:557
#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:3813
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
MOUNTMGR_MOUNT_POINT MountPoints[1]
Definition: mountmgr.h:89
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
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:24
BOOL WINAPI SetVolumeLabelW(IN LPCWSTR lpRootPathName, IN LPCWSTR lpVolumeName OPTIONAL)
Definition: volume.c:499
#define MAX_PATH
Definition: compat.h:26
BOOL WINAPI GetVolumePathNameA(IN LPCSTR lpszFileName, IN LPSTR lpszVolumePathName, IN DWORD cchBufferLength)
Definition: volume.c:747
_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
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
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
DWORD *typedef HANDLE
Definition: winlogon.h:52
LONG NTSTATUS
Definition: DriverTester.h:11
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
GLsizeiptr size
Definition: glext.h:5919
#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:3979
struct _FILE_FS_VOLUME_INFORMATION FILE_FS_VOLUME_INFORMATION
#define OUT
Definition: typedefs.h:39
ULONG SymbolicLinkNameOffset
Definition: mountmgr.h:78
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: mountmgr.h:79
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:923
#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:459
BOOL WINAPI FindNextVolumeA(IN HANDLE handle, IN LPSTR volume, IN DWORD len)
Definition: volume.c:1051
NTSYSAPI NTSTATUS WINAPI RtlSetThreadErrorMode(DWORD, LPDWORD)
BOOL WINAPI FindVolumeClose(IN HANDLE hFindVolume)
Definition: volume.c:737
#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