Synchronize with trunk revision 59781.
[reactos.git] / dll / win32 / kernel32 / client / file / disk.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS system libraries
4 * FILE: lib/kernel32/file/disk.c
5 * PURPOSE: Disk and Drive functions
6 * PROGRAMMER: Ariadne ( ariadne@xs4all.nl)
7 * Erik Bos, Alexandre Julliard :
8 * 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 <k32.h>
22 #define NDEBUG
23 #include <debug.h>
24 DEBUG_CHANNEL(kernel32file);
25
26 #define MAX_DOS_DRIVES 26
27 HANDLE WINAPI InternalOpenDirW(IN LPCWSTR DirName, IN BOOLEAN Write);
28
29 /*
30 * @implemented
31 */
32 /* Synced to Wine-2008/12/28 */
33 DWORD
34 WINAPI
35 GetLogicalDriveStringsA(IN DWORD nBufferLength,
36 IN LPSTR lpBuffer)
37 {
38 DWORD drive, count;
39 DWORD dwDriveMap;
40 LPSTR p;
41
42 dwDriveMap = GetLogicalDrives();
43
44 for (drive = count = 0; drive < MAX_DOS_DRIVES; drive++)
45 {
46 if (dwDriveMap & (1<<drive))
47 count++;
48 }
49
50
51 if ((count * 4) + 1 > nBufferLength) return ((count * 4) + 1);
52
53 p = lpBuffer;
54
55 for (drive = 0; drive < MAX_DOS_DRIVES; drive++)
56 if (dwDriveMap & (1<<drive))
57 {
58 *p++ = 'A' + (UCHAR)drive;
59 *p++ = ':';
60 *p++ = '\\';
61 *p++ = '\0';
62 }
63 *p = '\0';
64
65 return (count * 4);
66 }
67
68 /*
69 * @implemented
70 */
71 /* Synced to Wine-2008/12/28 */
72 DWORD
73 WINAPI
74 GetLogicalDriveStringsW(IN DWORD nBufferLength,
75 IN LPWSTR lpBuffer)
76 {
77 DWORD drive, count;
78 DWORD dwDriveMap;
79 LPWSTR p;
80
81 dwDriveMap = GetLogicalDrives();
82
83 for (drive = count = 0; drive < MAX_DOS_DRIVES; drive++)
84 {
85 if (dwDriveMap & (1<<drive))
86 count++;
87 }
88
89 if ((count * 4) + 1 > nBufferLength) return ((count * 4) + 1);
90
91 p = lpBuffer;
92 for (drive = 0; drive < MAX_DOS_DRIVES; drive++)
93 if (dwDriveMap & (1<<drive))
94 {
95 *p++ = (WCHAR)('A' + drive);
96 *p++ = (WCHAR)':';
97 *p++ = (WCHAR)'\\';
98 *p++ = (WCHAR)'\0';
99 }
100 *p = (WCHAR)'\0';
101
102 return (count * 4);
103 }
104
105 /*
106 * @implemented
107 */
108 /* Synced to Wine-? */
109 DWORD
110 WINAPI
111 GetLogicalDrives(VOID)
112 {
113 NTSTATUS Status;
114 PROCESS_DEVICEMAP_INFORMATION ProcessDeviceMapInfo;
115
116 /* Get the Device Map for this Process */
117 Status = NtQueryInformationProcess(NtCurrentProcess(),
118 ProcessDeviceMap,
119 &ProcessDeviceMapInfo,
120 sizeof(ProcessDeviceMapInfo),
121 NULL);
122
123 /* Return the Drive Map */
124 if (!NT_SUCCESS(Status))
125 {
126 BaseSetLastNTError(Status);
127 return 0;
128 }
129
130 return ProcessDeviceMapInfo.Query.DriveMap;
131 }
132
133 /*
134 * @implemented
135 */
136 BOOL
137 WINAPI
138 GetDiskFreeSpaceA(IN LPCSTR lpRootPathName,
139 OUT LPDWORD lpSectorsPerCluster,
140 OUT LPDWORD lpBytesPerSector,
141 OUT LPDWORD lpNumberOfFreeClusters,
142 OUT LPDWORD lpTotalNumberOfClusters)
143 {
144 PWCHAR RootPathNameW=NULL;
145
146 if (lpRootPathName)
147 {
148 if (!(RootPathNameW = FilenameA2W(lpRootPathName, FALSE)))
149 return FALSE;
150 }
151
152 return GetDiskFreeSpaceW (RootPathNameW,
153 lpSectorsPerCluster,
154 lpBytesPerSector,
155 lpNumberOfFreeClusters,
156 lpTotalNumberOfClusters);
157 }
158
159 /*
160 * @implemented
161 */
162 BOOL
163 WINAPI
164 GetDiskFreeSpaceW(IN LPCWSTR lpRootPathName,
165 OUT LPDWORD lpSectorsPerCluster,
166 OUT LPDWORD lpBytesPerSector,
167 OUT LPDWORD lpNumberOfFreeClusters,
168 OUT LPDWORD lpTotalNumberOfClusters)
169 {
170 FILE_FS_SIZE_INFORMATION FileFsSize;
171 IO_STATUS_BLOCK IoStatusBlock;
172 WCHAR RootPathName[MAX_PATH];
173 HANDLE hFile;
174 NTSTATUS errCode;
175
176 if (lpRootPathName)
177 {
178 wcsncpy (RootPathName, lpRootPathName, 3);
179 }
180 else
181 {
182 GetCurrentDirectoryW (MAX_PATH, RootPathName);
183 }
184 RootPathName[3] = 0;
185
186 hFile = InternalOpenDirW(RootPathName, FALSE);
187 if (INVALID_HANDLE_VALUE == hFile)
188 {
189 SetLastError(ERROR_PATH_NOT_FOUND);
190 return FALSE;
191 }
192
193 errCode = NtQueryVolumeInformationFile(hFile,
194 &IoStatusBlock,
195 &FileFsSize,
196 sizeof(FILE_FS_SIZE_INFORMATION),
197 FileFsSizeInformation);
198 if (!NT_SUCCESS(errCode))
199 {
200 CloseHandle(hFile);
201 BaseSetLastNTError (errCode);
202 return FALSE;
203 }
204
205 if (lpSectorsPerCluster)
206 *lpSectorsPerCluster = FileFsSize.SectorsPerAllocationUnit;
207 if (lpBytesPerSector)
208 *lpBytesPerSector = FileFsSize.BytesPerSector;
209 if (lpNumberOfFreeClusters)
210 *lpNumberOfFreeClusters = FileFsSize.AvailableAllocationUnits.u.LowPart;
211 if (lpTotalNumberOfClusters)
212 *lpTotalNumberOfClusters = FileFsSize.TotalAllocationUnits.u.LowPart;
213 CloseHandle(hFile);
214
215 return TRUE;
216 }
217
218 /*
219 * @implemented
220 */
221 BOOL
222 WINAPI
223 GetDiskFreeSpaceExA(IN LPCSTR lpDirectoryName OPTIONAL,
224 OUT PULARGE_INTEGER lpFreeBytesAvailableToCaller,
225 OUT PULARGE_INTEGER lpTotalNumberOfBytes,
226 OUT PULARGE_INTEGER lpTotalNumberOfFreeBytes)
227 {
228 PWCHAR DirectoryNameW=NULL;
229
230 if (lpDirectoryName)
231 {
232 if (!(DirectoryNameW = FilenameA2W(lpDirectoryName, FALSE)))
233 return FALSE;
234 }
235
236 return GetDiskFreeSpaceExW (DirectoryNameW ,
237 lpFreeBytesAvailableToCaller,
238 lpTotalNumberOfBytes,
239 lpTotalNumberOfFreeBytes);
240 }
241
242 /*
243 * @implemented
244 */
245 BOOL
246 WINAPI
247 GetDiskFreeSpaceExW(IN LPCWSTR lpDirectoryName OPTIONAL,
248 OUT PULARGE_INTEGER lpFreeBytesAvailableToCaller,
249 OUT PULARGE_INTEGER lpTotalNumberOfBytes,
250 OUT PULARGE_INTEGER lpTotalNumberOfFreeBytes)
251 {
252 union
253 {
254 FILE_FS_SIZE_INFORMATION FsSize;
255 FILE_FS_FULL_SIZE_INFORMATION FsFullSize;
256 } FsInfo;
257 IO_STATUS_BLOCK IoStatusBlock;
258 ULARGE_INTEGER BytesPerCluster;
259 HANDLE hFile;
260 NTSTATUS Status;
261
262 if (lpDirectoryName == NULL)
263 lpDirectoryName = L"\\";
264
265 hFile = InternalOpenDirW(lpDirectoryName, FALSE);
266 if (INVALID_HANDLE_VALUE == hFile)
267 {
268 return FALSE;
269 }
270
271 if (lpFreeBytesAvailableToCaller != NULL || lpTotalNumberOfBytes != NULL)
272 {
273 /* To get the free space available to the user associated with the
274 current thread, try FileFsFullSizeInformation. If this is not
275 supported by the file system, fall back to FileFsSize */
276
277 Status = NtQueryVolumeInformationFile(hFile,
278 &IoStatusBlock,
279 &FsInfo.FsFullSize,
280 sizeof(FsInfo.FsFullSize),
281 FileFsFullSizeInformation);
282
283 if (NT_SUCCESS(Status))
284 {
285 /* Close the handle before returning data
286 to avoid a handle leak in case of a fault! */
287 CloseHandle(hFile);
288
289 BytesPerCluster.QuadPart =
290 FsInfo.FsFullSize.BytesPerSector * FsInfo.FsFullSize.SectorsPerAllocationUnit;
291
292 if (lpFreeBytesAvailableToCaller != NULL)
293 {
294 lpFreeBytesAvailableToCaller->QuadPart =
295 BytesPerCluster.QuadPart * FsInfo.FsFullSize.CallerAvailableAllocationUnits.QuadPart;
296 }
297
298 if (lpTotalNumberOfBytes != NULL)
299 {
300 lpTotalNumberOfBytes->QuadPart =
301 BytesPerCluster.QuadPart * FsInfo.FsFullSize.TotalAllocationUnits.QuadPart;
302 }
303
304 if (lpTotalNumberOfFreeBytes != NULL)
305 {
306 lpTotalNumberOfFreeBytes->QuadPart =
307 BytesPerCluster.QuadPart * FsInfo.FsFullSize.ActualAvailableAllocationUnits.QuadPart;
308 }
309
310 return TRUE;
311 }
312 }
313
314 Status = NtQueryVolumeInformationFile(hFile,
315 &IoStatusBlock,
316 &FsInfo.FsSize,
317 sizeof(FsInfo.FsSize),
318 FileFsSizeInformation);
319
320 /* Close the handle before returning data
321 to avoid a handle leak in case of a fault! */
322 CloseHandle(hFile);
323
324 if (!NT_SUCCESS(Status))
325 {
326 BaseSetLastNTError (Status);
327 return FALSE;
328 }
329
330 BytesPerCluster.QuadPart =
331 FsInfo.FsSize.BytesPerSector * FsInfo.FsSize.SectorsPerAllocationUnit;
332
333 if (lpFreeBytesAvailableToCaller)
334 {
335 lpFreeBytesAvailableToCaller->QuadPart =
336 BytesPerCluster.QuadPart * FsInfo.FsSize.AvailableAllocationUnits.QuadPart;
337 }
338
339 if (lpTotalNumberOfBytes)
340 {
341 lpTotalNumberOfBytes->QuadPart =
342 BytesPerCluster.QuadPart * FsInfo.FsSize.TotalAllocationUnits.QuadPart;
343 }
344
345 if (lpTotalNumberOfFreeBytes)
346 {
347 lpTotalNumberOfFreeBytes->QuadPart =
348 BytesPerCluster.QuadPart * FsInfo.FsSize.AvailableAllocationUnits.QuadPart;
349 }
350
351 return TRUE;
352 }
353
354 /*
355 * @implemented
356 */
357 UINT
358 WINAPI
359 GetDriveTypeA(IN LPCSTR lpRootPathName)
360 {
361 PWCHAR RootPathNameW;
362
363 if (!(RootPathNameW = FilenameA2W(lpRootPathName, FALSE)))
364 return DRIVE_UNKNOWN;
365
366 return GetDriveTypeW(RootPathNameW);
367 }
368
369 /*
370 * @implemented
371 */
372 UINT
373 WINAPI
374 GetDriveTypeW(IN LPCWSTR lpRootPathName)
375 {
376 FILE_FS_DEVICE_INFORMATION FileFsDevice;
377 IO_STATUS_BLOCK IoStatusBlock;
378
379 HANDLE hFile;
380 NTSTATUS errCode;
381
382 hFile = InternalOpenDirW(lpRootPathName, FALSE);
383 if (hFile == INVALID_HANDLE_VALUE)
384 {
385 return DRIVE_NO_ROOT_DIR; /* According to WINE regression tests */
386 }
387
388 errCode = NtQueryVolumeInformationFile (hFile,
389 &IoStatusBlock,
390 &FileFsDevice,
391 sizeof(FILE_FS_DEVICE_INFORMATION),
392 FileFsDeviceInformation);
393 if (!NT_SUCCESS(errCode))
394 {
395 CloseHandle(hFile);
396 BaseSetLastNTError (errCode);
397 return 0;
398 }
399 CloseHandle(hFile);
400
401 switch (FileFsDevice.DeviceType)
402 {
403 case FILE_DEVICE_CD_ROM:
404 case FILE_DEVICE_CD_ROM_FILE_SYSTEM:
405 return DRIVE_CDROM;
406 case FILE_DEVICE_VIRTUAL_DISK:
407 return DRIVE_RAMDISK;
408 case FILE_DEVICE_NETWORK_FILE_SYSTEM:
409 return DRIVE_REMOTE;
410 case FILE_DEVICE_DISK:
411 case FILE_DEVICE_DISK_FILE_SYSTEM:
412 if (FileFsDevice.Characteristics & FILE_REMOTE_DEVICE)
413 return DRIVE_REMOTE;
414 if (FileFsDevice.Characteristics & FILE_REMOVABLE_MEDIA)
415 return DRIVE_REMOVABLE;
416 return DRIVE_FIXED;
417 }
418
419 ERR("Returning DRIVE_UNKNOWN for device type %d\n", FileFsDevice.DeviceType);
420
421 return DRIVE_UNKNOWN;
422 }
423
424 /* EOF */