PageRenderTime 77ms CodeModel.GetById 25ms RepoModel.GetById 2ms app.codeStats 0ms

/reactos/dll/win32/kernel32/client/file/disk.c

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