Leaked source code of windows server 2003
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.

1595 lines
48 KiB

  1. /*++
  2. Copyright (c) 1991-2001 Microsoft Corporation
  3. Module Name:
  4. autochk.cxx
  5. Abstract:
  6. This is the main program for the autocheck version of chkdsk.
  7. Author:
  8. Norbert P. Kusters (norbertk) 31-May-91
  9. --*/
  10. #include "ulib.hxx"
  11. #include "wstring.hxx"
  12. #include "fatvol.hxx"
  13. #include "untfs.hxx"
  14. #include "ntfsvol.hxx"
  15. #include "spackmsg.hxx"
  16. #include "tmackmsg.hxx"
  17. #include "error.hxx"
  18. #include "ifssys.hxx"
  19. #include "rtmsg.h"
  20. #include "rcache.hxx"
  21. #include "autoreg.hxx"
  22. #include "ifsserv.hxx"
  23. #include "mpmap.hxx"
  24. #if defined(FE_SB) && defined(_X86_)
  25. #include "machine.hxx"
  26. #endif
  27. #define CONTROL_NAME \
  28. L"\\Registry\\Machine\\System\\CurrentControlSet\\Control"
  29. #define VALUE_NAME L"SystemStartOptions"
  30. #define VALUE_BUFFER_SIZE \
  31. (sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 256 * sizeof(WCHAR))
  32. BOOLEAN
  33. RegistrySosOption(
  34. );
  35. extern "C" BOOLEAN
  36. InitializeUfat(
  37. PVOID DllHandle,
  38. ULONG Reason,
  39. PCONTEXT Context
  40. );
  41. extern "C" BOOLEAN
  42. InitializeUntfs(
  43. PVOID DllHandle,
  44. ULONG Reason,
  45. PCONTEXT Context
  46. );
  47. extern "C" BOOLEAN
  48. InitializeIfsUtil(
  49. PVOID DllHandle,
  50. ULONG Reason,
  51. PCONTEXT Context
  52. );
  53. USHORT
  54. InvokeAutoChk (
  55. IN PWSTRING DriveLetter,
  56. IN PWSTRING VolumeName,
  57. IN ULONG ChkdskFlags,
  58. IN BOOLEAN RemoveRegistry,
  59. IN BOOLEAN SetupMode,
  60. IN BOOLEAN Extend,
  61. IN ULONG LogfileSize,
  62. IN USHORT Algorithm,
  63. IN INT ArgCount,
  64. IN CHAR **ArgArray,
  65. IN PARRAY SkipList,
  66. IN OUT PMESSAGE Msg,
  67. OUT PULONG ExitStatus
  68. );
  69. BOOLEAN
  70. ExtendNtfsVolume(
  71. PCWSTRING DriveName,
  72. PMESSAGE Message
  73. );
  74. BOOLEAN
  75. DeregisterAutochk(
  76. int argc,
  77. char** argv
  78. );
  79. BOOLEAN
  80. QueryAllHardDrives(
  81. PMOUNT_POINT_MAP MountPointMap
  82. );
  83. BOOLEAN
  84. IsGuidVolName (
  85. PWSTRING VolName
  86. );
  87. int __cdecl
  88. main(
  89. int argc,
  90. char** argv,
  91. char** envp,
  92. ULONG DebugParameter
  93. )
  94. /*++
  95. Routine Description:
  96. This routine is the main program for autocheck FAT chkdsk.
  97. Arguments:
  98. argc, argv - Supplies the fully qualified NT path name of the
  99. the drive to check.
  100. Return Value:
  101. 0 - Success.
  102. 1 - Failure.
  103. --*/
  104. {
  105. if (!InitializeUlib( NULL, ! DLL_PROCESS_DETACH, NULL ) ||
  106. !InitializeIfsUtil(NULL,0,NULL) ||
  107. !InitializeUfat(NULL,0,NULL) ||
  108. !InitializeUntfs(NULL,0,NULL)) {
  109. return 1;
  110. }
  111. #if defined(FE_SB) && defined(_X86_)
  112. InitializeMachineId();
  113. #endif
  114. //
  115. // The declarations must come after these initialization functions.
  116. //
  117. DSTRING dos_drive_name;
  118. DSTRING volume_name;
  119. DSTRING drive_letter;
  120. ARRAY skip_list;
  121. AUTOCHECK_MESSAGE *msg = NULL;
  122. BOOLEAN onlyifdirty = TRUE;
  123. BOOLEAN recover = FALSE;
  124. BOOLEAN extend = FALSE;
  125. BOOLEAN remove_registry = FALSE;
  126. ULONG ArgOffset = 1;
  127. BOOLEAN SetupOutput = FALSE;
  128. BOOLEAN SetupTextMode = FALSE;
  129. BOOLEAN SetupSpecialFixLevel = FALSE;
  130. ULONG exit_status = 0;
  131. BOOLEAN SuppressOutput = TRUE; // dots only by default
  132. BOOLEAN all_drives = FALSE;
  133. BOOLEAN resize_logfile = FALSE;
  134. BOOLEAN skip_index_scan = FALSE;
  135. BOOLEAN skip_cycle_scan = FALSE;
  136. LONG logfile_size = 0;
  137. LONG algorithm = 0;
  138. BOOLEAN algorithm_specified = FALSE;
  139. MOUNT_POINT_MAP mount_point_map;
  140. ULONG i;
  141. USHORT rtncode;
  142. ULONG chkdsk_flags;
  143. DSTRING nt_name_prefix;
  144. DSTRING dos_guidname_prefix;
  145. if (!drive_letter.Initialize() ||
  146. !volume_name.Initialize() ||
  147. !nt_name_prefix.Initialize(NT_NAME_PREFIX) ||
  148. !dos_guidname_prefix.Initialize(DOS_GUIDNAME_PREFIX) ||
  149. !skip_list.Initialize()) {
  150. KdPrintEx((DPFLTR_AUTOCHK_ID,
  151. DPFLTR_WARNING_LEVEL,
  152. "Out of memory.\n"));
  153. return 1;
  154. }
  155. // Parse the arguments--the accepted arguments are:
  156. //
  157. // autochk [/s] [/dx:] [/p] [/r] [/m] [/i[:chunks]] [/c] nt-drive-name
  158. // autochk [/dx:] [/p] [/r] [/m] [/i[:chunks]] [/c] [/l:size] nt-drive-name
  159. // autochk [/s] /x dos-drive-name (obsolete in NT 5.0)
  160. // autochk [/k:drives] [/k:volname] ... *
  161. //
  162. // /t - setup text mode: selectively output messages thru Ioctl
  163. // /s - setup: no output
  164. // /d - the drive letter is x: (obsolete)
  165. // /p - check even if not dirty
  166. // /r - recover; implies /p
  167. // /l - resize log file to <size> kilobytes. May not be combined with
  168. // /s because /s explicitly inhibits logfile resizing.
  169. // /x - extend volume; obsolete in NT 5.0
  170. // /k - a list of drive letters or a guid volume name to skip
  171. // /m - remove registry entry after running
  172. // /e - turn on the volume upgrade bit; obsolete in NT 5.0
  173. // /i - include index entries checking; implies /p
  174. // /c - include checking of cycles within the directory tree; implies /p
  175. // /i:chunks
  176. // - does the index scan in <chunks> chunks; implies /p
  177. //
  178. //*****
  179. // Delete the following if when building a normal CONSOLE version for test
  180. //
  181. if (argc < 2) {
  182. // Not enough arguments.
  183. return 1;
  184. }
  185. for (ArgOffset = 1; ArgOffset < (ULONG)argc; ++ArgOffset) {
  186. if ((argv[ArgOffset][0] == '/' || argv[ArgOffset][0] == '-') &&
  187. (argv[ArgOffset][1] == 't' || argv[ArgOffset][1] == 'T') &&
  188. (argv[ArgOffset][2] == 0) ) {
  189. //
  190. // Then we're in silent mode plus I/O to setup
  191. //
  192. SetupTextMode = TRUE;
  193. continue;
  194. }
  195. if ((argv[ArgOffset][0] == '/' || argv[ArgOffset][0] == '-') &&
  196. (argv[ArgOffset][1] == 's' || argv[ArgOffset][1] == 'S') &&
  197. (argv[ArgOffset][2] == 0) ) {
  198. //
  199. // Then we're in silent mode
  200. //
  201. SetupOutput = TRUE;
  202. continue;
  203. }
  204. if ((argv[ArgOffset][0] == '/' || argv[ArgOffset][0] == '-') &&
  205. (argv[ArgOffset][1] == 'p' || argv[ArgOffset][1] == 'P') &&
  206. (argv[ArgOffset][2] == 0) ) {
  207. // argv[ArgOffset] is the /p parameter, so argv[ArgOffset+1]
  208. // must be the drive.
  209. onlyifdirty = FALSE;
  210. continue;
  211. }
  212. if( (argv[ArgOffset][0] == '/' || argv[ArgOffset][0] == '-') &&
  213. (argv[ArgOffset][1] == 'r' || argv[ArgOffset][1] == 'R') &&
  214. (argv[ArgOffset][2] == 0) ) {
  215. // Note that /r implies /p.
  216. //
  217. recover = TRUE;
  218. onlyifdirty = FALSE;
  219. continue;
  220. }
  221. if( (argv[ArgOffset][0] == '/' || argv[ArgOffset][0] == '-') &&
  222. (argv[ArgOffset][1] == 'x' || argv[ArgOffset][1] == 'X') &&
  223. (argv[ArgOffset][2] == 0) ) {
  224. // when the /x parameter is specified, we accept a
  225. // DOS name and do a complete check.
  226. //
  227. onlyifdirty = FALSE;
  228. extend = TRUE;
  229. if( !dos_drive_name.Initialize( argv[ArgOffset + 1] ) ||
  230. !IFS_SYSTEM::DosDriveNameToNtDriveName( &dos_drive_name,
  231. &volume_name ) ) {
  232. return 1;
  233. }
  234. ArgOffset++;
  235. continue;
  236. }
  237. #if 0
  238. if ((argv[ArgOffset][0] == '/' || argv[ArgOffset][0] == '-') &&
  239. (argv[ArgOffset][1] == 'd' || argv[ArgOffset][1] == 'D')) {
  240. //
  241. // A parameter of the form "/dX:" indicates that we are checking
  242. // the volume whose drive letter is X:.
  243. //
  244. if (!drive_letter.Initialize(&argv[ArgOffset][2])) {
  245. return 1;
  246. }
  247. continue;
  248. }
  249. #endif
  250. if ((argv[ArgOffset][0] == '/' || argv[ArgOffset][0] == '-') &&
  251. (argv[ArgOffset][1] == 'l' || argv[ArgOffset][1] == 'L')) {
  252. DSTRING number;
  253. // The /l parameter indicates that we're to resize the log file.
  254. // The size should always be specified, and it is in kilobytes.
  255. //
  256. resize_logfile = TRUE;
  257. if (!number.Initialize(&argv[ArgOffset][3]) ||
  258. !number.QueryNumber(&logfile_size) ||
  259. logfile_size < 0) {
  260. return 1;
  261. }
  262. logfile_size *= 1024;
  263. continue;
  264. }
  265. if ((argv[ArgOffset][0] == '/' || argv[ArgOffset][0] == '-') &&
  266. (argv[ArgOffset][1] == 'k' || argv[ArgOffset][1] == 'K')) {
  267. // Skip.
  268. PWSTRING s;
  269. DSTRING drive;
  270. DSTRING colon;
  271. if (!drive.Initialize(&argv[ArgOffset][3]) ||
  272. !colon.Initialize(L":")) {
  273. KdPrintEx((DPFLTR_AUTOCHK_ID,
  274. DPFLTR_WARNING_LEVEL,
  275. "Out of memory\n"));
  276. return 1;
  277. }
  278. if (drive.Stricmp(&dos_guidname_prefix,
  279. 0,
  280. dos_guidname_prefix.QueryChCount()) == 0) {
  281. // just a dos guid volume name, so store it
  282. s = drive.QueryString();
  283. if (!s ||
  284. !skip_list.Put(s)) {
  285. KdPrintEx((DPFLTR_AUTOCHK_ID,
  286. DPFLTR_WARNING_LEVEL,
  287. "Out of memory\n"));
  288. return 1;
  289. }
  290. #if 0
  291. KdPrintEx((DPFLTR_AUTOCHK_ID,
  292. DPFLTR_INFO_LEVEL,
  293. "AUTOCHK: guid name /k:%S\n",
  294. s->GetWSTR()));
  295. #endif
  296. continue;
  297. }
  298. // handle a list of dos drive names by inserting them
  299. // individually into the skip list
  300. while (drive.QueryChCount() != 0) {
  301. s = drive.QueryString(0, 1);
  302. if (!s ||
  303. !s->Strcat(&colon) ||
  304. !skip_list.Put(s)) {
  305. KdPrintEx((DPFLTR_AUTOCHK_ID,
  306. DPFLTR_WARNING_LEVEL,
  307. "Out of memory\n"));
  308. return 1;
  309. }
  310. #if 0
  311. KdPrintEx((DPFLTR_AUTOCHK_ID,
  312. DPFLTR_INFO_LEVEL,
  313. "AUTOCHK: drive letter /k:%S\n",
  314. s->GetWSTR()));
  315. #endif
  316. drive.DeleteChAt(0);
  317. }
  318. continue;
  319. }
  320. if ((argv[ArgOffset][0] == '/' || argv[ArgOffset][0] == '-') &&
  321. (argv[ArgOffset][1] == 'm' || argv[ArgOffset][1] == 'M')) {
  322. remove_registry = TRUE;
  323. continue;
  324. }
  325. if ((argv[ArgOffset][0] == '/' || argv[ArgOffset][0] == '-') &&
  326. (argv[ArgOffset][1] == 'i' || argv[ArgOffset][1] == 'I')) {
  327. DSTRING number;
  328. if (argv[ArgOffset][2] == ':') {
  329. if (skip_index_scan || algorithm_specified ||
  330. !number.Initialize(&argv[ArgOffset][3]) ||
  331. !number.QueryNumber(&algorithm) ||
  332. algorithm < 0 || algorithm > CHKDSK_MAX_ALGORITHM_VALUE) {
  333. return 1;
  334. }
  335. algorithm_specified = TRUE;
  336. onlyifdirty = FALSE;
  337. } else if (algorithm_specified) {
  338. return 1;
  339. } else {
  340. skip_index_scan = TRUE;
  341. onlyifdirty = FALSE;
  342. }
  343. continue;
  344. }
  345. if ((argv[ArgOffset][0] == '/' || argv[ArgOffset][0] == '-') &&
  346. (argv[ArgOffset][1] == 'c' || argv[ArgOffset][1] == 'C')) {
  347. skip_cycle_scan = TRUE;
  348. onlyifdirty = FALSE;
  349. continue;
  350. }
  351. if ((argv[ArgOffset][0] != '/' && argv[ArgOffset][0] != '-')) {
  352. // We've run off the options into the arguments.
  353. break;
  354. }
  355. }
  356. // argv[ArgOffset] is the drive;
  357. if (NULL != argv[ArgOffset]) {
  358. if ('*' == argv[ArgOffset][0]) {
  359. all_drives = TRUE;
  360. } else {
  361. all_drives = FALSE;
  362. //*****
  363. //
  364. // Substitute the following 3 lines for the next line to enable going
  365. // AUTOCHK C: like for CHKDSK (when building a normal CONSOLE version for test)
  366. //
  367. // if ( !dos_drive_name.Initialize( argv[ArgOffset] ) ||
  368. // !IFS_SYSTEM::DosDriveNameToNtDriveName( &dos_drive_name,
  369. // &volume_name ) ) {
  370. //******
  371. if (!volume_name.Initialize(argv[ArgOffset])) {
  372. //******
  373. return 1;
  374. }
  375. }
  376. }
  377. //
  378. // Determine whether to suppress output or not. If compiled with
  379. // DBG==1, print normal output. Otherwise look in the registry to
  380. // see if the machine has "SOS" in the NTLOADOPTIONS.
  381. //
  382. #if defined(_AUTOCHECK_DBG_)
  383. SuppressOutput = FALSE;
  384. #else /* _AUTOCHECK_DBG */
  385. if (RegistrySosOption()) {
  386. SuppressOutput = FALSE;
  387. }
  388. #endif /* _AUTOCHECK_DBG_ */
  389. //
  390. // If this is autochk /r, /l, /i, /c, we've been started from an explicit
  391. // registry entry and the dirty bit may not be set. We want to
  392. // deliver interesting output regardless.
  393. //
  394. if (recover || resize_logfile || algorithm_specified ||
  395. skip_index_scan || skip_cycle_scan) {
  396. SuppressOutput = FALSE;
  397. }
  398. if (extend) {
  399. KdPrintEx((DPFLTR_AUTOCHK_ID,
  400. DPFLTR_WARNING_LEVEL,
  401. "AUTOCHK: Option /x is no longer supported.\n"));
  402. return 1;
  403. }
  404. if (all_drives && (extend || SetupTextMode || SetupOutput)) {
  405. KdPrintEx((DPFLTR_AUTOCHK_ID,
  406. DPFLTR_WARNING_LEVEL,
  407. "AUTOCHK: Conflicting options that * and [xst] cannot be used at the same time.\n"));
  408. return 1;
  409. }
  410. if (SetupTextMode) {
  411. msg = NEW TM_AUTOCHECK_MESSAGE;
  412. } else if (SetupOutput) {
  413. msg = NEW SP_AUTOCHECK_MESSAGE;
  414. } else {
  415. msg = NEW AUTOCHECK_MESSAGE;
  416. }
  417. if (NULL == msg || !msg->Initialize(SuppressOutput)) {
  418. return 1;
  419. }
  420. #if defined(PRE_RELEASE_NOTICE)
  421. msg->Set(MSG_CHK_PRE_RELEASE_NOTICE);
  422. msg->Display();
  423. #endif
  424. #if defined(_AUTOCHECK_DBG_)
  425. for(ArgOffset=1; ArgOffset < (ULONG)argc; ArgOffset++) {
  426. KdPrintEx((DPFLTR_AUTOCHK_ID,
  427. DPFLTR_INFO_LEVEL,
  428. "AUTOCHK: Argument: %s\n",
  429. argv[ArgOffset]));
  430. }
  431. if (all_drives)
  432. KdPrintEx((DPFLTR_AUTOCHK_ID,
  433. DPFLTR_INFO_LEVEL,
  434. "AUTOCHK: All drives\n"));
  435. else
  436. KdPrintEx((DPFLTR_AUTOCHK_ID,
  437. DPFLTR_INFO_LEVEL,
  438. "AUTOCHK: Not all drives\n"));
  439. #endif
  440. if (!QueryAllHardDrives(&mount_point_map)) {
  441. KdPrintEx((DPFLTR_AUTOCHK_ID,
  442. DPFLTR_WARNING_LEVEL,
  443. "AUTOCHK: Unable to query all hard drives\n"));
  444. return 1;
  445. }
  446. if (skip_list.QueryMemberCount() > 0) {
  447. // convert all drive names to nt guid volume names
  448. DSTRING drive_name;
  449. PWSTRING drive;
  450. PARRAY_ITERATOR iter;
  451. #if 0
  452. KdPrintEx((DPFLTR_AUTOCHK_ID,
  453. DPFLTR_INFO_LEVEL,
  454. "AUTOCHK: Skip list has %d elements.\n",
  455. skip_list.QueryMemberCount()));
  456. #endif
  457. iter = (PARRAY_ITERATOR)skip_list.QueryIterator();
  458. if (iter == NULL)
  459. return 1;
  460. while (drive = (PWSTRING)iter->GetNext()) {
  461. #if 0
  462. KdPrintEx((DPFLTR_AUTOCHK_ID,
  463. DPFLTR_INFO_LEVEL,
  464. "AUTOCHK: Skip list input: %S.\n",
  465. drive->GetWSTR()));
  466. #endif
  467. if (drive->QueryChCount() == 2) {
  468. if (!mount_point_map.QueryVolumeName(drive, &drive_name)) {
  469. KdPrintEx((DPFLTR_AUTOCHK_ID,
  470. DPFLTR_WARNING_LEVEL,
  471. "AUTOCHK: Drive %S not recognized.\n",
  472. drive->GetWSTR()));
  473. continue;
  474. }
  475. } else {
  476. if (!IFS_SYSTEM::DosDriveNameToNtDriveName(drive, &drive_name)) {
  477. KdPrintEx((DPFLTR_AUTOCHK_ID,
  478. DPFLTR_WARNING_LEVEL,
  479. "AUTOCHK: Drive %S not recognized.\n",
  480. drive->GetWSTR()));
  481. continue;
  482. }
  483. }
  484. #if 0
  485. KdPrintEx((DPFLTR_AUTOCHK_ID,
  486. DPFLTR_INFO_LEVEL,
  487. "AUTOCHK: Skip list: %S.\n",
  488. drive_name.GetWSTR()));
  489. #endif
  490. if (!drive->Initialize(&drive_name)) {
  491. KdPrintEx((DPFLTR_AUTOCHK_ID,
  492. DPFLTR_WARNING_LEVEL,
  493. "Out of memory.\n"));
  494. DELETE(iter);
  495. return 1;
  496. }
  497. }
  498. DELETE(iter);
  499. }
  500. if (!all_drives &&
  501. drive_letter.QueryChCount() == 0) {
  502. // if drive letter is not specified
  503. if (volume_name.QueryChCount() == (nt_name_prefix.QueryChCount()+2) &&
  504. volume_name.Strcmp(&nt_name_prefix,
  505. 0,
  506. nt_name_prefix.QueryChCount()) == 0) {
  507. // looks like \??\<drive letter>: format
  508. // so, exact drive letter from volume_name
  509. if (!IFS_SYSTEM::NtDriveNameToDosDriveName(&volume_name, &drive_letter)) {
  510. KdPrintEx((DPFLTR_AUTOCHK_ID,
  511. DPFLTR_WARNING_LEVEL,
  512. "Out of memory.\n"));
  513. return 1;
  514. }
  515. DebugAssert(drive_letter.QueryChCount() == 2 &&
  516. drive_letter.QueryChAt(1) == (WCHAR)':');
  517. if (!mount_point_map.QueryVolumeName(&drive_letter, &volume_name)) {
  518. KdPrintEx((DPFLTR_AUTOCHK_ID,
  519. DPFLTR_WARNING_LEVEL,
  520. "AUTOCHK: Drive %S not found.\n",
  521. drive_letter.GetWSTR()));
  522. return 1;
  523. }
  524. } else if (IsGuidVolName(&volume_name)) {
  525. // looks like a guid volume name
  526. // so look it up from the mount point map
  527. if (!mount_point_map.QueryDriveName(&volume_name, &drive_letter)) {
  528. KdPrintEx((DPFLTR_AUTOCHK_ID,
  529. DPFLTR_WARNING_LEVEL,
  530. "AUTOCHK: Drive %S not found.\n",
  531. volume_name.GetWSTR()));
  532. return 1;
  533. }
  534. // drive_letter may still be empty
  535. // treat it as if there is no drive letter
  536. // during the "autocheck autochk *" case
  537. } else {
  538. // the volume name does not fit into any format
  539. // make drive letter the same as volume name
  540. if (!drive_letter.Initialize(&volume_name))
  541. return 1;
  542. }
  543. }
  544. // at this point, volume_name should contain an nt guid volume name
  545. chkdsk_flags = (onlyifdirty ? CHKDSK_CHECK_IF_DIRTY : 0);
  546. chkdsk_flags |= ((recover || extend) ? CHKDSK_RECOVER_FREE_SPACE : 0);
  547. chkdsk_flags |= (recover ? CHKDSK_RECOVER_ALLOC_SPACE : 0);
  548. chkdsk_flags |= (resize_logfile ? CHKDSK_RESIZE_LOGFILE : 0);
  549. chkdsk_flags |= (skip_index_scan ? CHKDSK_SKIP_INDEX_SCAN : 0);
  550. chkdsk_flags |= (skip_cycle_scan ? CHKDSK_SKIP_CYCLE_SCAN : 0);
  551. chkdsk_flags |= (algorithm_specified ? CHKDSK_ALGORITHM_SPECIFIED : 0);
  552. for (i = 0;;) {
  553. if (all_drives && !mount_point_map.GetAt(i++, &drive_letter, &volume_name))
  554. break;
  555. __try {
  556. rtncode = InvokeAutoChk(&drive_letter,
  557. &volume_name,
  558. chkdsk_flags,
  559. remove_registry,
  560. SetupOutput || SetupTextMode,
  561. extend,
  562. logfile_size,
  563. (USHORT)algorithm,
  564. argc,
  565. argv,
  566. &skip_list,
  567. msg,
  568. &exit_status);
  569. } __except (EXCEPTION_EXECUTE_HANDLER) {
  570. rtncode = 2;
  571. exit_status = CHKDSK_EXIT_COULD_NOT_FIX;
  572. }
  573. if (all_drives) {
  574. if (rtncode == 1) {
  575. // serious error return immediately
  576. return 1;
  577. } else if (rtncode == 2 || rtncode == 0) {
  578. // volume specific error or no error
  579. // re-initialize and continue
  580. if (!msg->Initialize(SuppressOutput))
  581. return 1;
  582. continue;
  583. } else {
  584. // illegal return code
  585. KdPrintEx((DPFLTR_AUTOCHK_ID,
  586. DPFLTR_WARNING_LEVEL,
  587. "AUTOCHK: Illegal return code %d\n",
  588. (ULONG)rtncode));
  589. return 1;
  590. }
  591. } else {
  592. if (SetupOutput || SetupTextMode) {
  593. SetupSpecialFixLevel = TRUE;
  594. }
  595. if (rtncode == 1) {
  596. // serious error return immediately
  597. return SetupSpecialFixLevel ? CHKDSK_EXIT_COULD_NOT_FIX : 1;
  598. } else if (rtncode == 2 || rtncode == 0) {
  599. // volume specific error or no error
  600. // leave anyway
  601. break;
  602. } else {
  603. // illegal return code
  604. KdPrintEx((DPFLTR_AUTOCHK_ID,
  605. DPFLTR_WARNING_LEVEL,
  606. "AUTOCHK: Illegal return code %d\n",
  607. (ULONG)rtncode));
  608. return SetupSpecialFixLevel ? CHKDSK_EXIT_COULD_NOT_FIX : 1;
  609. }
  610. }
  611. }
  612. msg->Set(MSG_CHK_AUTOCHK_COMPLETE);
  613. msg->Display();
  614. DELETE(msg);
  615. // If the /x switch was supplied, remove the
  616. // forcing entry from the registry, since Chkdsk
  617. // has completed successfully.
  618. //
  619. if (extend) {
  620. DeregisterAutochk( argc, argv );
  621. }
  622. if (SetupSpecialFixLevel) {
  623. #if defined(_AUTOCHECK_DBG_)
  624. if (exit_status != CHKDSK_EXIT_SUCCESS) {
  625. KdPrintEx((DPFLTR_AUTOCHK_ID,
  626. DPFLTR_INFO_LEVEL,
  627. "AUTOCHK: Exit Status %d\n",
  628. exit_status));
  629. }
  630. #endif
  631. return exit_status;
  632. } else {
  633. return 0;
  634. }
  635. }
  636. USHORT
  637. InvokeAutoChk (
  638. IN PWSTRING DriveLetter,
  639. IN PWSTRING VolumeName,
  640. IN ULONG ChkdskFlags,
  641. IN BOOLEAN RemoveRegistry,
  642. IN BOOLEAN SetupMode,
  643. IN BOOLEAN Extend,
  644. IN ULONG LogfileSize,
  645. IN USHORT Algorithm,
  646. IN INT ArgCount,
  647. IN CHAR **ArgArray,
  648. IN PARRAY SkipList,
  649. IN OUT PMESSAGE Msg,
  650. OUT PULONG ExitStatus
  651. )
  652. /*++
  653. Routine Description:
  654. This is the core of autochk. It checks the specified drive.
  655. Arguments:
  656. DriveLetter - Supplies the drive letter of the drive
  657. (can be empty string)
  658. VolumeName - Supplies the guid volume name of the drive
  659. ChkdskFlags - Supplies the chkdsk control flags
  660. RemoveRegistry - Supplies TRUE if registry entry is to be removed
  661. SetupMode - Supplies TRUE if invoked through setup
  662. Extend - Supplies TRUE if extending the volume (obsolete)
  663. LogfileSize - Supplies the size of the logfile
  664. Algorithm - Supplies the algorithm to use
  665. ArgCount - Supplies the number of arguments given to autochk.
  666. ArgArray - Supplies the arguments given to autochk.
  667. SkipList - Supplies the list of drives to skip checking
  668. Msg - Supplies the outlet of messages
  669. ExitStatus - Retrieves the exit status of chkdsk
  670. Return Value:
  671. 0 - Success
  672. 1 - Fatal error
  673. 2 - Volume specific error
  674. --*/
  675. {
  676. DSTRING fsname;
  677. DSTRING fsNameAndVersion;
  678. PFAT_VOL fatvol = NULL;
  679. PNTFS_VOL ntfsvol = NULL;
  680. PVOL_LIODPDRV vol = NULL;
  681. BOOLEAN SetupSpecialFixLevel = FALSE;
  682. PREAD_CACHE read_cache;
  683. DSTRING boot_execute_log_file_name;
  684. FSTRING boot_ex_temp;
  685. HMEM logged_message_mem;
  686. ULONG packed_log_length;
  687. DSTRING fatname;
  688. DSTRING fat32name;
  689. DSTRING ntfsname;
  690. DSTRING nt_name_prefix;
  691. DSTRING dos_guidname_prefix;
  692. BOOLEAN isDirty;
  693. BOOLEAN skip_autochk = FALSE;
  694. *ExitStatus = CHKDSK_EXIT_COULD_NOT_FIX;
  695. if (!fatname.Initialize("FAT") ||
  696. !fat32name.Initialize("FAT32") ||
  697. !ntfsname.Initialize("NTFS") ||
  698. !nt_name_prefix.Initialize(NT_NAME_PREFIX) ||
  699. !dos_guidname_prefix.Initialize(DOS_GUIDNAME_PREFIX)) {
  700. return 1;
  701. }
  702. if (VolumeName->QueryChCount() == 0) {
  703. KdPrintEx((DPFLTR_AUTOCHK_ID,
  704. DPFLTR_WARNING_LEVEL,
  705. "AUTOCHK: Volume name is missing.\n"));
  706. return 2; // continue if all_drives are enabled
  707. }
  708. if (DriveLetter->QueryChCount() == 0) {
  709. // unable to map VolumeName to a drive letter so do the default
  710. if (!IFS_SYSTEM::NtDriveNameToDosDriveName(VolumeName, DriveLetter)) {
  711. KdPrintEx((DPFLTR_AUTOCHK_ID,
  712. DPFLTR_WARNING_LEVEL,
  713. "Out of memory.\n"));
  714. return 1;
  715. }
  716. }
  717. // at this point DriveLetter and VolumeName should be well defined
  718. #if 0
  719. Msg->Set(MSG_CHK_NTFS_MESSAGE);
  720. Msg->Display("%s%W", "Drive Name: ", VolumeName);
  721. Msg->Display("%s%W", "Drive Letter: ", DriveLetter);
  722. #endif
  723. if (SkipList->QueryMemberCount() > 0) {
  724. PARRAY_ITERATOR iter = (PARRAY_ITERATOR)SkipList->QueryIterator();
  725. PWSTRING skip_item;
  726. if (iter == NULL)
  727. return 1;
  728. // skip drives that should not be checked
  729. while (skip_item = (PWSTRING)iter->GetNext()) {
  730. if (skip_item->Stricmp(VolumeName) == 0) {
  731. DELETE(iter);
  732. #if 0
  733. KdPrintEx((DPFLTR_AUTOCHK_ID,
  734. DPFLTR_INFO_LEVEL,
  735. "AUTOCHK: Skipping: %S.\n",
  736. VolumeName->GetWSTR()));
  737. #endif
  738. return 0;
  739. }
  740. }
  741. DELETE(iter);
  742. }
  743. if ((ChkdskFlags & CHKDSK_CHECK_IF_DIRTY) &&
  744. !(ChkdskFlags & CHKDSK_RESIZE_LOGFILE) &&
  745. IFS_SYSTEM::IsVolumeDirty(VolumeName,&isDirty) &&
  746. !isDirty) {
  747. KdPrintEx((DPFLTR_AUTOCHK_ID,
  748. DPFLTR_INFO_LEVEL,
  749. "AUTOCHK: Skipping %S because it's not dirty.\n",
  750. VolumeName->GetWSTR()));
  751. *ExitStatus = CHKDSK_EXIT_SUCCESS;
  752. skip_autochk = TRUE;
  753. }
  754. if (!skip_autochk) {
  755. if (!IFS_SYSTEM::QueryFileSystemName(VolumeName, &fsname,
  756. NULL, &fsNameAndVersion)) {
  757. Msg->Set( MSG_FS_NOT_DETERMINED );
  758. Msg->Display( "%W", VolumeName );
  759. return 2;
  760. }
  761. }
  762. Msg->SetLoggingEnabled();
  763. Msg->Set(MSG_CHK_RUNNING);
  764. Msg->Display("%W", DriveLetter);
  765. if (!skip_autochk) {
  766. Msg->Set(MSG_FILE_SYSTEM_TYPE);
  767. Msg->Display("%W", &fsname);
  768. if (fsname == fatname || fsname == fat32name) {
  769. if (!(fatvol = NEW FAT_VOL)) {
  770. KdPrintEx((DPFLTR_AUTOCHK_ID,
  771. DPFLTR_WARNING_LEVEL,
  772. "Out of memory.\n"));
  773. return 1;
  774. }
  775. if (NoError != fatvol->Initialize(Msg,
  776. VolumeName,
  777. (BOOLEAN)(ChkdskFlags & CHKDSK_CHECK_IF_DIRTY))) {
  778. DELETE(fatvol);
  779. return 2;
  780. }
  781. if ((read_cache = NEW READ_CACHE) &&
  782. read_cache->Initialize(fatvol, 75)) {
  783. fatvol->SetCache(read_cache);
  784. } else {
  785. DELETE(read_cache);
  786. }
  787. vol = fatvol;
  788. } else if (fsname == ntfsname) {
  789. if( Extend ) {
  790. // NOTE: this roundabout method is necessary to
  791. // convince NTFS to allow us to access the new
  792. // sectors on the volume.
  793. //
  794. if( !ExtendNtfsVolume( VolumeName, Msg ) ) {
  795. return 1;
  796. }
  797. if (!(ntfsvol = NEW NTFS_VOL)) {
  798. KdPrintEx((DPFLTR_AUTOCHK_ID,
  799. DPFLTR_WARNING_LEVEL,
  800. "Out of memory.\n"));
  801. return 1;
  802. }
  803. if (NoError != ntfsvol->Initialize( VolumeName, Msg ))
  804. return 1;
  805. if (!ntfsvol->Lock()) {
  806. Msg->Set( MSG_CANT_LOCK_THE_DRIVE );
  807. Msg->Display( "" );
  808. }
  809. } else {
  810. if (!(ntfsvol = NEW NTFS_VOL)) {
  811. KdPrintEx((DPFLTR_AUTOCHK_ID,
  812. DPFLTR_WARNING_LEVEL,
  813. "Out of memory.\n"));
  814. return 1;
  815. }
  816. if (NoError != ntfsvol->Initialize(VolumeName, Msg, TRUE)) {
  817. DELETE(ntfsvol);
  818. return 2;
  819. }
  820. if (SetupMode) {
  821. //
  822. // SetupSpecialFixLevel will be used for NTFS... it means
  823. // to refrain from resizing the log file.
  824. //
  825. SetupSpecialFixLevel = TRUE;
  826. }
  827. }
  828. // The read cache for NTFS CHKDSK gets set in VerifyAndFix.
  829. vol = ntfsvol;
  830. } else {
  831. Msg->Set( MSG_FS_NOT_SUPPORTED );
  832. Msg->Display( "%s%W", "AUTOCHK", &fsname );
  833. return 2;
  834. }
  835. } else {
  836. Msg->SetLoggingEnabled(FALSE); // no need to log anything if volume is clean
  837. Msg->DisplayMsg(MSG_CHK_VOLUME_CLEAN);
  838. }
  839. // If the /r, /l, /m, /i, /p, or /c switch is specified, remove the forcing
  840. // entry from the registry before calling Chkdsk, since
  841. // Chkdsk may reboot the system if we are checking the
  842. // boot partition.
  843. //
  844. if ((ChkdskFlags & (CHKDSK_RECOVER_ALLOC_SPACE |
  845. CHKDSK_RESIZE_LOGFILE |
  846. CHKDSK_ALGORITHM_SPECIFIED |
  847. CHKDSK_SKIP_INDEX_SCAN |
  848. CHKDSK_SKIP_CYCLE_SCAN)) ||
  849. !(ChkdskFlags & CHKDSK_CHECK_IF_DIRTY) ||
  850. RemoveRegistry) {
  851. DeregisterAutochk( ArgCount, ArgArray );
  852. }
  853. // Invoke chkdsk. Note that if the /r parameter is supplied,
  854. // we recover both free and allocated space, but if the /x
  855. // parameter is supplied, we only recover free space.
  856. //
  857. if (!skip_autochk &&
  858. !vol->ChkDsk(SetupSpecialFixLevel ? SetupSpecial : TotalFix,
  859. Msg,
  860. ChkdskFlags,
  861. LogfileSize,
  862. Algorithm,
  863. ExitStatus,
  864. DriveLetter)) {
  865. DELETE(vol);
  866. KdPrintEx((DPFLTR_AUTOCHK_ID,
  867. DPFLTR_WARNING_LEVEL,
  868. "AUTOCHK: ChkDsk failure\n"));
  869. return 2;
  870. }
  871. DELETE(vol);
  872. // Dump the message retained by the message object into a file.
  873. //
  874. if( (!Msg->IsInSetup() ||
  875. (*ExitStatus == CHKDSK_EXIT_ERRS_FIXED ||
  876. *ExitStatus == CHKDSK_EXIT_COULD_NOT_FIX)) &&
  877. Msg->IsLoggingEnabled() &&
  878. boot_execute_log_file_name.Initialize( VolumeName ) &&
  879. boot_ex_temp.Initialize( L"\\BOOTEX.LOG" ) &&
  880. boot_execute_log_file_name.Strcat( &boot_ex_temp ) &&
  881. logged_message_mem.Initialize() &&
  882. Msg->QueryPackedLog( &logged_message_mem, &packed_log_length ) ) {
  883. KdPrintEx((DPFLTR_AUTOCHK_ID,
  884. DPFLTR_INFO_LEVEL,
  885. "AUTOCHK: Dumping messages to bootex.log\n"));
  886. if (!IFS_SYSTEM::WriteToFile( &boot_execute_log_file_name,
  887. logged_message_mem.GetBuf(),
  888. packed_log_length,
  889. TRUE )) {
  890. Msg->Set(MSG_CHK_OUTPUT_LOG_ERROR);
  891. Msg->Display();
  892. KdPrintEx((DPFLTR_AUTOCHK_ID,
  893. DPFLTR_WARNING_LEVEL,
  894. "AUTOCHK: Error writing messages to BOOTEX.LOG\n"));
  895. }
  896. }
  897. return 0;
  898. }
  899. BOOLEAN
  900. RegistrySosOption(
  901. )
  902. /*++
  903. Routine Description:
  904. This function examines the registry to determine whether the
  905. user's NTLOADOPTIONS boot environment variable contains the string
  906. "SOS" or not.
  907. HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control:SystemStartOptions
  908. Arguments:
  909. None.
  910. Return Value:
  911. TRUE if "SOS" was set. Otherwise FALSE.
  912. --*/
  913. {
  914. NTSTATUS st;
  915. UNICODE_STRING uKeyName, uValueName;
  916. OBJECT_ATTRIBUTES ObjectAttributes;
  917. HANDLE hKey;
  918. WCHAR ValueBuf[VALUE_BUFFER_SIZE];
  919. PKEY_VALUE_PARTIAL_INFORMATION pKeyValueInfo =
  920. (PKEY_VALUE_PARTIAL_INFORMATION)ValueBuf;
  921. ULONG ValueLength;
  922. RtlInitUnicodeString(&uKeyName, CONTROL_NAME);
  923. InitializeObjectAttributes(&ObjectAttributes, &uKeyName,
  924. OBJ_CASE_INSENSITIVE, NULL, NULL);
  925. st = NtOpenKey(&hKey, KEY_READ, &ObjectAttributes);
  926. if (!NT_SUCCESS(st)) {
  927. KdPrintEx((DPFLTR_AUTOCHK_ID,
  928. DPFLTR_WARNING_LEVEL,
  929. "AUTOCHK: can't open control key: 0x%x\n",
  930. st));
  931. return FALSE;
  932. }
  933. RtlInitUnicodeString(&uValueName, VALUE_NAME);
  934. st = NtQueryValueKey(hKey, &uValueName, KeyValuePartialInformation,
  935. (PVOID)pKeyValueInfo, VALUE_BUFFER_SIZE, &ValueLength);
  936. DebugAssert(ValueLength < VALUE_BUFFER_SIZE);
  937. NtClose(hKey);
  938. if (!NT_SUCCESS(st)) {
  939. KdPrintEx((DPFLTR_AUTOCHK_ID,
  940. DPFLTR_WARNING_LEVEL,
  941. "AUTOCHK: can't query value key: 0x%x\n",
  942. st));
  943. return FALSE;
  944. }
  945. // uValue.Buffer = (PVOID)&pKeyValueInfo->Data;
  946. // uValue.Length = uValue.MaximumLength = (USHORT)pKeyValueInfo->DataLength;
  947. if (NULL != wcsstr((PWCHAR)&pKeyValueInfo->Data, L"SOS") ||
  948. NULL != wcsstr((PWCHAR)&pKeyValueInfo->Data, L"sos")) {
  949. return TRUE;
  950. }
  951. return FALSE;
  952. }
  953. BOOLEAN
  954. ExtendNtfsVolume(
  955. PCWSTRING DriveName,
  956. PMESSAGE Message
  957. )
  958. /*++
  959. Routine Description:
  960. This function changes the count of sectors in sector
  961. zero to agree with the drive object. This is useful
  962. when extending volume sets. Note that it requires that
  963. we be able to lock the volume, and that it should only
  964. be called if we know that the drive in question in an
  965. NTFS volume. This function also copies the boot sector
  966. to the end of the partition, where it's kept as a backup.
  967. Arguments:
  968. DriveName -- Supplies the name of the volume.
  969. Message -- Supplies an output channel for messages.
  970. Return Value:
  971. TRUE upon completion.
  972. --*/
  973. {
  974. LOG_IO_DP_DRIVE Drive;
  975. SECRUN Secrun;
  976. HMEM Mem;
  977. PPACKED_BOOT_SECTOR BootSector;
  978. if( !Drive.Initialize( DriveName, Message ) ||
  979. !Drive.Lock() ||
  980. !Mem.Initialize() ||
  981. !Secrun.Initialize( &Mem, &Drive, 0, 1 ) ||
  982. !Secrun.Read() ) {
  983. return FALSE;
  984. }
  985. BootSector = (PPACKED_BOOT_SECTOR)Secrun.GetBuf();
  986. //
  987. // We leave an extra sector at the end of the volume to contain
  988. // the new replica boot sector.
  989. //
  990. BootSector->NumberSectors.LowPart = Drive.QuerySectors().GetLowPart() - 1;
  991. BootSector->NumberSectors.HighPart = Drive.QuerySectors().GetHighPart();
  992. if (!Secrun.Write()) {
  993. return FALSE;
  994. }
  995. Secrun.Relocate( Drive.QuerySectors() - 2 );
  996. if (!Secrun.Write()) {
  997. KdPrintEx((DPFLTR_AUTOCHK_ID,
  998. DPFLTR_WARNING_LEVEL,
  999. "AUTOCHK: Error: %x\n",
  1000. Drive.QueryLastNtStatus()));
  1001. return FALSE;
  1002. }
  1003. return TRUE;
  1004. }
  1005. BOOLEAN
  1006. DeregisterAutochk(
  1007. int argc,
  1008. char** argv
  1009. )
  1010. /*++
  1011. Routine Description:
  1012. This function removes the registry entry which triggered
  1013. autochk.
  1014. Arguments:
  1015. argc -- Supplies the number of arguments given to autochk.
  1016. argv -- supplies the arguments given to autochk.
  1017. Return Value:
  1018. TRUE upon successful completion.
  1019. --*/
  1020. {
  1021. DSTRING CommandLineString,
  1022. CurrentArgString,
  1023. OneSpace;
  1024. int i;
  1025. // Reconstruct the command line and remove it from
  1026. // the registry. First, reconstruct the primary
  1027. // string, which is "autochk arg1 arg2...".
  1028. //
  1029. if( !CommandLineString.Initialize( "autocheck autochk" ) ||
  1030. !OneSpace.Initialize( " " ) ) {
  1031. return FALSE;
  1032. }
  1033. for( i = 1; i < argc; i++ ) {
  1034. if( !CurrentArgString.Initialize(argv[i] ) ||
  1035. !CommandLineString.Strcat( &OneSpace ) ||
  1036. !CommandLineString.Strcat( &CurrentArgString ) ) {
  1037. return FALSE;
  1038. }
  1039. }
  1040. return( AUTOREG::DeleteEntry( &CommandLineString ) );
  1041. }
  1042. BOOLEAN
  1043. QueryAllHardDrives(
  1044. PMOUNT_POINT_MAP MountPointMap
  1045. )
  1046. {
  1047. static BOOLEAN first_time = TRUE;
  1048. static HANDLE dos_devices_object_dir;
  1049. static ULONG context = 0;
  1050. WCHAR link_target_buffer[MAXIMUM_FILENAME_LENGTH];
  1051. POBJECT_DIRECTORY_INFORMATION
  1052. dir_info;
  1053. OBJECT_ATTRIBUTES object_attributes;
  1054. CHAR dir_info_buffer[1024];
  1055. ULONG length;
  1056. HANDLE handle;
  1057. BOOLEAN restart_scan;
  1058. NTSTATUS status;
  1059. UNICODE_STRING link_target;
  1060. UNICODE_STRING link_type_name;
  1061. UNICODE_STRING link_name;
  1062. UNICODE_STRING link_target_prefix1;
  1063. UNICODE_STRING link_target_prefix2;
  1064. UNICODE_STRING u;
  1065. DSTRING device_name;
  1066. DSTRING name;
  1067. DSTRING nt_name;
  1068. DSTRING dos_guidname_prefix;
  1069. BOOLEAN is_guidname;
  1070. DebugPtrAssert(MountPointMap);
  1071. if (!dos_guidname_prefix.Initialize(DOS_GUIDNAME_PREFIX)) {
  1072. KdPrintEx((DPFLTR_AUTOCHK_ID,
  1073. DPFLTR_WARNING_LEVEL,
  1074. "Out of memory.\n"));
  1075. return FALSE;
  1076. }
  1077. if (!MountPointMap->Initialize()) {
  1078. KdPrintEx((DPFLTR_AUTOCHK_ID,
  1079. DPFLTR_WARNING_LEVEL,
  1080. "Unable to initialize mount point map.\n"));
  1081. return FALSE;
  1082. }
  1083. link_target.Buffer = link_target_buffer;
  1084. dir_info = (POBJECT_DIRECTORY_INFORMATION)dir_info_buffer;
  1085. RtlInitUnicodeString(&link_type_name, L"SymbolicLink");
  1086. RtlInitUnicodeString(&link_target_prefix1, L"\\Device\\Volume");
  1087. RtlInitUnicodeString(&link_target_prefix2, L"\\Device\\Harddisk");
  1088. RtlInitUnicodeString(&link_name, GUID_VOLNAME_PREFIX);
  1089. restart_scan = TRUE;
  1090. RtlInitUnicodeString(&u, L"\\??");
  1091. InitializeObjectAttributes(&object_attributes, &u,
  1092. OBJ_CASE_INSENSITIVE,
  1093. NULL,
  1094. NULL);
  1095. status = NtOpenDirectoryObject(&dos_devices_object_dir,
  1096. DIRECTORY_ALL_ACCESS,
  1097. &object_attributes);
  1098. if (!NT_SUCCESS(status)) {
  1099. KdPrintEx((DPFLTR_AUTOCHK_ID,
  1100. DPFLTR_WARNING_LEVEL,
  1101. "AUTOCHK: Unable to open %wZ directory - Status == %lx\n",
  1102. &u,
  1103. status));
  1104. return FALSE;
  1105. }
  1106. for (;;) {
  1107. status = NtQueryDirectoryObject(dos_devices_object_dir,
  1108. (PVOID)dir_info,
  1109. sizeof(dir_info_buffer),
  1110. TRUE,
  1111. restart_scan,
  1112. &context,
  1113. &length);
  1114. if (status == STATUS_NO_MORE_ENTRIES) {
  1115. return TRUE;
  1116. }
  1117. if (!NT_SUCCESS(status)) {
  1118. KdPrintEx((DPFLTR_AUTOCHK_ID,
  1119. DPFLTR_WARNING_LEVEL,
  1120. "AUTOCHK: NtQueryDirectoryObject failed with %d\n",
  1121. status));
  1122. return FALSE;
  1123. }
  1124. #if 0
  1125. KdPrintEx((DPFLTR_AUTOCHK_ID,
  1126. DPFLTR_INFO_LEVEL,
  1127. "AUTOCHK: dir_info->TypeName: %wZ\n",
  1128. &(dir_info->TypeName)));
  1129. KdPrintEx((DPFLTR_AUTOCHK_ID,
  1130. DPFLTR_INFO_LEVEL,
  1131. "AUTOCHK: dir_info->Name: %wZ\n",
  1132. &(dir_info->Name)));
  1133. #endif
  1134. if (RtlEqualUnicodeString(&dir_info->TypeName, &link_type_name, TRUE) &&
  1135. ((is_guidname = RtlPrefixUnicodeString(&link_name, &dir_info->Name, TRUE)) ||
  1136. dir_info->Name.Buffer[(dir_info->Name.Length>>1)-1] == L':')) {
  1137. #if 0
  1138. KdPrintEx((DPFLTR_AUTOCHK_ID,
  1139. DPFLTR_INFO_LEVEL,
  1140. "AUTOCHK: dir_info->TypeName: %wZ\n",
  1141. &(dir_info->TypeName)));
  1142. KdPrintEx((DPFLTR_AUTOCHK_ID,
  1143. DPFLTR_INFO_LEVEL,
  1144. "AUTOCHK: dir_info->Name: %wZ\n",
  1145. &(dir_info->Name)));
  1146. #endif
  1147. InitializeObjectAttributes(&object_attributes,
  1148. &dir_info->Name,
  1149. OBJ_CASE_INSENSITIVE,
  1150. dos_devices_object_dir,
  1151. NULL);
  1152. status = NtOpenSymbolicLinkObject(&handle,
  1153. SYMBOLIC_LINK_ALL_ACCESS,
  1154. &object_attributes);
  1155. if (!NT_SUCCESS(status)) {
  1156. KdPrintEx((DPFLTR_AUTOCHK_ID,
  1157. DPFLTR_WARNING_LEVEL,
  1158. "AUTOCHK: NtOpenSymbolicLinkObject failed with %d\n",
  1159. status));
  1160. return FALSE;
  1161. }
  1162. link_target.Length = 0;
  1163. link_target.MaximumLength = sizeof(link_target_buffer);
  1164. status = NtQuerySymbolicLinkObject(handle,
  1165. &link_target,
  1166. NULL);
  1167. NtClose(handle);
  1168. if (NT_SUCCESS(status) &&
  1169. (RtlPrefixUnicodeString(&link_target_prefix1, &link_target, TRUE) ||
  1170. RtlPrefixUnicodeString(&link_target_prefix2, &link_target, TRUE))) {
  1171. if (!device_name.Initialize(link_target.Buffer,
  1172. link_target.Length / 2) ||
  1173. !name.Initialize(dir_info->Name.Buffer,
  1174. dir_info->Name.Length / 2)) {
  1175. KdPrintEx((DPFLTR_AUTOCHK_ID,
  1176. DPFLTR_WARNING_LEVEL,
  1177. "Out of memory.\n"));
  1178. return FALSE;
  1179. }
  1180. #if 0
  1181. KdPrintEx((DPFLTR_AUTOCHK_ID,
  1182. DPFLTR_INFO_LEVEL,
  1183. "AUTOCHK: Device Name: %S\n",
  1184. device_name.GetWSTR()));
  1185. #endif
  1186. if (is_guidname) {
  1187. if (!name.InsertString(0, &dos_guidname_prefix)) {
  1188. KdPrintEx((DPFLTR_AUTOCHK_ID,
  1189. DPFLTR_WARNING_LEVEL,
  1190. "Out of memory.\n"));
  1191. return FALSE;
  1192. }
  1193. if (!IFS_SYSTEM::DosDriveNameToNtDriveName(&name, &nt_name)) {
  1194. KdPrintEx((DPFLTR_AUTOCHK_ID,
  1195. DPFLTR_WARNING_LEVEL,
  1196. "Unable to translate dos drive name to nt drive name.\n"));
  1197. return FALSE;
  1198. }
  1199. #if 0
  1200. KdPrintEx((DPFLTR_AUTOCHK_ID,
  1201. DPFLTR_INFO_LEVEL,
  1202. "AUTOCHK: Volume Name: %S\n",
  1203. nt_name.GetWSTR()));
  1204. #endif
  1205. if (!MountPointMap->AddVolumeName(&device_name, &nt_name)) {
  1206. KdPrintEx((DPFLTR_AUTOCHK_ID,
  1207. DPFLTR_WARNING_LEVEL,
  1208. "Unable to add volume name into mount point map.\n"));
  1209. return FALSE;
  1210. }
  1211. } else {
  1212. DebugAssert(name.QueryChCount() == 2);
  1213. #if 0
  1214. KdPrintEx((DPFLTR_AUTOCHK_ID,
  1215. DPFLTR_INFO_LEVEL,
  1216. "AUTOCHK: Drive Name: %S\n",
  1217. name.GetWSTR()));
  1218. #endif
  1219. if (!MountPointMap->AddDriveName(&device_name, &name)) {
  1220. KdPrintEx((DPFLTR_AUTOCHK_ID,
  1221. DPFLTR_WARNING_LEVEL,
  1222. "Unable to add drive name into mount point map.\n"));
  1223. return FALSE;
  1224. }
  1225. }
  1226. } else if (!NT_SUCCESS(status)) {
  1227. KdPrintEx((DPFLTR_AUTOCHK_ID,
  1228. DPFLTR_WARNING_LEVEL,
  1229. "AUTOCHK: NtQuerySymbolicLinkObject failed with %d\n",
  1230. status));
  1231. }
  1232. }
  1233. restart_scan = FALSE;
  1234. }
  1235. //NOTREACHED
  1236. return FALSE;
  1237. }
  1238. BOOLEAN
  1239. IsGuidVolName (
  1240. PWSTRING VolName
  1241. )
  1242. {
  1243. DSTRING nt_name_prefix;
  1244. DSTRING guid_volname_prefix;
  1245. if (!nt_name_prefix.Initialize(NT_NAME_PREFIX) ||
  1246. !guid_volname_prefix.Initialize(GUID_VOLNAME_PREFIX)) {
  1247. KdPrintEx((DPFLTR_AUTOCHK_ID,
  1248. DPFLTR_WARNING_LEVEL,
  1249. "Out of memory.\n"));
  1250. return FALSE;
  1251. }
  1252. if (VolName->QueryChCount() <= nt_name_prefix.QueryChCount())
  1253. return FALSE;
  1254. if (VolName->Stricmp(&nt_name_prefix,
  1255. 0,
  1256. nt_name_prefix.QueryChCount()) != 0)
  1257. return FALSE;
  1258. if (VolName->Stricmp(&guid_volname_prefix,
  1259. nt_name_prefix.QueryChCount(),
  1260. guid_volname_prefix.QueryChCount()) != 0)
  1261. return FALSE;
  1262. return TRUE;
  1263. }