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.

2857 lines
77 KiB

  1. /*++
  2. Copyright (c) 1998-1999 Microsoft Corporation
  3. Module Name:
  4. filelist.c
  5. Abstract:
  6. this is the code that handles the file lists (exclusion/inclusion).
  7. Author:
  8. Paul McDaniel (paulmcd) 23-Jan-2000
  9. Revision History:
  10. --*/
  11. #include "precomp.h"
  12. //
  13. // Private prototypes.
  14. //
  15. //
  16. // linker commands
  17. //
  18. #ifdef ALLOC_PRAGMA
  19. #pragma alloc_text( PAGE, SrGetObjectName )
  20. #pragma alloc_text( PAGE, SrpFindFilePartW)
  21. #pragma alloc_text( PAGE, SrpFindFilePart )
  22. #pragma alloc_text( PAGE, SrFindCharReverse )
  23. #pragma alloc_text( PAGE, SrGetDestFileName )
  24. #pragma alloc_text( PAGE, SrGetNextFileNumber )
  25. #pragma alloc_text( PAGE, SrGetNextSeqNumber )
  26. #pragma alloc_text( PAGE, SrGetSystemVolume )
  27. #pragma alloc_text( PAGE, SrMarkFileBackedUp )
  28. #pragma alloc_text( PAGE, SrHasFileBeenBackedUp )
  29. #pragma alloc_text( PAGE, SrResetBackupHistory )
  30. #pragma alloc_text( PAGE, SrResetHistory )
  31. #pragma alloc_text( PAGE, SrGetVolumeDevice )
  32. #pragma alloc_text( PAGE, SrSetFileSecurity )
  33. #pragma alloc_text( PAGE, SrGetVolumeGuid )
  34. #pragma alloc_text( PAGE, SrAllocateFileNameBuffer )
  35. #pragma alloc_text( PAGE, SrFreeFileNameBuffer )
  36. #pragma alloc_text( PAGE, SrGetNumberOfLinks )
  37. #pragma alloc_text( PAGE, SrCheckVolume )
  38. #pragma alloc_text( PAGE, SrCheckForRestoreLocation )
  39. #pragma alloc_text( PAGE, SrGetMountVolume )
  40. #pragma alloc_text( PAGE, SrCheckFreeDiskSpace )
  41. #pragma alloc_text( PAGE, SrSetSecurityObjectAsSystem )
  42. #pragma alloc_text( PAGE, SrCheckForMountsInPath )
  43. #pragma alloc_text( PAGE, SrGetShortFileName )
  44. #endif // ALLOC_PRAGMA
  45. //
  46. // Private globals.
  47. //
  48. //
  49. // Public globals.
  50. //
  51. //
  52. // Public functions.
  53. //
  54. NTSTATUS
  55. SrGetObjectName(
  56. IN PSR_DEVICE_EXTENSION pExtension OPTIONAL,
  57. IN PVOID pObject,
  58. OUT PUNICODE_STRING pName,
  59. IN ULONG NameLength // size of the buffer in pName
  60. )
  61. {
  62. NTSTATUS Status;
  63. ULONG ReturnLength = 0;
  64. PVOID Buffer = NULL;
  65. ULONG BufferLength;
  66. PFILE_NAME_INFORMATION NameInfo;
  67. if (pExtension != NULL) {
  68. ASSERT( IS_VALID_FILE_OBJECT( (PFILE_OBJECT)pObject ) &&
  69. ((PFILE_OBJECT)pObject)->Vpb != NULL );
  70. //
  71. // We are getting the name of a file object, so
  72. // call SrQueryInformationFile to query the name.
  73. //
  74. BufferLength = NameLength + sizeof( ULONG );
  75. Buffer = ExAllocatePoolWithTag( PagedPool,
  76. BufferLength,
  77. SR_FILENAME_BUFFER_TAG);
  78. if (Buffer == NULL) {
  79. return STATUS_INSUFFICIENT_RESOURCES;
  80. }
  81. NameInfo = Buffer;
  82. Status = SrQueryInformationFile( pExtension->pTargetDevice,
  83. pObject,
  84. NameInfo,
  85. BufferLength,
  86. FileNameInformation,
  87. &ReturnLength );
  88. if (NT_SUCCESS( Status )) {
  89. //
  90. // We successfully got the name, so now build up the device name
  91. // and file name into the pName buffer passed in.
  92. //
  93. ASSERT( pExtension->pNtVolumeName );
  94. Status = RtlAppendUnicodeStringToString( pName,
  95. pExtension->pNtVolumeName );
  96. if (!NT_SUCCESS( Status )) {
  97. goto SrGetObjectName_Cleanup;
  98. }
  99. if ((pName->Length + NameInfo->FileNameLength + sizeof( WCHAR )) <=
  100. pName->MaximumLength ) {
  101. //
  102. // We have enough room in the buffer for the file name and
  103. // a NULL terminator.
  104. //
  105. RtlCopyMemory( &pName->Buffer[pName->Length/sizeof(WCHAR)],
  106. NameInfo->FileName,
  107. NameInfo->FileNameLength );
  108. pName->Length += (USHORT)NameInfo->FileNameLength;
  109. pName->Buffer[pName->Length/sizeof( WCHAR )] = UNICODE_NULL;
  110. } else {
  111. Status = STATUS_BUFFER_OVERFLOW;
  112. }
  113. }
  114. } else {
  115. ULONG NameBufferLength = NameLength - sizeof( UNICODE_STRING );
  116. ASSERT( IS_VALID_DEVICE_OBJECT( (PDEVICE_OBJECT)pObject ) );
  117. //
  118. // Use ObQueryNameString to get the name of the DeviceObject passed
  119. // in, but save space to NULL-terminate the name.
  120. //
  121. Status = ObQueryNameString( pObject,
  122. (POBJECT_NAME_INFORMATION) pName,
  123. NameBufferLength - sizeof( UNICODE_NULL ),
  124. &ReturnLength);
  125. if (NT_SUCCESS( Status )) {
  126. //
  127. // ObQueryNameString sets the MaximumLength of pName to something
  128. // it calculates, which is smaller than what we allocated. Fix this
  129. // up here and NULL terminate the string (we've already reserved
  130. // the space).
  131. //
  132. pName->MaximumLength = (USHORT)NameBufferLength;
  133. pName->Buffer[pName->Length/sizeof( WCHAR )] = UNICODE_NULL;
  134. }
  135. }
  136. SrGetObjectName_Cleanup:
  137. if (Buffer != NULL) {
  138. ExFreePoolWithTag( Buffer, SR_FILENAME_BUFFER_TAG );
  139. }
  140. RETURN( Status );
  141. }
  142. /***************************************************************************++
  143. Routine Description:
  144. Locates the file part of a fully qualified path.
  145. Arguments:
  146. pPath - Supplies the path to scan.
  147. Return Value:
  148. PSTR - The file part.
  149. --***************************************************************************/
  150. PWSTR
  151. SrpFindFilePartW(
  152. IN PWSTR pPath
  153. )
  154. {
  155. PWSTR pFilePart;
  156. PAGED_CODE();
  157. SrTrace(FUNC_ENTRY, ("SR!SrpFindFilePartW\n"));
  158. //
  159. // Strip off the path from the path.
  160. //
  161. pFilePart = wcsrchr( pPath, L'\\' );
  162. if (pFilePart == NULL)
  163. {
  164. pFilePart = pPath;
  165. }
  166. else
  167. {
  168. pFilePart++;
  169. }
  170. return pFilePart;
  171. } // SrpDbgFindFilePart
  172. /***************************************************************************++
  173. Routine Description:
  174. Locates the file part of a fully qualified path.
  175. Arguments:
  176. pPath - Supplies the path to scan.
  177. Return Value:
  178. PSTR - The file part.
  179. --***************************************************************************/
  180. PSTR
  181. SrpFindFilePart(
  182. IN PSTR pPath
  183. )
  184. {
  185. PSTR pFilePart;
  186. PAGED_CODE();
  187. SrTrace(FUNC_ENTRY, ("SR!SrpFindFilePart\n"));
  188. //
  189. // Strip off the path from the path.
  190. //
  191. pFilePart = strrchr( pPath, '\\' );
  192. if (pFilePart == NULL)
  193. {
  194. pFilePart = pPath;
  195. }
  196. else
  197. {
  198. pFilePart++;
  199. }
  200. return pFilePart;
  201. } // SrpFindFilePart
  202. NTSTATUS
  203. SrFindCharReverse(
  204. IN PWSTR pToken,
  205. IN ULONG TokenLength,
  206. IN WCHAR FindChar,
  207. OUT PWSTR * ppToken,
  208. OUT PULONG pTokenLength
  209. )
  210. {
  211. NTSTATUS Status;
  212. int i;
  213. ULONG TokenCount;
  214. PAGED_CODE();
  215. //
  216. // assume we didn't find it
  217. //
  218. Status = STATUS_OBJECT_NAME_NOT_FOUND;
  219. //
  220. // turn this into a count
  221. //
  222. TokenCount = TokenLength / sizeof(WCHAR);
  223. if (TokenCount == 0 || pToken == NULL || pToken[0] == UNICODE_NULL)
  224. goto end;
  225. //
  226. // start looking from the end
  227. //
  228. for (i = TokenCount - 1; i >= 0; i--)
  229. {
  230. if (pToken[i] == FindChar)
  231. break;
  232. }
  233. if (i >= 0)
  234. {
  235. //
  236. // found it!
  237. //
  238. *ppToken = pToken + i;
  239. *pTokenLength = (TokenCount - i) * sizeof(WCHAR);
  240. Status = STATUS_SUCCESS;
  241. }
  242. end:
  243. return Status;
  244. } // SrFindCharReverse
  245. /***************************************************************************++
  246. Routine Description:
  247. This routine generates the destination file name for a file that is being
  248. created in the restore location. This name had the extension of the file
  249. that is being backed up with a unique file name that is generated here.
  250. Arguments:
  251. pExtension - The SR_DEVICE_EXTENSION for the volume on which this file
  252. resides.
  253. pFileName - The name of the original file that is being backed up into
  254. the restore location. This file is in the SR's normalized form
  255. (e.g., \\Device\HarddiskVolume1\mydir\myfile.ext)
  256. pDestFileName - This unicode string gets filled in with the full path
  257. and file name for the destination file in the restore location.
  258. Return Value:
  259. NTSTATUS - Completion status.
  260. --***************************************************************************/
  261. NTSTATUS
  262. SrGetDestFileName(
  263. IN PSR_DEVICE_EXTENSION pExtension,
  264. IN PUNICODE_STRING pFileName,
  265. OUT PUNICODE_STRING pDestFileName
  266. )
  267. {
  268. NTSTATUS Status;
  269. PWSTR pFilePart;
  270. ULONG FilePartLength;
  271. ULONG NextFileNumber;
  272. ULONG CharCount;
  273. PAGED_CODE();
  274. ASSERT( (pFileName != NULL) && (pFileName->Length > 0));
  275. ASSERT( pDestFileName != NULL );
  276. ASSERT( IS_ACTIVITY_LOCK_ACQUIRED_EXCLUSIVE( pExtension ) ||
  277. IS_ACTIVITY_LOCK_ACQUIRED_SHARED( pExtension ) );
  278. //
  279. // Copy the volume name out of the device extension.
  280. //
  281. ASSERT( pExtension->pNtVolumeName != NULL );
  282. Status = RtlAppendUnicodeStringToString( pDestFileName,
  283. pExtension->pNtVolumeName );
  284. if (!NT_SUCCESS( Status ))
  285. {
  286. goto SrGetDestFileName_Exit;
  287. }
  288. //
  289. // and append our restore point location
  290. //
  291. CharCount = swprintf( &pDestFileName->Buffer[pDestFileName->Length/sizeof(WCHAR)],
  292. RESTORE_LOCATION,
  293. global->MachineGuid );
  294. pDestFileName->Length += (USHORT)CharCount * sizeof(WCHAR);
  295. //
  296. // and the actual restore directory; we don't need to acquire a lock
  297. // to read this because we already have the ActivityLock and this
  298. // will prevent the value from changing.
  299. //
  300. CharCount = swprintf( &pDestFileName->Buffer[pDestFileName->Length/sizeof(WCHAR)],
  301. L"\\" RESTORE_POINT_PREFIX L"%d\\",
  302. global->FileConfig.CurrentRestoreNumber );
  303. pDestFileName->Length += (USHORT)CharCount * sizeof(WCHAR);
  304. //
  305. // now get a number to use
  306. //
  307. Status = SrGetNextFileNumber(&NextFileNumber);
  308. if (!NT_SUCCESS(Status))
  309. {
  310. goto SrGetDestFileName_Exit;
  311. }
  312. //
  313. // use the "A" prefix (e.g. "A0000001.dll" )
  314. //
  315. swprintf( &pDestFileName->Buffer[pDestFileName->Length/sizeof(WCHAR)],
  316. RESTORE_FILE_PREFIX L"%07d",
  317. NextFileNumber );
  318. pDestFileName->Length += 8 * sizeof(WCHAR);
  319. //
  320. // We know that the pFileName contains a fully-normalized name, so
  321. // we just need to search for the '.' from the end of the name
  322. // to find the proper extension.
  323. //
  324. pFilePart = pFileName->Buffer;
  325. FilePartLength = pFileName->Length;
  326. Status = SrFindCharReverse( pFilePart,
  327. FilePartLength,
  328. L'.',
  329. &pFilePart,
  330. &FilePartLength );
  331. //
  332. // No extension is not supported!
  333. //
  334. if (!NT_SUCCESS(Status))
  335. {
  336. goto SrGetDestFileName_Exit;
  337. }
  338. //
  339. // now put the proper extension on
  340. //
  341. RtlCopyMemory( &pDestFileName->Buffer[pDestFileName->Length/sizeof(WCHAR)],
  342. pFilePart,
  343. FilePartLength );
  344. pDestFileName->Length += (USHORT)FilePartLength;
  345. //
  346. // NULL terminate it
  347. //
  348. ASSERT(pDestFileName->Length < pDestFileName->MaximumLength);
  349. pDestFileName->Buffer[pDestFileName->Length/sizeof(WCHAR)] = UNICODE_NULL;
  350. SrGetDestFileName_Exit:
  351. RETURN (Status);
  352. } // SrGetDestFileName
  353. NTSTATUS
  354. SrGetNextFileNumber(
  355. OUT PULONG pNextFileNumber
  356. )
  357. {
  358. NTSTATUS Status;
  359. PAGED_CODE();
  360. ASSERT(pNextFileNumber != NULL);
  361. *pNextFileNumber = InterlockedIncrement(&global->LastFileNameNumber);
  362. if (*pNextFileNumber >= global->FileConfig.FileNameNumber)
  363. {
  364. //
  365. // save out the number again
  366. //
  367. try {
  368. SrAcquireGlobalLockExclusive();
  369. //
  370. // double check with the lock held
  371. //
  372. if (*pNextFileNumber >= global->FileConfig.FileNameNumber)
  373. {
  374. global->FileConfig.FileNameNumber += SR_FILE_NUMBER_INCREMENT;
  375. //
  376. // save it out
  377. //
  378. Status = SrWriteConfigFile();
  379. CHECK_STATUS(Status);
  380. }
  381. } finally {
  382. SrReleaseGlobalLock();
  383. }
  384. }
  385. RETURN(STATUS_SUCCESS);
  386. } // SrGetNextFileNumber
  387. NTSTATUS
  388. SrGetNextSeqNumber(
  389. OUT PINT64 pNextSeqNumber
  390. )
  391. {
  392. NTSTATUS Status;
  393. PAGED_CODE();
  394. ASSERT(pNextSeqNumber != NULL);
  395. //
  396. // bummer , there is no interlocked increment for 64bits
  397. //
  398. try {
  399. SrAcquireGlobalLockExclusive();
  400. *pNextSeqNumber = ++(global->LastSeqNumber);
  401. if (*pNextSeqNumber >= global->FileConfig.FileSeqNumber)
  402. {
  403. //
  404. // save out the number again
  405. //
  406. global->FileConfig.FileSeqNumber += SR_SEQ_NUMBER_INCREMENT;
  407. //
  408. // save it out
  409. //
  410. Status = SrWriteConfigFile();
  411. CHECK_STATUS(Status);
  412. }
  413. } finally {
  414. SrReleaseGlobalLock();
  415. }
  416. RETURN(STATUS_SUCCESS);
  417. } // SrGetNextFileNumber
  418. /***************************************************************************++
  419. Routine Description:
  420. Returns the string location of the system volume. Get this by using the
  421. global cache'd system volume extension. If it can't be found (hasn't
  422. been attached yet), it queries the os to get the match for \\SystemRoot.
  423. Arguments:
  424. pFileName - holds the volume path on return (has to be a contigous block)
  425. pSystemVolumeExtension - SR's extension for the device that is attached
  426. to the system volume.
  427. pFileNameLength - holds the size of the buffer on in, and the size copied
  428. on out. both in bytes.
  429. Return Value:
  430. NTSTATUS - completion code.
  431. --***************************************************************************/
  432. NTSTATUS
  433. SrGetSystemVolume(
  434. OUT PUNICODE_STRING pFileName,
  435. OUT PSR_DEVICE_EXTENSION *ppSystemVolumeExtension,
  436. IN ULONG FileNameLength
  437. )
  438. {
  439. NTSTATUS Status;
  440. HANDLE FileHandle = NULL;
  441. IO_STATUS_BLOCK IoStatusBlock;
  442. OBJECT_ATTRIBUTES ObjectAttributes;
  443. PFILE_OBJECT pFileObject = NULL;
  444. UNICODE_STRING FileName;
  445. PDEVICE_OBJECT pFilterDevice;
  446. PDEVICE_OBJECT pRelatedDevice;
  447. PAGED_CODE();
  448. ASSERT( pFileName != NULL);
  449. ASSERT( ppSystemVolumeExtension != NULL );
  450. *ppSystemVolumeExtension = NULL;
  451. if (global->pSystemVolumeExtension == NULL) {
  452. //
  453. // don't have it cache'd, attempt to open the SystemRoot
  454. //
  455. RtlInitUnicodeString(&FileName, L"\\SystemRoot");
  456. InitializeObjectAttributes( &ObjectAttributes,
  457. &FileName,
  458. OBJ_KERNEL_HANDLE,
  459. NULL,
  460. NULL );
  461. Status = ZwCreateFile( &FileHandle,
  462. FILE_GENERIC_READ, // DesiredAccess
  463. &ObjectAttributes,
  464. &IoStatusBlock,
  465. NULL, // AllocationSize
  466. FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_NORMAL,
  467. FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
  468. FILE_OPEN,
  469. FILE_SYNCHRONOUS_IO_NONALERT,
  470. NULL, // EaBuffer
  471. 0 ); // EaLength
  472. if (!NT_SUCCESS(Status))
  473. goto end;
  474. //
  475. // now get the file object
  476. //
  477. Status = ObReferenceObjectByHandle( FileHandle,
  478. 0, // DesiredAccess
  479. *IoFileObjectType,
  480. KernelMode,
  481. (PVOID *) &pFileObject,
  482. NULL );
  483. if (!NT_SUCCESS(Status))
  484. goto end;
  485. //
  486. // and get our device's extension
  487. //
  488. pRelatedDevice = IoGetRelatedDeviceObject( pFileObject );
  489. if (pRelatedDevice == NULL )
  490. {
  491. Status = STATUS_INVALID_DEVICE_REQUEST;
  492. goto end;
  493. }
  494. pFilterDevice = SrGetFilterDevice(pRelatedDevice);
  495. if (pFilterDevice == NULL) {
  496. //
  497. // we are not attached to the system volume, just get the name
  498. // This happens during unload, when writing out the config file
  499. //
  500. Status = SrGetObjectName( NULL,
  501. pFileObject->Vpb->RealDevice,
  502. pFileName,
  503. FileNameLength );
  504. if (!NT_SUCCESS(Status))
  505. goto end;
  506. //
  507. // all done
  508. //
  509. goto end;
  510. }
  511. //
  512. // and store it
  513. //
  514. global->pSystemVolumeExtension = pFilterDevice->DeviceExtension;
  515. SrTrace( INIT, (
  516. "sr!SrGetSystemVolume: cached system volume [%wZ]\n",
  517. global->pSystemVolumeExtension->pNtVolumeName ));
  518. }
  519. ASSERT(global->pSystemVolumeExtension != NULL);
  520. ASSERT(global->pSystemVolumeExtension->pNtVolumeName != NULL);
  521. //
  522. // now use the cache'd value
  523. //
  524. if (FileNameLength <
  525. global->pSystemVolumeExtension->pNtVolumeName->Length) {
  526. Status = STATUS_BUFFER_OVERFLOW;
  527. } else {
  528. RtlCopyUnicodeString( pFileName,
  529. global->pSystemVolumeExtension->pNtVolumeName );
  530. *ppSystemVolumeExtension = global->pSystemVolumeExtension;
  531. Status = STATUS_SUCCESS;
  532. }
  533. end:
  534. if (pFileObject != NULL)
  535. {
  536. ObDereferenceObject(pFileObject);
  537. pFileObject = NULL;
  538. }
  539. if (FileHandle != NULL)
  540. {
  541. ZwClose(FileHandle);
  542. FileHandle = NULL;
  543. }
  544. RETURN(Status);
  545. } // SrGetSystemVolume
  546. /***************************************************************************++
  547. Routine Description:
  548. This routine updates the backup history for the given file. Based on the
  549. current event and the full file name, this routine decides whether to log
  550. this change against the file's unnamed data stream or the data stream
  551. currently being operation on.
  552. Arguments:
  553. pExtension - the SR device extension for the current volume.
  554. pFileName - holds the path name of the file that's been backed up.
  555. StreamNameLength - the length of the stream component of the file name
  556. if there is one.
  557. CurrentEvent - the event that is causing us to update the backup history
  558. FutureEventsToIgnore - the events that should be ignored in the future.
  559. Return Value:
  560. Returns STATUS_SUCCESS if we are able to successfully update the backup
  561. history, or the appropriate error code otherwise.
  562. --***************************************************************************/
  563. NTSTATUS
  564. SrMarkFileBackedUp(
  565. IN PSR_DEVICE_EXTENSION pExtension,
  566. IN PUNICODE_STRING pFileName,
  567. IN USHORT StreamNameLength,
  568. IN SR_EVENT_TYPE CurrentEvent,
  569. IN SR_EVENT_TYPE FutureEventsToIgnore
  570. )
  571. {
  572. NTSTATUS Status;
  573. ULONG_PTR Context = (ULONG_PTR) SrEventInvalid;
  574. HASH_KEY Key;
  575. PAGED_CODE();
  576. ASSERT( pFileName != NULL );
  577. //
  578. // Make sure our pFileName is correctly constructed.
  579. //
  580. ASSERT( IS_VALID_SR_STREAM_STRING( pFileName, StreamNameLength ) );
  581. //
  582. // Set up the hash key we need to lookup.
  583. //
  584. Key.FileName.Length = pFileName->Length;
  585. Key.FileName.MaximumLength = pFileName->MaximumLength;
  586. Key.FileName.Buffer = pFileName->Buffer;
  587. Key.StreamNameLength = RECORD_AGAINST_STREAM( CurrentEvent,
  588. StreamNameLength );
  589. try {
  590. SrAcquireBackupHistoryLockExclusive( pExtension );
  591. //
  592. // try and find a matching entry in the hash list
  593. //
  594. Status = HashFindEntry( pExtension->pBackupHistory,
  595. &Key,
  596. (PVOID*)&Context );
  597. if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
  598. {
  599. //
  600. // not found... add one
  601. //
  602. Status = HashAddEntry( pExtension->pBackupHistory,
  603. &Key,
  604. (PVOID)FutureEventsToIgnore );
  605. if (!NT_SUCCESS(Status))
  606. leave;
  607. }
  608. else if (NT_SUCCESS(Status))
  609. {
  610. //
  611. // add this to the mask
  612. //
  613. Context |= FutureEventsToIgnore;
  614. //
  615. // and update the entry
  616. //
  617. Status = HashAddEntry( pExtension->pBackupHistory,
  618. &Key,
  619. (PVOID)Context );
  620. if (Status == STATUS_DUPLICATE_OBJECTID)
  621. {
  622. Status = STATUS_SUCCESS;
  623. }
  624. else if (!NT_SUCCESS(Status))
  625. {
  626. leave;
  627. }
  628. }
  629. }finally {
  630. SrReleaseBackupHistoryLock( pExtension );
  631. }
  632. RETURN(Status);
  633. } // SrMarkFileBackedUp
  634. /***************************************************************************++
  635. Routine Description:
  636. This routine looks up in the backup history based on the name passed in
  637. whether or not this EventType has already been backed up for this file.
  638. With stream names, this is a little more complicated than it first appears.
  639. If this name contains a stream, we may have to look up to see if we have
  640. a history on the file name with and without the stream component of the
  641. name.
  642. Arguments:
  643. pExtension - SR's device extension for this volume. This contains
  644. our backup history structures.
  645. pFileName - The file name to lookup. If the name has a stream component,
  646. that stream component is in the buffer of this unicode string, but
  647. the length only designates the file-only name portion.
  648. StreamNameLength - Designates the extra bytes in addition to
  649. pFileName->Length that specify the stream component of the name.
  650. EventType - The current event that we are seeing on this file.
  651. Return Value:
  652. Returns TRUE if this file has already been backed up for this EventType,
  653. and FALSE otherwise.
  654. --***************************************************************************/
  655. BOOLEAN
  656. SrHasFileBeenBackedUp(
  657. IN PSR_DEVICE_EXTENSION pExtension,
  658. IN PUNICODE_STRING pFileName,
  659. IN USHORT StreamNameLength,
  660. IN SR_EVENT_TYPE EventType
  661. )
  662. {
  663. NTSTATUS Status;
  664. ULONG_PTR Context;
  665. HASH_KEY Key;
  666. SR_EVENT_TYPE EventsToIgnore = SrEventInvalid;
  667. BOOLEAN HasBeenBackedUp = FALSE;
  668. PAGED_CODE();
  669. ASSERT( pFileName != NULL );
  670. //
  671. // Make sure our pFileName is correctly constructed.
  672. //
  673. ASSERT( IS_VALID_SR_STREAM_STRING( pFileName, StreamNameLength ) );
  674. //
  675. // Setup our hash key. We will first do a lookup on the exact match
  676. // of the name passed in since this will be what hits the majority of the
  677. // time.
  678. //
  679. Key.FileName.Length = pFileName->Length;
  680. Key.FileName.MaximumLength = pFileName->MaximumLength;
  681. Key.FileName.Buffer = pFileName->Buffer;
  682. Key.StreamNameLength = StreamNameLength;
  683. try {
  684. SrAcquireBackupHistoryLockShared( pExtension );
  685. //
  686. // try and find a matching entry in the hash list
  687. //
  688. Status = HashFindEntry( pExtension->pBackupHistory,
  689. &Key,
  690. (PVOID*)&Context );
  691. if (Status == STATUS_OBJECT_NAME_NOT_FOUND || !NT_SUCCESS(Status))
  692. {
  693. //
  694. // We don't have a backup history entry for this name, so we
  695. // don't have any recorded events to igore for this name.
  696. //
  697. EventsToIgnore = SrEventInvalid;
  698. }
  699. else
  700. {
  701. //
  702. // Context contains the set of events that should be ignored
  703. // for this name.
  704. //
  705. EventsToIgnore = (SR_EVENT_TYPE)Context;
  706. }
  707. //
  708. // Now see if we have enough information to say with certainty whether
  709. // or not we should ignore this operation.
  710. //
  711. // We have two cases here:
  712. // 1. The name passed in has NO stream name component
  713. // In this case, the current value of EventsToIgnore is all
  714. // we have to make our decision. So figure out if our
  715. // EventType is in this list and return the appropriate
  716. // HasBeenBackedUp value.
  717. //
  718. // 2. The name passed in DOES have a stream name component
  719. // In this case, if our EventType is already in the
  720. // EventsToIgnore set, we are done. Otherwise, if this
  721. // EventType is relevant to the file-only name, check to
  722. // see if we have a backup history entry for that name.
  723. //
  724. if (StreamNameLength == 0)
  725. {
  726. HasBeenBackedUp = BooleanFlagOn( EventsToIgnore, EventType );
  727. leave;
  728. }
  729. else
  730. {
  731. if (FlagOn( EventsToIgnore, EventType ))
  732. {
  733. HasBeenBackedUp = TRUE;
  734. leave;
  735. }
  736. else
  737. {
  738. //
  739. // We need to see if we have a context on the file-only portion
  740. // of the name.
  741. //
  742. Key.FileName.Length = pFileName->Length;
  743. Key.FileName.MaximumLength = pFileName->MaximumLength;
  744. Key.FileName.Buffer = pFileName->Buffer;
  745. Key.StreamNameLength = 0;
  746. Status = HashFindEntry( pExtension->pBackupHistory,
  747. &Key,
  748. (PVOID*)&Context );
  749. if (Status == STATUS_OBJECT_NAME_NOT_FOUND || !NT_SUCCESS(Status))
  750. {
  751. //
  752. // We don't have a backup history entry for this name, so we
  753. // don't have any recorded events to igore for this name.
  754. //
  755. EventsToIgnore = SrEventInvalid;
  756. }
  757. else
  758. {
  759. //
  760. // Context contains the set of events that should be ignored
  761. // for this name.
  762. //
  763. EventsToIgnore = (SR_EVENT_TYPE)Context;
  764. }
  765. //
  766. // This is all we've got, so make our decision based on the
  767. // current value of EventsToIgnore.
  768. //
  769. HasBeenBackedUp = BooleanFlagOn( EventsToIgnore, EventType );
  770. }
  771. }
  772. }
  773. finally
  774. {
  775. SrReleaseBackupHistoryLock( pExtension );
  776. }
  777. return HasBeenBackedUp;
  778. } // SrHasFileBeenBackedUp
  779. /***************************************************************************++
  780. Routine Description:
  781. this will clear the backup history completely. this is done when a new
  782. restore point is created .
  783. Arguments:
  784. Return Value:
  785. NTSTATUS - completion code.
  786. --***************************************************************************/
  787. NTSTATUS
  788. SrResetBackupHistory(
  789. IN PSR_DEVICE_EXTENSION pExtension,
  790. IN PUNICODE_STRING pFileName OPTIONAL,
  791. IN USHORT StreamNameLength OPTIONAL,
  792. IN SR_EVENT_TYPE EventType
  793. )
  794. {
  795. NTSTATUS Status;
  796. ULONG_PTR Context;
  797. HASH_KEY Key;
  798. PAGED_CODE();
  799. try
  800. {
  801. SrAcquireBackupHistoryLockExclusive( pExtension );
  802. if (pFileName == NULL)
  803. {
  804. //
  805. // clear them all
  806. //
  807. HashClearEntries(pExtension->pBackupHistory);
  808. Status = STATUS_SUCCESS;
  809. }
  810. else if (StreamNameLength > 0)
  811. {
  812. //
  813. // clear just this one
  814. //
  815. //
  816. // Make sure our pFileName is correctly constructed.
  817. //
  818. ASSERT( IS_VALID_SR_STREAM_STRING( pFileName, StreamNameLength ) );
  819. Key.FileName.Length = pFileName->Length;
  820. Key.FileName.MaximumLength = pFileName->MaximumLength;
  821. Key.FileName.Buffer = pFileName->Buffer;
  822. Key.StreamNameLength = StreamNameLength;
  823. Status = HashFindEntry( pExtension->pBackupHistory,
  824. &Key,
  825. (PVOID*)&Context );
  826. if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
  827. {
  828. //
  829. // no entry, nothing to clear
  830. //
  831. Status = STATUS_SUCCESS;
  832. leave;
  833. }
  834. else if (!NT_SUCCESS(Status))
  835. {
  836. leave;
  837. }
  838. //
  839. // update/clear the existing entry
  840. //
  841. Context = EventType;
  842. Status = HashAddEntry( pExtension->pBackupHistory,
  843. &Key,
  844. (PVOID)Context );
  845. ASSERT(Status == STATUS_DUPLICATE_OBJECTID);
  846. if (Status == STATUS_DUPLICATE_OBJECTID)
  847. {
  848. Status = STATUS_SUCCESS;
  849. }
  850. else if (!NT_SUCCESS(Status))
  851. {
  852. leave;
  853. }
  854. }
  855. else
  856. {
  857. //
  858. // We've got to clear all entries associated with this file name.
  859. //
  860. Status = HashClearAllFileEntries( pExtension->pBackupHistory,
  861. pFileName );
  862. }
  863. }
  864. finally
  865. {
  866. SrReleaseBackupHistoryLock( pExtension );
  867. }
  868. RETURN(Status);
  869. } // SrResetBackupHistory
  870. /***************************************************************************++
  871. Routine Description:
  872. this is a callback function for HashprocessEntries that is used to reset
  873. the history on all files that match the directory prefix. this is called
  874. when a directory is renamed, invaliding all hash entries with the
  875. directory's new name, as they are no longer the same file.
  876. Arguments:
  877. Return Value:
  878. NTSTATUS - completion code.
  879. --***************************************************************************/
  880. PVOID
  881. SrResetHistory(
  882. IN PHASH_KEY pKey,
  883. IN PVOID pEntryContext,
  884. PUNICODE_STRING pDirectoryName
  885. )
  886. {
  887. PAGED_CODE();
  888. //
  889. // does this directory prefix match the key?
  890. //
  891. if (RtlPrefixUnicodeString(pDirectoryName, &pKey->FileName, TRUE))
  892. {
  893. //
  894. // return a new context of invalid event.
  895. //
  896. SrTrace(HASH, ("sr!SrResetHistory: clearing %wZ\n", &pKey->FileName));
  897. return (PVOID)(ULONG_PTR)SrEventInvalid;
  898. }
  899. else
  900. {
  901. //
  902. // do nothing, keep the old context
  903. //
  904. return pEntryContext;
  905. }
  906. } // SrResetHistory
  907. /***************************************************************************++
  908. Routine Description:
  909. returns the proper volume device object for this file object. handles
  910. if the file is open or not.
  911. Arguments:
  912. Return Value:
  913. NTSTATUS - completion code.
  914. --***************************************************************************/
  915. PDEVICE_OBJECT
  916. SrGetVolumeDevice(
  917. PFILE_OBJECT pFileObject
  918. )
  919. {
  920. PAGED_CODE();
  921. //
  922. // is this file open?
  923. //
  924. if (pFileObject->Vpb != NULL)
  925. return pFileObject->Vpb->RealDevice;
  926. //
  927. // otherwise is there a related file object?
  928. //
  929. if (pFileObject->RelatedFileObject != NULL)
  930. {
  931. ASSERT(pFileObject->RelatedFileObject->Vpb != NULL);
  932. if (pFileObject->RelatedFileObject->Vpb != NULL)
  933. return pFileObject->RelatedFileObject->Vpb->RealDevice;
  934. }
  935. //
  936. // otherwise it's unopened and not a relative open
  937. //
  938. return pFileObject->DeviceObject;
  939. } // SrGetVolumeDevice
  940. /***************************************************************************++
  941. Routine Description:
  942. this will set the security descriptor for the object referenced by
  943. FileHandle. it will create a DACL for either system access
  944. (non-recursive) OR eveyone access (recursive) depending on the SystemOnly
  945. flag. the OWNER of the file will be BUILTIN\Administrators .
  946. Arguments:
  947. Return Value:
  948. NTSTATUS - Completion status.
  949. --***************************************************************************/
  950. NTSTATUS
  951. SrSetFileSecurity(
  952. IN HANDLE FileHandle,
  953. IN BOOLEAN SystemOnly,
  954. IN BOOLEAN SetDacl
  955. )
  956. {
  957. NTSTATUS Status;
  958. SECURITY_DESCRIPTOR SecurityDescriptor;
  959. #define DaclLength 128
  960. UCHAR DaclBuffer[DaclLength];
  961. PACL pDacl = (PACL) &DaclBuffer[0];
  962. PACE_HEADER pAce;
  963. SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;
  964. SID_IDENTIFIER_AUTHORITY WorldAuthority = SECURITY_WORLD_SID_AUTHORITY;
  965. //
  966. // SID on the stack only has space for 1 subauthority
  967. //
  968. C_ASSERT(ANYSIZE_ARRAY == 1);
  969. SID LocalSystemSid;
  970. SID EveryoneSid;
  971. PSID pAdminsSid = NULL;
  972. ULONG SecurityInformation = 0;
  973. PAGED_CODE();
  974. try {
  975. //
  976. // create the security descriptor
  977. //
  978. Status = RtlCreateSecurityDescriptor( &SecurityDescriptor,
  979. SECURITY_DESCRIPTOR_REVISION );
  980. if (!NT_SUCCESS(Status))
  981. leave;
  982. if (SetDacl)
  983. {
  984. //
  985. // construct the DACL
  986. //
  987. Status = RtlCreateAcl(pDacl, DaclLength, ACL_REVISION);
  988. if (!NT_SUCCESS(Status))
  989. leave;
  990. //
  991. // is this for system only access ?
  992. //
  993. if (SystemOnly)
  994. {
  995. //
  996. // Construct the local system sid
  997. //
  998. Status = RtlInitializeSid(&LocalSystemSid, &NtAuthority, 1);
  999. if (!NT_SUCCESS(Status))
  1000. leave;
  1001. *RtlSubAuthoritySid(&LocalSystemSid, 0) = SECURITY_LOCAL_SYSTEM_RID;
  1002. //
  1003. // just mark it with the local system sid, no inherit
  1004. //
  1005. Status = RtlAddAccessAllowedAce( pDacl,
  1006. ACL_REVISION,
  1007. STANDARD_RIGHTS_ALL | GENERIC_ALL,
  1008. &LocalSystemSid );
  1009. if (!NT_SUCCESS(Status))
  1010. leave;
  1011. }
  1012. else
  1013. {
  1014. //
  1015. // Construct the everyone sid
  1016. //
  1017. Status = RtlInitializeSid(&EveryoneSid, &WorldAuthority, 1);
  1018. if (!NT_SUCCESS(Status))
  1019. leave;
  1020. *RtlSubAuthoritySid(&EveryoneSid, 0) = SECURITY_WORLD_RID;
  1021. //
  1022. // mark it with the everyone sid, full inherit
  1023. //
  1024. Status = RtlAddAccessAllowedAce( pDacl,
  1025. ACL_REVISION,
  1026. STANDARD_RIGHTS_ALL | GENERIC_ALL,
  1027. &EveryoneSid );
  1028. if (!NT_SUCCESS(Status))
  1029. leave;
  1030. //
  1031. // set the flags to full inherit (LAME! should use
  1032. // RtlAddAccessAllowedAceEx but it isn't exported from ntoskrnl.lib )
  1033. //
  1034. Status = RtlGetAce(pDacl, 0, &pAce);
  1035. if (!NT_SUCCESS(Status))
  1036. leave;
  1037. pAce->AceFlags = OBJECT_INHERIT_ACE|CONTAINER_INHERIT_ACE;
  1038. }
  1039. //
  1040. // put the dacl in the descriptor
  1041. //
  1042. Status = RtlSetDaclSecurityDescriptor( &SecurityDescriptor,
  1043. TRUE,
  1044. pDacl,
  1045. FALSE );
  1046. if (!NT_SUCCESS(Status))
  1047. leave;
  1048. //
  1049. // mark it as protected so that no parent DACL changes what we've set
  1050. //
  1051. // we should really use RtlSetControlSecurityDescriptor but it isn't
  1052. // included in ntoskrnl.lib (lame!)
  1053. //
  1054. SecurityDescriptor.Control |= SE_DACL_PROTECTED;
  1055. SecurityInformation |= DACL_SECURITY_INFORMATION;
  1056. } // if (SetDacl)
  1057. //
  1058. // construct the local admin sid
  1059. //
  1060. pAdminsSid = SR_ALLOCATE_POOL( PagedPool,
  1061. RtlLengthRequiredSid(2),
  1062. SR_SECURITY_DATA_TAG );
  1063. if (pAdminsSid == NULL)
  1064. {
  1065. Status = STATUS_INSUFFICIENT_RESOURCES;
  1066. leave;
  1067. }
  1068. Status = RtlInitializeSid(pAdminsSid, &NtAuthority, 2);
  1069. if (!NT_SUCCESS(Status))
  1070. leave;
  1071. *RtlSubAuthoritySid(pAdminsSid, 0) = SECURITY_BUILTIN_DOMAIN_RID;
  1072. *RtlSubAuthoritySid(pAdminsSid, 1) = DOMAIN_ALIAS_RID_ADMINS;
  1073. //
  1074. // set the owner to admins
  1075. //
  1076. Status = RtlSetOwnerSecurityDescriptor( &SecurityDescriptor,
  1077. pAdminsSid,
  1078. FALSE );
  1079. if (!NT_SUCCESS(Status))
  1080. leave;
  1081. SecurityInformation |= OWNER_SECURITY_INFORMATION;
  1082. //
  1083. // now set it on the file object
  1084. //
  1085. Status = SrSetSecurityObjectAsSystem( FileHandle,
  1086. SecurityInformation,
  1087. &SecurityDescriptor );
  1088. if (!NT_SUCCESS(Status))
  1089. leave;
  1090. } finally {
  1091. Status = FinallyUnwind(SrSetFileSecurity, Status);
  1092. if (pAdminsSid != NULL)
  1093. {
  1094. SR_FREE_POOL( pAdminsSid, SR_SECURITY_DATA_TAG );
  1095. pAdminsSid = NULL;
  1096. }
  1097. }
  1098. RETURN(Status);
  1099. } // SrSetFileSecurity
  1100. /***************************************************************************++
  1101. Routine Description:
  1102. this will lookup the volume guid and return it to the caller.
  1103. Arguments:
  1104. pVolumeName - the nt name of the volume (\Device\HardDiskVolume1)
  1105. pVolumeGuid - holds the guid on retunr ( {xxx-x-x-x} )
  1106. Return Value:
  1107. NTSTATUS - Completion status.
  1108. --***************************************************************************/
  1109. NTSTATUS
  1110. SrGetVolumeGuid(
  1111. IN PUNICODE_STRING pVolumeName,
  1112. OUT PWCHAR pVolumeGuid
  1113. )
  1114. {
  1115. NTSTATUS Status;
  1116. PMOUNTMGR_MOUNT_POINT pMountPoint = NULL;
  1117. PMOUNTMGR_MOUNT_POINTS pMountPoints = NULL;
  1118. PMOUNTMGR_MOUNT_POINT pVolumePoint;
  1119. UNICODE_STRING DeviceName;
  1120. UNICODE_STRING VolumePoint;
  1121. IO_STATUS_BLOCK IoStatusBlock;
  1122. PKEVENT pEvent = NULL;
  1123. PIRP pIrp;
  1124. PDEVICE_OBJECT pDeviceObject;
  1125. PFILE_OBJECT pFileObject = NULL;
  1126. ULONG MountPointsLength;
  1127. ULONG Index;
  1128. PAGED_CODE();
  1129. ASSERT(pVolumeName != NULL);
  1130. ASSERT(pVolumeGuid != NULL);
  1131. try {
  1132. //
  1133. // bind to the volume mount point manager's device
  1134. //
  1135. RtlInitUnicodeString(&DeviceName, MOUNTMGR_DEVICE_NAME);
  1136. Status = IoGetDeviceObjectPointer( &DeviceName,
  1137. FILE_READ_ATTRIBUTES,
  1138. &pFileObject,
  1139. &pDeviceObject );
  1140. if (!NT_SUCCESS(Status))
  1141. leave;
  1142. //
  1143. // allocate some space for the input mount point (the volume name)
  1144. //
  1145. pMountPoint = SR_ALLOCATE_STRUCT_WITH_SPACE( PagedPool,
  1146. MOUNTMGR_MOUNT_POINT,
  1147. pVolumeName->Length,
  1148. SR_MOUNT_POINTS_TAG );
  1149. if (pMountPoint == NULL)
  1150. {
  1151. Status = STATUS_INSUFFICIENT_RESOURCES;
  1152. leave;
  1153. }
  1154. RtlZeroMemory(pMountPoint, sizeof(MOUNTMGR_MOUNT_POINT));
  1155. pMountPoint->DeviceNameOffset = sizeof(MOUNTMGR_MOUNT_POINT);
  1156. pMountPoint->DeviceNameLength = pVolumeName->Length;
  1157. RtlCopyMemory( pMountPoint + 1,
  1158. pVolumeName->Buffer,
  1159. pVolumeName->Length );
  1160. //
  1161. // allocate some space for the mount points we are going to query for
  1162. //
  1163. MountPointsLength = 1024 * 2;
  1164. //
  1165. // init an event for use
  1166. //
  1167. pEvent = SR_ALLOCATE_STRUCT(NonPagedPool, KEVENT, SR_KEVENT_TAG);
  1168. if (pEvent == NULL)
  1169. {
  1170. Status = STATUS_INSUFFICIENT_RESOURCES;
  1171. leave;
  1172. }
  1173. KeInitializeEvent(pEvent, SynchronizationEvent, FALSE);
  1174. retry:
  1175. ASSERT(pMountPoints == NULL);
  1176. pMountPoints = (PMOUNTMGR_MOUNT_POINTS)SR_ALLOCATE_ARRAY( PagedPool,
  1177. UCHAR,
  1178. MountPointsLength,
  1179. SR_MOUNT_POINTS_TAG );
  1180. if (pMountPoints == NULL)
  1181. {
  1182. Status = STATUS_INSUFFICIENT_RESOURCES;
  1183. leave;
  1184. }
  1185. //
  1186. // call into the mount manager to get all of the mount points
  1187. //
  1188. pIrp = IoBuildDeviceIoControlRequest( IOCTL_MOUNTMGR_QUERY_POINTS,
  1189. pDeviceObject,
  1190. pMountPoint, // InputBuffer
  1191. sizeof(MOUNTMGR_MOUNT_POINT)
  1192. + pMountPoint->DeviceNameLength,
  1193. pMountPoints, // OutputBuffer
  1194. MountPointsLength,
  1195. FALSE, // InternalIoctl
  1196. pEvent,
  1197. &IoStatusBlock );
  1198. if (pIrp == NULL)
  1199. {
  1200. Status = STATUS_INSUFFICIENT_RESOURCES;
  1201. leave;
  1202. }
  1203. //
  1204. // call the driver
  1205. //
  1206. Status = IoCallDriver(pDeviceObject, pIrp);
  1207. if (Status == STATUS_PENDING)
  1208. {
  1209. Status = KeWaitForSingleObject( pEvent,
  1210. Executive,
  1211. KernelMode,
  1212. FALSE,
  1213. NULL );
  1214. ASSERT(NT_SUCCESS(Status));
  1215. Status = IoStatusBlock.Status;
  1216. }
  1217. //
  1218. // do we need a larger buffer?
  1219. //
  1220. if (Status == STATUS_BUFFER_OVERFLOW)
  1221. {
  1222. //
  1223. // how much should we allocate? (odd IoStatusBlock isn't used - this
  1224. // was copied straight from volmount.c ).
  1225. //
  1226. MountPointsLength = pMountPoints->Size;
  1227. SR_FREE_POOL(pMountPoints, SR_MOUNT_POINTS_TAG);
  1228. pMountPoints = NULL;
  1229. //
  1230. // call the driver again!
  1231. //
  1232. goto retry;
  1233. }
  1234. else if (!NT_SUCCESS(Status))
  1235. {
  1236. leave;
  1237. }
  1238. //
  1239. // walk through all of the mount points return and find the
  1240. // volume guid name
  1241. //
  1242. for (Index = 0; Index < pMountPoints->NumberOfMountPoints; ++Index)
  1243. {
  1244. pVolumePoint = &pMountPoints->MountPoints[Index];
  1245. VolumePoint.Length = pVolumePoint->SymbolicLinkNameLength;
  1246. VolumePoint.Buffer = (PWSTR)( ((PUCHAR)pMountPoints)
  1247. + pVolumePoint->SymbolicLinkNameOffset);
  1248. if (MOUNTMGR_IS_VOLUME_NAME(&VolumePoint))
  1249. {
  1250. //
  1251. // found it!
  1252. //
  1253. break;
  1254. }
  1255. } // for (Index = 0; pMountPoints->NumberOfMountPoints; ++Index)
  1256. //
  1257. // did we find it?
  1258. //
  1259. if (Index == pMountPoints->NumberOfMountPoints)
  1260. {
  1261. Status = STATUS_OBJECT_NAME_NOT_FOUND;
  1262. leave;
  1263. }
  1264. //
  1265. // return it!
  1266. //
  1267. ASSERT(VolumePoint.Buffer[10] == L'{');
  1268. RtlCopyMemory( pVolumeGuid,
  1269. &VolumePoint.Buffer[10],
  1270. SR_GUID_BUFFER_LENGTH );
  1271. pVolumeGuid[SR_GUID_BUFFER_LENGTH/sizeof(WCHAR)] = UNICODE_NULL;
  1272. SrTrace(NOTIFY, ("SR!SrGetVolumeGuid(%wZ, %ws)\n",
  1273. pVolumeName, pVolumeGuid ));
  1274. } finally {
  1275. //
  1276. // check for unhandled exceptions
  1277. //
  1278. Status = FinallyUnwind(SrGetVolumeGuid, Status);
  1279. if (pEvent != NULL)
  1280. {
  1281. SR_FREE_POOL(pEvent, SR_KEVENT_TAG);
  1282. pEvent = NULL;
  1283. }
  1284. if (pMountPoint != NULL)
  1285. {
  1286. SR_FREE_POOL(pMountPoint, SR_MOUNT_POINTS_TAG);
  1287. pMountPoint = NULL;
  1288. }
  1289. if (pMountPoints != NULL)
  1290. {
  1291. SR_FREE_POOL(pMountPoints, SR_MOUNT_POINTS_TAG);
  1292. pMountPoints = NULL;
  1293. }
  1294. if (pFileObject != NULL)
  1295. {
  1296. ObDereferenceObject(pFileObject);
  1297. pFileObject = NULL;
  1298. }
  1299. }
  1300. RETURN(Status);
  1301. } // SrGetVolumeGuid
  1302. //
  1303. // paulmcd: 7/2000: remove the lookaside code so that the verifier can
  1304. // catch any invalid memory accesses
  1305. //
  1306. NTSTATUS
  1307. SrAllocateFileNameBuffer (
  1308. IN ULONG TokenLength,
  1309. OUT PUNICODE_STRING * ppBuffer
  1310. )
  1311. {
  1312. PAGED_CODE();
  1313. ASSERT(ppBuffer != NULL);
  1314. //
  1315. // is the file name too big ?
  1316. //
  1317. if (TokenLength > SR_MAX_FILENAME_LENGTH)
  1318. {
  1319. RETURN(STATUS_OBJECT_PATH_SYNTAX_BAD);
  1320. }
  1321. #ifdef USE_LOOKASIDE
  1322. *ppBuffer = ExAllocateFromPagedLookasideList(
  1323. &global->FileNameBufferLookaside
  1324. );
  1325. #else
  1326. *ppBuffer = SR_ALLOCATE_STRUCT_WITH_SPACE( PagedPool,
  1327. UNICODE_STRING,
  1328. SR_MAX_FILENAME_LENGTH+sizeof(WCHAR),
  1329. SR_FILENAME_BUFFER_TAG );
  1330. #endif
  1331. if (*ppBuffer == NULL)
  1332. {
  1333. RETURN(STATUS_INSUFFICIENT_RESOURCES);
  1334. }
  1335. (*ppBuffer)->Buffer = (PWCHAR)((*ppBuffer) + 1);
  1336. (*ppBuffer)->Length = 0;
  1337. (*ppBuffer)->MaximumLength = SR_MAX_FILENAME_LENGTH;
  1338. RETURN(STATUS_SUCCESS);
  1339. } // SrAllocateFileNameBuffer
  1340. VOID
  1341. SrFreeFileNameBuffer (
  1342. IN PUNICODE_STRING pBuffer
  1343. )
  1344. {
  1345. PAGED_CODE();
  1346. ASSERT(pBuffer != NULL);
  1347. #ifdef USE_LOOKASIDE
  1348. ExFreeToPagedLookasideList(
  1349. &global->FileNameBufferLookaside,
  1350. pBuffer );
  1351. #else
  1352. SR_FREE_POOL( pBuffer,
  1353. SR_FILENAME_BUFFER_TAG );
  1354. #endif
  1355. } // SrFreeFileNameBuffer
  1356. /***************************************************************************++
  1357. Routine Description:
  1358. this routine will return the number of hardlinks outstanding on this file
  1359. Arguments:
  1360. NextDeviceObject - the device object where this query will begin.
  1361. FileObject - the object to query
  1362. pNumberOfLinks - returns the number of links
  1363. Return Value:
  1364. NTSTATUS - Completion status.
  1365. --***************************************************************************/
  1366. NTSTATUS
  1367. SrGetNumberOfLinks(
  1368. IN PDEVICE_OBJECT NextDeviceObject,
  1369. IN PFILE_OBJECT FileObject,
  1370. OUT ULONG * pNumberOfLinks
  1371. )
  1372. {
  1373. FILE_STANDARD_INFORMATION StandardInformation;
  1374. NTSTATUS Status = STATUS_SUCCESS;
  1375. ASSERT(NextDeviceObject != NULL );
  1376. ASSERT(FileObject != NULL);
  1377. ASSERT(pNumberOfLinks != NULL);
  1378. PAGED_CODE();
  1379. Status = SrQueryInformationFile( NextDeviceObject,
  1380. FileObject,
  1381. &StandardInformation,
  1382. sizeof(StandardInformation),
  1383. FileStandardInformation,
  1384. NULL );
  1385. if (!NT_SUCCESS( Status )) {
  1386. RETURN( Status );
  1387. }
  1388. *pNumberOfLinks = StandardInformation.NumberOfLinks;
  1389. RETURN( Status );
  1390. } // SrGetNumberOfLinks
  1391. /***************************************************************************++
  1392. Routine Description:
  1393. this checks the volume provided if necessary. a hash table is used
  1394. to prevent redundant checks. if it is necessary to check this volume,
  1395. this function will do so and create any needed directory structures.
  1396. this includes the volume restore location + current restore point
  1397. location.
  1398. it will fire the first write notification to any listening usermode
  1399. process.
  1400. Arguments:
  1401. pVolumeName - the name of the volume to check on
  1402. ForceCheck - force a check. this is passed as TRUE if an SrBackupFile
  1403. failed due to path not found.
  1404. Return Value:
  1405. NTSTATUS - Completion status.
  1406. --***************************************************************************/
  1407. NTSTATUS
  1408. SrCheckVolume(
  1409. IN PSR_DEVICE_EXTENSION pExtension,
  1410. IN BOOLEAN ForceCheck
  1411. )
  1412. {
  1413. NTSTATUS Status;
  1414. PUNICODE_STRING pLogFileName = NULL;
  1415. BOOLEAN ReleaseLock = FALSE;
  1416. ASSERT(ExIsResourceAcquiredShared(&pExtension->ActivityLock));
  1417. PAGED_CODE();
  1418. //
  1419. // has the drive already been checked?
  1420. //
  1421. if (!ForceCheck && pExtension->DriveChecked)
  1422. {
  1423. //
  1424. // all done then
  1425. //
  1426. return STATUS_SUCCESS;
  1427. }
  1428. try {
  1429. Status = STATUS_SUCCESS;
  1430. //
  1431. // grab the lock EXCLUSIVE
  1432. //
  1433. SrAcquireGlobalLockExclusive();
  1434. ReleaseLock = TRUE;
  1435. //
  1436. // delay load our file config (we have to wait for the file systems
  1437. // to become active)
  1438. //
  1439. if (!global->FileConfigLoaded)
  1440. {
  1441. Status = SrReadConfigFile();
  1442. if (!NT_SUCCESS(Status))
  1443. leave;
  1444. global->FileConfigLoaded = TRUE;
  1445. }
  1446. } finally {
  1447. SrReleaseGlobalLock();
  1448. }
  1449. if (!NT_SUCCESS_NO_DBGBREAK( Status )) {
  1450. goto SrCheckVolume_Cleanup;
  1451. }
  1452. try {
  1453. SrAcquireLogLockExclusive( pExtension );
  1454. //
  1455. // check it again with the lock held.
  1456. //
  1457. if (!ForceCheck && pExtension->DriveChecked)
  1458. {
  1459. //
  1460. // all done then
  1461. //
  1462. leave;
  1463. }
  1464. //
  1465. // Check to make sure that the volume is enabled.
  1466. //
  1467. if (!SR_LOGGING_ENABLED(pExtension))
  1468. {
  1469. leave;
  1470. }
  1471. //
  1472. // first time we've seen this volume, need to check it
  1473. //
  1474. SrTrace( NOTIFY, ("SR!SrCheckVolume(%wZ, %d)\n",
  1475. pExtension->pNtVolumeName,
  1476. (ULONG)ForceCheck ));
  1477. //
  1478. // get the volume guid. this can't be done in SrAttachToVolume as it
  1479. // won't work at boot time as the mount mgr is not happy about being
  1480. // called that early
  1481. //
  1482. pExtension->VolumeGuid.Length = SR_GUID_BUFFER_LENGTH;
  1483. pExtension->VolumeGuid.MaximumLength = SR_GUID_BUFFER_LENGTH;
  1484. pExtension->VolumeGuid.Buffer = &pExtension->VolumeGuidBuffer[0];
  1485. Status = SrGetVolumeGuid( pExtension->pNtVolumeName,
  1486. &pExtension->VolumeGuidBuffer[0] );
  1487. if (!NT_SUCCESS(Status)) {
  1488. leave;
  1489. }
  1490. //
  1491. // look for an existing restore location
  1492. //
  1493. Status = SrCheckForRestoreLocation( pExtension );
  1494. //
  1495. // if it failed we might need to create a new restore store .
  1496. //
  1497. if (Status == STATUS_OBJECT_NAME_NOT_FOUND ||
  1498. Status == STATUS_OBJECT_PATH_NOT_FOUND)
  1499. {
  1500. //
  1501. // fire a notification for the first write on this volume
  1502. //
  1503. Status = SrFireNotification( SrNotificationVolumeFirstWrite,
  1504. pExtension,
  1505. 0 );
  1506. if (!NT_SUCCESS(Status))
  1507. leave;
  1508. //
  1509. // and create a new restore location
  1510. //
  1511. Status = SrCreateRestoreLocation( pExtension );
  1512. if (!NT_SUCCESS(Status))
  1513. leave;
  1514. } else if (!NT_SUCCESS(Status)) {
  1515. leave;
  1516. }
  1517. //
  1518. // and start logging
  1519. //
  1520. if (pExtension->pLogContext == NULL)
  1521. {
  1522. Status = SrAllocateFileNameBuffer(SR_MAX_FILENAME_LENGTH, &pLogFileName);
  1523. if (!NT_SUCCESS(Status))
  1524. leave;
  1525. Status = SrGetLogFileName( pExtension->pNtVolumeName,
  1526. SR_FILENAME_BUFFER_LENGTH,
  1527. pLogFileName );
  1528. if (!NT_SUCCESS(Status))
  1529. leave;
  1530. //
  1531. // start logging!
  1532. //
  1533. Status = SrLogStart( pLogFileName,
  1534. pExtension,
  1535. &pExtension->pLogContext );
  1536. if (!NT_SUCCESS(Status))
  1537. {
  1538. leave;
  1539. }
  1540. }
  1541. //
  1542. // the drive is now checked
  1543. //
  1544. pExtension->DriveChecked = TRUE;
  1545. //
  1546. // we are all done
  1547. //
  1548. } finally {
  1549. //
  1550. // check for unhandled exceptions
  1551. //
  1552. Status = FinallyUnwind(SrCheckVolume, Status);
  1553. SrReleaseLogLock( pExtension );
  1554. }
  1555. SrCheckVolume_Cleanup:
  1556. if (pLogFileName != NULL)
  1557. {
  1558. SrFreeFileNameBuffer( pLogFileName );
  1559. pLogFileName = NULL;
  1560. }
  1561. RETURN(Status);
  1562. } // SrCheckVolume
  1563. /***************************************************************************++
  1564. Routine Description:
  1565. this will check for a restore location on the volume provided.
  1566. this consists of checking both the location + the restore point location.
  1567. it will return failure for no restore location, but will alwasy create
  1568. the restore point location as long as a good restore location is found.
  1569. Arguments:
  1570. pVolumeName - the nt name of the volume to check on
  1571. Return Value:
  1572. NTSTATUS - Completion status.
  1573. --***************************************************************************/
  1574. NTSTATUS
  1575. SrCheckForRestoreLocation(
  1576. IN PSR_DEVICE_EXTENSION pExtension
  1577. )
  1578. {
  1579. NTSTATUS Status;
  1580. HANDLE Handle = NULL;
  1581. ULONG CharCount;
  1582. PUNICODE_STRING pDirectoryName = NULL;
  1583. IO_STATUS_BLOCK IoStatusBlock;
  1584. OBJECT_ATTRIBUTES ObjectAttributes;
  1585. PFILE_RENAME_INFORMATION pRenameInformation = NULL;
  1586. PUNICODE_STRING pVolumeName;
  1587. ASSERT( IS_VALID_SR_DEVICE_EXTENSION( pExtension ));
  1588. ASSERT( IS_ACTIVITY_LOCK_ACQUIRED_EXCLUSIVE( pExtension) ||
  1589. IS_LOG_LOCK_ACQUIRED_EXCLUSIVE( pExtension ) );
  1590. PAGED_CODE();
  1591. try {
  1592. pVolumeName = pExtension->pNtVolumeName;
  1593. ASSERT( pVolumeName != NULL );
  1594. //
  1595. // need to check for an existing _restore directory?
  1596. //
  1597. RtlZeroMemory(&IoStatusBlock, sizeof(IoStatusBlock));
  1598. //
  1599. // grab a filename buffer
  1600. //
  1601. Status = SrAllocateFileNameBuffer(SR_MAX_FILENAME_LENGTH, &pDirectoryName);
  1602. if (!NT_SUCCESS(Status))
  1603. leave;
  1604. //
  1605. // create our restore point location string
  1606. //
  1607. CharCount = swprintf( pDirectoryName->Buffer,
  1608. VOLUME_FORMAT RESTORE_LOCATION,
  1609. pVolumeName,
  1610. global->MachineGuid );
  1611. pDirectoryName->Length = (USHORT)CharCount * sizeof(WCHAR);
  1612. InitializeObjectAttributes( &ObjectAttributes,
  1613. pDirectoryName,
  1614. OBJ_KERNEL_HANDLE,
  1615. NULL,
  1616. NULL );
  1617. Status = SrIoCreateFile( &Handle,
  1618. FILE_LIST_DIRECTORY | SYNCHRONIZE,
  1619. &ObjectAttributes,
  1620. &IoStatusBlock,
  1621. NULL,
  1622. FILE_ATTRIBUTE_NORMAL,
  1623. FILE_SHARE_READ | FILE_SHARE_WRITE,
  1624. FILE_OPEN, // OPEN_EXISTING
  1625. FILE_DIRECTORY_FILE
  1626. | FILE_SYNCHRONOUS_IO_NONALERT
  1627. | FILE_OPEN_FOR_BACKUP_INTENT,
  1628. NULL,
  1629. 0, // EaLength
  1630. IO_IGNORE_SHARE_ACCESS_CHECK,
  1631. pExtension->pTargetDevice );
  1632. if (!NT_SUCCESS_NO_DBGBREAK(Status))
  1633. leave;
  1634. //
  1635. // the correct location existed .
  1636. // this is a good restore point to use
  1637. //
  1638. ZwClose(Handle);
  1639. Handle = NULL;
  1640. //
  1641. // is there a restore point directory
  1642. //
  1643. //
  1644. // check our current restore points sub directory; don't need to protect
  1645. // access to CurrentRestoreNumber because we are protected by the
  1646. // ActivityLock.
  1647. //
  1648. CharCount = swprintf( &pDirectoryName->Buffer[pDirectoryName->Length/sizeof(WCHAR)],
  1649. L"\\" RESTORE_POINT_PREFIX L"%d",
  1650. global->FileConfig.CurrentRestoreNumber );
  1651. pDirectoryName->Length += (USHORT)CharCount * sizeof(WCHAR);
  1652. InitializeObjectAttributes( &ObjectAttributes,
  1653. pDirectoryName,
  1654. OBJ_KERNEL_HANDLE,
  1655. NULL,
  1656. NULL );
  1657. Status = SrIoCreateFile( &Handle,
  1658. FILE_LIST_DIRECTORY | SYNCHRONIZE,
  1659. &ObjectAttributes,
  1660. &IoStatusBlock,
  1661. NULL,
  1662. FILE_ATTRIBUTE_NORMAL,
  1663. FILE_SHARE_READ | FILE_SHARE_WRITE,
  1664. FILE_OPEN, // OPEN_EXISTING
  1665. FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT,
  1666. NULL,
  1667. 0, // EaLength
  1668. IO_IGNORE_SHARE_ACCESS_CHECK,
  1669. pExtension->pTargetDevice );
  1670. if (!NT_SUCCESS_NO_DBGBREAK(Status))
  1671. leave;
  1672. //
  1673. // all done, it was there
  1674. //
  1675. ZwClose(Handle);
  1676. Handle = NULL;
  1677. } finally {
  1678. //
  1679. // check for unhandled exceptions
  1680. //
  1681. Status = FinallyUnwind(SrCheckForRestoreLocation, Status);
  1682. if (Handle != NULL)
  1683. {
  1684. ZwClose(Handle);
  1685. Handle = NULL;
  1686. }
  1687. if (pDirectoryName != NULL)
  1688. {
  1689. SrFreeFileNameBuffer(pDirectoryName);
  1690. pDirectoryName = NULL;
  1691. }
  1692. }
  1693. //
  1694. // don't use RETURN.. it's normal to return NOT_FOUND
  1695. //
  1696. return Status;
  1697. } // SrCheckForRestoreLocation
  1698. NTSTATUS
  1699. SrGetMountVolume(
  1700. IN PFILE_OBJECT pFileObject,
  1701. OUT PUNICODE_STRING * ppMountVolume
  1702. )
  1703. {
  1704. NTSTATUS Status;
  1705. HANDLE FileHandle = NULL;
  1706. HANDLE EventHandle = NULL;
  1707. BOOLEAN RestoreFileObjectFlag = FALSE;
  1708. IO_STATUS_BLOCK IoStatusBlock;
  1709. PREPARSE_DATA_BUFFER pReparseHeader = NULL;
  1710. OBJECT_ATTRIBUTES ObjectAttributes;
  1711. PAGED_CODE();
  1712. ASSERT(IS_VALID_FILE_OBJECT(pFileObject));
  1713. ASSERT(ppMountVolume != NULL);
  1714. try {
  1715. *ppMountVolume = NULL;
  1716. //
  1717. // get the current mount point information
  1718. //
  1719. pReparseHeader = SR_ALLOCATE_POOL( PagedPool,
  1720. MAXIMUM_REPARSE_DATA_BUFFER_SIZE,
  1721. SR_REPARSE_HEADER_TAG );
  1722. if (pReparseHeader == NULL)
  1723. {
  1724. Status = STATUS_INSUFFICIENT_RESOURCES;
  1725. leave;
  1726. }
  1727. RtlZeroMemory(pReparseHeader, MAXIMUM_REPARSE_DATA_BUFFER_SIZE);
  1728. //
  1729. // first turn off any synchro bit that is set. we want
  1730. // async for our calls. this does :
  1731. //
  1732. // 1) avoids the iomgr from grabbing the FileObjectLock. this
  1733. // will deadlock if it attempts to grab it.
  1734. //
  1735. if (FlagOn(pFileObject->Flags, FO_SYNCHRONOUS_IO))
  1736. {
  1737. RestoreFileObjectFlag = TRUE;
  1738. pFileObject->Flags = pFileObject->Flags ^ FO_SYNCHRONOUS_IO;
  1739. }
  1740. //
  1741. // get a handle
  1742. //
  1743. Status = ObOpenObjectByPointer( pFileObject,
  1744. OBJ_KERNEL_HANDLE,
  1745. NULL, // PassedAccessState
  1746. FILE_READ_ATTRIBUTES,
  1747. *IoFileObjectType,
  1748. KernelMode,
  1749. &FileHandle );
  1750. if (!NT_SUCCESS(Status)) {
  1751. leave;
  1752. }
  1753. InitializeObjectAttributes( &ObjectAttributes,
  1754. NULL,
  1755. OBJ_KERNEL_HANDLE,
  1756. NULL,
  1757. NULL );
  1758. Status = ZwCreateEvent( &EventHandle,
  1759. EVENT_ALL_ACCESS,
  1760. &ObjectAttributes,
  1761. SynchronizationEvent,
  1762. FALSE);
  1763. if (!NT_SUCCESS(Status)) {
  1764. leave;
  1765. }
  1766. //
  1767. // get the old mount volume name
  1768. //
  1769. Status = ZwFsControlFile( FileHandle,
  1770. EventHandle,
  1771. NULL, // ApcRoutine OPTIONAL,
  1772. NULL, // ApcContext OPTIONAL,
  1773. &IoStatusBlock,
  1774. FSCTL_GET_REPARSE_POINT,
  1775. NULL, // InputBuffer OPTIONAL,
  1776. 0, // InputBufferLength,
  1777. pReparseHeader,
  1778. MAXIMUM_REPARSE_DATA_BUFFER_SIZE );
  1779. if (Status == STATUS_PENDING)
  1780. {
  1781. Status = ZwWaitForSingleObject( EventHandle, FALSE, NULL );
  1782. if (!NT_SUCCESS(Status)) {
  1783. leave;
  1784. }
  1785. Status = IoStatusBlock.Status;
  1786. }
  1787. if ((STATUS_NOT_A_REPARSE_POINT == Status) ||
  1788. !NT_SUCCESS(Status)) {
  1789. leave;
  1790. }
  1791. if (pReparseHeader->ReparseTag != IO_REPARSE_TAG_MOUNT_POINT ||
  1792. pReparseHeader->ReparseDataLength == 0)
  1793. {
  1794. Status = STATUS_NOT_A_REPARSE_POINT;
  1795. leave;
  1796. }
  1797. //
  1798. // grab the volume name
  1799. //
  1800. Status = SrAllocateFileNameBuffer( pReparseHeader->MountPointReparseBuffer.SubstituteNameLength,
  1801. ppMountVolume );
  1802. if (!NT_SUCCESS(Status)) {
  1803. leave;
  1804. }
  1805. RtlCopyMemory( (*ppMountVolume)->Buffer,
  1806. pReparseHeader->MountPointReparseBuffer.PathBuffer,
  1807. pReparseHeader->MountPointReparseBuffer.SubstituteNameLength );
  1808. (*ppMountVolume)->Length = pReparseHeader->MountPointReparseBuffer.SubstituteNameLength;
  1809. } finally {
  1810. Status = FinallyUnwind(SrGetMountVolume, Status);
  1811. if (pReparseHeader != NULL)
  1812. {
  1813. SR_FREE_POOL(pReparseHeader, SR_REPARSE_HEADER_TAG);
  1814. pReparseHeader = NULL;
  1815. }
  1816. if (FileHandle != NULL)
  1817. {
  1818. ZwClose(FileHandle);
  1819. FileHandle = NULL;
  1820. }
  1821. if (EventHandle != NULL)
  1822. {
  1823. ZwClose(EventHandle);
  1824. EventHandle = NULL;
  1825. }
  1826. if (RestoreFileObjectFlag)
  1827. {
  1828. pFileObject->Flags = pFileObject->Flags | FO_SYNCHRONOUS_IO;
  1829. }
  1830. if (!NT_SUCCESS_NO_DBGBREAK(Status) && *ppMountVolume != NULL)
  1831. {
  1832. SrFreeFileNameBuffer(*ppMountVolume);
  1833. *ppMountVolume = NULL;
  1834. }
  1835. }
  1836. #if DBG
  1837. //
  1838. // We don't want to break if we see STATUS_NOT_A_REPARSE_POINT.
  1839. //
  1840. if (STATUS_NOT_A_REPARSE_POINT == Status) {
  1841. return Status;
  1842. }
  1843. #endif
  1844. RETURN(Status);
  1845. } // SrGetMountVolume
  1846. NTSTATUS
  1847. SrCheckFreeDiskSpace(
  1848. IN HANDLE FileHandle,
  1849. IN PUNICODE_STRING pVolumeName OPTIONAL
  1850. )
  1851. {
  1852. NTSTATUS Status;
  1853. FILE_FS_FULL_SIZE_INFORMATION FsFullSizeInformation;
  1854. IO_STATUS_BLOCK IoStatus;
  1855. UNREFERENCED_PARAMETER( pVolumeName );
  1856. PAGED_CODE();
  1857. Status = ZwQueryVolumeInformationFile( FileHandle,
  1858. &IoStatus,
  1859. &FsFullSizeInformation,
  1860. sizeof(FsFullSizeInformation),
  1861. FileFsFullSizeInformation );
  1862. if (!NT_SUCCESS(Status))
  1863. RETURN(Status);
  1864. //
  1865. // make sure there is 50mb free
  1866. //
  1867. if ((FsFullSizeInformation.ActualAvailableAllocationUnits.QuadPart *
  1868. FsFullSizeInformation.SectorsPerAllocationUnit *
  1869. FsFullSizeInformation.BytesPerSector) < SR_MIN_DISK_FREE_SPACE)
  1870. {
  1871. //
  1872. // this disk is too full for us
  1873. //
  1874. SrTrace( NOTIFY, ("sr!SrCheckFreeDiskSpace: skipping %wZ due to < 50mb free\n",
  1875. pVolumeName ));
  1876. RETURN(STATUS_DISK_FULL);
  1877. }
  1878. RETURN(STATUS_SUCCESS);
  1879. } // SrCheckFreeDiskSpace
  1880. /***************************************************************************++
  1881. Routine Description:
  1882. this is a private version of ZwSetSecurityObject. This works around
  1883. a bug in ntfs that does not allow you to change the OWNER to admin,
  1884. even though PreviousMode is KernelMode.
  1885. Arguments:
  1886. Return Value:
  1887. NTSTATUS - Completion status.
  1888. --***************************************************************************/
  1889. NTSTATUS
  1890. SrSetSecurityObjectAsSystem(
  1891. IN HANDLE Handle,
  1892. IN SECURITY_INFORMATION SecurityInformation,
  1893. IN PSECURITY_DESCRIPTOR SecurityDescriptor
  1894. )
  1895. {
  1896. NTSTATUS Status;
  1897. PACCESS_TOKEN pSystemToken;
  1898. PACCESS_TOKEN pSavedThreadToken = NULL;
  1899. BOOLEAN SavedCopyOnOpen;
  1900. BOOLEAN SavedEffectiveOnly;
  1901. BOOLEAN RevertImpersonation = FALSE;
  1902. SECURITY_IMPERSONATION_LEVEL SavedLevel;
  1903. PAGED_CODE();
  1904. try {
  1905. Status = STATUS_SUCCESS;
  1906. //
  1907. // get the system token off of the system process
  1908. //
  1909. pSystemToken = PsReferencePrimaryToken(global->pSystemProcess);
  1910. if (pSystemToken == NULL)
  1911. {
  1912. Status = STATUS_NO_TOKEN;
  1913. leave;
  1914. }
  1915. //
  1916. // get this current thread's token (if any)
  1917. //
  1918. pSavedThreadToken = PsReferenceImpersonationToken( PsGetCurrentThread(),
  1919. &SavedCopyOnOpen,
  1920. &SavedEffectiveOnly,
  1921. &SavedLevel );
  1922. //
  1923. // OK if (pSavedThreadToken == NULL)
  1924. //
  1925. //
  1926. // impersonate the system token on this thread (if we are not already)
  1927. //
  1928. if (pSavedThreadToken != pSystemToken)
  1929. {
  1930. Status = PsImpersonateClient( PsGetCurrentThread(),
  1931. pSystemToken,
  1932. TRUE, // CopyOnOpen
  1933. TRUE, // EffectiveOnly
  1934. SecurityImpersonation );
  1935. if (!NT_SUCCESS(Status))
  1936. leave;
  1937. RevertImpersonation = TRUE;
  1938. }
  1939. //
  1940. // change the OWNER now
  1941. //
  1942. Status = ZwSetSecurityObject( Handle,
  1943. SecurityInformation,
  1944. SecurityDescriptor );
  1945. if (!NT_SUCCESS(Status))
  1946. leave;
  1947. } finally {
  1948. if (RevertImpersonation)
  1949. {
  1950. NTSTATUS TempStatus;
  1951. //
  1952. // now revert the impersonation back
  1953. //
  1954. TempStatus = PsImpersonateClient( PsGetCurrentThread(),
  1955. pSavedThreadToken, // OK if NULL
  1956. SavedCopyOnOpen,
  1957. SavedEffectiveOnly,
  1958. SavedLevel );
  1959. //
  1960. // not much we can do if this fails
  1961. //
  1962. ASSERT(NT_SUCCESS(TempStatus));
  1963. }
  1964. if (pSavedThreadToken != NULL)
  1965. {
  1966. PsDereferenceImpersonationToken(pSavedThreadToken);
  1967. pSavedThreadToken = NULL;
  1968. }
  1969. if (pSystemToken != NULL)
  1970. {
  1971. ObDereferenceObject(pSystemToken);
  1972. pSystemToken = NULL;
  1973. }
  1974. }
  1975. RETURN(Status);
  1976. } // SrSetSecurityObjectAsSystem
  1977. /***************************************************************************++
  1978. Routine Description:
  1979. this is will check if the fileobject passed in really is on the volume
  1980. represented by pExtension .
  1981. if it is not (due to mount points in the path) then it returns the real
  1982. file name and the real volume it's on.
  1983. Arguments:
  1984. Return Value:
  1985. NTSTATUS - Completion status.
  1986. --***************************************************************************/
  1987. NTSTATUS
  1988. SrCheckForMountsInPath(
  1989. IN PSR_DEVICE_EXTENSION pExtension,
  1990. IN PFILE_OBJECT pFileObject,
  1991. OUT BOOLEAN * pMountInPath
  1992. )
  1993. {
  1994. PDEVICE_OBJECT pFilterDevice;
  1995. PAGED_CODE();
  1996. ASSERT(IS_VALID_SR_DEVICE_EXTENSION(pExtension));
  1997. ASSERT(IS_VALID_FILE_OBJECT(pFileObject));
  1998. ASSERT(pFileObject->Vpb != NULL && pFileObject->Vpb->DeviceObject != NULL);
  1999. *pMountInPath = FALSE;
  2000. //
  2001. // get our device extension that we have attached to this VPB
  2002. //
  2003. pFilterDevice = SrGetFilterDevice(pFileObject->Vpb->DeviceObject);
  2004. if (pFilterDevice == NULL)
  2005. {
  2006. RETURN(STATUS_INVALID_DEVICE_STATE);
  2007. }
  2008. //
  2009. // check it against the passed in extension for a match
  2010. //
  2011. if (pFilterDevice->DeviceExtension == pExtension)
  2012. {
  2013. //
  2014. // it's normal, leave early
  2015. //
  2016. RETURN(STATUS_SUCCESS);
  2017. }
  2018. //
  2019. // we went through a mount point
  2020. //
  2021. *pMountInPath = TRUE;
  2022. RETURN(STATUS_SUCCESS);
  2023. } // SrCheckForMountsInPath
  2024. /***************************************************************************++
  2025. Routine Description:
  2026. Return the short file name for the given file object
  2027. Arguments:
  2028. pExtension - The SR device extension for the volume on which this file
  2029. resides.
  2030. pFileObject - The file for which we are querying the short name.
  2031. pShortName - The unicode string that will get set to the short name.
  2032. Return Value:
  2033. Returns STATUS_SUCCESS if the shortname is retrieved successfully.
  2034. Returns STATUS_OBJECT_NAME_NOT_FOUND if this file does not have a
  2035. short name (e.g., hardlinks).
  2036. Returns STATUS_BUFFER_OVERFLOW if pShortName is not large enough to hold
  2037. the shortname returned.
  2038. --***************************************************************************/
  2039. NTSTATUS
  2040. SrGetShortFileName(
  2041. IN PSR_DEVICE_EXTENSION pExtension,
  2042. IN PFILE_OBJECT pFileObject,
  2043. OUT PUNICODE_STRING pShortName
  2044. )
  2045. {
  2046. NTSTATUS Status;
  2047. PFILE_NAME_INFORMATION pNameInfo;
  2048. CHAR buffer[sizeof(FILE_NAME_INFORMATION)+(SR_SHORT_NAME_CHARS+1)*sizeof(WCHAR)];
  2049. PAGED_CODE();
  2050. //
  2051. // make the query
  2052. //
  2053. Status = SrQueryInformationFile( pExtension->pTargetDevice,
  2054. pFileObject,
  2055. buffer,
  2056. sizeof(buffer),
  2057. FileAlternateNameInformation,
  2058. NULL );
  2059. if (STATUS_OBJECT_NAME_NOT_FOUND == Status ||
  2060. !NT_SUCCESS( Status ))
  2061. {
  2062. //
  2063. // STATUS_OBJECT_NAME_NOT_FOUND is a valid error that the caller
  2064. // should be able to deal with. Some files do not have shortname
  2065. // (e.g., hardlinks). If we hit some other error, just return that
  2066. // also and let the caller deal.
  2067. //
  2068. return Status;
  2069. }
  2070. pNameInfo = (PFILE_NAME_INFORMATION) buffer;
  2071. //
  2072. // return the short name
  2073. //
  2074. if (pShortName->MaximumLength < pNameInfo->FileNameLength /*+ sizeof(WCHAR)*/)
  2075. {
  2076. return STATUS_BUFFER_OVERFLOW;
  2077. }
  2078. //
  2079. // copy the name over
  2080. //
  2081. RtlCopyMemory( pShortName->Buffer,
  2082. pNameInfo->FileName,
  2083. pNameInfo->FileNameLength );
  2084. //
  2085. // update the length and NULL terminate
  2086. //
  2087. pShortName->Length = (USHORT)pNameInfo->FileNameLength;
  2088. //pShortName->Buffer[pShortName->Length/sizeof(WCHAR)] = UNICODE_NULL;
  2089. return STATUS_SUCCESS;
  2090. }