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.

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