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.

1773 lines
46 KiB

  1. /*++
  2. Copyright (c) 1998-1999 Microsoft Corporation
  3. Module Name:
  4. sisbackup.cpp
  5. Abstract:
  6. The SIS Backup dll.
  7. Author:
  8. Bill Bolosky [bolosky] March 1998
  9. Revision History:
  10. --*/
  11. #include "sibp.h"
  12. BOOLEAN
  13. NonSISEnabledVolume(
  14. PSIB_RESTORE_VOLUME_STRUCTURE restoreStructure)
  15. /*++
  16. Routine Description:
  17. Figure out if restoreStructure represents a SIS enabled volume.
  18. First, we check to see if we've already made the check, in which
  19. case we return the value we already stored. If not, then we
  20. open a root handle, and send down a mal-formed SIS_COPYFILE request.
  21. If we get back ERROR_INVALID_FUNCTION then it's not SIS enabled. If
  22. we get back ERROR_INVALID_PARAMETER, then it's a SIS-enabled volume.
  23. If we get back anything else, then we can't prove it's not SIS enabled,
  24. and we just retry the next time we're asked.
  25. Caller must hold the mutex in the restore volume structure.
  26. Arguments:
  27. restoreStructure - A pointer to the restore structure representing
  28. the volume to check.
  29. Return Value:
  30. Returns TRUE if this is not a SIS-enabled volume, FALSE if it is or
  31. if it can't be determined.
  32. --*/
  33. {
  34. if (restoreStructure->checkedForSISEnabledVolume) {
  35. return !restoreStructure->isSISEnabledVolume;
  36. }
  37. HANDLE volumeRootHandle;
  38. PWCHAR volumeRootName;
  39. //
  40. // Allocate space for a string containing the volume root name including the trailing
  41. // backslash. It will be two (wide) characters longer than restoreStructure->volumeRoot
  42. // because of the backslash and null terminator.
  43. //
  44. volumeRootName = (PWCHAR) malloc ((wcslen(restoreStructure->volumeRoot) + 2) * sizeof(WCHAR));
  45. if (NULL == volumeRootName) {
  46. //
  47. // Guess we can't check, just assume it's OK.
  48. //
  49. #if DBG
  50. DbgPrint("SISBkup: NonSISEnabledVolume: unable to allocate space for volume root name\n");
  51. #endif // DBG
  52. return FALSE;
  53. }
  54. wcscpy(volumeRootName,restoreStructure->volumeRoot);
  55. wcscat(volumeRootName,L"\\");
  56. volumeRootHandle = CreateFileW(
  57. volumeRootName,
  58. 0, // don't need any access for this check
  59. FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
  60. NULL, // security attributes
  61. OPEN_EXISTING,
  62. FILE_FLAG_BACKUP_SEMANTICS, // needed to open a directory
  63. NULL); // hTemplateFile
  64. free(volumeRootName);
  65. volumeRootName = NULL;
  66. if (INVALID_HANDLE_VALUE == volumeRootHandle) {
  67. return FALSE;
  68. }
  69. //
  70. // Send a malformed FSCTL_SIS_COPYFILE down on the handle we just opened.
  71. //
  72. DWORD bytesReturned;
  73. BOOL worked = DeviceIoControl(
  74. volumeRootHandle,
  75. FSCTL_SIS_COPYFILE,
  76. NULL, // input buffer (this is a malformed request, after all)
  77. 0, // i.b. size
  78. NULL, // output buffer
  79. 0, // o.b. size
  80. &bytesReturned,
  81. NULL); // lap
  82. CloseHandle(volumeRootHandle);
  83. if (worked) {
  84. //
  85. // This is bizarre!
  86. //
  87. #if DBG
  88. DbgPrint("SISBkup: malformed FSCTL_SIS_COPYFILE worked!\n");
  89. #endif // DBG
  90. return FALSE;
  91. }
  92. if (GetLastError() == ERROR_INVALID_FUNCTION) {
  93. //
  94. // No one recognized the copyfile request, or SIS decided that
  95. // this isn't a SIS enabled volume. Say no.
  96. //
  97. restoreStructure->checkedForSISEnabledVolume = TRUE;
  98. restoreStructure->isSISEnabledVolume = FALSE;
  99. return TRUE;
  100. }
  101. if (GetLastError() == ERROR_INVALID_PARAMETER) {
  102. //
  103. // This means that SIS saw the request and thinks this is
  104. // a SIS enabled volume. Say so.
  105. //
  106. restoreStructure->checkedForSISEnabledVolume = TRUE;
  107. restoreStructure->isSISEnabledVolume = TRUE;
  108. return FALSE;
  109. }
  110. //
  111. // Else, it's some weird error. We can't prove it's not a SIS volume.
  112. //
  113. #if DBG
  114. DbgPrint("SISBkup: got unexpected error from SIS_FSCTL_COPYFILE, %d\n",GetLastError());
  115. #endif // DBG
  116. return FALSE;
  117. }
  118. VOID
  119. SipComputeChecksum(
  120. IN PVOID buffer,
  121. IN ULONG size,
  122. IN OUT PLONGLONG checksum)
  123. /*++
  124. Routine Description:
  125. Compute a checksum for a buffer. We use the "131 hash," which
  126. work by keeping a 64 bit running total, and for each 32 bits of
  127. data multiplying the 64 bits by 131 and adding in the next 32
  128. bits. Must be called at PASSIVE_LEVEL, and all aruments
  129. may be pagable.
  130. Arguments:
  131. buffer - pointer to the data to be checksummed
  132. size - size of the data to be checksummed
  133. checksum - pointer to large integer to receive the checksum. This
  134. may be within the buffer, and SipComputeChecksum guarantees that
  135. the initial value will be used in computing the checksum.
  136. Return Value:
  137. Returns STATUS_SUCCESS or an error returned from the actual disk write.
  138. --*/
  139. {
  140. LONGLONG runningTotal;
  141. PULONG ptr = (PULONG)buffer;
  142. ULONG bytesRemaining = size;
  143. runningTotal = *checksum;
  144. while (bytesRemaining >= sizeof(*ptr)) {
  145. runningTotal = runningTotal * 131 + *ptr;
  146. bytesRemaining -= sizeof(*ptr);
  147. ptr++;
  148. }
  149. if (bytesRemaining > 0) {
  150. ULONG extra;
  151. ASSERT(bytesRemaining < sizeof (ULONG));
  152. extra = 0;
  153. RtlMoveMemory(&extra, ptr, bytesRemaining);
  154. runningTotal = runningTotal * 131 + extra;
  155. }
  156. *checksum = runningTotal;
  157. }
  158. void
  159. TryOpeningFile(
  160. PWCHAR fileName)
  161. {
  162. HANDLE fileHandle;
  163. fileHandle = CreateFileW(
  164. fileName,
  165. GENERIC_READ,
  166. FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
  167. NULL, // security attributes
  168. OPEN_EXISTING,
  169. FILE_FLAG_BACKUP_SEMANTICS,
  170. NULL); // template file
  171. if (INVALID_HANDLE_VALUE != fileHandle) {
  172. CloseHandle(fileHandle);
  173. }
  174. }
  175. LONG
  176. CsidCompare(
  177. IN PCSID id1,
  178. IN PCSID id2)
  179. {
  180. PLONGLONG keyValue1 = (PLONGLONG)id1;
  181. PLONGLONG keyValue2 = keyValue1 + 1;
  182. PLONGLONG nodeValue1 = (PLONGLONG)id2;
  183. PLONGLONG nodeValue2 = nodeValue1 + 1;
  184. if (*keyValue1 < *nodeValue1) {
  185. return -1;
  186. } else if (*keyValue1 > *nodeValue1) {
  187. return 1;
  188. } else {
  189. if (*keyValue2 < *nodeValue2) {
  190. return -1;
  191. } else if (*keyValue2 > *nodeValue2) {
  192. return 1;
  193. } else {
  194. return 0;
  195. }
  196. }
  197. }
  198. NTSTATUS
  199. FilenameFromCSid(
  200. IN PCSID CSid,
  201. IN PWCHAR volumeRoot,
  202. OUT PWCHAR *fileName)
  203. {
  204. PWCHAR uuidString;
  205. RPC_STATUS status;
  206. *fileName = (PWCHAR)malloc(
  207. wcslen(volumeRoot) * sizeof(WCHAR)
  208. + SIS_CSDIR_STRING_SIZE
  209. + INDEX_MAX_NUMERIC_STRING_LENGTH
  210. + sizeof(WCHAR));
  211. if (NULL == *fileName) {
  212. return STATUS_INSUFFICIENT_RESOURCES;
  213. }
  214. wcscpy(*fileName,volumeRoot);
  215. wcscat(*fileName,SIS_CSDIR_STRING);
  216. status = UuidToStringW(CSid,(unsigned short **)&uuidString);
  217. if (RPC_S_OK != status) {
  218. free(*fileName);
  219. *fileName = NULL;
  220. return STATUS_INSUFFICIENT_RESOURCES;
  221. }
  222. wcscat(*fileName,uuidString);
  223. wcscat(*fileName,L".sis");
  224. RpcStringFreeW((unsigned short **)&uuidString);
  225. return STATUS_SUCCESS;
  226. }
  227. NTSTATUS
  228. CSidFromFilename(
  229. IN PWCHAR FileName,
  230. OUT PCSID CSid)
  231. {
  232. #define UUID_STRING_MAX_LENGTH 100// Should get this length from somewhere better...
  233. PWCHAR trailingSlash;
  234. PWCHAR dot;
  235. WCHAR uuid[UUID_STRING_MAX_LENGTH];
  236. DWORD uuidChars = 0;
  237. trailingSlash = wcsrchr(FileName, '\\');
  238. if (NULL == trailingSlash) {
  239. //
  240. // Assume that it's just the CS file without the directory name, etc.
  241. //
  242. trailingSlash = FileName - 1;
  243. }
  244. dot = wcsrchr(FileName, '.');
  245. if (NULL != dot) {
  246. uuidChars = (DWORD)(dot - (trailingSlash + 1));
  247. }
  248. if ((uuidChars <= 0) || (uuidChars >= UUID_STRING_MAX_LENGTH)) {
  249. //
  250. // Something's bogus about the filename. Give up.
  251. //
  252. return STATUS_OBJECT_NAME_INVALID;
  253. }
  254. memcpy(uuid,trailingSlash+1,uuidChars * sizeof(WCHAR));
  255. uuid[uuidChars] = 0;
  256. if (RPC_S_OK != UuidFromStringW((unsigned short *)uuid,CSid)) {
  257. return STATUS_OBJECT_NAME_INVALID;
  258. }
  259. return STATUS_SUCCESS;
  260. }
  261. NTSTATUS
  262. SisCreateBackupStructureI(
  263. IN PWCHAR volumeRoot,
  264. OUT PVOID *sisBackupStructure,
  265. OUT PWCHAR *commonStoreRootPathname,
  266. OUT PULONG countOfCommonStoreFilesToBackup,
  267. OUT PWCHAR **commonStoreFilesToBackup)
  268. {
  269. PSIB_BACKUP_VOLUME_STRUCTURE backupVolumeStructure;
  270. backupVolumeStructure = (PSIB_BACKUP_VOLUME_STRUCTURE)malloc(sizeof(SIB_BACKUP_VOLUME_STRUCTURE));
  271. if (NULL == backupVolumeStructure) {
  272. return STATUS_INSUFFICIENT_RESOURCES;
  273. }
  274. backupVolumeStructure->linkTree = new AVLTree<BackupFileEntry>;
  275. if (NULL == backupVolumeStructure->linkTree) {
  276. free(backupVolumeStructure);
  277. return STATUS_INSUFFICIENT_RESOURCES;
  278. }
  279. //
  280. // Allocate space for our private copy of the volume root name, being sure to leave space for
  281. // the terminating NULL.
  282. //
  283. backupVolumeStructure->volumeRoot = (PWCHAR)malloc((wcslen(volumeRoot) + 1) * sizeof(WCHAR));
  284. if (NULL == backupVolumeStructure->volumeRoot) {
  285. delete backupVolumeStructure->linkTree;
  286. free(backupVolumeStructure);
  287. return STATUS_INSUFFICIENT_RESOURCES;
  288. }
  289. wcscpy(backupVolumeStructure->volumeRoot, volumeRoot);
  290. //
  291. // Allocate space for the common store root pathname that we return, being sure
  292. // to leave room for the terminating NULL.
  293. //
  294. *commonStoreRootPathname = (PWCHAR) malloc(SIS_CSDIR_STRING_SIZE + (wcslen(volumeRoot) + 1) * sizeof(WCHAR));
  295. if (NULL == *commonStoreRootPathname) {
  296. free(backupVolumeStructure->volumeRoot);
  297. delete backupVolumeStructure->linkTree;
  298. free(backupVolumeStructure);
  299. return STATUS_INSUFFICIENT_RESOURCES;
  300. }
  301. wcscpy(*commonStoreRootPathname,volumeRoot);
  302. wcscat(*commonStoreRootPathname,SIS_CSDIR_STRING);
  303. InitializeCriticalSection(backupVolumeStructure->criticalSection);
  304. *countOfCommonStoreFilesToBackup = 0;
  305. *commonStoreFilesToBackup = NULL;
  306. *sisBackupStructure = backupVolumeStructure;
  307. return STATUS_SUCCESS;
  308. }
  309. NTSTATUS
  310. SisCSFilesToBackupForLinkI(
  311. IN PVOID sisBackupStructure,
  312. IN PVOID reparseData,
  313. IN ULONG reparseDataSize,
  314. IN PVOID thisFileContext OPTIONAL,
  315. OUT PVOID *matchingFileContext OPTIONAL,
  316. OUT PULONG countOfCommonStoreFilesToBackup,
  317. OUT PWCHAR **commonStoreFilesToBackup)
  318. {
  319. PREPARSE_DATA_BUFFER reparseDataBuffer = (PREPARSE_DATA_BUFFER)reparseData;
  320. PSI_REPARSE_BUFFER sisReparseBuffer = (PSI_REPARSE_BUFFER)reparseDataBuffer->GenericReparseBuffer.DataBuffer;
  321. BackupFileEntry entry[1];
  322. BackupFileEntry *foundEntry, *newEntry;
  323. PSIB_BACKUP_VOLUME_STRUCTURE backupVolumeStructure = (PSIB_BACKUP_VOLUME_STRUCTURE)sisBackupStructure;
  324. PVOID matchedContext = NULL;
  325. PWCHAR CSFileName[MAX_PATH];
  326. NTSTATUS status;
  327. EnterCriticalSection(backupVolumeStructure->criticalSection);
  328. if (reparseDataSize != SIS_REPARSE_DATA_SIZE) {
  329. //
  330. // It's the wrong size to contain a SIS reparse buffer, so we don't
  331. // want to add any CS files based on it.
  332. //
  333. status = STATUS_INVALID_PARAMETER;
  334. goto Error;
  335. }
  336. if (IO_REPARSE_TAG_SIS != reparseDataBuffer->ReparseTag ||
  337. sizeof(SI_REPARSE_BUFFER) != reparseDataBuffer->ReparseDataLength) {
  338. //
  339. // The size or tag is wrong. Ignore it.
  340. //
  341. status = STATUS_INVALID_PARAMETER;
  342. goto Error;
  343. }
  344. if ((SIS_REPARSE_BUFFER_FORMAT_VERSION != sisReparseBuffer->ReparsePointFormatVersion) &&
  345. (4 != sisReparseBuffer->ReparsePointFormatVersion)) {
  346. //
  347. // We don't understand this format SIS reparse point. This is probably an
  348. // old dll version.
  349. //
  350. status = STATUS_INVALID_PARAMETER;
  351. goto Error;
  352. }
  353. //
  354. // The only thing we really care about is the CSIndex of the file. See if we've
  355. // already backed up a file with a matching CSIndex by looking in the tree.
  356. //
  357. entry->CSid = sisReparseBuffer->CSid;
  358. foundEntry = backupVolumeStructure->linkTree->findFirstLessThanOrEqualTo(entry);
  359. if ((NULL != foundEntry) && (*foundEntry == entry)) {
  360. //
  361. // We already returned the CS file that backs this link. Return the caller's
  362. // context for that link.
  363. //
  364. matchedContext = foundEntry->callerContext;
  365. goto BackupNoCSFiles;
  366. }
  367. //
  368. // This is the first time we've seen this particular CS file, so back it up.
  369. //
  370. newEntry = new BackupFileEntry;
  371. if (NULL == newEntry) {
  372. LeaveCriticalSection(backupVolumeStructure->criticalSection);
  373. return STATUS_INSUFFICIENT_RESOURCES;
  374. }
  375. newEntry->callerContext = thisFileContext;
  376. newEntry->CSid = sisReparseBuffer->CSid;
  377. if (!backupVolumeStructure->linkTree->insert(newEntry)) {
  378. delete newEntry;
  379. LeaveCriticalSection(backupVolumeStructure->criticalSection);
  380. return STATUS_INSUFFICIENT_RESOURCES;
  381. }
  382. if (NULL != matchingFileContext) {
  383. *matchingFileContext = NULL;
  384. }
  385. *countOfCommonStoreFilesToBackup = 1;
  386. *commonStoreFilesToBackup = (PWCHAR *)malloc(sizeof(PWCHAR) * *countOfCommonStoreFilesToBackup);
  387. if (NULL == *commonStoreFilesToBackup) {
  388. backupVolumeStructure->linkTree->remove(newEntry);
  389. delete newEntry;
  390. *countOfCommonStoreFilesToBackup = 0;
  391. LeaveCriticalSection(backupVolumeStructure->criticalSection);
  392. return STATUS_INSUFFICIENT_RESOURCES;
  393. }
  394. status = FilenameFromCSid(
  395. &sisReparseBuffer->CSid,
  396. backupVolumeStructure->volumeRoot,
  397. &(*commonStoreFilesToBackup)[0]);
  398. LeaveCriticalSection(backupVolumeStructure->criticalSection);
  399. return STATUS_SUCCESS;
  400. BackupNoCSFiles:
  401. if (NULL != matchingFileContext) {
  402. *matchingFileContext = matchedContext;
  403. }
  404. *countOfCommonStoreFilesToBackup = 0;
  405. *commonStoreFilesToBackup = NULL;
  406. LeaveCriticalSection(backupVolumeStructure->criticalSection);
  407. return STATUS_SUCCESS;
  408. Error:
  409. if (NULL != matchingFileContext) {
  410. *matchingFileContext = matchedContext;
  411. }
  412. *countOfCommonStoreFilesToBackup = 0;
  413. *commonStoreFilesToBackup = NULL;
  414. LeaveCriticalSection(backupVolumeStructure->criticalSection);
  415. return status;
  416. }
  417. NTSTATUS
  418. SisFreeBackupStructureI(
  419. IN PVOID sisBackupStructure)
  420. {
  421. PSIB_BACKUP_VOLUME_STRUCTURE backupVolumeStructure = (PSIB_BACKUP_VOLUME_STRUCTURE)sisBackupStructure;
  422. BackupFileEntry *entry;
  423. while (!backupVolumeStructure->linkTree->empty()) {
  424. entry = backupVolumeStructure->linkTree->findMin();
  425. assert(NULL != entry);
  426. backupVolumeStructure->linkTree->remove(entry);
  427. delete entry;
  428. }
  429. free(backupVolumeStructure->volumeRoot);
  430. delete backupVolumeStructure->linkTree;
  431. DeleteCriticalSection(backupVolumeStructure->criticalSection);
  432. free(backupVolumeStructure);
  433. return STATUS_SUCCESS;
  434. }
  435. NTSTATUS
  436. SisCreateRestoreStructureI(
  437. IN PWCHAR volumeRoot,
  438. OUT PVOID *sisRestoreStructure,
  439. OUT PWCHAR *commonStoreRootPathname,
  440. OUT PULONG countOfCommonStoreFilesToRestore,
  441. OUT PWCHAR **commonStoreFilesToRestore)
  442. {
  443. PSIB_RESTORE_VOLUME_STRUCTURE restoreVolumeStructure;
  444. DWORD sectorsPerCluster, freeClusters, totalClusters;
  445. restoreVolumeStructure = (PSIB_RESTORE_VOLUME_STRUCTURE)malloc(sizeof(SIB_RESTORE_VOLUME_STRUCTURE));
  446. if (NULL == restoreVolumeStructure) {
  447. return STATUS_INSUFFICIENT_RESOURCES;
  448. }
  449. restoreVolumeStructure->linkTree = new AVLTree<RestoreFileEntry>;
  450. if (NULL == restoreVolumeStructure->linkTree) {
  451. free(restoreVolumeStructure);
  452. return STATUS_INSUFFICIENT_RESOURCES;
  453. }
  454. //
  455. // Allocate space for our private copy of the volume root name, being sure to leave space for
  456. // the terminating NULL.
  457. //
  458. restoreVolumeStructure->volumeRoot = (PWCHAR)malloc((wcslen(volumeRoot) + 1) * sizeof(WCHAR));
  459. if (NULL == restoreVolumeStructure->volumeRoot) {
  460. delete restoreVolumeStructure->linkTree;
  461. free(restoreVolumeStructure);
  462. return STATUS_INSUFFICIENT_RESOURCES;
  463. }
  464. wcscpy(restoreVolumeStructure->volumeRoot, volumeRoot);
  465. //
  466. // Allocate space for the common store root pathname that we return, being sure
  467. // to leave room for the terminating NULL.
  468. //
  469. *commonStoreRootPathname = (PWCHAR) malloc(SIS_CSDIR_STRING_SIZE + (wcslen(volumeRoot) + 1) * sizeof(WCHAR));
  470. if (NULL == *commonStoreRootPathname) {
  471. free(restoreVolumeStructure->volumeRoot);
  472. delete restoreVolumeStructure->linkTree;
  473. free(restoreVolumeStructure);
  474. return STATUS_INSUFFICIENT_RESOURCES;
  475. }
  476. wcscpy(*commonStoreRootPathname,volumeRoot);
  477. wcscat(*commonStoreRootPathname,SIS_CSDIR_STRING);
  478. InitializeCriticalSection(restoreVolumeStructure->criticalSection);
  479. *countOfCommonStoreFilesToRestore = 0;
  480. *commonStoreFilesToRestore = NULL;
  481. if (!GetDiskFreeSpaceW(
  482. volumeRoot,
  483. &sectorsPerCluster,
  484. &restoreVolumeStructure->VolumeSectorSize,
  485. &freeClusters,
  486. &totalClusters)) {
  487. //
  488. // The call failed. Just assume it's 512 bytes.
  489. //
  490. restoreVolumeStructure->VolumeSectorSize = 512;
  491. }
  492. restoreVolumeStructure->sector = (PSIS_BACKPOINTER)malloc(restoreVolumeStructure->VolumeSectorSize);
  493. if (NULL == restoreVolumeStructure->sector) {
  494. free(restoreVolumeStructure->volumeRoot);
  495. delete restoreVolumeStructure->linkTree;
  496. free(restoreVolumeStructure);
  497. free(*commonStoreRootPathname);
  498. *commonStoreRootPathname = NULL;
  499. return STATUS_INSUFFICIENT_RESOURCES;
  500. }
  501. restoreVolumeStructure->alignedSectorBuffer = (PVOID)malloc(restoreVolumeStructure->VolumeSectorSize * 2);
  502. if (NULL == restoreVolumeStructure->alignedSectorBuffer) {
  503. free(restoreVolumeStructure->sector);
  504. free(restoreVolumeStructure->volumeRoot);
  505. delete restoreVolumeStructure->linkTree;
  506. free(restoreVolumeStructure);
  507. free(*commonStoreRootPathname);
  508. *commonStoreRootPathname = NULL;
  509. return STATUS_INSUFFICIENT_RESOURCES;
  510. }
  511. restoreVolumeStructure->alignedSector = (PVOID)((
  512. ((UINT_PTR)restoreVolumeStructure->alignedSectorBuffer +
  513. restoreVolumeStructure->VolumeSectorSize) /
  514. restoreVolumeStructure->VolumeSectorSize) *
  515. restoreVolumeStructure->VolumeSectorSize);
  516. ASSERT(restoreVolumeStructure->alignedSector >= restoreVolumeStructure->alignedSectorBuffer);
  517. ASSERT((PCHAR)restoreVolumeStructure->alignedSectorBuffer + restoreVolumeStructure->VolumeSectorSize >= (PCHAR)restoreVolumeStructure->alignedSector);
  518. memset(restoreVolumeStructure->alignedSector,255,restoreVolumeStructure->VolumeSectorSize);
  519. *sisRestoreStructure = restoreVolumeStructure;
  520. return STATUS_SUCCESS;
  521. }
  522. NTSTATUS
  523. SisFixValidDataLengthI(
  524. PSIB_RESTORE_VOLUME_STRUCTURE restoreVolumeStructure,
  525. IN HANDLE restoredFileHandle)
  526. {
  527. #define BIGGER_THAN_AN_ALLOCATION_REGION (128 * 1024) // should get this from somewhere else
  528. //
  529. // Figure out if we need to extend ValidDataLength. We need to do this
  530. // if the final range of the file is unallocated.
  531. //
  532. FILE_STANDARD_INFORMATION standardInfo[1];
  533. FILE_END_OF_FILE_INFORMATION endOfFileInfo[1];
  534. FILE_ALLOCATED_RANGE_BUFFER inArb[1];
  535. const unsigned outArbSize = 10;
  536. FILE_ALLOCATED_RANGE_BUFFER outArb[outArbSize];
  537. NTSTATUS status;
  538. IO_STATUS_BLOCK Iosb[1];
  539. DWORD bytesReturned;
  540. LARGE_INTEGER rangeToZero;
  541. FILE_BASIC_INFORMATION basicInfo[1];
  542. BOOLEAN basicInfoValid = FALSE;
  543. DWORD nBytesWritten;
  544. unsigned i;
  545. FILE_ZERO_DATA_INFORMATION zeroInfo[1];
  546. LARGE_INTEGER WriteOffset;
  547. status = NtQueryInformationFile(
  548. restoredFileHandle,
  549. Iosb,
  550. standardInfo,
  551. sizeof(FILE_STANDARD_INFORMATION),
  552. FileStandardInformation);
  553. if (!NT_SUCCESS(status)) {
  554. #if DBG
  555. DbgPrint("SisFixValidDataLength: unable to query standard info on link file, 0x%x\n",status);
  556. #endif // DBG
  557. return status;
  558. }
  559. ASSERT(STATUS_PENDING != status);
  560. endOfFileInfo->EndOfFile = standardInfo->EndOfFile;
  561. if (standardInfo->EndOfFile.QuadPart > BIGGER_THAN_AN_ALLOCATION_REGION) {
  562. rangeToZero.QuadPart = inArb->FileOffset.QuadPart = standardInfo->EndOfFile.QuadPart - BIGGER_THAN_AN_ALLOCATION_REGION;
  563. rangeToZero.QuadPart -= rangeToZero.QuadPart % BIGGER_THAN_AN_ALLOCATION_REGION; // round it down.
  564. } else {
  565. rangeToZero.QuadPart = inArb->FileOffset.QuadPart = 0;
  566. }
  567. inArb->Length.QuadPart = MAXLONGLONG - inArb->FileOffset.QuadPart;
  568. if (!DeviceIoControl(
  569. restoredFileHandle,
  570. FSCTL_QUERY_ALLOCATED_RANGES,
  571. inArb,
  572. sizeof(FILE_ALLOCATED_RANGE_BUFFER),
  573. outArb,
  574. sizeof(FILE_ALLOCATED_RANGE_BUFFER) * outArbSize,
  575. &bytesReturned,
  576. NULL)) { // lap
  577. #if DBG
  578. DbgPrint("SisFixValidDataLength: unable to query allocated ranges on link file, %d\n",GetLastError());
  579. #endif // DBG
  580. return STATUS_UNSUCCESSFUL;
  581. }
  582. ASSERT(bytesReturned / sizeof(FILE_ALLOCATED_RANGE_BUFFER) < outArbSize); // this relies on knowledge about the minimum allocated range size
  583. ASSERT(bytesReturned % sizeof(FILE_ALLOCATED_RANGE_BUFFER) == 0);
  584. if (bytesReturned > 0) {
  585. unsigned lastElement = bytesReturned/sizeof(FILE_ALLOCATED_RANGE_BUFFER) - 1;
  586. ASSERT(lastElement < outArbSize);
  587. rangeToZero.QuadPart = outArb[lastElement].FileOffset.QuadPart + outArb[lastElement].Length.QuadPart;
  588. }
  589. status = NtQueryInformationFile(
  590. restoredFileHandle,
  591. Iosb,
  592. basicInfo,
  593. sizeof(FILE_BASIC_INFORMATION),
  594. FileBasicInformation);
  595. if (NT_SUCCESS(status)) {
  596. ASSERT(STATUS_PENDING != status); // because we didn't open the file for overlapped.
  597. basicInfoValid = TRUE;
  598. } else {
  599. #if DBG
  600. DbgPrint("SisFixValidDataLength: unable to query basic info on link file, 0x%x\n",status);
  601. #endif // DBG
  602. }
  603. WriteOffset.QuadPart = ((standardInfo->EndOfFile.QuadPart +
  604. restoreVolumeStructure->VolumeSectorSize +
  605. BIGGER_THAN_AN_ALLOCATION_REGION) / restoreVolumeStructure->VolumeSectorSize) *
  606. restoreVolumeStructure->VolumeSectorSize;
  607. ASSERT(WriteOffset.QuadPart >= standardInfo->EndOfFile.QuadPart);
  608. ASSERT(standardInfo->EndOfFile.QuadPart + restoreVolumeStructure->VolumeSectorSize < WriteOffset.QuadPart);
  609. if ((WriteOffset.LowPart != SetFilePointer(
  610. restoredFileHandle,
  611. WriteOffset.LowPart,
  612. &WriteOffset.HighPart,
  613. FILE_BEGIN))
  614. || (NO_ERROR != GetLastError())) {
  615. #if DBG
  616. DbgPrint("SisFixValidDataLength: unable to SetFilePointer, %d\n",GetLastError());
  617. #endif // DBG
  618. return STATUS_UNSUCCESSFUL;
  619. }
  620. if (!WriteFile(restoredFileHandle,
  621. restoreVolumeStructure->alignedSectorBuffer,
  622. restoreVolumeStructure->VolumeSectorSize, // bytes to write
  623. &nBytesWritten,
  624. NULL)) { // overlapped
  625. #if DBG
  626. DbgPrint("SisFixValidDataLength: unable to append a byte to advance ValidDataLength, %d\n",GetLastError());
  627. #endif // DBG
  628. }
  629. //
  630. // Truncate the file, erasing the sector we just wrote.
  631. //
  632. status = NtSetInformationFile(
  633. restoredFileHandle,
  634. Iosb,
  635. endOfFileInfo,
  636. sizeof(FILE_END_OF_FILE_INFORMATION),
  637. FileEndOfFileInformation);
  638. if (rangeToZero.QuadPart < standardInfo->EndOfFile.QuadPart) {
  639. //
  640. // Re-zero the end of the file in order to deallocate it.
  641. //
  642. zeroInfo->FileOffset = rangeToZero;
  643. zeroInfo->BeyondFinalZero.QuadPart = MAXLONGLONG;
  644. if (!DeviceIoControl(
  645. restoredFileHandle,
  646. FSCTL_SET_ZERO_DATA,
  647. zeroInfo,
  648. sizeof(FILE_ZERO_DATA_INFORMATION),
  649. NULL, // output buffer
  650. 0, // o.b. size
  651. &bytesReturned,
  652. NULL)) { // overlapped
  653. #if DBG
  654. DbgPrint("SisFixValidDataLength: unable to zero trailing portion of file, %d\n",GetLastError());
  655. #endif // DBG
  656. }
  657. }
  658. #if DBG
  659. if (!NT_SUCCESS(status)) {
  660. DbgPrint("SisFixValidDataLength: unable to truncate file after extending it to advance ValidDataLength, 0x%x\n",status);
  661. }
  662. #endif // DBG
  663. //
  664. // Reset the dates on the file.
  665. //
  666. status = NtSetInformationFile(
  667. restoredFileHandle,
  668. Iosb,
  669. basicInfo,
  670. sizeof(FILE_BASIC_INFORMATION),
  671. FileBasicInformation);
  672. #if DBG
  673. if (!NT_SUCCESS(status)) {
  674. DbgPrint("SisFixValidDataLength: unable to reset times after extending file to advance ValidDataLength, 0x%x\n",status);
  675. }
  676. #endif // DBG
  677. return status;
  678. }
  679. NTSTATUS
  680. SisRestoredLinkI(
  681. IN PVOID sisRestoreStructure,
  682. IN PWCHAR restoredFileName,
  683. IN PVOID reparseData,
  684. IN ULONG reparseDataSize,
  685. OUT PULONG countOfCommonStoreFilesToRestore,
  686. OUT PWCHAR **commonStoreFilesToRestore)
  687. {
  688. PSIB_RESTORE_VOLUME_STRUCTURE restoreVolumeStructure = (PSIB_RESTORE_VOLUME_STRUCTURE)sisRestoreStructure;
  689. PREPARSE_DATA_BUFFER reparseDataBuffer = (PREPARSE_DATA_BUFFER)reparseData;
  690. PSI_REPARSE_BUFFER sisReparseBuffer = (PSI_REPARSE_BUFFER)reparseDataBuffer->GenericReparseBuffer.DataBuffer;
  691. RestoreFileEntry entry[1];
  692. RestoreFileEntry *foundEntry, *newEntry;
  693. PWCHAR CSFileName = NULL;
  694. BOOLEAN foundCSFile;
  695. HANDLE fileHandle;
  696. BOOLEAN openFile = TRUE;
  697. NTSTATUS status;
  698. DWORD bytesReturned;
  699. DWORD fileAttributes;
  700. BOOLEAN readonlyAttributeCleared = FALSE;
  701. EnterCriticalSection(restoreVolumeStructure->criticalSection);
  702. if (NonSISEnabledVolume(restoreVolumeStructure)) {
  703. //
  704. // This isn't a SIS enabled volume, so tell the user that.
  705. // There's no NT status code corresponding to ERROR_VOLUME_NOT_SIS_ENABLED,
  706. // so we set the win32 code and return STATUS_UNSUCCESSFUL, which makes
  707. // the wrapper function not change the win32 error.
  708. //
  709. SetLastError(ERROR_VOLUME_NOT_SIS_ENABLED);
  710. status = STATUS_UNSUCCESSFUL;
  711. goto Error;
  712. }
  713. //
  714. // Do consistency checks on the reparse point to see if we can understand it.
  715. //
  716. if (reparseDataSize != SIS_REPARSE_DATA_SIZE) {
  717. //
  718. // It's the wrong size to contain a SIS reparse buffer, so we don't
  719. // want to restore any CS files based on it.
  720. //
  721. status = STATUS_INVALID_PARAMETER;
  722. goto Error;
  723. }
  724. if (IO_REPARSE_TAG_SIS != reparseDataBuffer->ReparseTag ||
  725. sizeof(SI_REPARSE_BUFFER) != reparseDataBuffer->ReparseDataLength) {
  726. //
  727. // The size or tag is wrong. Ignore it.
  728. //
  729. status = STATUS_INVALID_PARAMETER;
  730. goto Error;
  731. }
  732. if ((SIS_REPARSE_BUFFER_FORMAT_VERSION != sisReparseBuffer->ReparsePointFormatVersion) &&
  733. (4 != sisReparseBuffer->ReparsePointFormatVersion)) {
  734. //
  735. // We don't understand this format SIS reparse point. This is probably an
  736. // old dll version.
  737. //
  738. status = STATUS_INVALID_PARAMETER;
  739. goto Error;
  740. }
  741. //
  742. // The only thing we really care about is the CSid and checksum of the file. See if we've
  743. // already returned a file with a matching CSid by looking in the tree.
  744. //
  745. entry->CSid = sisReparseBuffer->CSid;
  746. foundEntry = restoreVolumeStructure->linkTree->findFirstLessThanOrEqualTo(entry);
  747. if ((NULL != foundEntry) && (*foundEntry == entry)) {
  748. //
  749. // We already returned the CS file that backs this link. Enter the name of this file
  750. // on the linked list for this CS file.
  751. //
  752. PendingRestoredFile *restoredFile = new PendingRestoredFile;
  753. if (NULL == restoredFile) {
  754. LeaveCriticalSection(restoreVolumeStructure->criticalSection);
  755. #if DBG
  756. DbgPrint("couldn't allocate restored file\n");
  757. #endif // DBG
  758. return STATUS_INSUFFICIENT_RESOURCES;
  759. }
  760. restoredFile->fileName = (PWCHAR) malloc((wcslen(restoredFileName) + 1) * sizeof(WCHAR) );
  761. if (NULL == restoredFile->fileName) {
  762. delete restoredFile;
  763. #if DBG
  764. DbgPrint("couldn't allocate restored file filename\n");
  765. #endif // DBG
  766. LeaveCriticalSection(restoreVolumeStructure->criticalSection);
  767. return STATUS_INSUFFICIENT_RESOURCES;
  768. }
  769. wcscpy(restoredFile->fileName,restoredFileName);
  770. restoredFile->CSFileChecksum = sisReparseBuffer->CSChecksum;
  771. restoredFile->next = foundEntry->files;
  772. foundEntry->files = restoredFile;
  773. goto RestoreNoCSFiles;
  774. }
  775. //
  776. // This is the first time we've seen this particular CS file. See if it still
  777. // exists in the \SIS Common Store directory.
  778. //
  779. status = FilenameFromCSid(&sisReparseBuffer->CSid,restoreVolumeStructure->volumeRoot,&CSFileName);
  780. if (!NT_SUCCESS(status)) {
  781. if (NULL != CSFileName) {
  782. free(CSFileName);
  783. }
  784. LeaveCriticalSection(restoreVolumeStructure->criticalSection);
  785. return status;
  786. }
  787. fileHandle = CreateFileW(
  788. CSFileName,
  789. GENERIC_READ | GENERIC_WRITE,
  790. FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
  791. NULL,
  792. OPEN_EXISTING,
  793. FILE_ATTRIBUTE_NORMAL,
  794. NULL);
  795. if (INVALID_HANDLE_VALUE == fileHandle) {
  796. if (GetLastError() == ERROR_SHARING_VIOLATION) {
  797. //
  798. // The file exists, we just couldn't open it.
  799. //
  800. foundCSFile = TRUE;
  801. } else {
  802. foundCSFile = FALSE;
  803. }
  804. } else {
  805. foundCSFile = TRUE;
  806. CloseHandle(fileHandle);
  807. }
  808. if (foundCSFile) {
  809. //
  810. // We don't add it to the tree here, even though that might speed up things somewhat.
  811. // The reason is that someone could come along and delete all of the references to the
  812. // file (including the one that we just created) and then the backing file would go away.
  813. // If we'd entered it in the tree, and we try to restore a subsequent link to the file,
  814. // we'd not notice that the backing file was gone and would restore a dangling link.
  815. //
  816. openFile = FALSE; // There's no need to open this file, since it's a good link.
  817. HANDLE restoredFileHandle = CreateFileW(
  818. restoredFileName,
  819. GENERIC_READ | GENERIC_WRITE,
  820. FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
  821. NULL,
  822. OPEN_EXISTING,
  823. FILE_FLAG_BACKUP_SEMANTICS|FILE_FLAG_NO_BUFFERING|FILE_OPEN_REPARSE_POINT,
  824. NULL);
  825. if (INVALID_HANDLE_VALUE == restoredFileHandle) {
  826. fileAttributes = GetFileAttributesW(restoredFileName);
  827. if (fileAttributes & FILE_ATTRIBUTE_READONLY) {
  828. DWORD newFileAttributes = fileAttributes & ~FILE_ATTRIBUTE_READONLY;
  829. if (0 == newFileAttributes) {
  830. newFileAttributes = FILE_ATTRIBUTE_NORMAL;
  831. }
  832. if (!SetFileAttributesW(restoredFileName,newFileAttributes)) {
  833. #if DBG
  834. DbgPrint("sisbkup: SisRestoredLinkI: unable to reset read only attribute on link, %d\n",GetLastError());
  835. #endif DBG
  836. } else {
  837. readonlyAttributeCleared = TRUE;
  838. }
  839. //
  840. // Now that we've (tried to) cleared the read only attribute, re-try the file open.
  841. //
  842. restoredFileHandle = CreateFileW(
  843. restoredFileName,
  844. GENERIC_READ | GENERIC_WRITE,
  845. FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
  846. NULL,
  847. OPEN_EXISTING,
  848. FILE_FLAG_BACKUP_SEMANTICS|FILE_FLAG_NO_BUFFERING|FILE_OPEN_REPARSE_POINT,
  849. NULL);
  850. }
  851. }
  852. if (INVALID_HANDLE_VALUE != restoredFileHandle) {
  853. } else {
  854. #if DBG
  855. DbgPrint("SisRestoredLinkI: Unable to open link file in order to fix ValidDataLength, %d\n",::GetLastError());
  856. #endif // DBG
  857. status = STATUS_UNSUCCESSFUL; // This will leave the win32 error code undisturbed
  858. goto Error;
  859. }
  860. CHAR reparseBuffer[SIS_REPARSE_DATA_SIZE];
  861. if (!DeviceIoControl(
  862. restoredFileHandle,
  863. FSCTL_GET_REPARSE_POINT,
  864. 0,
  865. NULL,
  866. reparseBuffer,
  867. SIS_REPARSE_DATA_SIZE,
  868. &bytesReturned,
  869. NULL)) {
  870. #if DBG
  871. DbgPrint("SisRestoredLinkI: Unable to get reparse point, %d\n",::GetLastError());
  872. #endif // DBG
  873. status = STATUS_UNSUCCESSFUL; // This will leave the win32 error code undisturbed
  874. goto Error;
  875. }
  876. status = SisFixValidDataLengthI(restoreVolumeStructure,restoredFileHandle);
  877. if (!NT_SUCCESS(status)) {
  878. #if DBG
  879. DbgPrint("SisRestoredLink: unable to fix up valid data length, 0x%x, %d\n",status,::GetLastError());
  880. #endif // DBG
  881. CloseHandle(restoredFileHandle);
  882. goto Error;
  883. }
  884. //
  885. // Reset the reparse point, which has been destroyed by the last operation.
  886. //
  887. if (!DeviceIoControl(
  888. restoredFileHandle,
  889. FSCTL_SET_REPARSE_POINT,
  890. reparseData,
  891. reparseDataSize,
  892. NULL,
  893. 0,
  894. &bytesReturned,
  895. NULL)) {
  896. #if DBG
  897. DbgPrint("SisRestoredLink: unable to reset reparse point, %d\n",::GetLastError());
  898. #endif // DBG
  899. CloseHandle(restoredFileHandle);
  900. status = STATUS_UNSUCCESSFUL; // This will leave the win32 error code undisturbed
  901. goto Error;
  902. }
  903. CloseHandle(restoredFileHandle);
  904. if (readonlyAttributeCleared) {
  905. SetFileAttributesW(restoredFileName,fileAttributes);
  906. readonlyAttributeCleared = FALSE;
  907. }
  908. goto RestoreNoCSFiles;
  909. }
  910. //
  911. // It's not already in the common store directory. Enter it in the tree and return it to
  912. // the user.
  913. //
  914. newEntry = new RestoreFileEntry;
  915. if (NULL == newEntry) {
  916. LeaveCriticalSection(restoreVolumeStructure->criticalSection);
  917. return STATUS_INSUFFICIENT_RESOURCES;
  918. }
  919. newEntry->CSid = sisReparseBuffer->CSid;
  920. newEntry->files = new PendingRestoredFile;
  921. if (NULL == newEntry->files) {
  922. LeaveCriticalSection(restoreVolumeStructure->criticalSection);
  923. delete newEntry;
  924. return STATUS_INSUFFICIENT_RESOURCES;
  925. }
  926. newEntry->files->next = NULL;
  927. newEntry->files->fileName = (PWCHAR) malloc((wcslen(restoredFileName) + 1) * sizeof(WCHAR));
  928. newEntry->files->CSFileChecksum = sisReparseBuffer->CSChecksum;
  929. if (NULL == newEntry->files->fileName) {
  930. LeaveCriticalSection(restoreVolumeStructure->criticalSection);
  931. delete newEntry->files;
  932. delete newEntry;
  933. return STATUS_INSUFFICIENT_RESOURCES;
  934. }
  935. wcscpy(newEntry->files->fileName,restoredFileName);
  936. if (!restoreVolumeStructure->linkTree->insert(newEntry)) {
  937. *countOfCommonStoreFilesToRestore = 0;
  938. LeaveCriticalSection(restoreVolumeStructure->criticalSection);
  939. delete newEntry->files;
  940. delete newEntry;
  941. return STATUS_INSUFFICIENT_RESOURCES;
  942. }
  943. *countOfCommonStoreFilesToRestore = 1;
  944. *commonStoreFilesToRestore = (PWCHAR *)malloc(sizeof(PWCHAR) * *countOfCommonStoreFilesToRestore);
  945. if (NULL == *commonStoreFilesToRestore) {
  946. restoreVolumeStructure->linkTree->remove(newEntry);
  947. *countOfCommonStoreFilesToRestore = 0;
  948. LeaveCriticalSection(restoreVolumeStructure->criticalSection);
  949. delete newEntry->files;
  950. delete newEntry;
  951. return STATUS_INSUFFICIENT_RESOURCES;
  952. }
  953. status = FilenameFromCSid(
  954. &sisReparseBuffer->CSid,
  955. restoreVolumeStructure->volumeRoot,
  956. &(*commonStoreFilesToRestore)[0]);
  957. if (!NT_SUCCESS(status)) {
  958. restoreVolumeStructure->linkTree->remove(newEntry);
  959. *countOfCommonStoreFilesToRestore = 0;
  960. LeaveCriticalSection(restoreVolumeStructure->criticalSection);
  961. free(*commonStoreFilesToRestore);
  962. delete newEntry->files;
  963. delete newEntry;
  964. return status;
  965. }
  966. if (openFile) {
  967. TryOpeningFile(restoredFileName);
  968. }
  969. LeaveCriticalSection(restoreVolumeStructure->criticalSection);
  970. return STATUS_SUCCESS;
  971. RestoreNoCSFiles:
  972. *countOfCommonStoreFilesToRestore = 0;
  973. *commonStoreFilesToRestore = NULL;
  974. if (openFile) {
  975. TryOpeningFile(restoredFileName);
  976. }
  977. LeaveCriticalSection(restoreVolumeStructure->criticalSection);
  978. return STATUS_SUCCESS;
  979. Error:
  980. *countOfCommonStoreFilesToRestore = 0;
  981. *commonStoreFilesToRestore = NULL;
  982. if (readonlyAttributeCleared) {
  983. SetFileAttributesW(restoredFileName,fileAttributes);
  984. }
  985. if (openFile) {
  986. TryOpeningFile(restoredFileName);
  987. }
  988. LeaveCriticalSection(restoreVolumeStructure->criticalSection);
  989. return status;
  990. }
  991. NTSTATUS
  992. SisRestoredCommonStoreFileI(
  993. IN PVOID sisRestoreStructure,
  994. IN PWCHAR commonStoreFileName)
  995. {
  996. PSIB_RESTORE_VOLUME_STRUCTURE restoreVolumeStructure = (PSIB_RESTORE_VOLUME_STRUCTURE)sisRestoreStructure;
  997. HANDLE fileHandle = INVALID_HANDLE_VALUE;
  998. NTSTATUS status;
  999. DWORD bytesRead, bytesWritten;
  1000. LONGLONG checksum;
  1001. CSID CSid;
  1002. RestoreFileEntry entry[1];
  1003. RestoreFileEntry *foundEntry, *newEntry;
  1004. PWCHAR BPStreamName = NULL;
  1005. status = CSidFromFilename(commonStoreFileName,&CSid);
  1006. if (!NT_SUCCESS(status)) {
  1007. //
  1008. // It was a bogus filename. Punt.
  1009. //
  1010. return status;
  1011. }
  1012. BPStreamName = (PWCHAR) malloc((wcslen(commonStoreFileName) + 1) * sizeof(WCHAR) + BACKPOINTER_STREAM_NAME_SIZE);
  1013. if (NULL == BPStreamName) {
  1014. return STATUS_INSUFFICIENT_RESOURCES;
  1015. }
  1016. wcscpy(BPStreamName, commonStoreFileName);
  1017. wcscat(BPStreamName, BACKPOINTER_STREAM_NAME);
  1018. //
  1019. // We just need to reinitialize the backpointer stream for this file so that it looks like
  1020. // it has no references.
  1021. //
  1022. EnterCriticalSection(restoreVolumeStructure->criticalSection);
  1023. if (NonSISEnabledVolume(restoreVolumeStructure)) {
  1024. //
  1025. // This isn't a SIS enabled volume, so tell the user that.
  1026. // There's no NT status code corresponding to ERROR_VOLUME_NOT_SIS_ENABLED,
  1027. // so we set the win32 code and return STATUS_UNSUCCESSFUL, which makes
  1028. // the wrapper function not change the win32 error.
  1029. //
  1030. SetLastError(ERROR_VOLUME_NOT_SIS_ENABLED);
  1031. status = STATUS_UNSUCCESSFUL;
  1032. goto Error;
  1033. }
  1034. //
  1035. // Now open the file.
  1036. //
  1037. fileHandle = CreateFileW(
  1038. BPStreamName,
  1039. GENERIC_READ | GENERIC_WRITE,
  1040. 0, // exclusive
  1041. NULL,
  1042. OPEN_EXISTING,
  1043. FILE_ATTRIBUTE_NORMAL | FILE_FLAG_BACKUP_SEMANTICS,
  1044. NULL);
  1045. free(BPStreamName);
  1046. BPStreamName = NULL;
  1047. if (INVALID_HANDLE_VALUE == fileHandle) {
  1048. status = STATUS_UNSUCCESSFUL; // This will cause the C wrapper to not call SetLastError
  1049. #if DBG
  1050. DbgPrint("SisRestoredCommonStoreFile: unable to open common store file, %d\n",GetLastError());
  1051. #endif // DBG
  1052. goto Error;
  1053. }
  1054. //
  1055. // Read in the first sector.
  1056. //
  1057. if (!ReadFile(
  1058. fileHandle,
  1059. restoreVolumeStructure->sector,
  1060. restoreVolumeStructure->VolumeSectorSize,
  1061. &bytesRead,
  1062. NULL)) {
  1063. status = STATUS_UNSUCCESSFUL; // This will cause the C wrapper to not call SetLastError
  1064. #if DBG
  1065. DbgPrint("SisRestoredCommonStoreFile: Unable to read in first BP sector, %d\n",GetLastError());
  1066. #endif // DBG
  1067. goto Error;
  1068. }
  1069. if (bytesRead < sizeof(SIS_BACKPOINTER_STREAM_HEADER)) {
  1070. status = STATUS_UNSUCCESSFUL; // This will cause the C wrapper to not call SetLastError
  1071. goto Error;
  1072. }
  1073. #define Header ((PSIS_BACKPOINTER_STREAM_HEADER)restoreVolumeStructure->sector)
  1074. if ((BACKPOINTER_STREAM_FORMAT_VERSION != Header->FormatVersion) ||
  1075. (BACKPOINTER_MAGIC != Header->Magic)) {
  1076. #undef Header
  1077. #if DBG
  1078. DbgPrint("SisRectoredCommonStoreFile: restored CS file has bogus header format version/Magic\n");
  1079. #endif // DBG
  1080. } else {
  1081. //
  1082. // Fill in the backpointer portion of the sector with
  1083. // null entries.
  1084. //
  1085. for (unsigned i = SIS_BACKPOINTER_RESERVED_ENTRIES;
  1086. i < (restoreVolumeStructure->VolumeSectorSize / sizeof(SIS_BACKPOINTER));
  1087. i++) {
  1088. restoreVolumeStructure->sector[i].LinkFileIndex.QuadPart = MAXLONGLONG;
  1089. restoreVolumeStructure->sector[i].LinkFileNtfsId.QuadPart = MAXLONGLONG;
  1090. }
  1091. //
  1092. // Write out the new sector.
  1093. //
  1094. SetFilePointer(fileHandle,0,NULL,FILE_BEGIN);
  1095. if (!WriteFile(
  1096. fileHandle,
  1097. restoreVolumeStructure->sector,
  1098. restoreVolumeStructure->VolumeSectorSize,
  1099. &bytesWritten,
  1100. NULL)) {
  1101. #if DBG
  1102. DbgPrint("SisRestoredCommonStoreFile: write failed %d\n",GetLastError());
  1103. #endif // DBG
  1104. }
  1105. }
  1106. //
  1107. // Make the stream be exactly one sector long.
  1108. //
  1109. SetFilePointer(fileHandle,restoreVolumeStructure->VolumeSectorSize,NULL,FILE_BEGIN);
  1110. SetEndOfFile(fileHandle);
  1111. CloseHandle(fileHandle);
  1112. fileHandle = INVALID_HANDLE_VALUE;
  1113. //
  1114. // Look up in the tree and find the files that we restored to this link.
  1115. // Open them and rewrite their reparse points.
  1116. //
  1117. entry->CSid = CSid;
  1118. foundEntry = restoreVolumeStructure->linkTree->findFirstLessThanOrEqualTo(entry);
  1119. if ((NULL != foundEntry) && (*foundEntry == entry)) {
  1120. //
  1121. // We've got a match. Cruise the list and set the reparse points on all of the
  1122. // files.
  1123. //
  1124. while (NULL != foundEntry->files) {
  1125. HANDLE restoredFileHandle;
  1126. PendingRestoredFile *thisFile = foundEntry->files;
  1127. DWORD bytesReturned;
  1128. DWORD fileAttributes;
  1129. BOOLEAN readOnlyAttributeCleared = FALSE;
  1130. restoredFileHandle = CreateFileW(
  1131. thisFile->fileName,
  1132. GENERIC_READ | GENERIC_WRITE,
  1133. 0, // exclusive
  1134. NULL,
  1135. OPEN_EXISTING,
  1136. FILE_FLAG_BACKUP_SEMANTICS|FILE_FLAG_NO_BUFFERING,
  1137. NULL);
  1138. if (INVALID_HANDLE_VALUE == restoredFileHandle) {
  1139. //
  1140. // Check the read only file attribute, and reset it if necessary.
  1141. //
  1142. fileAttributes = GetFileAttributesW(thisFile->fileName);
  1143. if (fileAttributes & FILE_ATTRIBUTE_READONLY) {
  1144. DWORD newFileAttributes = fileAttributes & ~FILE_ATTRIBUTE_READONLY;
  1145. if (0 == newFileAttributes) {
  1146. newFileAttributes = FILE_ATTRIBUTE_NORMAL;
  1147. }
  1148. if (!SetFileAttributesW(thisFile->fileName,newFileAttributes)) {
  1149. #if DBG
  1150. DbgPrint("sisbkup: unable to clear read only attribute on file %ws\n",thisFile->fileName);
  1151. #endif // DBG
  1152. }
  1153. readOnlyAttributeCleared = TRUE;
  1154. restoredFileHandle = CreateFileW(
  1155. thisFile->fileName,
  1156. GENERIC_READ | GENERIC_WRITE,
  1157. 0, // exclusive
  1158. NULL,
  1159. OPEN_EXISTING,
  1160. FILE_FLAG_BACKUP_SEMANTICS|FILE_FLAG_NO_BUFFERING,
  1161. NULL);
  1162. }
  1163. }
  1164. if (INVALID_HANDLE_VALUE != restoredFileHandle) {
  1165. SisFixValidDataLengthI(restoreVolumeStructure, restoredFileHandle);
  1166. //
  1167. // Rewrite the reparse point.
  1168. //
  1169. CHAR reparseBuffer[SIS_REPARSE_DATA_SIZE];
  1170. PSI_REPARSE_BUFFER sisReparseBuffer;
  1171. #define reparseData ((PREPARSE_DATA_BUFFER)reparseBuffer)
  1172. reparseData->ReparseTag = IO_REPARSE_TAG_SIS;
  1173. reparseData->Reserved = 0xb010; // ??
  1174. reparseData->ReparseDataLength = sizeof(SI_REPARSE_BUFFER);
  1175. sisReparseBuffer = (PSI_REPARSE_BUFFER)reparseData->GenericReparseBuffer.DataBuffer;
  1176. sisReparseBuffer->ReparsePointFormatVersion = SIS_REPARSE_BUFFER_FORMAT_VERSION;
  1177. sisReparseBuffer->Reserved = 0xb111b010;
  1178. sisReparseBuffer->CSid = CSid;
  1179. sisReparseBuffer->LinkIndex.QuadPart = 0; // This just gets reset by the filter driver
  1180. sisReparseBuffer->LinkFileNtfsId.QuadPart = 0; // This just gets reset by the filter driver
  1181. sisReparseBuffer->CSFileNtfsId.QuadPart = 0; // This just gets reset by the filter driver
  1182. //
  1183. // Use the CS file checksum that was read from the reparse point on the backup
  1184. // tape. We need this for security reasons, because otherwise a bogus backed up
  1185. // link could suddenly become valid.
  1186. //
  1187. sisReparseBuffer->CSChecksum = thisFile->CSFileChecksum;
  1188. //
  1189. // Compute the checksum.
  1190. //
  1191. sisReparseBuffer->Checksum.QuadPart = 0;
  1192. SipComputeChecksum(
  1193. sisReparseBuffer,
  1194. sizeof(SI_REPARSE_BUFFER) - sizeof sisReparseBuffer->Checksum,
  1195. &sisReparseBuffer->Checksum.QuadPart);
  1196. //
  1197. // Set the reparse point.
  1198. //
  1199. if (!DeviceIoControl(
  1200. restoredFileHandle,
  1201. FSCTL_SET_REPARSE_POINT,
  1202. reparseBuffer,
  1203. FIELD_OFFSET(REPARSE_DATA_BUFFER, GenericReparseBuffer.DataBuffer) +
  1204. reparseData->ReparseDataLength,
  1205. NULL,
  1206. 0,
  1207. &bytesReturned,
  1208. NULL)) {
  1209. #if DBG
  1210. DbgPrint("sisbackup: SisRestoredCommonStoreFile: set reparse point failed %d\n",GetLastError());
  1211. #endif // DBG
  1212. }
  1213. CloseHandle(restoredFileHandle);
  1214. #undef reparseData
  1215. } else {
  1216. #if DBG
  1217. DbgPrint("sisbackup: unable to open link file for file %ws, %d\n",thisFile->fileName,GetLastError());
  1218. #endif // DBG
  1219. }
  1220. if (readOnlyAttributeCleared) {
  1221. if (!SetFileAttributesW(thisFile->fileName,fileAttributes)) {
  1222. #if DBG
  1223. DbgPrint("sisbackup: unable to reset read only attribute on %ws\n",thisFile->fileName);
  1224. #endif // DBG
  1225. }
  1226. }
  1227. foundEntry->files = thisFile->next;
  1228. free(thisFile->fileName);
  1229. delete thisFile;
  1230. }
  1231. restoreVolumeStructure->linkTree->remove(foundEntry);
  1232. delete foundEntry;
  1233. } else {
  1234. #if DBG
  1235. DbgPrint("restored common store file: didn't find tree match\n");
  1236. #endif // DBG
  1237. }
  1238. LeaveCriticalSection(restoreVolumeStructure->criticalSection);
  1239. return STATUS_SUCCESS;
  1240. Error:
  1241. if (INVALID_HANDLE_VALUE != fileHandle) {
  1242. CloseHandle(fileHandle);
  1243. }
  1244. LeaveCriticalSection(restoreVolumeStructure->criticalSection);
  1245. return status;
  1246. }
  1247. NTSTATUS
  1248. SisFreeRestoreStructureI(
  1249. IN PVOID sisRestoreStructure)
  1250. {
  1251. PSIB_RESTORE_VOLUME_STRUCTURE restoreVolumeStructure = (PSIB_RESTORE_VOLUME_STRUCTURE)sisRestoreStructure;
  1252. RestoreFileEntry *entry;
  1253. //
  1254. // Cruise the link tree and clean up any remaining file entries.
  1255. //
  1256. while (NULL != (entry = restoreVolumeStructure->linkTree->findMin())) {
  1257. while (NULL != entry->files) {
  1258. PendingRestoredFile *thisFile = entry->files;
  1259. entry->files = thisFile->next;
  1260. free(thisFile->fileName);
  1261. delete thisFile;
  1262. }
  1263. restoreVolumeStructure->linkTree->remove(entry);
  1264. }
  1265. DeleteCriticalSection(restoreVolumeStructure->criticalSection);
  1266. free(restoreVolumeStructure->sector);
  1267. free(restoreVolumeStructure->alignedSectorBuffer);
  1268. free(restoreVolumeStructure->volumeRoot);
  1269. delete restoreVolumeStructure->linkTree;
  1270. free(restoreVolumeStructure);
  1271. return STATUS_SUCCESS;
  1272. }
  1273. extern "C" {
  1274. BOOL __stdcall
  1275. SisCreateBackupStructure(
  1276. IN PWCHAR volumeRoot,
  1277. OUT PVOID *sisBackupStructure,
  1278. OUT PWCHAR *commonStoreRootPathname,
  1279. OUT PULONG countOfCommonStoreFilesToBackup,
  1280. OUT PWCHAR **commonStoreFilesToBackup)
  1281. {
  1282. NTSTATUS status;
  1283. status = SisCreateBackupStructureI(
  1284. volumeRoot,
  1285. sisBackupStructure,
  1286. commonStoreRootPathname,
  1287. countOfCommonStoreFilesToBackup,
  1288. commonStoreFilesToBackup);
  1289. if (STATUS_UNSUCCESSFUL != status) {
  1290. SetLastError(RtlNtStatusToDosError(status));
  1291. }
  1292. return NT_SUCCESS(status);
  1293. }
  1294. BOOL __stdcall
  1295. SisCSFilesToBackupForLink(
  1296. IN PVOID sisBackupStructure,
  1297. IN PVOID reparseData,
  1298. IN ULONG reparseDataSize,
  1299. IN PVOID thisFileContext OPTIONAL,
  1300. OUT PVOID *matchingFileContext OPTIONAL,
  1301. OUT PULONG countOfCommonStoreFilesToBackup,
  1302. OUT PWCHAR **commonStoreFilesToBackup)
  1303. {
  1304. NTSTATUS status;
  1305. status = SisCSFilesToBackupForLinkI(
  1306. sisBackupStructure,
  1307. reparseData,
  1308. reparseDataSize,
  1309. thisFileContext,
  1310. matchingFileContext,
  1311. countOfCommonStoreFilesToBackup,
  1312. commonStoreFilesToBackup);
  1313. if (STATUS_UNSUCCESSFUL != status) {
  1314. SetLastError(RtlNtStatusToDosError(status));
  1315. }
  1316. return NT_SUCCESS(status);
  1317. }
  1318. BOOL __stdcall
  1319. SisFreeBackupStructure(
  1320. IN PVOID sisBackupStructure)
  1321. {
  1322. NTSTATUS status;
  1323. status = SisFreeBackupStructureI(
  1324. sisBackupStructure);
  1325. if (STATUS_UNSUCCESSFUL != status) {
  1326. SetLastError(RtlNtStatusToDosError(status));
  1327. }
  1328. return NT_SUCCESS(status);
  1329. }
  1330. BOOL __stdcall
  1331. SisCreateRestoreStructure(
  1332. IN PWCHAR volumeRoot,
  1333. OUT PVOID *sisRestoreStructure,
  1334. OUT PWCHAR *commonStoreRootPathname,
  1335. OUT PULONG countOfCommonStoreFilesToRestore,
  1336. OUT PWCHAR **commonStoreFilesToRestore)
  1337. {
  1338. NTSTATUS status;
  1339. status = SisCreateRestoreStructureI(
  1340. volumeRoot,
  1341. sisRestoreStructure,
  1342. commonStoreRootPathname,
  1343. countOfCommonStoreFilesToRestore,
  1344. commonStoreFilesToRestore);
  1345. if (STATUS_UNSUCCESSFUL != status) {
  1346. SetLastError(RtlNtStatusToDosError(status));
  1347. }
  1348. return NT_SUCCESS(status);
  1349. }
  1350. BOOL __stdcall
  1351. SisRestoredLink(
  1352. IN PVOID sisRestoreStructure,
  1353. IN PWCHAR restoredFileName,
  1354. IN PVOID reparseData,
  1355. IN ULONG reparseDataSize,
  1356. OUT PULONG countOfCommonStoreFilesToRestore,
  1357. OUT PWCHAR **commonStoreFilesToRestore)
  1358. {
  1359. NTSTATUS status;
  1360. status = SisRestoredLinkI(
  1361. sisRestoreStructure,
  1362. restoredFileName,
  1363. reparseData,
  1364. reparseDataSize,
  1365. countOfCommonStoreFilesToRestore,
  1366. commonStoreFilesToRestore);
  1367. if (STATUS_UNSUCCESSFUL != status) {
  1368. SetLastError(RtlNtStatusToDosError(status));
  1369. }
  1370. return NT_SUCCESS(status);
  1371. }
  1372. BOOL __stdcall
  1373. SisRestoredCommonStoreFile(
  1374. IN PVOID sisRestoreStructure,
  1375. IN PWCHAR commonStoreFileName)
  1376. {
  1377. NTSTATUS status;
  1378. status = SisRestoredCommonStoreFileI(
  1379. sisRestoreStructure,
  1380. commonStoreFileName);
  1381. if (STATUS_UNSUCCESSFUL != status) {
  1382. SetLastError(RtlNtStatusToDosError(status));
  1383. }
  1384. return NT_SUCCESS(status);
  1385. }
  1386. BOOL __stdcall
  1387. SisFreeRestoreStructure(
  1388. IN PVOID sisRestoreStructure)
  1389. {
  1390. NTSTATUS status;
  1391. status = SisFreeRestoreStructureI(
  1392. sisRestoreStructure);
  1393. if (STATUS_UNSUCCESSFUL != status) {
  1394. SetLastError(RtlNtStatusToDosError(status));
  1395. }
  1396. return NT_SUCCESS(status);
  1397. }
  1398. VOID __stdcall
  1399. SisFreeAllocatedMemory(
  1400. IN PVOID allocatedSpace)
  1401. {
  1402. if (NULL != allocatedSpace) {
  1403. free(allocatedSpace);
  1404. }
  1405. }
  1406. BOOL WINAPI DLLEntryPoint(HANDLE hDLL, DWORD dwReason, LPVOID lpReserved)
  1407. {
  1408. return( TRUE );
  1409. }
  1410. }