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.

1756 lines
49 KiB

  1. // Copyright (c) 1996-1999 Microsoft Corporation
  2. //+-------------------------------------------------------------------------
  3. //
  4. // Microsoft Windows
  5. //
  6. // File: fileops.cxx
  7. //
  8. // Contents: OBJID and file operations
  9. //
  10. // Classes:
  11. //
  12. // Functions:
  13. //
  14. //
  15. //
  16. // History: 18-Nov-96 BillMo Created.
  17. //
  18. // Notes:
  19. //
  20. // Codework:
  21. //
  22. //--------------------------------------------------------------------------
  23. #include <pch.cxx>
  24. #pragma hdrstop
  25. #include "trklib.hxx"
  26. #include "mountmgr.h"
  27. //+-------------------------------------------------------------------
  28. //
  29. // Function: ConvertToNtPath, public
  30. //
  31. // Synopsis: Convert the path in the buffer to an Nt style path, in the
  32. // other buffer.
  33. //
  34. // Arguments: [pwszVolumePath] -- In. Buffer containing Dos style path.
  35. // [pwszNtPath] -- Out. Buffer for new path.
  36. // [cwcBuf] -- In. Size of buffer in wide chars.
  37. //
  38. // Returns: Return value is length in characters (not including nul)
  39. // of converted path. Zero if not completely converted.
  40. //
  41. //--------------------------------------------------------------------
  42. unsigned
  43. ConvertToNtPath(const TCHAR *ptszVolumePath, WCHAR *pwszNtPath, ULONG cwcBuf)
  44. {
  45. unsigned i=12; // for \DosDevices\ .
  46. WCHAR *pwszWrite = pwszNtPath;
  47. ULONG cwcLeft = cwcBuf;
  48. BOOL fDone = FALSE;
  49. unsigned ret;
  50. if (ptszVolumePath[0] == TEXT('\\') && ptszVolumePath[1] == TEXT('\\'))
  51. {
  52. i+=3;
  53. ptszVolumePath++;
  54. // i = 15
  55. // ptszVolumePath -----\ .
  56. // |
  57. // v
  58. // \\billmo2\rootd
  59. //
  60. }
  61. if (cwcLeft > i)
  62. {
  63. memcpy(pwszWrite, L"\\DosDevices\\UNC", i*sizeof(WCHAR));
  64. pwszWrite += i;
  65. cwcLeft -= i;
  66. while (cwcLeft)
  67. {
  68. *pwszWrite = (WCHAR) *ptszVolumePath;
  69. cwcLeft --;
  70. if (*ptszVolumePath == 0)
  71. {
  72. // we just copied a null
  73. fDone = TRUE;
  74. break;
  75. }
  76. else
  77. {
  78. ptszVolumePath++;
  79. pwszWrite++;
  80. }
  81. }
  82. }
  83. ret = (fDone ? (unsigned)(pwszWrite - pwszNtPath) : 0);
  84. return(ret);
  85. }
  86. //+----------------------------------------------------------------------------
  87. //
  88. // IsLocalObjectVolume
  89. //
  90. // Determine if the specified volume (specified as a mount manager volume
  91. // name) is capable of object IDs (i.e. NTFS5). The tracking service
  92. // currently only supports fixed volumes, so this routine really only
  93. // returns true for fixed NTFS5 volumes.
  94. //
  95. // The input is a "volume name", as opposed to a volume device name
  96. // (i.e. it has a trailing slash). E.g.:
  97. //
  98. // \\?\Volume{8baec120-078b-11d2-824b-000000000000}\
  99. //
  100. // The proper way to implement this routine is to open the filesystem
  101. // on this device, query for its FS attributes, and check for the
  102. // supports-object-ids bit. But the ugly side-effect of this is that
  103. // we end up opening every volume on the system during system bootup,
  104. // including the floppies. So as a workaround, we look up the device
  105. // in the object directory first, and only bother to check for the
  106. // bit on "\Device\HarddiskVolume" type devices.
  107. //
  108. //+----------------------------------------------------------------------------
  109. const TCHAR *s_tszHarddiskDevicePrefix = TEXT("\\Device\\HarddiskVolume");
  110. BOOL
  111. IsLocalObjectVolume( const TCHAR *ptszVolumeName )
  112. {
  113. TCHAR tszTargetSymLink[ MAX_PATH ];
  114. TCHAR tszVolumeDeviceName[ MAX_PATH + 1 ];
  115. ULONG cchVolumeName;
  116. DWORD dwFsFlags = 0;
  117. // Validate the volume name prefix.
  118. //TrkAssert( !_tcsnicmp( TEXT("\\\\?\\"), ptszVolumeName, 4 ) );
  119. /*
  120. // For the QueryDosDevice call, we need to strip the "\\?\"
  121. // from the beginning of the name.
  122. cchVolumeName = _tcslen( &ptszVolumeName[4] );
  123. memcpy( tszVolumeDeviceName, &ptszVolumeName[4],
  124. cchVolumeName * sizeof(TCHAR) );
  125. // Also for the QueryDosDevice call, we nee to strip the
  126. // whack from the end of the name.
  127. TrkAssert( TEXT('\\') == tszVolumeDeviceName[cchVolumeName-1] );
  128. tszVolumeDeviceName[ cchVolumeName - 1 ] = TEXT('\0');
  129. // Query for this device's symlink.
  130. if( !QueryDosDevice( tszVolumeDeviceName,
  131. tszTargetSymLink,
  132. sizeof(tszTargetSymLink)/sizeof(TCHAR) ))
  133. {
  134. TrkLog(( TRKDBG_MISC,
  135. TEXT("Couldn't query %s for symlink in obj dir (%lu)"),
  136. tszVolumeDeviceName, GetLastError() ));
  137. return FALSE;
  138. }
  139. TrkLog(( TRKDBG_MISC,
  140. TEXT("Volume %s is %s"),
  141. ptszVolumeName, tszTargetSymLink ));
  142. // Is this a harddisk? I.e., does the symlink have the \Device\HarddiskVolume
  143. // prefix?
  144. if( _tcsnicmp( tszTargetSymLink,
  145. s_tszHarddiskDevicePrefix,
  146. _tcslen(s_tszHarddiskDevicePrefix) ))
  147. {
  148. // No, assume therefore that it's not an object (NTFS5) volume.
  149. return FALSE;
  150. }
  151. // Otherwise, is it a fixed harddisk?
  152. else if( DRIVE_FIXED != GetDriveType(ptszVolumeName) )
  153. // No - we don't currently handle removeable media.
  154. return FALSE;
  155. */
  156. if( DRIVE_FIXED != GetDriveType(ptszVolumeName) )
  157. return FALSE;
  158. // Finally, check to see if it supports object IDs
  159. if( GetVolumeInformation(ptszVolumeName,
  160. NULL,
  161. 0,
  162. NULL,
  163. NULL,
  164. &dwFsFlags,
  165. NULL,
  166. 0 )
  167. &&
  168. (dwFsFlags & FILE_SUPPORTS_OBJECT_IDS) )
  169. {
  170. // Yes, it's a fixed harddisk that supports OIDs
  171. return TRUE;
  172. }
  173. else
  174. // It's a fixed harddisk, but it doesn't supports
  175. // OIDs (it's probably FAT).
  176. return FALSE;
  177. }
  178. #if 0
  179. BOOL
  180. IsLocalObjectVolume( const TCHAR *ptszVolumeDeviceName )
  181. {
  182. BOOL fObjectIdCapable = FALSE;
  183. TCHAR tszVol[4];
  184. TCHAR tszRootOfVolume[MAX_PATH+1];
  185. DWORD dw;
  186. DWORD dwFsFlags;
  187. UINT DriveType;
  188. _tcscpy( tszRootOfVolume, ptszVolumeDeviceName );
  189. _tcscat( tszRootOfVolume, TEXT("\\") );
  190. // Get the drive type
  191. DriveType = GetDriveType(tszRootOfVolume);
  192. // Return TRUE if the drive type is fixed, and if
  193. // the filesystem attribute bit is set that indicates
  194. // that object IDs are supported.
  195. return ( ( DRIVE_FIXED == DriveType
  196. /*|| DRIVE_REMOVABLE == DriveType*/
  197. )
  198. &&
  199. GetVolumeInformation(tszRootOfVolume,
  200. NULL,
  201. 0,
  202. NULL,
  203. NULL,
  204. &dwFsFlags,
  205. NULL,
  206. 0 )
  207. &&
  208. (dwFsFlags & FILE_SUPPORTS_OBJECT_IDS) );
  209. }
  210. #endif
  211. //+-------------------------------------------------------------------
  212. //
  213. // Function: MapLocalPathToUNC
  214. //
  215. // Synopsis: Convert a volume-relative path to a UNC path.
  216. // Since there could be multiple UNC paths which cover
  217. // this local path, that which provides greatest
  218. // coverage & access will be returns (e.g., "C:\"
  219. // covers more than "C:\Docs".
  220. //
  221. // Arguments: [tszLocalPath] (in)
  222. // A local path, including the drive letter.
  223. // [tszUNC] (out)
  224. // An equivalent UNC path which provides the
  225. // greatest access.
  226. //
  227. // Returns: [HRESULT]
  228. //
  229. // Exceptions: None
  230. //
  231. //--------------------------------------------------------------------
  232. HRESULT
  233. MapLocalPathToUNC( RPC_BINDING_HANDLE IDL_handle,
  234. const TCHAR *ptszLocalPath,
  235. TCHAR *ptszUNC )
  236. {
  237. // -----
  238. // Locals
  239. // ------
  240. HRESULT hr = S_OK; // Return value
  241. CShareEnumerator cShareEnum;
  242. ULONG ulBestMerit;
  243. TCHAR tszBestShare[ MAX_PATH + 1 ];
  244. TCHAR tszBestPath[ MAX_PATH + 1 ];
  245. ULONG cchBestPath = 0;
  246. // ----------
  247. // Initialize
  248. // ----------
  249. __try
  250. {
  251. // Open an enumeration of the disk shares on this machine.
  252. // If we early-exit due to an exception, it will clean itself up.
  253. // NOTE: The ptszLocalPath is only provided until we can fix
  254. // GetAccessLevel so that it doesn't have to do opens.
  255. cShareEnum.Initialize( IDL_handle );
  256. ulBestMerit = cShareEnum.GetMinimumMerit() - 1;
  257. // --------------------
  258. // Enumerate the shares
  259. // --------------------
  260. while( cShareEnum.Next() )
  261. {
  262. // Does this share cover the local path?
  263. if( cShareEnum.CoversDrivePath( ptszLocalPath ))
  264. {
  265. // Is this a better share than anything we've seen so far?
  266. if( cShareEnum.GetMerit() > ulBestMerit )
  267. {
  268. // We have a new best share. We'll hang on to both
  269. // the share and it's path.
  270. _tcscpy( tszBestShare, cShareEnum.GetShareName() );
  271. _tcscpy( tszBestPath, cShareEnum.GetSharePath() );
  272. ulBestMerit = cShareEnum.GetMerit();
  273. cchBestPath = cShareEnum.QueryCCHSharePath();
  274. }
  275. } // if( cenumShares.QueryCCHSharePath() < cchBestPath )
  276. } // while( cenumShares.Next() )
  277. // Did we find a share which encompasses the file?
  278. if( 0 == cchBestPath )
  279. {
  280. hr = HRESULT_FROM_WIN32( ERROR_PATH_NOT_FOUND );
  281. goto Exit;
  282. }
  283. // -------------------
  284. // Create the UNC path
  285. // -------------------
  286. _tcscpy( ptszUNC, cShareEnum.GetMachineName() );
  287. _tcscat( ptszUNC, TEXT("\\") );
  288. _tcscat( ptszUNC, tszBestShare );
  289. if ( ptszLocalPath[ cchBestPath ] != TEXT('\\') )
  290. _tcscat( ptszUNC, TEXT("\\") );
  291. _tcscat( ptszUNC, &ptszLocalPath[ cchBestPath ] );
  292. hr = S_OK;
  293. } // __try
  294. __except( BreakOnDebuggableException() )
  295. {
  296. hr = GetExceptionCode();
  297. }
  298. // ----
  299. // Exit
  300. // ----
  301. Exit:
  302. if( FAILED(hr) )
  303. {
  304. TrkLog(( TRKDBG_ERROR,
  305. TEXT("MapLocalPathToUNC returned hr=%08x"), hr ));
  306. }
  307. return( hr );
  308. } // MapLocalPathToUNC
  309. //+-------------------------------------------------------------------
  310. //
  311. // Function: OpenVolume, public
  312. //
  313. // [ptszVolumeDeviceName] is a Win32 name for a volume in the NT
  314. // namespace, *without* the trailing whack. E.g.
  315. //
  316. // \\.\A:
  317. //
  318. // if you append a whack on the end of this, it opens the root
  319. // of the volume, not the volume itself.
  320. //
  321. //--------------------------------------------------------------------
  322. NTSTATUS
  323. OpenVolume( const TCHAR *ptszVolumeDeviceName, HANDLE * phVolume )
  324. {
  325. NTSTATUS status;
  326. FILE_FS_DEVICE_INFORMATION DeviceInfo;
  327. IO_STATUS_BLOCK Iosb;
  328. HANDLE hDirect = NULL;
  329. // First, open the file in direct mode (by only opening it for
  330. // file_read_attributes). This will open the volume but not cause
  331. // any filesystem to be loaded. This was done for the following scenario:
  332. // A volume gets dismounted and goes offline for some reason. Trkwks
  333. // gets the dismount notification and closes its handles. Something
  334. // attempt to open the volume, and IO loads the RAW filesystem (if no other
  335. // filesystem can be loaded, IO always loads the rawfs). This causes a
  336. // mount notification. Trkwks gets this mount notification and
  337. // tries to reopen its handles. It can open the volume handle, but it's
  338. // just to the rawfs. It tries to open the oid index, but IO returns an
  339. // invalid parameter error. Trkwks then closes all of its handles again,
  340. // including the volume handle. When all handles are closed on rawfs in this
  341. // way, it automatically dismounts (without sending a dismount notification).
  342. // The problem is, when trkwks opened the volume handle, it mounted the
  343. // volume (rawfs) and caused a new mount notification, which it now receives
  344. // and tries to open its handles again. In this way trkwks goes into an
  345. // infinite loop.
  346. //
  347. // The solution is to open the volume direct, and see if it's really mounted.
  348. // If not, don't try to open the volume.
  349. status = TrkCreateFile(
  350. ptszVolumeDeviceName,
  351. FILE_READ_ATTRIBUTES,
  352. FILE_ATTRIBUTE_NORMAL,
  353. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  354. FILE_OPEN,
  355. FILE_SYNCHRONOUS_IO_NONALERT,
  356. NULL,
  357. &hDirect );
  358. if( !NT_SUCCESS(status) ) goto Exit;
  359. // Check for the current mount status.
  360. status = NtQueryVolumeInformationFile(
  361. hDirect,
  362. &Iosb,
  363. &DeviceInfo,
  364. sizeof(DeviceInfo),
  365. FileFsDeviceInformation );
  366. NtClose( hDirect );
  367. if( !NT_SUCCESS(status) ) goto Exit;
  368. if( !(FILE_DEVICE_IS_MOUNTED & DeviceInfo.Characteristics) )
  369. {
  370. // This volume isn't currently mounted, and we don't want to be
  371. // the ones to mount it.
  372. TrkLog(( TRKDBG_WARNING, TEXT("Attempted to open dismounted volume (%s)"),
  373. ptszVolumeDeviceName ));
  374. status = STATUS_VOLUME_DISMOUNTED;
  375. goto Exit;
  376. }
  377. // The filesystem is already mounted, so it's OK for us to
  378. // open our handle.
  379. status = TrkCreateFile(
  380. ptszVolumeDeviceName,
  381. FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES,
  382. FILE_ATTRIBUTE_NORMAL,
  383. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  384. FILE_OPEN,
  385. FILE_SYNCHRONOUS_IO_NONALERT,
  386. NULL,
  387. phVolume );
  388. Exit:
  389. TrkAssert(NT_SUCCESS(status) || *phVolume == NULL);
  390. return(status);
  391. }
  392. //+----------------------------------------------------------------------------
  393. //
  394. // Function: CheckVolumeWriteProtection
  395. //
  396. // Check the filesystem attributes on a volume to see if it's write-
  397. // protected.
  398. //
  399. //+----------------------------------------------------------------------------
  400. NTSTATUS
  401. CheckVolumeWriteProtection( const TCHAR *ptszVolumeDeviceName,
  402. BOOL *pfWriteProtected )
  403. {
  404. NTSTATUS status;
  405. HANDLE hVolume = NULL;
  406. IO_STATUS_BLOCK Iosb;
  407. FILE_FS_ATTRIBUTE_INFORMATION FsAttrs;
  408. status = OpenVolume( ptszVolumeDeviceName, &hVolume );
  409. if( !NT_SUCCESS(status) )
  410. {
  411. TrkLog(( TRKDBG_WARNING, TEXT("Couldn't open volume - 0x%08x (%s)"),
  412. status, ptszVolumeDeviceName ));
  413. goto Exit;
  414. }
  415. status = NtQueryVolumeInformationFile(
  416. hVolume,
  417. &Iosb,
  418. &FsAttrs,
  419. sizeof(FsAttrs),
  420. FileFsAttributeInformation );
  421. if( !NT_SUCCESS(status) && STATUS_BUFFER_OVERFLOW != status)
  422. {
  423. TrkLog(( TRKDBG_WARNING, TEXT("Couldn't query fs attrs - 0x%08x (%s)"),
  424. status, ptszVolumeDeviceName ));
  425. goto Exit;
  426. }
  427. if( FILE_READ_ONLY_VOLUME & FsAttrs.FileSystemAttributes )
  428. *pfWriteProtected = TRUE;
  429. else
  430. *pfWriteProtected = FALSE;
  431. status = STATUS_SUCCESS;
  432. Exit:
  433. if( NULL != hVolume )
  434. NtClose( hVolume );
  435. return status;
  436. }
  437. //+-------------------------------------------------------------------
  438. //
  439. // Function: MapVolumeDeviceNameToIndex
  440. //
  441. // Map a volume device name, as defined by the mount manager, to a
  442. // zero-relative index, where 0 represents 'A:'. A "volume device name"
  443. // is e.g.
  444. //
  445. // \\?\Volume{96765fc3-9c72-11d1-b93d-000000000000}
  446. //
  447. // a "volume name" is the volume device name post-pended with a
  448. // whack (it is in this form that the mount manager returns the name).
  449. //
  450. //+-------------------------------------------------------------------
  451. /*
  452. LONG
  453. MapVolumeDeviceNameToIndex( TCHAR *ptszVolumeDeviceName )
  454. {
  455. // BUGBUG: Rewrite this to use IOCTL_MOUNTMGR_QUERY_POINTS
  456. TCHAR tszVolumeNameOfCaller[ CCH_MAX_VOLUME_NAME + 1 ];
  457. TCHAR tszVolumeNameForRoot[ CCH_MAX_VOLUME_NAME + 1 ];
  458. TCHAR tszRoot[] = TEXT("*:\\");
  459. // Convert the caller's volume name to a volume device name.
  460. _tcscpy( tszVolumeNameOfCaller, ptszVolumeDeviceName );
  461. _tcscat( tszVolumeNameOfCaller, TEXT("\\") );
  462. // Loop through all the possible drive letters, trying to find the
  463. // caller's volume name.
  464. for( LONG iVol = 0; iVol < NUM_VOLUMES; iVol++ )
  465. {
  466. tszRoot[0] = TEXT('A') + iVol;
  467. if( GetVolumeNameForVolumeMountPoint( tszRoot, tszVolumeNameForRoot, sizeof(tszVolumeNameForRoot) ))
  468. {
  469. // We have a real volume with a name. See if it's the name we seek.
  470. if( 0 == _tcscmp( tszVolumeNameForRoot, tszVolumeNameOfCaller ))
  471. return( iVol );
  472. }
  473. }
  474. return( -1 );
  475. }
  476. */
  477. LONG
  478. MapVolumeDeviceNameToIndex( TCHAR *ptszVolumeDeviceName )
  479. {
  480. HANDLE hMountManager = INVALID_HANDLE_VALUE;
  481. BYTE MountPointBuffer[ sizeof(MOUNTMGR_MOUNT_POINT) + MAX_PATH ];
  482. PMOUNTMGR_MOUNT_POINT pMountPoint = (PMOUNTMGR_MOUNT_POINT) MountPointBuffer;
  483. BYTE MountPointsBuffer[ MAX_PATH ];
  484. PMOUNTMGR_MOUNT_POINTS pMountPoints = (PMOUNTMGR_MOUNT_POINTS) MountPointsBuffer;
  485. BOOL fQuerySuccessful = FALSE;
  486. ULONG cbMountPoints = 0;
  487. ULONG cbVolumeDeviceName;
  488. LONG iVol = -1;
  489. __try
  490. {
  491. // Open the mount manager.
  492. hMountManager = CreateFileW( MOUNTMGR_DOS_DEVICE_NAME, GENERIC_READ,
  493. FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
  494. OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,
  495. INVALID_HANDLE_VALUE );
  496. if( INVALID_HANDLE_VALUE == hMountManager )
  497. {
  498. TrkLog(( TRKDBG_ERROR, TEXT("Couldn't open MountManager") ));
  499. TrkRaiseLastError();
  500. }
  501. // Initialize the input (pMountPoint)
  502. pMountPoint = (PMOUNTMGR_MOUNT_POINT) MountPointBuffer;
  503. memset(pMountPoint, 0, sizeof(MountPointBuffer) );
  504. cbVolumeDeviceName = sizeof(TCHAR) * _tcslen(ptszVolumeDeviceName);
  505. // Load the name of the device for which we wish to query. We convert
  506. // this from Win32 "\\?\" form to NT "\??\" form.
  507. pMountPoint->DeviceNameOffset = sizeof(MOUNTMGR_MOUNT_POINT);
  508. pMountPoint->DeviceNameLength = cbVolumeDeviceName;
  509. _tcscpy( (TCHAR*)( MountPointBuffer + pMountPoint->DeviceNameOffset ),
  510. TEXT("\\??") );
  511. _tcscat( (TCHAR*)( MountPointBuffer + pMountPoint->DeviceNameOffset ),
  512. &ptszVolumeDeviceName[3] );
  513. // Query the mount manager for info on this device.
  514. ULONG cQueryAttempts = 0; // Guarantee no infinite loop.
  515. fQuerySuccessful = FALSE;
  516. cbMountPoints = sizeof(MountPointsBuffer);
  517. while( !fQuerySuccessful )
  518. {
  519. // Check for an infinite loop.
  520. if( cQueryAttempts > 100 )
  521. {
  522. TrkLog(( TRKDBG_ERROR,
  523. TEXT("Failed IOCTL_MOUNTMGR_QUERY_POINTS (%lu, loop detect)"), GetLastError() ));
  524. TrkRaiseLastError();
  525. }
  526. // Query the mount manager
  527. fQuerySuccessful = DeviceIoControl( hMountManager,
  528. IOCTL_MOUNTMGR_QUERY_POINTS,
  529. pMountPoint,
  530. sizeof(MountPointBuffer),
  531. pMountPoints,
  532. cbMountPoints,
  533. &cbMountPoints,
  534. NULL);
  535. // Did it work?
  536. if( fQuerySuccessful )
  537. // Yes, we got the info.
  538. break;
  539. // Otherwise, do we need a bigger out-buf?
  540. else if( ERROR_MORE_DATA == GetLastError() )
  541. {
  542. // Yes, the size of the necessary out-buf is at
  543. // the beginning of the out-buf we provided.
  544. cbMountPoints = pMountPoints->Size;
  545. // The initial guess buffer is on the stack, not heap.
  546. if( (PMOUNTMGR_MOUNT_POINTS) MountPointsBuffer != pMountPoints )
  547. delete [] pMountPoints;
  548. pMountPoints = (PMOUNTMGR_MOUNT_POINTS) new BYTE[ cbMountPoints ];
  549. if( NULL == pMountPoints )
  550. {
  551. TrkLog(( TRKDBG_ERROR, TEXT("Couldn't alloc pMountPoints") ));
  552. TrkRaiseWin32Error( ERROR_NOT_ENOUGH_MEMORY );
  553. }
  554. }
  555. // Of it's not a more-data error, then there's nothing more we can do.
  556. else
  557. break;
  558. } // while( !fQuerySuccessful )
  559. // Raise if the query failed.
  560. if( !fQuerySuccessful )
  561. {
  562. TrkLog(( TRKDBG_WARNING,
  563. TEXT("Failed IOCTL_MOUNTMGR_QUERY_POINTS (%lu)"), GetLastError() ));
  564. TrkRaiseLastError();
  565. }
  566. // Loop through the returned mount points. There should be 2: one of
  567. // the form "\??\Volume{8baec120-078b-11d2-824b-000000000000}",
  568. // and one of the form "\DosDevices\C:" (for the C drive).
  569. static const WCHAR wszSymLinkPrefix[] = { L"\\DosDevices\\" };
  570. ULONG cchSymLinkPrefix = sizeof(wszSymLinkPrefix)/sizeof(WCHAR) - 1;
  571. for( int i = 0; i < pMountPoints->NumberOfMountPoints; ++i )
  572. {
  573. PMOUNTMGR_MOUNT_POINT pOutPoint = &pMountPoints->MountPoints[i];
  574. WCHAR wc;
  575. const WCHAR *pwszSymLinkName
  576. = (PWCHAR)( (BYTE*)pMountPoints + pOutPoint->SymbolicLinkNameOffset );
  577. if( pOutPoint->SymbolicLinkNameLength/sizeof(WCHAR) >= 14
  578. &&
  579. 0 == wcsncmp( pwszSymLinkName, wszSymLinkPrefix, cchSymLinkPrefix )
  580. &&
  581. pOutPoint->UniqueIdLength )
  582. {
  583. wc = pwszSymLinkName[ cchSymLinkPrefix ];
  584. if( TEXT('a') <= wc && wc <= TEXT('z') )
  585. {
  586. iVol = wc - TEXT('a');
  587. break;
  588. }
  589. else if( TEXT('A') <= wc && wc <= TEXT('Z') )
  590. {
  591. iVol = wc - TEXT('A');
  592. break;
  593. }
  594. }
  595. }
  596. }
  597. __finally
  598. {
  599. if( INVALID_HANDLE_VALUE != hMountManager )
  600. CloseHandle( hMountManager );
  601. if( (PMOUNTMGR_MOUNT_POINTS) MountPointsBuffer != pMountPoints
  602. &&
  603. NULL != pMountPoints )
  604. {
  605. delete [] pMountPoints;
  606. }
  607. }
  608. return iVol;
  609. }
  610. //+----------------------------------------------------------------------------
  611. //
  612. // IsSystemVolumeInformation
  613. //
  614. // Is the given volume-relative path under the "System Volume Information"
  615. // directory?
  616. //
  617. // Note: This is hard-coded for now, but will be replaced by a forthcoming
  618. // Rtl export.
  619. //
  620. //+----------------------------------------------------------------------------
  621. BOOL
  622. IsSystemVolumeInformation( const TCHAR *ptszPath )
  623. {
  624. return 0 == _wcsnicmp( s_tszSystemVolumeInformation,
  625. ptszPath,
  626. wcslen(s_tszSystemVolumeInformation)/sizeof(WCHAR) );
  627. }
  628. //+-------------------------------------------------------------------
  629. //
  630. // OpenFileById
  631. //
  632. // Given an NTFS5 object ID, open the file and returns its handle.
  633. //
  634. //--------------------------------------------------------------------
  635. NTSTATUS
  636. OpenFileById( const TCHAR *ptszVolumeDeviceName,
  637. const CObjId &oid,
  638. ACCESS_MASK AccessMask,
  639. ULONG ShareAccess,
  640. ULONG AdditionalCreateOptions,
  641. HANDLE *ph)
  642. {
  643. NTSTATUS status;
  644. // A buffer for the id-based path. This path is the volume's
  645. // path followed by the 16 byte object ID
  646. TCHAR tszPath[ MAX_PATH + 1 ] = { TEXT('\0') }; // Init to prevent prefix error.
  647. // Parameters for NtCreateFile
  648. OBJECT_ATTRIBUTES ObjectAttr;
  649. IO_STATUS_BLOCK IoStatus;
  650. UNICODE_STRING uPath;
  651. PVOID pFreeBuffer = NULL;
  652. // Compose a buffer with a Win32-style name with a dummy value where
  653. // the object ID will go (use "12345678" for now). It's Win32-style
  654. // in that we will pass it to RtlDosPathNameToNtPathName below.
  655. TrkAssert( NULL != ptszVolumeDeviceName );
  656. _tcscpy( tszPath, ptszVolumeDeviceName );
  657. _tcscat( tszPath, TEXT("\\") );
  658. _tcscat( tszPath, TEXT("12345678") );
  659. // Convert to the NT path to this volume
  660. if( !RtlDosPathNameToNtPathName_U( tszPath, &uPath, NULL, NULL ))
  661. {
  662. status = STATUS_OBJECT_NAME_INVALID;
  663. goto Exit;
  664. }
  665. pFreeBuffer = uPath.Buffer;
  666. // Put in the real object ID in place of the "12345678"
  667. TrkAssert( oid.Size() == 16 );
  668. oid.SerializeRaw( reinterpret_cast<BYTE*>(&uPath.Buffer[ (uPath.Length-oid.Size()) / sizeof(uPath.Buffer[0]) ]) );
  669. // And open the file
  670. InitializeObjectAttributes( &ObjectAttr, // Structure
  671. &uPath, // Name (identifier)
  672. OBJ_CASE_INSENSITIVE, // Attributes
  673. 0, // Root
  674. 0 ); // Security
  675. status = NtCreateFile( ph,
  676. AccessMask,
  677. &ObjectAttr, &IoStatus,
  678. NULL,
  679. FILE_ATTRIBUTE_NORMAL,
  680. ShareAccess,
  681. FILE_OPEN,
  682. FILE_OPEN_BY_FILE_ID | FILE_OPEN_NO_RECALL | FILE_SYNCHRONOUS_IO_NONALERT
  683. | AdditionalCreateOptions,
  684. NULL,
  685. 0 );
  686. if( !NT_SUCCESS(status) )
  687. {
  688. *ph = NULL;
  689. goto Exit;
  690. }
  691. // ----
  692. // Exit
  693. // ----
  694. Exit:
  695. if( !NT_SUCCESS(status) && status != STATUS_OBJECT_NAME_NOT_FOUND )
  696. {
  697. TrkLog(( TRKDBG_MISC, TEXT("OpenFileById returned status=%08X"), status ));
  698. }
  699. if( NULL != pFreeBuffer )
  700. RtlFreeHeap( RtlProcessHeap(), 0, pFreeBuffer );
  701. return( status );
  702. } // OpenFileById
  703. //+----------------------------------------------------------------------
  704. //
  705. // Function: SetVolId
  706. //
  707. // Synopsis: Set the volume ID on a local volume.
  708. //
  709. // Returns: NTSTATUS
  710. //
  711. // Note: Setting the volid (and changing a volume's lable) triggers
  712. // a GUID_IO_VOLUME_CHANGE PNP device event.
  713. //
  714. //+----------------------------------------------------------------------------
  715. NTSTATUS
  716. SetVolId( const TCHAR *ptszVolumeDeviceName, const CVolumeId &volid )
  717. {
  718. NTSTATUS status = STATUS_SUCCESS;
  719. UNICODE_STRING usPath;
  720. PVOID pFreeBuffer = NULL;
  721. HANDLE hVol = NULL;
  722. FILE_FS_OBJECTID_INFORMATION file_fs_objectid_information;
  723. OBJECT_ATTRIBUTES ObjectAttr;
  724. IO_STATUS_BLOCK IoStatus;
  725. EnableRestorePrivilege();
  726. // Generate the NT path name to this volume. The VolumeDeviceName has
  727. // no trailing whack, so we'll be opening the volume, not the root dir of
  728. // the volume.
  729. if( !RtlDosPathNameToNtPathName_U( ptszVolumeDeviceName, &usPath, NULL, NULL ))
  730. {
  731. status = STATUS_OBJECT_NAME_INVALID;
  732. goto Exit;
  733. }
  734. pFreeBuffer = usPath.Buffer;
  735. // Fill in an ObjectAttributes for the NtCreateFile request
  736. InitializeObjectAttributes( &ObjectAttr, // Structure
  737. &usPath, // Name (identifier)
  738. OBJ_CASE_INSENSITIVE, // Attributes
  739. 0, // Root
  740. 0 ); // Security
  741. // Open the volume.
  742. // You wouldn't think that FILE_SHARE_WRITE would be necessary, but
  743. // without it we encounter a STATUS_UNABLE_TO_DELETE_SECTION error.
  744. // Also, we must use NtOpenFile; if we use NtCreateFile(...,FILE_OPEN,...),
  745. // we get a STATUS_ACCESS_DENIED error on the NtSetVolumeInformationFile
  746. // call.
  747. status = NtOpenFile( &hVol,
  748. SYNCHRONIZE | FILE_GENERIC_READ | FILE_GENERIC_WRITE,
  749. &ObjectAttr, &IoStatus,
  750. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  751. FILE_SYNCHRONOUS_IO_NONALERT
  752. );
  753. if( !NT_SUCCESS(status) )
  754. {
  755. hVol = NULL;
  756. TrkLog(( TRKDBG_ERROR, TEXT("SetVolId couldn't open the volume %s (status=%08x)"),
  757. ptszVolumeDeviceName, status ));
  758. goto Exit;
  759. }
  760. // Set the Volume ID
  761. file_fs_objectid_information = volid;
  762. status = NtSetVolumeInformationFile( hVol, &IoStatus,
  763. &file_fs_objectid_information,
  764. sizeof(file_fs_objectid_information),
  765. FileFsObjectIdInformation );
  766. if( !NT_SUCCESS(status) )
  767. {
  768. TrkLog(( TRKDBG_ERROR, TEXT("SetVolId couldn't set volume ID on volume %s (status=%08x)"),
  769. ptszVolumeDeviceName, status ));
  770. goto Exit;
  771. }
  772. // ----
  773. // Exit
  774. // ----
  775. Exit:
  776. if( NULL != hVol )
  777. NtClose( hVol );
  778. if( NULL != pFreeBuffer )
  779. RtlFreeHeap( RtlProcessHeap(), 0, pFreeBuffer );
  780. return( status );
  781. }
  782. //+----------------------------------------------------------------------------
  783. //
  784. // Function: TrkCreateFile
  785. //
  786. // Synopsis: Creates a file using NtCreateFile.
  787. //
  788. // Arguments: [pwszCompleteDosPath] (in)
  789. // The path to open, in 'dos' format as opposed to
  790. // NT format (e.g. "\\m\s\f" rather than "\DosDevices\..."
  791. // [AccessMask] (in)
  792. // Required access. SYNCRHONIZE is requested automatically.
  793. // [Attributes] (in)
  794. // [ShareAccess] (in)
  795. // [CreationDisposition] (in)
  796. // [CreateOptions] (in)
  797. // [lpSecurityAttributes] (in)
  798. // [ph] (out)
  799. // The resulting file handle. Always set to NULL when function
  800. // is entered.
  801. //
  802. // Returns: NTSTATUS
  803. //
  804. //+----------------------------------------------------------------------------
  805. NTSTATUS
  806. TrkCreateFile( const WCHAR *pwszCompleteDosPath,
  807. ACCESS_MASK AccessMask,
  808. ULONG Attributes,
  809. ULONG ShareAccess,
  810. ULONG CreationDisposition,
  811. ULONG CreateOptions,
  812. LPSECURITY_ATTRIBUTES lpSecurityAttributes,
  813. HANDLE *ph)
  814. {
  815. NTSTATUS status;
  816. // Parameters for NtCreateFile
  817. OBJECT_ATTRIBUTES ObjectAttr;
  818. IO_STATUS_BLOCK IoStatus;
  819. // E.g. "\??\D:\..."
  820. UNICODE_STRING uPath;
  821. PVOID pFreeBuffer = NULL;
  822. *ph = NULL;
  823. // -------------
  824. // Open the File
  825. // -------------
  826. // Generate the NT path name
  827. if( !RtlDosPathNameToNtPathName_U( pwszCompleteDosPath, &uPath, NULL, NULL ))
  828. {
  829. status = STATUS_OBJECT_NAME_INVALID;
  830. goto Exit;
  831. }
  832. pFreeBuffer = uPath.Buffer;
  833. // Set up the ObjectAttributes
  834. InitializeObjectAttributes( &ObjectAttr, // Structure
  835. &uPath, // Name (identifier)
  836. OBJ_CASE_INSENSITIVE, // Attributes
  837. 0, // Root
  838. 0 ); // Security
  839. if( NULL != lpSecurityAttributes )
  840. {
  841. ObjectAttr.SecurityDescriptor = lpSecurityAttributes->lpSecurityDescriptor;
  842. if ( lpSecurityAttributes->bInheritHandle )
  843. {
  844. ObjectAttr.Attributes |= OBJ_INHERIT;
  845. }
  846. }
  847. // Create/Open the file
  848. status = NtCreateFile( ph,
  849. AccessMask | SYNCHRONIZE,
  850. &ObjectAttr, &IoStatus,
  851. NULL,
  852. Attributes,
  853. ShareAccess,
  854. CreationDisposition,
  855. CreateOptions, // | FILE_SYNCHRONOUS_IO_NONALERT,
  856. NULL, // No EA buffer
  857. 0 );
  858. if( !NT_SUCCESS(status) )
  859. {
  860. *ph = NULL;
  861. goto Exit;
  862. }
  863. // ----
  864. // Exit
  865. // ----
  866. Exit:
  867. if( NULL != pFreeBuffer )
  868. RtlFreeHeap( RtlProcessHeap(), 0, pFreeBuffer );
  869. return( status );
  870. } // TrkCreateFile
  871. //+----------------------------------------------------------------------------
  872. //
  873. // Function: FindLocalPath
  874. //
  875. // Synopsis: Given a volume index and a file ObjectId, return a volume-relative
  876. // path to the file, and return the file's Birth ID. The returned
  877. // path does not have the drive letter prefix.
  878. //
  879. // Inputs: [ptszVolumeDeviceName] (in)
  880. // The volume on which to search.
  881. // [objid] (in)
  882. // The ObjectID to search for on this volume.
  883. // [pdroidBirth] (out)
  884. // If the function is successful, returns the found file's
  885. // birth ID.
  886. // [ptszLocalPath] (out)
  887. // If the function is successful, returns the volume-relative
  888. // path (includes the drive letter).
  889. //
  890. // Returns: [NTSTATUS]
  891. //
  892. // Exceptions: None.
  893. //
  894. //+----------------------------------------------------------------------------
  895. NTSTATUS
  896. FindLocalPath( IN const TCHAR *ptszVolumeDeviceName,
  897. IN const CObjId &objid,
  898. OUT CDomainRelativeObjId *pdroidBirth,
  899. OUT TCHAR *ptszLocalPath )
  900. {
  901. // ------
  902. // Locals
  903. // ------
  904. NTSTATUS status;
  905. IO_STATUS_BLOCK Iosb;
  906. HANDLE hFile = NULL;
  907. // Open the file
  908. status = OpenFileById( ptszVolumeDeviceName,
  909. objid,
  910. SYNCHRONIZE | FILE_READ_ATTRIBUTES,
  911. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  912. 0,
  913. &hFile);
  914. if( !NT_SUCCESS(status) )
  915. {
  916. hFile = NULL;
  917. goto Exit;
  918. }
  919. // Get the file's birth ID
  920. status = GetBirthId( hFile, pdroidBirth );
  921. if( !NT_SUCCESS(status) ) goto Exit;
  922. // Get the volume-relative path
  923. status = QueryVolRelativePath( hFile, ptszLocalPath );
  924. if( !NT_SUCCESS(status) ) goto Exit;
  925. // When ptszLocalPath is a root directory, no relative path
  926. // will be found. i.e. "d:" will remain "d:", instead of "d:\", which is
  927. // what we want. We have to put the '\' in here.
  928. if(TEXT('\0') == ptszLocalPath[0])
  929. {
  930. ptszLocalPath[0] = TEXT('\\');
  931. ptszLocalPath[1] = TEXT('\0');
  932. }
  933. // ----
  934. // Exit
  935. // ----
  936. Exit:
  937. if( NULL != hFile )
  938. NtClose( hFile );
  939. if( !NT_SUCCESS(status)
  940. &&
  941. STATUS_OBJECT_PATH_NOT_FOUND != status
  942. &&
  943. STATUS_OBJECT_NAME_NOT_FOUND != status
  944. &&
  945. STATUS_INVALID_PARAMETER != status // Happens when the objid is really the volid
  946. )
  947. {
  948. TrkLog(( TRKDBG_MISC,
  949. TEXT("FindLocalPath returned status=%08X"), status ));
  950. }
  951. return( status );
  952. }
  953. //+----------------------------------------------------------------------------
  954. //
  955. // Function: GetDroids
  956. //
  957. // Synopsis: Get the current and birth domain-relative object IDs from
  958. // a file. If rgoEnum is RGO_GET_OBJECT_ID, then an object ID
  959. // will be generated if necessary. If RGO_READ_OBJECT_ID is
  960. // specified, and the file doesn't already have an object ID,
  961. // then STATUS_OBJECT_NAME_NOT_FOUND will be returned.
  962. //
  963. // Inputs: [tszFile] (in)
  964. // The file who's object ID is to be retrieved.
  965. // [pdroidCurrent] (out)
  966. // The file's CDomainRelativeObjId.
  967. // [pdroidBirth] (out)
  968. // The file's birth CDomainRelativeObjId
  969. // [rgoEnum] (in)
  970. // RGO_READ_OBJECTID => Read the object IDs, return
  971. // STATUS_OBJECT_NAME_NOT_FOUND if none exist.
  972. // RGO_GET_OBJECTID => Get the object IDs, generating
  973. // and setting if necessary.
  974. //
  975. // Returns: NTSTATUS, outputs zero on error
  976. //
  977. // Exceptions: None
  978. //
  979. //+----------------------------------------------------------------------------
  980. NTSTATUS
  981. GetDroids( HANDLE hFile,
  982. CDomainRelativeObjId *pdroidCurrent,
  983. CDomainRelativeObjId *pdroidBirth,
  984. RGO_ENUM rgoEnum )
  985. {
  986. NTSTATUS status = STATUS_SUCCESS;
  987. // Filled by NtQueryInformationFile
  988. FILE_OBJECTID_BUFFER fobOID;
  989. IO_STATUS_BLOCK Iosb;
  990. CDomainRelativeObjId droidCurrent;
  991. CDomainRelativeObjId droidBirth;
  992. pdroidCurrent->Init();
  993. pdroidBirth->Init();
  994. // -----------------
  995. // Get the Object ID
  996. // -----------------
  997. // Use the file handle to get the file's Object ID
  998. memset( &fobOID, 0, sizeof(fobOID) );
  999. status = NtFsControlFile(
  1000. hFile,
  1001. NULL,
  1002. NULL,
  1003. NULL,
  1004. &Iosb,
  1005. RGO_READ_OBJECTID == rgoEnum ? FSCTL_GET_OBJECT_ID : FSCTL_CREATE_OR_GET_OBJECT_ID,
  1006. NULL,
  1007. 0,
  1008. &fobOID, // Out buffer
  1009. sizeof(fobOID) ); // Out buffer size
  1010. if( !NT_SUCCESS(status) )
  1011. goto Exit;
  1012. // ---------------
  1013. // Load the Droids
  1014. // ---------------
  1015. droidBirth.InitFromFOB( fobOID );
  1016. droidBirth.GetVolumeId().Normalize();
  1017. status = droidCurrent.InitFromFile( hFile, fobOID );
  1018. if( !NT_SUCCESS(status) ) goto Exit;
  1019. *pdroidCurrent = droidCurrent;
  1020. *pdroidBirth = droidBirth;
  1021. // ----
  1022. // Exit
  1023. // ----
  1024. Exit:
  1025. if( !NT_SUCCESS(status)
  1026. &&
  1027. STATUS_OBJECT_NAME_NOT_FOUND != status // Ignore non-link source
  1028. &&
  1029. STATUS_INVALID_DEVICE_REQUEST != status // Ignore e.g. FAT
  1030. &&
  1031. STATUS_VOLUME_NOT_UPGRADED != status // Ignore NTFS4
  1032. )
  1033. {
  1034. TrkLog(( TRKDBG_ERROR,
  1035. TEXT("GetDroids returned ntstatus=%08X"), status ));
  1036. }
  1037. return( status );
  1038. }
  1039. // Following is a wrapper that takes a filename, opens the file,
  1040. // and then calls the above GetDroids with the file handle.
  1041. NTSTATUS
  1042. GetDroids( const TCHAR *ptszFile,
  1043. CDomainRelativeObjId *pdroidCurrent,
  1044. CDomainRelativeObjId *pdroidBirth,
  1045. RGO_ENUM rgoEnum )
  1046. {
  1047. HANDLE hFile = NULL;
  1048. NTSTATUS status = STATUS_SUCCESS;
  1049. __try
  1050. {
  1051. status = TrkCreateFile( ptszFile, SYNCHRONIZE | FILE_READ_ATTRIBUTES, FILE_ATTRIBUTE_NORMAL,
  1052. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  1053. FILE_OPEN,
  1054. FILE_OPEN_NO_RECALL | FILE_SYNCHRONOUS_IO_NONALERT,
  1055. NULL, &hFile );
  1056. if( !NT_SUCCESS(status ))
  1057. {
  1058. hFile = NULL;
  1059. goto Exit;
  1060. }
  1061. status = GetDroids( hFile, pdroidCurrent, pdroidBirth, rgoEnum );
  1062. }
  1063. __finally
  1064. {
  1065. if( NULL != hFile )
  1066. NtClose( hFile );
  1067. }
  1068. Exit:
  1069. return( status );
  1070. }
  1071. //+----------------------------------------------------------------------------
  1072. //
  1073. // Function: SetObjId
  1074. //
  1075. // Synopsis: Sets an Object ID (GUID) on a file.
  1076. //
  1077. // Inputs: [ptszFile] (in)
  1078. // The file to be indexed.
  1079. // [objid] (in)
  1080. // The ID to put on the file.
  1081. // [droidBirth] (in)
  1082. // The BirthId to put on the file.
  1083. //
  1084. // Returns: NTSTATUS
  1085. //
  1086. // Exceptions: None
  1087. //
  1088. //+----------------------------------------------------------------------------
  1089. NTSTATUS
  1090. SetObjId( const HANDLE hFile,
  1091. CObjId objid,
  1092. const CDomainRelativeObjId &droidBirth )
  1093. {
  1094. // --------------
  1095. // Initialization
  1096. // --------------
  1097. NTSTATUS status = STATUS_SUCCESS;
  1098. FILE_OBJECTID_BUFFER fobOID;
  1099. IO_STATUS_BLOCK IoStatus;
  1100. // Initialize the request buffer
  1101. memset( &fobOID, 0, sizeof(fobOID) );
  1102. droidBirth.SerializeRaw( fobOID.ExtendedInfo );
  1103. objid.SerializeRaw( fobOID.ObjectId );
  1104. // Send the FSCTL
  1105. status = NtFsControlFile(
  1106. hFile,
  1107. NULL,
  1108. NULL,
  1109. NULL,
  1110. &IoStatus,
  1111. FSCTL_SET_OBJECT_ID,
  1112. &fobOID,
  1113. sizeof(fobOID),
  1114. NULL, // Out buffer
  1115. 0); // Out buffer size
  1116. if( !NT_SUCCESS(status) ) goto Exit;
  1117. // ----
  1118. // Exit
  1119. // ----
  1120. Exit:
  1121. if( !NT_SUCCESS(status) )
  1122. {
  1123. TrkLog(( TRKDBG_ERROR,
  1124. TEXT("SetObjId returned ntstatus=%08X"), status ));
  1125. }
  1126. return( status );
  1127. }
  1128. NTSTATUS
  1129. SetObjId( const TCHAR *ptszFile,
  1130. CObjId objid,
  1131. const CDomainRelativeObjId &droidBirth )
  1132. {
  1133. NTSTATUS status = STATUS_SUCCESS;
  1134. HANDLE hFile = NULL;
  1135. __try
  1136. {
  1137. // Setting the object ID requires restore privelege, but no
  1138. // file access.
  1139. EnableRestorePrivilege();
  1140. status = TrkCreateFile( ptszFile, FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES,
  1141. FILE_ATTRIBUTE_NORMAL,
  1142. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  1143. FILE_OPEN,
  1144. FILE_OPEN_FOR_BACKUP_INTENT | FILE_OPEN_NO_RECALL | FILE_SYNCHRONOUS_IO_NONALERT,
  1145. NULL, &hFile );
  1146. if( !NT_SUCCESS(status ))
  1147. {
  1148. hFile = NULL;
  1149. goto Exit;
  1150. }
  1151. status = SetObjId( hFile, objid, droidBirth );
  1152. }
  1153. __finally
  1154. {
  1155. if( NULL != hFile )
  1156. NtClose( hFile );
  1157. }
  1158. Exit:
  1159. return( status );
  1160. }
  1161. //+----------------------------------------------------------------------------
  1162. //
  1163. // Function: MakeObjIdReborn
  1164. //
  1165. // Synopsis: Resets the birth ID on a file to it's current location.
  1166. //
  1167. // Inputs: [hFile]
  1168. // The handle of the file to delete the object id of.
  1169. //
  1170. // Returns: NTSTATUS
  1171. //
  1172. // Exceptions: None
  1173. //
  1174. //+----------------------------------------------------------------------------
  1175. NTSTATUS
  1176. MakeObjIdReborn(const TCHAR *ptszVolumeDeviceName, const CObjId &objid)
  1177. {
  1178. // --------------
  1179. // Initialization
  1180. // --------------
  1181. NTSTATUS status = STATUS_SUCCESS;
  1182. HANDLE hFile = NULL;
  1183. IO_STATUS_BLOCK IoStatus;
  1184. // Open the file
  1185. EnableRestorePrivilege();
  1186. status = OpenFileById(ptszVolumeDeviceName,
  1187. objid,
  1188. SYNCHRONIZE | FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES,
  1189. FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
  1190. FILE_OPEN_FOR_BACKUP_INTENT, // for FSCTL_DELETE_OBJECT_ID
  1191. &hFile);
  1192. if( !NT_SUCCESS(status) )
  1193. {
  1194. hFile = NULL;
  1195. TrkLog(( (STATUS_SHARING_VIOLATION == status || STATUS_ACCESS_DENIED == status)
  1196. ? TRKDBG_MISC : TRKDBG_ERROR,
  1197. TEXT("Couldn't make born again objid (%s) on %s, failed open (%08x)"),
  1198. (const TCHAR*)CDebugString(objid), ptszVolumeDeviceName, status ));
  1199. goto Exit;
  1200. }
  1201. // Clear the file's birth ID
  1202. status = MakeObjIdReborn( hFile );
  1203. if( !NT_SUCCESS(status) && STATUS_OBJECT_NAME_NOT_FOUND != status )
  1204. {
  1205. TrkLog(( TRKDBG_ERROR, TEXT("Couldn't make born again Object ID (%s) on %s:, failed delete (%08x)"),
  1206. (const TCHAR*)CDebugString(objid), ptszVolumeDeviceName, status ));
  1207. goto Exit;
  1208. }
  1209. // ----
  1210. // Exit
  1211. // ----
  1212. Exit:
  1213. if( NULL != hFile )
  1214. NtClose( hFile );
  1215. #if DBG
  1216. if( !NT_SUCCESS(status)
  1217. &&
  1218. STATUS_SHARING_VIOLATION != status
  1219. &&
  1220. STATUS_ACCESS_DENIED != status )
  1221. {
  1222. TCHAR tszPath[ MAX_PATH + 1 ];
  1223. NTSTATUS statusDebug;
  1224. hFile = NULL;
  1225. statusDebug = OpenFileById( ptszVolumeDeviceName, objid,
  1226. SYNCHRONIZE | FILE_READ_ATTRIBUTES,
  1227. FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
  1228. FILE_ATTRIBUTE_NORMAL,
  1229. &hFile );
  1230. if( !NT_SUCCESS(statusDebug) )
  1231. hFile = NULL;
  1232. if( NT_SUCCESS(statusDebug) )
  1233. statusDebug = QueryVolRelativePath( hFile, tszPath );
  1234. else
  1235. TrkLog(( TRKDBG_ERROR, TEXT("Couldn't OpenFileById (%08x)"), statusDebug ));
  1236. if( NT_SUCCESS(statusDebug) )
  1237. TrkLog(( TRKDBG_ERROR, TEXT("Failed to make born again objid on %s:%s"),
  1238. ptszVolumeDeviceName, tszPath ));
  1239. else
  1240. TrkLog(( TRKDBG_ERROR, TEXT("Couldn't QueryVolRelativePath (%08x)"), statusDebug ));
  1241. if( NULL != hFile )
  1242. NtClose( hFile );
  1243. }
  1244. #endif
  1245. return( status );
  1246. }
  1247. NTSTATUS
  1248. MakeObjIdReborn(HANDLE hFile )
  1249. {
  1250. NTSTATUS status = STATUS_SUCCESS;
  1251. status = SetBirthId( hFile, CDomainRelativeObjId( ));
  1252. if( !NT_SUCCESS(status) ) goto Exit;
  1253. Exit:
  1254. return( status );
  1255. }
  1256. //+----------------------------------------------------------------------------
  1257. //
  1258. // SetBirthId
  1259. //
  1260. // The the birth ID on a file. The object ID isn't altered.
  1261. //
  1262. //+----------------------------------------------------------------------------
  1263. NTSTATUS
  1264. SetBirthId( HANDLE hFile,
  1265. const CDomainRelativeObjId &droidBirth )
  1266. {
  1267. // --------------
  1268. // Initialization
  1269. // --------------
  1270. NTSTATUS status = STATUS_SUCCESS;
  1271. BOOL fOpen = FALSE;
  1272. CObjId objidNull;
  1273. FILE_OBJECTID_BUFFER fobOID;
  1274. UNICODE_STRING uPath;
  1275. IO_STATUS_BLOCK IoStatus;
  1276. // Initialize the request buffer
  1277. memset( &fobOID, 0, sizeof(fobOID) );
  1278. droidBirth.SerializeRaw( fobOID.ExtendedInfo );
  1279. objidNull.SerializeRaw( fobOID.ObjectId );
  1280. // Send the FSCTL
  1281. status = NtFsControlFile(
  1282. hFile,
  1283. NULL,
  1284. NULL,
  1285. NULL,
  1286. &IoStatus,
  1287. FSCTL_SET_OBJECT_ID_EXTENDED,
  1288. &fobOID.ExtendedInfo,
  1289. sizeof(fobOID.ExtendedInfo),
  1290. NULL, // Out buffer
  1291. 0); // Out buffer size
  1292. if( !NT_SUCCESS(status) ) goto Exit;
  1293. // ----
  1294. // Exit
  1295. // ----
  1296. Exit:
  1297. if( !NT_SUCCESS(status) )
  1298. {
  1299. TrkLog(( TRKDBG_ERROR,
  1300. TEXT("SetBirthId returned ntstatus=%08X"), status ));
  1301. }
  1302. return( status );
  1303. }
  1304. // Set the birth ID given a path, rather than a handle.
  1305. NTSTATUS
  1306. SetBirthId( const TCHAR *ptszFile,
  1307. const CDomainRelativeObjId &droidBirth )
  1308. {
  1309. NTSTATUS status = STATUS_SUCCESS;
  1310. HANDLE hFile = NULL;
  1311. __try
  1312. {
  1313. EnableRestorePrivilege();
  1314. status = TrkCreateFile( ptszFile, SYNCHRONIZE | FILE_WRITE_ATTRIBUTES,
  1315. FILE_ATTRIBUTE_NORMAL,
  1316. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  1317. FILE_OPEN,
  1318. FILE_OPEN_FOR_BACKUP_INTENT | FILE_OPEN_NO_RECALL | FILE_SYNCHRONOUS_IO_NONALERT,
  1319. NULL, &hFile );
  1320. if( !NT_SUCCESS(status ))
  1321. {
  1322. hFile = NULL;
  1323. goto Exit;
  1324. }
  1325. status = SetBirthId( hFile, droidBirth );
  1326. }
  1327. __finally
  1328. {
  1329. if( NULL != hFile )
  1330. NtClose( hFile );
  1331. }
  1332. Exit:
  1333. return( status );
  1334. }
  1335. //+----------------------------------------------------------------------------
  1336. //
  1337. // Function: GetBirthId
  1338. //
  1339. // Synopsis: Get the birth ID from a given file.
  1340. //
  1341. // Parameters: [hFile] (in)
  1342. // The file to query.
  1343. // [pdroidBirth] (out)
  1344. // The file's birth ID.
  1345. //
  1346. // Returns: [NTSTATUS]
  1347. //
  1348. //+----------------------------------------------------------------------------
  1349. NTSTATUS
  1350. GetBirthId( IN HANDLE hFile,
  1351. OUT CDomainRelativeObjId *pdroidBirth )
  1352. {
  1353. NTSTATUS status = STATUS_SUCCESS;
  1354. FILE_OBJECTID_BUFFER fobOID;
  1355. IO_STATUS_BLOCK IoStatus;
  1356. TrkAssert( NULL != pdroidBirth );
  1357. TrkAssert( INVALID_HANDLE_VALUE != hFile && NULL != hFile );
  1358. status = NtFsControlFile(
  1359. hFile,
  1360. NULL, NULL, NULL,
  1361. &IoStatus,
  1362. FSCTL_GET_OBJECT_ID,
  1363. NULL, 0,
  1364. &fobOID,
  1365. sizeof(fobOID));
  1366. if( !NT_SUCCESS(status) ) goto Exit;
  1367. // Load the droid from the objid buffer.
  1368. pdroidBirth->InitFromFOB( fobOID );
  1369. // Clear the bit xvol-move bit, which is not considered part of the ID.
  1370. pdroidBirth->GetVolumeId().Normalize();
  1371. Exit:
  1372. return( status );
  1373. }