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