DEFRAG.C
上传用户:shshsw
上传日期:2007-01-06
资源大小:37k
文件大小:18k
源码类别:

磁盘编程

开发平台:

Others

  1. //====================================================================
  2. //
  3. // Defrag.c
  4. //
  5. // Copyright (C) 1997 Mark Russinovich
  6. //
  7. // This program demonstrates the use of NT 4.0 FAT and NTFS cluster
  8. // movement File System Control functions.
  9. //
  10. //====================================================================
  11. #include <windows.h>
  12. #include <stdio.h>
  13. #include <conio.h>
  14. #include "defrag.h"
  15. //--------------------------------------------------------------------
  16. //                         D E F I N E S
  17. //--------------------------------------------------------------------
  18. //
  19. // Interval at which output is paused (in lines)
  20. //
  21. #define PAUSEINTERVAL 24
  22. //
  23. // Size of the buffer we read file mapping information into.
  24. // The buffer is big enough to hold the 16 bytes that 
  25. // come back at the head of the buffer (the number of entries 
  26. // and the starting virtual cluster), as well as 512 pairs
  27. // of [virtual cluster, logical cluster] pairs.
  28. //
  29. #define FILEMAPSIZE (512+2)
  30. //
  31. // Size of the bitmap buffer we pass in. Its large enough to
  32. // hold information for the 16-byte header that's returned
  33. // plus the indicated number of bytes, each of which has 8 bits 
  34. // (imagine that!)
  35. //
  36. #define BITMAPBYTES 4096
  37. #define BITMAPSIZE (BITMAPBYTES+2*sizeof(ULONGLONG))
  38. //
  39. // Invalid longlong number
  40. //
  41. #define LLINVALID ((ULONGLONG) -1)
  42. //--------------------------------------------------------------------
  43. //                        G L O B A L S
  44. //--------------------------------------------------------------------
  45. //
  46. // Handle for the raw volume that was opened
  47. //
  48. HANDLE VolumeHandle;
  49. //
  50. // Buffer to read file mapping information into
  51. //
  52. ULONGLONG FileMap[ FILEMAPSIZE ];
  53. //
  54. // Buffer thats passed to bitmap function
  55. //
  56. BYTE BitMap[ BITMAPSIZE ];
  57. //
  58. // Bit shifting array for efficient processing of the bitmap
  59. //
  60. BYTE BitShift[] = { 1, 2, 4, 8, 16, 32, 64, 128 };
  61. //--------------------------------------------------------------------
  62. //                      F U N C T I O N S
  63. //--------------------------------------------------------------------
  64. //--------------------------------------------------------------------
  65. //
  66. // PrintNtError
  67. //
  68. // Translates an NTDLL error code into its text equivalent. This
  69. // only deals with ones commonly returned by defragmenting FS Control
  70. // commands.
  71. //--------------------------------------------------------------------
  72. void PrintNtError( NTSTATUS Status )
  73. {
  74. switch( Status ) {
  75. case STATUS_SUCCESS:
  76. printf("STATUS_SUCCESSnn");
  77. break;
  78. case STATUS_INVALID_PARAMETER:
  79. printf("STATUS_INVALID_PARAMETERnn");
  80. break;
  81. case STATUS_BUFFER_TOO_SMALL:
  82. printf("STATUS_BUFFER_TOO_SMALLnn");
  83. break;
  84. case STATUS_ALREADY_COMMITTED:
  85. printf("STATUS_ALREADY_COMMITTEDnn");
  86. break;
  87. case STATUS_INVALID_DEVICE_REQUEST:
  88. printf("STATUS_INVALID_DEVICE_REQUESTnn");
  89. break;
  90. default:
  91. printf("0x%08xnn", Status );
  92. break;
  93. }   
  94. }
  95. //--------------------------------------------------------------------
  96. //
  97. // PrintWin32Error
  98. // 
  99. // Translates a Win32 error into a text equivalent
  100. //
  101. //--------------------------------------------------------------------
  102. void PrintWin32Error( DWORD ErrorCode )
  103. {
  104. LPVOID lpMsgBuf;
  105.  
  106. FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
  107. NULL, ErrorCode, 
  108. MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
  109. (LPTSTR) &lpMsgBuf, 0, NULL );
  110. printf("%sn", lpMsgBuf );
  111. LocalFree( lpMsgBuf );
  112. }
  113. //--------------------------------------------------------------------
  114. //
  115. // PrintHelp
  116. //
  117. //--------------------------------------------------------------------
  118. void PrintHelp()
  119. {
  120. printf("nCommands:nn");
  121. printf("Dump bitmap free clusters:n");
  122. printf("     b [offset]n");
  123. printf("Enumerate clusters of file:n");
  124. printf("     n [filename]n");
  125. printf("Move clusters:n");
  126. printf("     m [file] [off] [tgt] [numclust]n");
  127. printf("Quit:n");
  128. printf("     qn");
  129. printf("n");
  130. }
  131. //--------------------------------------------------------------------
  132. //
  133. // PauseOutput
  134. //
  135. // After n lines have printed, stop and wait for the user to continue.
  136. // 'q' causes the function to return false.
  137. //
  138. //--------------------------------------------------------------------
  139. BOOL PauseOutput( DWORD Count ) 
  140. {
  141. char key;
  142. if( !(Count % PAUSEINTERVAL )) {
  143. printf("more ('q' to quit): "); 
  144. fflush(stdout);
  145. key = getch();
  146. printf("n");
  147. if( key == 'q' ) {
  148. printf("nEnumeration aborted.nn");
  149. return FALSE;
  150. }
  151. }
  152. return TRUE;
  153. }
  154. //--------------------------------------------------------------------
  155. //
  156. // OpenVolume
  157. //
  158. // Open the volume for defragging, a flag that is new for NT 4.0.
  159. //
  160. //--------------------------------------------------------------------
  161. DWORD OpenVolume( int DriveId ) 
  162. {
  163. static char volumeName[] = "\\.\A:";
  164. //
  165. // open the volume
  166. //
  167. volumeName[4] = DriveId + 'A'; 
  168. VolumeHandle = CreateFile( volumeName, GENERIC_READ, 
  169. FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 
  170. 0, 0 );
  171. if( VolumeHandle == INVALID_HANDLE_VALUE ) {
  172. return GetLastError();
  173. }
  174. return ERROR_SUCCESS;
  175. }
  176. //--------------------------------------------------------------------
  177. //
  178. // DumpBitmap
  179. //
  180. // Start at the offset specified (if any) and dumps all the free
  181. // clusters on the volume to the end of the volume or until
  182. // the user stops the dump with a 'q'.
  183. //
  184. //--------------------------------------------------------------------
  185. void DumpBitmap( char *argument )
  186. {
  187. DWORD status;
  188. PBITMAP_DESCRIPTOR bitMappings;
  189. ULONGLONG cluster;
  190. ULONGLONG numFree;
  191. ULONGLONG startLcn;
  192. ULONGLONG nextLcn;
  193. ULONGLONG lastLcn;
  194. IO_STATUS_BLOCK ioStatus;
  195. ULONGLONG i;
  196. int lines;
  197. //
  198. // Start scanning at the cluster offset the user specifies
  199. //
  200. bitMappings = (PBITMAP_DESCRIPTOR) BitMap;
  201. cluster = 0;
  202. nextLcn = 0;
  203. lines = 0;
  204. lastLcn = LLINVALID;
  205. sscanf( argument, " %I64d ", &nextLcn );
  206. while( !(status = NtFsControlFile( VolumeHandle, NULL, NULL, 0, &ioStatus,
  207. FSCTL_GET_VOLUME_BITMAP,
  208. &nextLcn, sizeof( cluster ),
  209. bitMappings, BITMAPSIZE )) ||
  210.  status == STATUS_BUFFER_OVERFLOW ||
  211.  status == STATUS_PENDING ) {
  212. // 
  213. // If the operation is pending, wait for it to finish
  214. //
  215. if( status == STATUS_PENDING ) {
  216. WaitForSingleObject( VolumeHandle, INFINITE );
  217. //
  218. // Get the status from the status block
  219. //
  220. if( ioStatus.Status != STATUS_SUCCESS && 
  221. ioStatus.Status != STATUS_BUFFER_OVERFLOW ) {
  222. printf("nGet Volume Bitmap: ");
  223. PrintNtError( ioStatus.Status );
  224. return;
  225. }
  226. }
  227. //
  228. // Print the range we're starting at
  229. //
  230. if( !lines ) {
  231. printf("nFree clusters starting at offset: %I64dn", 
  232. bitMappings->StartLcn );
  233. }
  234. //
  235. // Scan through the returned bitmap info, looking for empty clusters
  236. //
  237. startLcn = bitMappings->StartLcn;
  238. numFree = 0;
  239. cluster = LLINVALID;
  240. for( i = 0; i < min( bitMappings->ClustersToEndOfVol, 8*BITMAPBYTES); i++ ) {
  241. if( !(bitMappings->Map[ i/8 ] & BitShift[ i % 8 ])) {
  242. //
  243. // Cluster is free
  244. //
  245. if( cluster == LLINVALID ) {
  246. cluster = startLcn + i;
  247. numFree = 1;
  248. } else {
  249. numFree++;
  250. }
  251. } else {
  252. //
  253. // Cluster is not free
  254. //
  255. if( cluster != LLINVALID ) {
  256. if( lastLcn == cluster ) {
  257. lastLcn = LLINVALID;
  258. } else {
  259. //
  260. // See if we should continue
  261. //
  262. if( !PauseOutput( ++lines ) ) {
  263. return;
  264. }
  265. printf("   LCN: %I64d LEN: %I64dn", cluster, numFree );
  266. numFree = 0;
  267. lastLcn = cluster;
  268. cluster = LLINVALID;
  269. }
  270. }
  271. }
  272. //
  273. // See if we should continue
  274. //
  275. if( !PauseOutput( ++lines ) ) {
  276. return;
  277. }
  278. //
  279. // Print any remaining
  280. //
  281. if( cluster != LLINVALID && lastLcn != cluster ) {
  282. printf("   LCN: %I64d LEN: %I64dn", cluster, numFree );
  283. numFree = 0;
  284. cluster = LLINVALID;
  285. }
  286. //
  287. // End of volume?
  288. //
  289. if( status != STATUS_BUFFER_OVERFLOW ) {
  290. printf("End of volume.nn");
  291. return;
  292. }
  293. //
  294. // Move to the next block
  295. //
  296. nextLcn = bitMappings->StartLcn + i;
  297. }
  298. //
  299. // We only get here when there's an error
  300. //
  301. printf("nGet Volume Bitmap: ");
  302. PrintNtError( status );
  303. }
  304. //--------------------------------------------------------------------
  305. //
  306. // DumpFile
  307. //
  308. // Dumps the clusters belonging to the specified file until the
  309. // end of the file or the user stops the dump.
  310. //
  311. //--------------------------------------------------------------------
  312. void DumpFile( int drive, char *argument )
  313. {
  314. DWORD status;
  315. int i;
  316. HANDLE sourceFile;
  317. char fileName[MAX_PATH];
  318. IO_STATUS_BLOCK ioStatus;
  319. ULONGLONG startVcn;
  320. PGET_RETRIEVAL_DESCRIPTOR fileMappings;
  321. int lines = 0;
  322. //
  323. // Make the name into a real pathname
  324. //
  325. if( strlen( argument ) > 1 && argument[0] != '\' &&
  326. argument[0] != 'A'+drive &&
  327. argument[0] != 'a'+drive ) 
  328. sprintf(fileName, "%C:\%s", drive+'A', argument );
  329. else if( strlen( argument ) > 1 && argument[0] == '\') 
  330. sprintf(fileName, "%C:%s", drive+'A', argument );
  331. else
  332. strcpy(fileName, argument );
  333. printf("nClusters for file: %sn", fileName );
  334. //
  335. // Open the file
  336. //
  337. sourceFile = CreateFile( fileName, GENERIC_READ, 
  338. FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 
  339. FILE_FLAG_NO_BUFFERING, 0 );
  340. if( sourceFile == INVALID_HANDLE_VALUE ) {
  341. printf("Failed to open file: ");
  342. PrintWin32Error( GetLastError() );
  343. return;
  344. }
  345. //
  346. // Start dumping the mapping information. Go until we hit the end of the
  347. // file.
  348. //
  349. startVcn = 0;
  350. fileMappings = (PGET_RETRIEVAL_DESCRIPTOR) FileMap;
  351. while( !(status = NtFsControlFile( sourceFile, NULL, NULL, 0, &ioStatus,
  352. FSCTL_GET_RETRIEVAL_POINTERS,
  353. &startVcn, sizeof( startVcn ),
  354. fileMappings, FILEMAPSIZE * sizeof(LARGE_INTEGER) ) ) ||
  355.  status == STATUS_BUFFER_OVERFLOW ||
  356.  status == STATUS_PENDING ) {
  357. // 
  358. // If the operation is pending, wait for it to finish
  359. //
  360. if( status == STATUS_PENDING ) {
  361. WaitForSingleObject( sourceFile, INFINITE ); 
  362. //
  363. // Get the status from the status block
  364. //
  365. if( ioStatus.Status != STATUS_SUCCESS && 
  366. ioStatus.Status != STATUS_BUFFER_OVERFLOW ) {
  367. printf("Enumerate file clusters: ");
  368. PrintNtError( ioStatus.Status );
  369. return;
  370. }
  371. }
  372. //
  373. // Loop through the buffer of number/cluster pairs, printing them
  374. // out.
  375. //
  376. startVcn = fileMappings->StartVcn;
  377. for( i = 0; i < (ULONGLONG) fileMappings->NumberOfPairs; i++ ) {
  378. //
  379. // See if we should continue
  380. //
  381. if( !PauseOutput( ++lines ) ) {
  382. return;
  383. }  
  384. //
  385. // On NT 4.0, a compressed virtual run (0-filled) is 
  386. // identified with a cluster offset of -1
  387. //
  388. if( fileMappings->Pair[i].Lcn == LLINVALID ) {
  389. printf("   VCN: %I64d VIRTUAL LEN: %I64dn",
  390. startVcn, fileMappings->Pair[i].Vcn - startVcn ); 
  391. } else {
  392. printf("   VCN: %I64d LCN: %I64d LEN: %I64dn",
  393. startVcn, fileMappings->Pair[i].Lcn, 
  394. fileMappings->Pair[i].Vcn - startVcn );
  395. }
  396. startVcn = fileMappings->Pair[i].Vcn;
  397. }
  398. //
  399. // If the buffer wasn't overflowed, then we're done
  400. //
  401. if( !status ) break;
  402. }
  403. CloseHandle( sourceFile );
  404. //
  405. // Print any error code
  406. //
  407. printf("Enumerate file clusters: ");
  408. PrintNtError( status );
  409. }
  410. //--------------------------------------------------------------------
  411. //
  412. // MoveClusterUsage
  413. //
  414. // Prints the syntax of the demonstration program's move file command.
  415. //
  416. //--------------------------------------------------------------------
  417. void MoveClusterUsage()
  418. {
  419. printf("nMove File's syntax is:n   m [filename] [fileoffset] [target] [numclusters]nn");
  420. printf("Example:n   m c:\foo\bar 5 3455 10n");
  421. printf("   c:\foo\bar       File to moven");
  422. printf("   5                Start offset (in clusters) of the cluster in file to moven");
  423. printf("   3455             Target cluster on driven");
  424. printf("   10               Number of clusters to moven");
  425. printf("n   This would direct 10 clusters, starting at offset 5 clustersn"
  426. "   in the file, to be moved to logical cluster 3455 on the volume.nn");
  427. return;
  428. }
  429. //--------------------------------------------------------------------
  430. //
  431. // MoveCluster
  432. //
  433. // This uses the FSCT_MOVE_FILE interface to move the clusters of a
  434. // file specified by the user as arguments. MoveFile requires a 
  435. // file handle, an offset within the file, the number of sectors of
  436. // the file to move, and the target cluster on the drive to move the
  437. // clusters to.
  438. //
  439. //--------------------------------------------------------------------
  440. void MoveCluster( int drive, char *argument )
  441. {
  442. DWORD status;
  443. IO_STATUS_BLOCK ioStatus;
  444. char *argptr;
  445. HANDLE sourceFile;
  446. char fileName[MAX_PATH];
  447. LARGE_INTEGER startVcn, targetLcn;
  448. DWORD numClusters;
  449. MOVEFILE_DESCRIPTOR moveFile;
  450. //
  451. // First, we have to extract the file name
  452. //
  453. argptr = argument;
  454. while( *argptr && *argptr != ' ' ) argptr++;
  455. if( !*argptr ) {
  456. MoveClusterUsage();
  457. return; 
  458. }
  459. //
  460. // Make the name into a real pathname
  461. //
  462. *argptr = 0;
  463. if( strlen( argument ) > 1 && argument[0] != '\' &&
  464. argument[0] != 'A'+drive &&
  465. argument[0] != 'a'+drive ) 
  466. sprintf(fileName, "%C:\%s", drive+'A', argument );
  467. else if( strlen( argument ) > 1 && argument[0] == '\') 
  468. sprintf(fileName, "%C:%s", drive+'A', argument );
  469. else
  470. strcpy(fileName, argument );
  471. // 
  472. // Get numeric parameters
  473. //
  474. argument = argptr+1;
  475. if( sscanf( argument, " %I64d %I64d %d ", &startVcn, &targetLcn, &numClusters ) != 3) {
  476. MoveClusterUsage();
  477. return;
  478. }
  479. //
  480. // Tell user what we're going to try
  481. //
  482. printf("nMoving file %s:n", fileName );
  483. printf("   Start Offset: %I64dn", startVcn );
  484. printf("   Number of Clusters: %dn", numClusters );
  485. printf("   Target Cluster: %I64dn", targetLcn );
  486. //
  487. // Open the file
  488. //
  489. sourceFile = CreateFile( fileName, GENERIC_READ, 
  490. FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 
  491. FILE_FLAG_NO_BUFFERING, 0 );
  492. if( sourceFile == INVALID_HANDLE_VALUE ) {
  493. printf("Failed to open file: ");
  494. PrintWin32Error( GetLastError() );
  495. return;
  496. }
  497. //
  498. // Setup movefile descriptor and make the call
  499. //
  500. moveFile.FileHandle = sourceFile;
  501. moveFile.StartVcn = startVcn;
  502. moveFile.TargetLcn = targetLcn;
  503. moveFile.NumVcns = numClusters;
  504. status = NtFsControlFile( VolumeHandle, NULL, NULL, 0, &ioStatus,
  505. FSCTL_MOVE_FILE,
  506. &moveFile, sizeof( moveFile ),
  507. NULL, 0 );
  508. // 
  509. // If the operation is pending, wait for it to finish
  510. //
  511. if( status == STATUS_PENDING ) {
  512. WaitForSingleObject( sourceFile, INFINITE ); 
  513. status = ioStatus.Status;
  514. }
  515. //
  516. // Print status
  517. //
  518. printf("Move cluster status: ");
  519. PrintNtError( status );
  520. }
  521. //--------------------------------------------------------------------
  522. //
  523. // ExtractCommand
  524. //
  525. // Given a command line, searches for 1 character command, and then
  526. // returns a pointer to first non-whitespace following.
  527. //
  528. //--------------------------------------------------------------------
  529. char ExtractCommand( char *command, char **argument )
  530. {
  531. char cmdChar;
  532. //
  533. // Look for the command character
  534. //
  535. while( *command && *command == ' ') command++;
  536. if( !*command) return (char) 0;
  537. cmdChar = *command;
  538. command++;
  539. //
  540. // Now look for argument
  541. //
  542. while( *command && *command == ' ' ) command++;
  543. *argument = command;
  544. return cmdChar;
  545. }
  546. //--------------------------------------------------------------------
  547. //
  548. // main
  549. //
  550. // Process simple commands for enumerating the clusters of a file,
  551. // reading the volume bitmap, and moving a cluster of a particular 
  552. // file.
  553. //
  554. //--------------------------------------------------------------------
  555. int main( int argc, char *argv[])
  556. {
  557. DWORD status;
  558. int drive;
  559. char command[256];
  560. char *argument;
  561. char cmdChar;
  562. //
  563. // Get the drive to open off the command line
  564. //
  565. if( argc != 2) {
  566. printf("Usage: %s <drive letter>n", argv[0] );
  567. exit(1);
  568. }
  569. printf("nNT 4.0 Defragmentation Demonstration Program V1.0n");
  570. printf("Copyright (C) 1997 Mark Russinovichn");
  571. printf("http://www.ntinternals.comnn");
  572. if( argv[1][0] >= 'a' && argv[1][0] <= 'z' ) {
  573. drive = argv[1][0] - 'a';
  574. } else if( argv[1][0] >= 'A' && argv[1][0] <= 'Z' ) {
  575. drive = argv[1][0] - 'A';
  576. } else if( argv[1][0] == '/' ) {
  577. printf("Usage: %s <drive letter>n", argv[0] );
  578. exit(1);
  579. } else {
  580. printf("illegal drive: %cn", argv[1][0] );
  581. exit(1);
  582. }
  583. //
  584. // Get the NtFsControlFile entry point
  585. //
  586. if( !(NtFsControlFile = (void *) GetProcAddress( GetModuleHandle("ntdll.dll"),
  587. "NtFsControlFile" )) ) {
  588. printf("Could not find NtFsControlFile entry point in NTDLL.DLLn");
  589. exit(1);
  590. }
  591. //
  592. // Open the volume
  593. //
  594. printf("Opening volume: %cn", drive+'A' );
  595. status = OpenVolume(drive);
  596. printf("Open status: ");
  597. PrintWin32Error( status );
  598. if( status != ERROR_SUCCESS ) {
  599. printf("Exiting.n");
  600. exit(0);
  601. }
  602. //
  603. // Get commands 
  604. //
  605. printf("Enter commands ('?' for help):nn");
  606. while(1) {
  607. printf(": ");
  608. fflush(stdout );
  609. gets( command );
  610. cmdChar = ExtractCommand( command, &argument );
  611. switch( cmdChar ) {
  612. //
  613. // Dump bitmap information
  614. //
  615. case 'b':
  616. case 'B':
  617. DumpBitmap( argument );
  618. break;
  619. //
  620. // Help
  621. //
  622. case '?':
  623. case 'H':
  624. case 'h':
  625. PrintHelp();
  626. break;
  627. //
  628. // Move Cluster
  629. //
  630. case 'm':
  631. case 'M':
  632. MoveCluster( drive, argument );
  633. break;
  634. //
  635. // Get cluster map for file specified by name
  636. //
  637. case 'N':
  638. case 'n':
  639. DumpFile( drive, argument );
  640. break;
  641. //
  642. // Quit
  643. //
  644. case 'Q':
  645. case 'q':
  646. printf("nQuitingn");
  647. exit(0);
  648. break;
  649. case 0:
  650. break;
  651. default:
  652. printf("nInvalid commandnn");
  653. break;
  654. }
  655. }
  656. return 0;
  657. }