Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

539 lines
12 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. sparse.c
  5. Abstract:
  6. This file contains code for commands that affect
  7. sparse files.
  8. Author:
  9. Wesley Witt [wesw] 1-March-2000
  10. Revision History:
  11. --*/
  12. #include <precomp.h>
  13. INT
  14. SparseHelp(
  15. IN INT argc,
  16. IN PWSTR argv[]
  17. )
  18. {
  19. DisplayMsg( MSG_USAGE_SPARSE );
  20. return EXIT_CODE_SUCCESS;
  21. }
  22. BOOL
  23. GetSparseFlag(
  24. HANDLE Handle
  25. )
  26. /*++
  27. Routine Description:
  28. Retrieves the sparse attribute bit from an open file handle. If there's
  29. an error (due to the file system not supporting FileAttributeTagInformation)
  30. then we assume that the file cannot be sparse.
  31. Arguments:
  32. Handle - handle to the stream.
  33. Return Value:
  34. TRUE => stream attached to Handle is sparse
  35. FALSE otherwise
  36. --*/
  37. {
  38. FILE_ATTRIBUTE_TAG_INFORMATION TagInformation;
  39. IO_STATUS_BLOCK iosb;
  40. NTSTATUS Status;
  41. Status = NtQueryInformationFile( Handle,
  42. &iosb,
  43. &TagInformation,
  44. sizeof( TagInformation ),
  45. FileAttributeTagInformation );
  46. if (NT_SUCCESS( Status ) &&
  47. (TagInformation.FileAttributes & FILE_ATTRIBUTE_SPARSE_FILE) != 0) {
  48. return TRUE;
  49. } else {
  50. return FALSE;
  51. }
  52. }
  53. INT
  54. SetSparse(
  55. IN INT argc,
  56. IN PWSTR argv[]
  57. )
  58. /*++
  59. Routine Description:
  60. This routine set the file specified as sparse.
  61. Arguments:
  62. argc - The argument count.
  63. argv - Array of Strings of the form :
  64. ' fscutl setsparse <pathname>'.
  65. Return Value:
  66. None
  67. --*/
  68. {
  69. PWSTR Filename = NULL;
  70. HANDLE FileHandle = INVALID_HANDLE_VALUE;
  71. BOOL Status;
  72. DWORD BytesReturned;
  73. INT ExitCode = EXIT_CODE_SUCCESS;
  74. try {
  75. if (argc != 1) {
  76. DisplayMsg( MSG_SETSPARSE_USAGE );
  77. if (argc != 0) {
  78. ExitCode = EXIT_CODE_FAILURE;
  79. }
  80. leave;
  81. }
  82. Filename = GetFullPath( argv[0] );
  83. if (!Filename) {
  84. DisplayError();
  85. ExitCode = EXIT_CODE_FAILURE;
  86. leave;
  87. }
  88. if (!IsVolumeLocalNTFS( Filename[0] )) {
  89. DisplayMsg( MSG_NTFS_REQUIRED );
  90. ExitCode = EXIT_CODE_FAILURE;
  91. leave;
  92. }
  93. FileHandle = CreateFile(
  94. Filename,
  95. GENERIC_WRITE,
  96. FILE_SHARE_READ | FILE_SHARE_WRITE,
  97. NULL,
  98. OPEN_EXISTING,
  99. FILE_ATTRIBUTE_NORMAL,
  100. NULL
  101. );
  102. if (FileHandle == INVALID_HANDLE_VALUE) {
  103. DisplayError();
  104. ExitCode = EXIT_CODE_FAILURE;
  105. leave;
  106. }
  107. Status = DeviceIoControl(
  108. FileHandle,
  109. FSCTL_SET_SPARSE,
  110. NULL,
  111. 0,
  112. NULL,
  113. 0,
  114. &BytesReturned,
  115. (LPOVERLAPPED)NULL
  116. );
  117. if (!Status) {
  118. DisplayError();
  119. ExitCode = EXIT_CODE_FAILURE;
  120. leave;
  121. }
  122. } finally {
  123. if (FileHandle != INVALID_HANDLE_VALUE) {
  124. CloseHandle( FileHandle );
  125. }
  126. free( Filename );
  127. }
  128. return ExitCode;
  129. }
  130. INT
  131. QuerySparse(
  132. IN INT argc,
  133. IN PWSTR argv[]
  134. )
  135. /*++
  136. Routine Description:
  137. This routine queries the file specified to see if it is sparse.
  138. Arguments:
  139. argc - The argument count.
  140. argv - Array of Strings of the form :
  141. ' fscutl setsparse <pathname>'.
  142. Return Value:
  143. None
  144. --*/
  145. {
  146. PWSTR Filename = NULL;
  147. HANDLE FileHandle = INVALID_HANDLE_VALUE;
  148. PVOID Frs;
  149. INT ExitCode = EXIT_CODE_SUCCESS;
  150. try {
  151. if (argc != 1) {
  152. DisplayMsg( MSG_QUERYSPARSE_USAGE );
  153. if (argc != 0) {
  154. ExitCode = EXIT_CODE_FAILURE;
  155. }
  156. leave;
  157. }
  158. Filename = GetFullPath( argv[0] );
  159. if (!Filename) {
  160. DisplayError();
  161. ExitCode = EXIT_CODE_FAILURE;
  162. leave;
  163. }
  164. if (!IsVolumeLocalNTFS( Filename[0] )) {
  165. DisplayMsg( MSG_NTFS_REQUIRED );
  166. ExitCode = EXIT_CODE_FAILURE;
  167. leave;
  168. }
  169. FileHandle = CreateFile(
  170. Filename,
  171. GENERIC_READ,
  172. FILE_SHARE_READ | FILE_SHARE_WRITE,
  173. NULL,
  174. OPEN_EXISTING,
  175. FILE_ATTRIBUTE_NORMAL,
  176. NULL
  177. );
  178. if (FileHandle == INVALID_HANDLE_VALUE) {
  179. DisplayError();
  180. ExitCode = EXIT_CODE_FAILURE;
  181. leave;
  182. }
  183. Filename[2] = 0;
  184. if (GetSparseFlag( FileHandle )) {
  185. DisplayMsg( MSG_SPARSE_IS_SET );
  186. } else {
  187. DisplayMsg( MSG_SPARSE_ISNOT_SET );
  188. }
  189. } finally {
  190. if (FileHandle != INVALID_HANDLE_VALUE) {
  191. CloseHandle( FileHandle );
  192. }
  193. free( Filename );
  194. }
  195. return ExitCode;
  196. }
  197. INT
  198. SetSparseRange(
  199. IN INT argc,
  200. IN PWSTR argv[]
  201. )
  202. /*++
  203. Routine Description:
  204. This routine sets a range of the file as sparse.
  205. Arguments:
  206. argc - The argument count.
  207. argv - Array of Strings of the form :
  208. ' fscutl setsparse <pathname>'.
  209. Return Value:
  210. None
  211. --*/
  212. {
  213. PWSTR Filename = NULL;
  214. HANDLE FileHandle = INVALID_HANDLE_VALUE;
  215. FILE_ZERO_DATA_INFORMATION ZeroData;
  216. ULONG BytesReturned;
  217. BOOL b;
  218. PWSTR EndPtr;
  219. ULONGLONG v;
  220. INT ExitCode = EXIT_CODE_SUCCESS;
  221. try {
  222. if (argc != 3) {
  223. DisplayMsg( MSG_SETSPARSE_RANGE_USAGE );
  224. if (argc != 0) {
  225. ExitCode = EXIT_CODE_FAILURE;
  226. }
  227. leave;
  228. }
  229. Filename = GetFullPath( argv[0] );
  230. if (!Filename) {
  231. DisplayError();
  232. ExitCode = EXIT_CODE_FAILURE;
  233. leave;
  234. }
  235. if (!IsVolumeLocalNTFS( Filename[0] )) {
  236. DisplayMsg( MSG_NTFS_REQUIRED );
  237. ExitCode = EXIT_CODE_FAILURE;
  238. leave;
  239. }
  240. FileHandle = CreateFile(
  241. Filename,
  242. GENERIC_READ | GENERIC_WRITE,
  243. FILE_SHARE_READ,
  244. NULL,
  245. OPEN_EXISTING,
  246. FILE_ATTRIBUTE_NORMAL,
  247. NULL
  248. );
  249. if (FileHandle == INVALID_HANDLE_VALUE) {
  250. DisplayError();
  251. ExitCode = EXIT_CODE_FAILURE;
  252. leave;
  253. }
  254. Filename[2] = 0;
  255. if (!GetSparseFlag( FileHandle )) {
  256. DisplayMsg( MSG_FILE_IS_NOT_SPARSE );
  257. ExitCode = EXIT_CODE_FAILURE;
  258. leave;
  259. }
  260. v = My_wcstoui64( argv[1], &EndPtr, 0 );
  261. if (UnsignedI64NumberCheck( v, EndPtr)) {
  262. DisplayMsg( MSG_SETSPARSE_RANGE_USAGE );
  263. ExitCode = EXIT_CODE_FAILURE;
  264. leave;
  265. }
  266. ZeroData.FileOffset.QuadPart = v;
  267. v = My_wcstoui64( argv[2], &EndPtr, 0 );
  268. if (UnsignedI64NumberCheck( v, EndPtr)) {
  269. DisplayMsg( MSG_SETSPARSE_RANGE_USAGE );
  270. ExitCode = EXIT_CODE_FAILURE;
  271. leave;
  272. }
  273. ZeroData.BeyondFinalZero.QuadPart = v + ZeroData.FileOffset.QuadPart;
  274. b = DeviceIoControl(
  275. FileHandle,
  276. FSCTL_SET_ZERO_DATA,
  277. &ZeroData,
  278. sizeof(ZeroData),
  279. NULL,
  280. 0,
  281. &BytesReturned,
  282. NULL
  283. );
  284. if (!b) {
  285. DisplayError();
  286. ExitCode = EXIT_CODE_FAILURE;
  287. leave;
  288. }
  289. } finally {
  290. if (FileHandle != INVALID_HANDLE_VALUE) {
  291. CloseHandle( FileHandle );
  292. }
  293. free( Filename );
  294. }
  295. return ExitCode;
  296. }
  297. INT
  298. QuerySparseRange(
  299. IN INT argc,
  300. IN PWSTR argv[]
  301. )
  302. /*++
  303. Routine Description:
  304. This routine queries a range of the file specified to see if it is sparse.
  305. Arguments:
  306. argc - The argument count.
  307. argv - Array of Strings of the form :
  308. ' fscutl setsparse <pathname>'.
  309. Return Value:
  310. None
  311. --*/
  312. {
  313. PWSTR Filename = NULL;
  314. HANDLE FileHandle = INVALID_HANDLE_VALUE;
  315. BOOL b;
  316. FILE_ALLOCATED_RANGE_BUFFER RangesIn;
  317. PFILE_ALLOCATED_RANGE_BUFFER Ranges = NULL;
  318. ULONG NumRanges = 0;
  319. ULONG RangesSz = 0;
  320. ULONG BytesReturned;
  321. ULONG i;
  322. ULONG RangesReturned;
  323. LONGLONG LastOffset = 0;
  324. LARGE_INTEGER FileSize;
  325. ULONG gle = 0;
  326. INT ExitCode = EXIT_CODE_SUCCESS;
  327. try {
  328. if (argc != 1) {
  329. DisplayMsg( MSG_QUERYSPARSE_RANGE_USAGE );
  330. if (argc != 0) {
  331. ExitCode = EXIT_CODE_FAILURE;
  332. }
  333. leave;
  334. }
  335. Filename = GetFullPath( argv[0] );
  336. if (!Filename) {
  337. DisplayError();
  338. ExitCode = EXIT_CODE_FAILURE;
  339. leave;
  340. }
  341. if (!IsVolumeLocalNTFS( Filename[0] )) {
  342. DisplayMsg( MSG_NTFS_REQUIRED );
  343. ExitCode = EXIT_CODE_FAILURE;
  344. leave;
  345. }
  346. FileHandle = CreateFile(
  347. Filename,
  348. GENERIC_READ,
  349. FILE_SHARE_READ | FILE_SHARE_WRITE,
  350. NULL,
  351. OPEN_EXISTING,
  352. FILE_ATTRIBUTE_NORMAL,
  353. NULL
  354. );
  355. if (FileHandle == INVALID_HANDLE_VALUE) {
  356. DisplayError();
  357. ExitCode = EXIT_CODE_FAILURE;
  358. leave;
  359. }
  360. Filename[2] = 0;
  361. if (!GetSparseFlag( FileHandle )) {
  362. DisplayMsg( MSG_FILE_IS_NOT_SPARSE );
  363. ExitCode = EXIT_CODE_FAILURE;
  364. leave;
  365. }
  366. NumRanges = 64;
  367. RangesSz = sizeof(FILE_ALLOCATED_RANGE_BUFFER) * NumRanges;
  368. Ranges = (PFILE_ALLOCATED_RANGE_BUFFER) malloc( RangesSz );
  369. if (Ranges == NULL) {
  370. DisplayError();
  371. ExitCode = EXIT_CODE_FAILURE;
  372. leave;
  373. }
  374. memset( Ranges, 0, RangesSz );
  375. GetFileSizeEx( FileHandle, &FileSize );
  376. RangesIn.FileOffset.QuadPart = 0;
  377. RangesIn.Length.QuadPart = FileSize.QuadPart;
  378. do {
  379. b = DeviceIoControl(
  380. FileHandle,
  381. FSCTL_QUERY_ALLOCATED_RANGES,
  382. &RangesIn,
  383. sizeof(RangesIn),
  384. Ranges,
  385. RangesSz,
  386. &BytesReturned,
  387. NULL
  388. );
  389. if (!b) {
  390. gle = GetLastError();
  391. if (gle == ERROR_INSUFFICIENT_BUFFER) {
  392. //
  393. // No data were returned because the buffer is too small
  394. //
  395. free( Ranges );
  396. NumRanges += 64;
  397. RangesSz = sizeof(FILE_ALLOCATED_RANGE_BUFFER) * NumRanges;
  398. Ranges = (PFILE_ALLOCATED_RANGE_BUFFER) malloc( RangesSz );
  399. if (Ranges == NULL) {
  400. DisplayError();
  401. ExitCode = EXIT_CODE_FAILURE;
  402. leave;
  403. }
  404. memset( Ranges, 0, RangesSz );
  405. } else if (gle == ERROR_MORE_DATA) {
  406. } else {
  407. DisplayError();
  408. ExitCode = EXIT_CODE_FAILURE;
  409. leave;
  410. }
  411. }
  412. RangesReturned = BytesReturned / sizeof(FILE_ALLOCATED_RANGE_BUFFER);
  413. for (i=0; i<RangesReturned; i++) {
  414. if (Ranges[i].FileOffset.QuadPart >= LastOffset) {
  415. wprintf( L"sparse range: [%I64d] [%I64d]\n", Ranges[i].FileOffset.QuadPart, Ranges[i].Length.QuadPart );
  416. }
  417. LastOffset = Ranges[i].FileOffset.QuadPart;
  418. }
  419. } while(gle);
  420. } finally {
  421. if (FileHandle != INVALID_HANDLE_VALUE) {
  422. CloseHandle( FileHandle );
  423. }
  424. free( Ranges );
  425. free( Filename );
  426. }
  427. return ExitCode;
  428. }