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.

756 lines
20 KiB

  1. /*++
  2. Copyright (c) 1990-2000 Microsoft Corporation
  3. Module Name:
  4. entry.cxx
  5. Abstract:
  6. This module contains the entry points for UNTFS.DLL. These
  7. include:
  8. Chkdsk
  9. ChkdskEx
  10. Format
  11. FormatEx
  12. Recover
  13. Extend
  14. Author:
  15. Bill McJohn (billmc) 31-05-91
  16. Environment:
  17. ULIB, User Mode
  18. --*/
  19. #include <pch.cxx>
  20. #define _NTAPI_ULIB_
  21. #define _UNTFS_MEMBER_
  22. #include "ulib.hxx"
  23. #include "error.hxx"
  24. #include "untfs.hxx"
  25. #include "ntfsvol.hxx"
  26. #include "path.hxx"
  27. #include "ifssys.hxx"
  28. #include "rcache.hxx"
  29. #include "ifsserv.hxx"
  30. extern "C" {
  31. #include "nturtl.h"
  32. }
  33. #include "message.hxx"
  34. #include "rtmsg.h"
  35. BOOLEAN
  36. FAR APIENTRY
  37. Chkdsk(
  38. IN PCWSTRING NtDriveName,
  39. IN OUT PMESSAGE Message,
  40. IN BOOLEAN Fix,
  41. IN BOOLEAN Verbose,
  42. IN BOOLEAN OnlyIfDirty,
  43. IN BOOLEAN Recover,
  44. IN PPATH PathToCheck,
  45. IN BOOLEAN Extend,
  46. IN BOOLEAN ResizeLogFile,
  47. IN ULONG DesiredLogFileSize,
  48. OUT PULONG ExitStatus
  49. )
  50. /*++
  51. Routine Description:
  52. Check an NTFS volume.
  53. Arguments:
  54. NtDrivName supplies the name of the drive to check
  55. Message supplies an outlet for messages
  56. Fix TRUE if Chkdsk should fix errors
  57. Verbose TRUE if Chkdsk should list every file it finds
  58. OnlyIfDirty TRUE if the drive should be checked only if
  59. it is dirty
  60. Recover TRUE if the drive is to be completely checked
  61. for bad sectors.
  62. PathToCheck supplies a path to files Chkdsk should check
  63. for contiguity
  64. Extend TRUE if Chkdsk should extend the volume
  65. ResizeLogfile TRUE if Chkdsk should resize the logfile.
  66. DesiredLogfileSize if ResizeLogfile is true, supplies the desired logfile
  67. size, or 0 if we're to resize the logfile to the
  68. default size.
  69. ExitStatus Returns information about whether the chkdsk failed
  70. Return Value:
  71. TRUE if successful.
  72. --*/
  73. {
  74. NTFS_VOL NtfsVol;
  75. BOOLEAN RecoverFree, RecoverAlloc;
  76. BOOLEAN r;
  77. DWORD oldErrorMode;
  78. ULONG flags;
  79. if (Extend) {
  80. LOG_IO_DP_DRIVE Drive;
  81. SECRUN Secrun;
  82. HMEM Mem;
  83. PPACKED_BOOT_SECTOR BootSector;
  84. if( !Drive.Initialize( NtDriveName, Message ) ||
  85. !Drive.Lock() ||
  86. !Mem.Initialize() ||
  87. !Secrun.Initialize( &Mem, &Drive, 0, 1 ) ||
  88. !Secrun.Read() ) {
  89. return FALSE;
  90. }
  91. BootSector = (PPACKED_BOOT_SECTOR)Secrun.GetBuf();
  92. BootSector->NumberSectors.LowPart = Drive.QuerySectors().GetLowPart();
  93. BootSector->NumberSectors.HighPart = Drive.QuerySectors().GetHighPart();
  94. if (!Secrun.Write()) {
  95. *ExitStatus = CHKDSK_EXIT_COULD_NOT_CHK;
  96. return FALSE;
  97. }
  98. }
  99. RecoverFree = RecoverAlloc = Recover;
  100. if (Extend) {
  101. // If we're to extend the volume, we also want to verify the
  102. // new free space we're adding.
  103. //
  104. RecoverFree = TRUE;
  105. }
  106. // disable popups while we initialize the volume
  107. oldErrorMode = SetErrorMode( SEM_FAILCRITICALERRORS );
  108. if (!NtfsVol.Initialize(NtDriveName, Message)) {
  109. SetErrorMode ( oldErrorMode );
  110. *ExitStatus = CHKDSK_EXIT_COULD_NOT_CHK;
  111. return FALSE;
  112. }
  113. // Re-enable hardware popups
  114. SetErrorMode ( oldErrorMode );
  115. if (Fix || (ResizeLogFile && DesiredLogFileSize != 0)) {
  116. if (!NtfsVol.IsWriteable()) {
  117. Message->DisplayMsg(MSG_CHK_WRITE_PROTECTED);
  118. *ExitStatus = CHKDSK_EXIT_COULD_NOT_CHK;
  119. return FALSE;
  120. }
  121. if (!NtfsVol.Lock()) {
  122. // The client wants to modify the drive, but we can't lock it.
  123. // Offer to do it on next reboot.
  124. //
  125. Message->DisplayMsg(MSG_CHKDSK_ON_REBOOT_PROMPT);
  126. if (Message->IsYesResponse( FALSE )) {
  127. flags = Recover ? CHKDSK_RECOVER : 0;
  128. flags |= ResizeLogFile ? CHKDSK_RESIZE_LOGFILE : 0;
  129. if (NtfsVol.ForceAutochk( Fix,
  130. flags,
  131. DesiredLogFileSize,
  132. 0,
  133. NtDriveName )) {
  134. Message->DisplayMsg(MSG_CHKDSK_SCHEDULED);
  135. } else {
  136. Message->DisplayMsg(MSG_CHKDSK_CANNOT_SCHEDULE);
  137. }
  138. }
  139. *ExitStatus = CHKDSK_EXIT_COULD_NOT_CHK;
  140. return FALSE;
  141. }
  142. }
  143. if (!Fix && ResizeLogFile) {
  144. if (!NtfsVol.GetNtfsSuperArea()->ResizeCleanLogFile( Message,
  145. TRUE, /* ExplicitResize */
  146. DesiredLogFileSize )) {
  147. Message->DisplayMsg(MSG_CHK_NTFS_RESIZING_LOG_FILE_FAILED);
  148. return FALSE;
  149. }
  150. return TRUE;
  151. }
  152. flags = (Verbose ? CHKDSK_VERBOSE : 0);
  153. flags |= (OnlyIfDirty ? CHKDSK_CHECK_IF_DIRTY : 0);
  154. flags |= (RecoverFree ? CHKDSK_RECOVER_FREE_SPACE : 0);
  155. flags |= (RecoverAlloc ? CHKDSK_RECOVER_ALLOC_SPACE : 0);
  156. flags |= (ResizeLogFile ? CHKDSK_RESIZE_LOGFILE : 0);
  157. return NtfsVol.ChkDsk( Fix ? TotalFix : CheckOnly,
  158. Message,
  159. flags,
  160. DesiredLogFileSize,
  161. 0,
  162. ExitStatus );
  163. }
  164. BOOLEAN
  165. FAR APIENTRY
  166. ChkdskEx(
  167. IN PCWSTRING NtDriveName,
  168. IN OUT PMESSAGE Message,
  169. IN BOOLEAN Fix,
  170. IN PCHKDSKEX_FN_PARAM Param,
  171. OUT PULONG ExitStatus
  172. )
  173. /*++
  174. Routine Description:
  175. Check an NTFS volume.
  176. Arguments:
  177. NtDrivName supplies the name of the drive to check
  178. Message supplies an outlet for messages
  179. Fix TRUE if Chkdsk should fix errors
  180. Param supplies the chkdsk parameter block
  181. ExitStatus Returns information about whether the chkdsk failed
  182. Return Value:
  183. TRUE if successful.
  184. --*/
  185. {
  186. NTFS_VOL NtfsVol;
  187. BOOLEAN RecoverFree, RecoverAlloc;
  188. BOOLEAN r;
  189. DWORD oldErrorMode;
  190. USHORT algorithm;
  191. if (Param->Major != 1 || (Param->Minor != 0 && Param->Minor != 1)) {
  192. *ExitStatus = CHKDSK_EXIT_COULD_NOT_CHK;
  193. return FALSE;
  194. }
  195. if (Param->Major > 1 || (Param->Major == 1 && Param->Minor == 1)) {
  196. algorithm = Param->Algorithm;
  197. } else
  198. algorithm = 0;
  199. if (Param->Flags & CHKDSK_EXTEND) {
  200. LOG_IO_DP_DRIVE Drive;
  201. SECRUN Secrun;
  202. HMEM Mem;
  203. PPACKED_BOOT_SECTOR BootSector;
  204. if( !Drive.Initialize( NtDriveName, Message ) ||
  205. !Drive.Lock() ||
  206. !Mem.Initialize() ||
  207. !Secrun.Initialize( &Mem, &Drive, 0, 1 ) ||
  208. !Secrun.Read() ) {
  209. return FALSE;
  210. }
  211. BootSector = (PPACKED_BOOT_SECTOR)Secrun.GetBuf();
  212. BootSector->NumberSectors.LowPart = Drive.QuerySectors().GetLowPart();
  213. BootSector->NumberSectors.HighPart = Drive.QuerySectors().GetHighPart();
  214. if (!Secrun.Write()) {
  215. *ExitStatus = CHKDSK_EXIT_COULD_NOT_CHK;
  216. return FALSE;
  217. }
  218. }
  219. RecoverFree = RecoverAlloc = (BOOLEAN)(Param->Flags & CHKDSK_RECOVER);
  220. if (Param->Flags & CHKDSK_EXTEND) {
  221. // If we're to extend the volume, we also want to verify the
  222. // new free space we're adding.
  223. //
  224. RecoverFree = TRUE;
  225. }
  226. // disable popups while we initialize the volume
  227. oldErrorMode = SetErrorMode( SEM_FAILCRITICALERRORS );
  228. if (!NtfsVol.Initialize(NtDriveName, Message)) {
  229. SetErrorMode ( oldErrorMode );
  230. *ExitStatus = CHKDSK_EXIT_COULD_NOT_CHK;
  231. return FALSE;
  232. }
  233. // Re-enable hardware popups
  234. SetErrorMode ( oldErrorMode );
  235. if (Fix || ((Param->Flags & CHKDSK_RESIZE_LOGFILE) &&
  236. Param->LogFileSize != 0)) {
  237. MSGID msgId = MSG_CHKDSK_ON_REBOOT_PROMPT;
  238. WCHAR windows_path[MAX_PATH];
  239. DSTRING sdrive, nt_drive_name;
  240. BOOLEAN system_drive = FALSE;
  241. BOOLEAN do_not_dismount = FALSE;
  242. if (!NtfsVol.IsWriteable()) {
  243. Message->DisplayMsg(MSG_CHK_WRITE_PROTECTED);
  244. *ExitStatus = CHKDSK_EXIT_COULD_NOT_CHK;
  245. return FALSE;
  246. }
  247. if (GetWindowsDirectory(windows_path, sizeof(windows_path)/sizeof(WCHAR)) &&
  248. wcslen(windows_path) >= 2 &&
  249. windows_path[1] == TEXT(':') &&
  250. !(windows_path[2] = 0) &&
  251. sdrive.Initialize(windows_path) &&
  252. IFS_SYSTEM::DosDriveNameToNtDriveName(&sdrive, &nt_drive_name)) {
  253. system_drive = nt_drive_name.Stricmp(NtDriveName) == 0;
  254. } else {
  255. Message->DisplayMsg(MSG_CHK_UNABLE_TO_TELL_IF_SYSTEM_DRIVE);
  256. system_drive = FALSE;
  257. }
  258. if (!system_drive) {
  259. if (!NtfsVol.Lock()) {
  260. if (!(Param->Flags & CHKDSK_FORCE)) {
  261. Message->DisplayMsg(MSG_CHKDSK_FORCE_DISMOUNT_PROMPT);
  262. if (Message->IsYesResponse( FALSE )) {
  263. if (IFS_SYSTEM::DismountVolume(NtDriveName)) {
  264. Message->DisplayMsg(MSG_VOLUME_DISMOUNTED);
  265. } else
  266. msgId = MSG_CHKDSK_DISMOUNT_ON_REBOOT_PROMPT;
  267. } else {
  268. do_not_dismount = TRUE;
  269. }
  270. } else if (IFS_SYSTEM::DismountVolume(NtDriveName)) {
  271. Message->DisplayMsg(MSG_VOLUME_DISMOUNTED);
  272. } else
  273. msgId = MSG_CHKDSK_DISMOUNT_ON_REBOOT_PROMPT;
  274. // disable popups while we initialize the volume
  275. oldErrorMode = SetErrorMode( SEM_FAILCRITICALERRORS );
  276. if (!NtfsVol.Initialize(NtDriveName, Message)) {
  277. SetErrorMode ( oldErrorMode );
  278. *ExitStatus = CHKDSK_EXIT_COULD_NOT_CHK;
  279. return FALSE;
  280. }
  281. // Re-enable hardware popups
  282. SetErrorMode ( oldErrorMode );
  283. }
  284. }
  285. if (do_not_dismount || !NtfsVol.Lock()) {
  286. // The client wants to modify the drive, but we can't lock it.
  287. // Offer to do it on next reboot.
  288. //
  289. Message->DisplayMsg(msgId);
  290. if (Message->IsYesResponse( FALSE )) {
  291. if (NtfsVol.ForceAutochk( Fix,
  292. Param->Flags,
  293. Param->LogFileSize,
  294. algorithm,
  295. NtDriveName )) {
  296. Message->DisplayMsg(MSG_CHKDSK_SCHEDULED);
  297. } else {
  298. Message->DisplayMsg(MSG_CHKDSK_CANNOT_SCHEDULE);
  299. }
  300. }
  301. *ExitStatus = CHKDSK_EXIT_COULD_NOT_CHK;
  302. return FALSE;
  303. }
  304. }
  305. if (!Fix && (Param->Flags & CHKDSK_RESIZE_LOGFILE)) {
  306. if (!NtfsVol.GetNtfsSuperArea()->ResizeCleanLogFile( Message,
  307. TRUE, /* ExplicitResize */
  308. Param->LogFileSize )) {
  309. Message->DisplayMsg(MSG_CHK_NTFS_RESIZING_LOG_FILE_FAILED);
  310. *ExitStatus = CHKDSK_EXIT_COULD_NOT_CHK;
  311. return FALSE;
  312. }
  313. *ExitStatus = CHKDSK_EXIT_SUCCESS;
  314. return TRUE;
  315. }
  316. return NtfsVol.ChkDsk( Fix ? TotalFix : CheckOnly,
  317. Message,
  318. Param->Flags,
  319. Param->LogFileSize,
  320. algorithm,
  321. ExitStatus );
  322. }
  323. BOOLEAN
  324. FAR APIENTRY
  325. Format(
  326. IN PCWSTRING NtDriveName,
  327. IN OUT PMESSAGE Message,
  328. IN BOOLEAN Quick,
  329. IN BOOLEAN BackwardCompatible,
  330. IN MEDIA_TYPE MediaType,
  331. IN PCWSTRING LabelString,
  332. IN ULONG ClusterSize
  333. )
  334. /*++
  335. Routine Description:
  336. Format an NTFS volume.
  337. Arguments:
  338. NtDriveName -- supplies the name (in NT API form) of the volume
  339. Message -- supplies an outlet for messages
  340. Quick -- supplies a flag to indicate whether to do Quick Format
  341. BackwardCompatible
  342. -- supplies a flag to indicate if formatting to previous
  343. version of file system (e.g. FAT32->FAT16, NTFS 5.0->NTFS 4.0)
  344. MediaType -- supplies the volume's Media Type
  345. LabelString -- supplies the volume's label
  346. ClusterSize -- supplies the cluster size for the volume.
  347. --*/
  348. {
  349. DP_DRIVE DpDrive;
  350. NTFS_VOL NtfsVol;
  351. ULONG SectorsNeeded;
  352. FORMAT_ERROR_CODE errcode;
  353. ULONG flags;
  354. if (ClusterSize && ClusterSize > 64*1024) {
  355. Message->DisplayMsg(MSG_FMT_ALLOCATION_SIZE_EXCEEDED);
  356. return FALSE;
  357. }
  358. if (!DpDrive.Initialize( NtDriveName, Message )) {
  359. return FALSE;
  360. }
  361. if (DpDrive.IsFloppy()) {
  362. Message->DisplayMsg(MSG_NTFS_FORMAT_NO_FLOPPIES);
  363. return FALSE;
  364. }
  365. SectorsNeeded = NTFS_SA::QuerySectorsInElementaryStructures( &DpDrive );
  366. if( SectorsNeeded > DpDrive.QuerySectors() ) {
  367. Message->DisplayMsg( MSG_FMT_VOLUME_TOO_SMALL );
  368. return FALSE;
  369. }
  370. errcode = NtfsVol.Initialize( NtDriveName,
  371. Message,
  372. FALSE,
  373. !Quick,
  374. MediaType );
  375. if (errcode == NoError) {
  376. flags = (BackwardCompatible ? FORMAT_BACKWARD_COMPATIBLE : 0);
  377. errcode = NtfsVol.Format( LabelString, Message, flags, ClusterSize );
  378. }
  379. if (errcode == LockError) {
  380. Message->DisplayMsg(MSG_CANT_LOCK_THE_DRIVE);
  381. return FALSE;
  382. } else
  383. return (errcode == NoError);
  384. }
  385. BOOLEAN
  386. FAR APIENTRY
  387. FormatEx(
  388. IN PCWSTRING NtDriveName,
  389. IN OUT PMESSAGE Message,
  390. IN PFORMATEX_FN_PARAM Param,
  391. IN MEDIA_TYPE MediaType
  392. )
  393. /*++
  394. Routine Description:
  395. Format an NTFS volume.
  396. Arguments:
  397. NtDriveName -- supplies the name (in NT API form) of the volume
  398. Message -- supplies an outlet for messages
  399. Param -- supplies the format parameter block
  400. MediaType -- supplies the volume's Media Type
  401. --*/
  402. {
  403. DP_DRIVE DpDrive;
  404. NTFS_VOL NtfsVol;
  405. ULONG SectorsNeeded;
  406. FORMAT_ERROR_CODE errcode;
  407. if (Param->Major != 1 || Param->Minor != 0) {
  408. return FALSE;
  409. }
  410. if (Param->ClusterSize && Param->ClusterSize > 64*1024) {
  411. Message->DisplayMsg(MSG_FMT_ALLOCATION_SIZE_EXCEEDED);
  412. return FALSE;
  413. }
  414. if (!DpDrive.Initialize( NtDriveName, Message )) {
  415. return FALSE;
  416. }
  417. if (DpDrive.IsFloppy()) {
  418. Message->DisplayMsg(MSG_NTFS_FORMAT_NO_FLOPPIES);
  419. return FALSE;
  420. }
  421. SectorsNeeded = NTFS_SA::QuerySectorsInElementaryStructures( &DpDrive );
  422. if( SectorsNeeded > DpDrive.QuerySectors() ) {
  423. Message->DisplayMsg( MSG_FMT_VOLUME_TOO_SMALL );
  424. return FALSE;
  425. }
  426. errcode = NtfsVol.Initialize( NtDriveName,
  427. Message,
  428. FALSE,
  429. (Param->Flags & FORMAT_QUICK) ? 0 : 1,
  430. MediaType );
  431. if (errcode == NoError) {
  432. errcode = NtfsVol.Format( Param->LabelString,
  433. Message,
  434. Param->Flags,
  435. Param->ClusterSize );
  436. }
  437. if (errcode == LockError) {
  438. if (!(Param->Flags & FORMAT_FORCE)) {
  439. Message->DisplayMsg(MSG_FMT_FORCE_DISMOUNT_PROMPT);
  440. if (Message->IsYesResponse(FALSE) &&
  441. IFS_SYSTEM::DismountVolume(NtDriveName)) {
  442. Message->DisplayMsg(MSG_VOLUME_DISMOUNTED);
  443. } else {
  444. Message->DisplayMsg(MSG_CANT_LOCK_THE_DRIVE);
  445. return FALSE;
  446. }
  447. } else if (IFS_SYSTEM::DismountVolume(NtDriveName)) {
  448. Message->DisplayMsg(MSG_VOLUME_DISMOUNTED);
  449. }
  450. errcode = NtfsVol.Initialize( NtDriveName,
  451. Message,
  452. FALSE,
  453. (Param->Flags & FORMAT_QUICK) ? 0 : 1,
  454. MediaType );
  455. if (errcode == NoError) {
  456. errcode = NtfsVol.Format( Param->LabelString,
  457. Message,
  458. Param->Flags,
  459. Param->ClusterSize );
  460. }
  461. if (errcode == LockError) {
  462. Message->DisplayMsg(MSG_CANT_LOCK_THE_DRIVE);
  463. return FALSE;
  464. } else
  465. return (errcode == NoError);
  466. } else
  467. return (errcode == NoError);
  468. }
  469. BOOLEAN
  470. FAR APIENTRY
  471. Recover(
  472. IN PPATH RecFilePath,
  473. IN OUT PMESSAGE Message
  474. )
  475. /*++
  476. Routine Description:
  477. Recover a file on an NTFS disk.
  478. Arguments:
  479. RecFilePath -- supplies the path to the file to recover
  480. Message -- supplies a channel for messages
  481. Return Value:
  482. TRUE if successful.
  483. --*/
  484. {
  485. NTFS_VOL NtfsVol;
  486. PWSTRING FullPath;
  487. PWSTRING DosDriveName;
  488. DSTRING NtDriveName;
  489. BOOLEAN Result;
  490. FullPath = RecFilePath->QueryDirsAndName();
  491. DosDriveName = RecFilePath->QueryDevice();
  492. if ( DosDriveName == NULL ||
  493. !IFS_SYSTEM::DosDriveNameToNtDriveName(DosDriveName,
  494. &NtDriveName) ||
  495. FullPath == NULL ) {
  496. DELETE(DosDriveName);
  497. DELETE(FullPath);
  498. return FALSE;
  499. }
  500. Message->DisplayMsg(MSG_RECOV_BEGIN,
  501. "%W", DosDriveName);
  502. Message->WaitForUserSignal();
  503. Result = ( NtfsVol.Initialize( &NtDriveName, Message ) &&
  504. NtfsVol.Recover( FullPath, Message ) );
  505. DELETE(DosDriveName);
  506. DELETE(FullPath);
  507. return Result;
  508. }
  509. BOOLEAN
  510. FAR APIENTRY
  511. Extend(
  512. IN PCWSTRING NtDriveName,
  513. IN OUT PMESSAGE Message,
  514. IN BOOLEAN Verify
  515. )
  516. /*++
  517. Routine Description:
  518. Extend an NTFS volume without going through the whole chkdsk
  519. process.
  520. Arguments:
  521. NtDrivName Supplies the name of the drive to extend.
  522. Message Supplies an outlet for messages.
  523. Verify TRUE if we should verify the new space.
  524. Return Value:
  525. TRUE if successful.
  526. --*/
  527. {
  528. BIG_INT nsecOldSize; // previous size in sectors
  529. //
  530. // First save the old volume size from the boot sector, then query
  531. // the new size from the device driver and write a new boot sector
  532. // contining that size. When the Drive object is destroyed, the
  533. // dasd handle will be closed.
  534. //
  535. {
  536. LOG_IO_DP_DRIVE Drive;
  537. SECRUN Secrun;
  538. HMEM Mem;
  539. PPACKED_BOOT_SECTOR BootSector;
  540. if( !Drive.Initialize( NtDriveName, Message ) ||
  541. !Drive.Lock() ||
  542. !Mem.Initialize() ||
  543. !Secrun.Initialize( &Mem, &Drive, 0, 1 ) ||
  544. !Secrun.Read() ) {
  545. return FALSE;
  546. }
  547. BootSector = (PPACKED_BOOT_SECTOR)Secrun.GetBuf();
  548. nsecOldSize = BootSector->NumberSectors;
  549. // Leave one sector at the end of the volume for the replica boot
  550. // sector.
  551. //
  552. BootSector->NumberSectors.LowPart = (Drive.QuerySectors() - 1).GetLowPart();
  553. BootSector->NumberSectors.HighPart = (Drive.QuerySectors() - 1).GetHighPart();
  554. if (!Secrun.Write()) {
  555. return FALSE;
  556. }
  557. }
  558. //
  559. // When the ntfs volume object is initialized, it will get the new
  560. // size from the boot sector. When it opens a handle on the volume,
  561. // the filesystem will re-mount and pick up the new size, as well.
  562. //
  563. NTFS_VOL ntfs_vol;
  564. if (!ntfs_vol.Initialize(NtDriveName, Message) || !ntfs_vol.Lock()) {
  565. return FALSE;
  566. }
  567. return ntfs_vol.Extend(Message, Verify, nsecOldSize);
  568. }