Fixed warnings.
[reactos.git] / reactos / lib / kernel32 / file / volume.c
1 /* $Id: volume.c,v 1.27 2002/12/06 17:33:16 ekohl Exp $
2 *
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS system libraries
5 * FILE: lib/kernel32/file/volume.c
6 * PURPOSE: File volume functions
7 * PROGRAMMER: Ariadne ( ariadne@xs4all.nl)
8 * Erik Bos, Alexandre Julliard :
9 * GetLogicalDriveStringsA,
10 * GetLogicalDriveStringsW, GetLogicalDrives
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 <ddk/ntddk.h>
23 #include <windows.h>
24 #include <ntos/minmax.h>
25
26 #define NDEBUG
27 #include <kernel32/kernel32.h>
28 #include <kernel32/error.h>
29
30
31 #define MAX_DOS_DRIVES 26
32
33
34 static HANDLE
35 InternalOpenDirW(LPCWSTR DirName,
36 BOOLEAN Write)
37 {
38 UNICODE_STRING NtPathU;
39 OBJECT_ATTRIBUTES ObjectAttributes;
40 NTSTATUS errCode;
41 IO_STATUS_BLOCK IoStatusBlock;
42 HANDLE hFile;
43
44 if (!RtlDosPathNameToNtPathName_U((LPWSTR)DirName,
45 &NtPathU,
46 NULL,
47 NULL))
48 {
49 DPRINT("Invalid path\n");
50 SetLastError(ERROR_BAD_PATHNAME);
51 return INVALID_HANDLE_VALUE;
52 }
53
54 InitializeObjectAttributes(&ObjectAttributes,
55 &NtPathU,
56 Write ? FILE_WRITE_ATTRIBUTES : FILE_READ_ATTRIBUTES,
57 NULL,
58 NULL);
59
60 errCode = NtCreateFile (&hFile,
61 Write ? FILE_GENERIC_WRITE : FILE_GENERIC_READ,
62 &ObjectAttributes,
63 &IoStatusBlock,
64 NULL,
65 0,
66 FILE_SHARE_READ|FILE_SHARE_WRITE,
67 FILE_OPEN,
68 0,
69 NULL,
70 0);
71
72 RtlFreeUnicodeString(&NtPathU);
73
74 if (!NT_SUCCESS(errCode))
75 {
76 SetLastErrorByStatus (errCode);
77 return INVALID_HANDLE_VALUE;
78 }
79 return hFile;
80 }
81
82
83 DWORD STDCALL
84 GetLogicalDriveStringsA(DWORD nBufferLength,
85 LPSTR lpBuffer)
86 {
87 DWORD drive, count;
88 DWORD dwDriveMap;
89
90 dwDriveMap = SharedUserData->DosDeviceMap;
91
92 for (drive = count = 0; drive < MAX_DOS_DRIVES; drive++)
93 {
94 if (dwDriveMap & (1<<drive))
95 count++;
96 }
97
98
99 if (count * 4 * sizeof(char) <= nBufferLength)
100 {
101 LPSTR p = lpBuffer;
102
103 for (drive = 0; drive < MAX_DOS_DRIVES; drive++)
104 if (dwDriveMap & (1<<drive))
105 {
106 *p++ = 'A' + drive;
107 *p++ = ':';
108 *p++ = '\\';
109 *p++ = '\0';
110 }
111 *p = '\0';
112 }
113 return (count * 4 * sizeof(char));
114 }
115
116
117 DWORD STDCALL
118 GetLogicalDriveStringsW(DWORD nBufferLength,
119 LPWSTR lpBuffer)
120 {
121 DWORD drive, count;
122 DWORD dwDriveMap;
123
124 dwDriveMap = SharedUserData->DosDeviceMap;
125
126 for (drive = count = 0; drive < MAX_DOS_DRIVES; drive++)
127 {
128 if (dwDriveMap & (1<<drive))
129 count++;
130 }
131
132 if (count * 4 * sizeof(WCHAR) <= nBufferLength)
133 {
134 LPWSTR p = lpBuffer;
135 for (drive = 0; drive < MAX_DOS_DRIVES; drive++)
136 if (dwDriveMap & (1<<drive))
137 {
138 *p++ = (WCHAR)('A' + drive);
139 *p++ = (WCHAR)':';
140 *p++ = (WCHAR)'\\';
141 *p++ = (WCHAR)'\0';
142 }
143 *p = (WCHAR)'\0';
144 }
145 return (count * 4 * sizeof(WCHAR));
146 }
147
148
149 DWORD STDCALL
150 GetLogicalDrives(VOID)
151 {
152 return(SharedUserData->DosDeviceMap);
153 }
154
155
156 WINBOOL STDCALL
157 GetDiskFreeSpaceA (
158 LPCSTR lpRootPathName,
159 LPDWORD lpSectorsPerCluster,
160 LPDWORD lpBytesPerSector,
161 LPDWORD lpNumberOfFreeClusters,
162 LPDWORD lpTotalNumberOfClusters
163 )
164 {
165 UNICODE_STRING RootPathNameU;
166 ANSI_STRING RootPathName;
167 WINBOOL Result;
168
169 RtlInitAnsiString (&RootPathName,
170 (LPSTR)lpRootPathName);
171
172 RtlInitUnicodeString (&RootPathNameU,
173 NULL);
174
175 if (lpRootPathName)
176 {
177 /* convert ansi (or oem) string to unicode */
178 if (bIsFileApiAnsi)
179 RtlAnsiStringToUnicodeString (&RootPathNameU,
180 &RootPathName,
181 TRUE);
182 else
183 RtlOemStringToUnicodeString (&RootPathNameU,
184 &RootPathName,
185 TRUE);
186 }
187
188 Result = GetDiskFreeSpaceW (RootPathNameU.Buffer,
189 lpSectorsPerCluster,
190 lpBytesPerSector,
191 lpNumberOfFreeClusters,
192 lpTotalNumberOfClusters);
193
194 if (lpRootPathName)
195 {
196 RtlFreeHeap (RtlGetProcessHeap (),
197 0,
198 RootPathNameU.Buffer);
199 }
200
201 return Result;
202 }
203
204
205 WINBOOL STDCALL
206 GetDiskFreeSpaceW(
207 LPCWSTR lpRootPathName,
208 LPDWORD lpSectorsPerCluster,
209 LPDWORD lpBytesPerSector,
210 LPDWORD lpNumberOfFreeClusters,
211 LPDWORD lpTotalNumberOfClusters
212 )
213 {
214 FILE_FS_SIZE_INFORMATION FileFsSize;
215 IO_STATUS_BLOCK IoStatusBlock;
216 WCHAR RootPathName[MAX_PATH];
217 HANDLE hFile;
218 NTSTATUS errCode;
219
220 if (lpRootPathName)
221 {
222 wcsncpy (RootPathName, lpRootPathName, 3);
223 }
224 else
225 {
226 GetCurrentDirectoryW (MAX_PATH, RootPathName);
227 RootPathName[3] = 0;
228 }
229
230 hFile = InternalOpenDirW(lpRootPathName, FALSE);
231 if (INVALID_HANDLE_VALUE == hFile)
232 {
233 return FALSE;
234 }
235
236 errCode = NtQueryVolumeInformationFile(hFile,
237 &IoStatusBlock,
238 &FileFsSize,
239 sizeof(FILE_FS_SIZE_INFORMATION),
240 FileFsSizeInformation);
241 if (!NT_SUCCESS(errCode))
242 {
243 CloseHandle(hFile);
244 SetLastErrorByStatus (errCode);
245 return FALSE;
246 }
247
248 *lpBytesPerSector = FileFsSize.BytesPerSector;
249 *lpSectorsPerCluster = FileFsSize.SectorsPerAllocationUnit;
250 *lpNumberOfFreeClusters = FileFsSize.AvailableAllocationUnits.u.LowPart;
251 *lpTotalNumberOfClusters = FileFsSize.TotalAllocationUnits.u.LowPart;
252 CloseHandle(hFile);
253 return TRUE;
254 }
255
256
257 WINBOOL STDCALL
258 GetDiskFreeSpaceExA (
259 LPCSTR lpDirectoryName,
260 PULARGE_INTEGER lpFreeBytesAvailableToCaller,
261 PULARGE_INTEGER lpTotalNumberOfBytes,
262 PULARGE_INTEGER lpTotalNumberOfFreeBytes
263 )
264 {
265 UNICODE_STRING DirectoryNameU;
266 ANSI_STRING DirectoryName;
267 WINBOOL Result;
268
269 RtlInitAnsiString (&DirectoryName,
270 (LPSTR)lpDirectoryName);
271
272 RtlInitUnicodeString (&DirectoryNameU,
273 NULL);
274
275 if (lpDirectoryName)
276 {
277 /* convert ansi (or oem) string to unicode */
278 if (bIsFileApiAnsi)
279 RtlAnsiStringToUnicodeString (&DirectoryNameU,
280 &DirectoryName,
281 TRUE);
282 else
283 RtlOemStringToUnicodeString (&DirectoryNameU,
284 &DirectoryName,
285 TRUE);
286 }
287
288 Result = GetDiskFreeSpaceExW (DirectoryNameU.Buffer,
289 lpFreeBytesAvailableToCaller,
290 lpTotalNumberOfBytes,
291 lpTotalNumberOfFreeBytes);
292
293 if (lpDirectoryName)
294 {
295 RtlFreeHeap (RtlGetProcessHeap (),
296 0,
297 DirectoryNameU.Buffer);
298 }
299
300 return Result;
301 }
302
303
304 WINBOOL STDCALL
305 GetDiskFreeSpaceExW(
306 LPCWSTR lpDirectoryName,
307 PULARGE_INTEGER lpFreeBytesAvailableToCaller,
308 PULARGE_INTEGER lpTotalNumberOfBytes,
309 PULARGE_INTEGER lpTotalNumberOfFreeBytes
310 )
311 {
312 FILE_FS_SIZE_INFORMATION FileFsSize;
313 IO_STATUS_BLOCK IoStatusBlock;
314 ULARGE_INTEGER BytesPerCluster;
315 WCHAR RootPathName[MAX_PATH];
316 HANDLE hFile;
317 NTSTATUS errCode;
318
319 if (lpDirectoryName)
320 {
321 wcsncpy (RootPathName, lpDirectoryName, 3);
322 }
323 else
324 {
325 GetCurrentDirectoryW (MAX_PATH, RootPathName);
326 RootPathName[3] = 0;
327 }
328
329 hFile = InternalOpenDirW(lpDirectoryName, FALSE);
330 if (INVALID_HANDLE_VALUE == hFile)
331 {
332 return FALSE;
333 }
334
335 errCode = NtQueryVolumeInformationFile(hFile,
336 &IoStatusBlock,
337 &FileFsSize,
338 sizeof(FILE_FS_SIZE_INFORMATION),
339 FileFsSizeInformation);
340 if (!NT_SUCCESS(errCode))
341 {
342 CloseHandle(hFile);
343 SetLastErrorByStatus (errCode);
344 return FALSE;
345 }
346
347 BytesPerCluster.QuadPart =
348 FileFsSize.BytesPerSector * FileFsSize.SectorsPerAllocationUnit;
349
350 // FIXME: Use quota information
351 if (lpFreeBytesAvailableToCaller)
352 lpFreeBytesAvailableToCaller->QuadPart =
353 BytesPerCluster.QuadPart * FileFsSize.AvailableAllocationUnits.QuadPart;
354
355 if (lpTotalNumberOfBytes)
356 lpTotalNumberOfBytes->QuadPart =
357 BytesPerCluster.QuadPart * FileFsSize.TotalAllocationUnits.QuadPart;
358 if (lpTotalNumberOfFreeBytes)
359 lpTotalNumberOfFreeBytes->QuadPart =
360 BytesPerCluster.QuadPart * FileFsSize.AvailableAllocationUnits.QuadPart;
361
362 CloseHandle(hFile);
363 return TRUE;
364 }
365
366
367 UINT STDCALL
368 GetDriveTypeA(LPCSTR lpRootPathName)
369 {
370 UNICODE_STRING RootPathNameU;
371 ANSI_STRING RootPathName;
372 UINT Result;
373
374 RtlInitAnsiString (&RootPathName,
375 (LPSTR)lpRootPathName);
376
377 /* convert ansi (or oem) string to unicode */
378 if (bIsFileApiAnsi)
379 RtlAnsiStringToUnicodeString (&RootPathNameU,
380 &RootPathName,
381 TRUE);
382 else
383 RtlOemStringToUnicodeString (&RootPathNameU,
384 &RootPathName,
385 TRUE);
386
387 Result = GetDriveTypeW (RootPathNameU.Buffer);
388
389 RtlFreeHeap (RtlGetProcessHeap (),
390 0,
391 RootPathNameU.Buffer);
392
393 return Result;
394 }
395
396 UINT STDCALL
397 GetDriveTypeW(LPCWSTR lpRootPathName)
398 {
399 FILE_FS_DEVICE_INFORMATION FileFsDevice;
400 IO_STATUS_BLOCK IoStatusBlock;
401
402 HANDLE hFile;
403 NTSTATUS errCode;
404
405 hFile = InternalOpenDirW(lpRootPathName, FALSE);
406 if (hFile == INVALID_HANDLE_VALUE)
407 {
408 return 0;
409 }
410
411 errCode = NtQueryVolumeInformationFile (hFile,
412 &IoStatusBlock,
413 &FileFsDevice,
414 sizeof(FILE_FS_DEVICE_INFORMATION),
415 FileFsDeviceInformation);
416 if (!NT_SUCCESS(errCode))
417 {
418 CloseHandle(hFile);
419 SetLastErrorByStatus (errCode);
420 return 0;
421 }
422 CloseHandle(hFile);
423 return (UINT)FileFsDevice.DeviceType;
424 }
425
426
427 WINBOOL STDCALL
428 GetVolumeInformationA(
429 LPCSTR lpRootPathName,
430 LPSTR lpVolumeNameBuffer,
431 DWORD nVolumeNameSize,
432 LPDWORD lpVolumeSerialNumber,
433 LPDWORD lpMaximumComponentLength,
434 LPDWORD lpFileSystemFlags,
435 LPSTR lpFileSystemNameBuffer,
436 DWORD nFileSystemNameSize
437 )
438 {
439 UNICODE_STRING RootPathNameU;
440 UNICODE_STRING FileSystemNameU;
441 UNICODE_STRING VolumeNameU;
442 ANSI_STRING RootPathName;
443 ANSI_STRING VolumeName;
444 ANSI_STRING FileSystemName;
445 WINBOOL Result;
446
447 RtlInitAnsiString (&RootPathName,
448 (LPSTR)lpRootPathName);
449
450 /* convert ansi (or oem) string to unicode */
451 if (bIsFileApiAnsi)
452 RtlAnsiStringToUnicodeString (&RootPathNameU,
453 &RootPathName,
454 TRUE);
455 else
456 RtlOemStringToUnicodeString (&RootPathNameU,
457 &RootPathName,
458 TRUE);
459
460 VolumeNameU.Length = 0;
461 VolumeNameU.MaximumLength = nVolumeNameSize * sizeof(WCHAR);
462 VolumeNameU.Buffer = RtlAllocateHeap (RtlGetProcessHeap (),
463 0,
464 VolumeNameU.MaximumLength);
465
466 FileSystemNameU.Length = 0;
467 FileSystemNameU.MaximumLength = nFileSystemNameSize * sizeof(WCHAR);
468 FileSystemNameU.Buffer = RtlAllocateHeap (RtlGetProcessHeap (),
469 0,
470 FileSystemNameU.MaximumLength);
471
472 Result = GetVolumeInformationW (RootPathNameU.Buffer,
473 VolumeNameU.Buffer,
474 nVolumeNameSize,
475 lpVolumeSerialNumber,
476 lpMaximumComponentLength,
477 lpFileSystemFlags,
478 FileSystemNameU.Buffer,
479 nFileSystemNameSize);
480
481 if (Result)
482 {
483 VolumeNameU.Length = wcslen(VolumeNameU.Buffer) * sizeof(WCHAR);
484 VolumeName.Length = 0;
485 VolumeName.MaximumLength = nVolumeNameSize;
486 VolumeName.Buffer = lpVolumeNameBuffer;
487
488 FileSystemNameU.Length = wcslen(FileSystemNameU.Buffer) * sizeof(WCHAR);
489 FileSystemName.Length = 0;
490 FileSystemName.MaximumLength = nFileSystemNameSize;
491 FileSystemName.Buffer = lpFileSystemNameBuffer;
492
493 /* convert unicode strings to ansi (or oem) */
494 if (bIsFileApiAnsi)
495 {
496 RtlUnicodeStringToAnsiString (&VolumeName,
497 &VolumeNameU,
498 FALSE);
499 RtlUnicodeStringToAnsiString (&FileSystemName,
500 &FileSystemNameU,
501 FALSE);
502 }
503 else
504 {
505 RtlUnicodeStringToOemString (&VolumeName,
506 &VolumeNameU,
507 FALSE);
508 RtlUnicodeStringToOemString (&FileSystemName,
509 &FileSystemNameU,
510 FALSE);
511 }
512 }
513
514 RtlFreeHeap (RtlGetProcessHeap (),
515 0,
516 RootPathNameU.Buffer);
517 RtlFreeHeap (RtlGetProcessHeap (),
518 0,
519 VolumeNameU.Buffer);
520 RtlFreeHeap (RtlGetProcessHeap (),
521 0,
522 FileSystemNameU.Buffer);
523
524 return Result;
525 }
526
527
528
529
530 #define FS_VOLUME_BUFFER_SIZE (MAX_PATH + sizeof(FILE_FS_VOLUME_INFORMATION))
531
532 #define FS_ATTRIBUTE_BUFFER_SIZE (MAX_PATH + sizeof(FILE_FS_ATTRIBUTE_INFORMATION))
533
534
535 WINBOOL STDCALL
536 GetVolumeInformationW(
537 LPCWSTR lpRootPathName,
538 LPWSTR lpVolumeNameBuffer,
539 DWORD nVolumeNameSize,
540 LPDWORD lpVolumeSerialNumber,
541 LPDWORD lpMaximumComponentLength,
542 LPDWORD lpFileSystemFlags,
543 LPWSTR lpFileSystemNameBuffer,
544 DWORD nFileSystemNameSize
545 )
546 {
547 PFILE_FS_VOLUME_INFORMATION FileFsVolume;
548 PFILE_FS_ATTRIBUTE_INFORMATION FileFsAttribute;
549 IO_STATUS_BLOCK IoStatusBlock;
550 OBJECT_ATTRIBUTES ObjectAttributes;
551 USHORT Buffer[FS_VOLUME_BUFFER_SIZE];
552 USHORT Buffer2[FS_ATTRIBUTE_BUFFER_SIZE];
553
554 HANDLE hFile;
555 NTSTATUS errCode;
556
557 FileFsVolume = (PFILE_FS_VOLUME_INFORMATION)Buffer;
558 FileFsAttribute = (PFILE_FS_ATTRIBUTE_INFORMATION)Buffer2;
559
560 DPRINT("FileFsVolume %p\n", FileFsVolume);
561 DPRINT("FileFsAttribute %p\n", FileFsAttribute);
562
563 hFile = InternalOpenDirW(lpRootPathName, FALSE);
564 if (hFile == INVALID_HANDLE_VALUE)
565 {
566 return FALSE;
567 }
568
569 DPRINT("hFile: %x\n", hFile);
570 errCode = NtQueryVolumeInformationFile(hFile,
571 &IoStatusBlock,
572 FileFsVolume,
573 FS_VOLUME_BUFFER_SIZE,
574 FileFsVolumeInformation);
575 if ( !NT_SUCCESS(errCode) ) {
576 DPRINT("Status: %x\n", errCode);
577 CloseHandle(hFile);
578 SetLastErrorByStatus (errCode);
579 return FALSE;
580 }
581
582 if (lpVolumeSerialNumber)
583 *lpVolumeSerialNumber = FileFsVolume->VolumeSerialNumber;
584
585 if (lpVolumeNameBuffer)
586 wcsncpy (lpVolumeNameBuffer,
587 FileFsVolume->VolumeLabel,
588 min(nVolumeNameSize,MAX_PATH));
589
590 errCode = NtQueryVolumeInformationFile (hFile,
591 &IoStatusBlock,
592 FileFsAttribute,
593 FS_ATTRIBUTE_BUFFER_SIZE,
594 FileFsAttributeInformation);
595 if (!NT_SUCCESS(errCode))
596 {
597 DPRINT("Status: %x\n", errCode);
598 CloseHandle(hFile);
599 SetLastErrorByStatus (errCode);
600 return FALSE;
601 }
602
603 if (lpFileSystemFlags)
604 *lpFileSystemFlags = FileFsAttribute->FileSystemAttributes;
605 if (lpMaximumComponentLength)
606 *lpMaximumComponentLength = FileFsAttribute->MaximumComponentNameLength;
607 if (lpFileSystemNameBuffer)
608 wcsncpy(lpFileSystemNameBuffer, FileFsAttribute->FileSystemName,min(nFileSystemNameSize,MAX_PATH));
609
610 CloseHandle(hFile);
611 return TRUE;
612 }
613
614
615 WINBOOL
616 STDCALL
617 SetVolumeLabelA (
618 LPCSTR lpRootPathName,
619 LPCSTR lpVolumeName
620 )
621 {
622 UNICODE_STRING RootPathNameU;
623 ANSI_STRING RootPathName;
624 UNICODE_STRING VolumeNameU;
625 ANSI_STRING VolumeName;
626 WINBOOL Result;
627
628 RtlInitAnsiString (&RootPathName,
629 (LPSTR)lpRootPathName);
630 RtlInitAnsiString (&VolumeName,
631 (LPSTR)lpVolumeName);
632
633 /* convert ansi (or oem) strings to unicode */
634 if (bIsFileApiAnsi)
635 {
636 RtlAnsiStringToUnicodeString (&RootPathNameU,
637 &RootPathName,
638 TRUE);
639 RtlAnsiStringToUnicodeString (&VolumeNameU,
640 &VolumeName,
641 TRUE);
642 }
643 else
644 {
645 RtlOemStringToUnicodeString (&RootPathNameU,
646 &RootPathName,
647 TRUE);
648 RtlOemStringToUnicodeString (&VolumeNameU,
649 &VolumeName,
650 TRUE);
651 }
652
653 Result = SetVolumeLabelW (RootPathNameU.Buffer,
654 VolumeNameU.Buffer);
655
656 RtlFreeHeap (RtlGetProcessHeap (),
657 0,
658 RootPathNameU.Buffer);
659 RtlFreeHeap (RtlGetProcessHeap (),
660 0,
661 VolumeNameU.Buffer);
662
663 return Result;
664 }
665
666
667 WINBOOL STDCALL
668 SetVolumeLabelW(LPCWSTR lpRootPathName,
669 LPCWSTR lpVolumeName)
670 {
671 PFILE_FS_LABEL_INFORMATION LabelInfo;
672 IO_STATUS_BLOCK IoStatusBlock;
673 ULONG LabelLength;
674 HANDLE hFile;
675 NTSTATUS Status;
676
677 LabelLength = wcslen(lpVolumeName) * sizeof(WCHAR);
678 LabelInfo = RtlAllocateHeap(RtlGetProcessHeap(),
679 0,
680 sizeof(FILE_FS_LABEL_INFORMATION) +
681 LabelLength);
682 LabelInfo->VolumeLabelLength = LabelLength;
683 wcscpy(LabelInfo->VolumeLabel,
684 lpVolumeName);
685
686 hFile = InternalOpenDirW(lpRootPathName, TRUE);
687 if (INVALID_HANDLE_VALUE == hFile)
688 {
689 return FALSE;
690 }
691
692 Status = NtSetVolumeInformationFile(hFile,
693 &IoStatusBlock,
694 LabelInfo,
695 sizeof(FILE_FS_LABEL_INFORMATION) +
696 LabelLength,
697 FileFsLabelInformation);
698
699 RtlFreeHeap(RtlGetProcessHeap(),
700 0,
701 LabelInfo);
702
703 if (!NT_SUCCESS(Status))
704 {
705 DPRINT("Status: %x\n", Status);
706 CloseHandle(hFile);
707 SetLastErrorByStatus(Status);
708 return FALSE;
709 }
710
711 CloseHandle(hFile);
712 return TRUE;
713 }
714
715 /* EOF */