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