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.

541 lines
15 KiB

  1. /*++
  2. 1998 Seagate Software, Inc. All rights reserved
  3. Module Name:
  4. WsbUsn.cpp
  5. Abstract:
  6. Functions to manipulate the USN journal and USN records on a file
  7. Author:
  8. Rick Winter [rick] 11-17-97
  9. Revision History:
  10. --*/
  11. #include "stdafx.h"
  12. #define HSM_FILE_CHANGED (USN_REASON_DATA_OVERWRITE | USN_REASON_DATA_EXTEND | USN_REASON_DATA_TRUNCATION | USN_REASON_FILE_DELETE)
  13. // Local functions
  14. static HANDLE OpenVol(OLECHAR* volName);
  15. HRESULT
  16. WsbCheckUsnJournalForChanges(
  17. OLECHAR* volName,
  18. ULONGLONG fileUsnJournalId,
  19. LONGLONG FileId,
  20. LONGLONG StartUsn,
  21. LONGLONG StopUsn,
  22. BOOL* pChanged
  23. )
  24. /*++
  25. Routine Description:
  26. Check the USN Journal for changes to the unnamed data stream for this
  27. file between the given USNs.
  28. Arguments:
  29. volName - Volume name
  30. FileId - File ID of file
  31. StartUsn - USN to start at in journal
  32. StopUsn - USN to stop at in journal
  33. pChanged - Pointer to result: TRUE for change
  34. Return Value:
  35. S_OK - success
  36. --*/
  37. {
  38. ULONGLONG Buffer[1024];
  39. HRESULT hr = S_OK;
  40. IO_STATUS_BLOCK Iosb;
  41. USN NextUsn;
  42. NTSTATUS Status;
  43. READ_USN_JOURNAL_DATA ReadUsnJournalData;
  44. DWORD ReturnedByteCount;
  45. ULONGLONG usnId;
  46. PUSN_RECORD pUsnRecord;
  47. HANDLE volHandle = INVALID_HANDLE_VALUE;
  48. WsbTraceIn(OLESTR("WsbCheckUsnJournalForChanges"),
  49. OLESTR("volName = %ls, FileId = %I64x, StartUsn = %I64d, StopUsn = %I64d"),
  50. volName, FileId, StartUsn, StopUsn);
  51. try {
  52. WsbAffirmPointer(pChanged);
  53. *pChanged = FALSE;
  54. volHandle = OpenVol(volName);
  55. WsbAffirmHandle(volHandle);
  56. // Get the journal ID
  57. WsbAffirmHr(WsbGetUsnJournalId(volName, &usnId));
  58. // If we got a non-zero journal id, cpmare to the current one and fail if they are not equal
  59. if ((fileUsnJournalId != 0) && (fileUsnJournalId != usnId)) {
  60. WsbTraceAlways(
  61. OLESTR("WsbCheckUsnJournalForChanges: Current Usn journal id %I64x doesn't match file Usn journal id %I64x\n"),
  62. usnId, fileUsnJournalId);
  63. WsbThrow(E_FAIL);
  64. }
  65. // Set up read info
  66. NextUsn = StartUsn;
  67. ReadUsnJournalData.UsnJournalID = usnId;
  68. ReadUsnJournalData.ReasonMask = HSM_FILE_CHANGED;
  69. ReadUsnJournalData.ReturnOnlyOnClose = TRUE;
  70. ReadUsnJournalData.Timeout = 0; // ????
  71. ReadUsnJournalData.BytesToWaitFor = 0; // ??????
  72. // Loop through journal entries
  73. while (!*pChanged) {
  74. ReadUsnJournalData.StartUsn = NextUsn;
  75. Status = NtFsControlFile( volHandle,
  76. NULL,
  77. NULL,
  78. NULL,
  79. &Iosb,
  80. FSCTL_READ_USN_JOURNAL,
  81. &ReadUsnJournalData,
  82. sizeof(ReadUsnJournalData),
  83. &Buffer,
  84. sizeof(Buffer) );
  85. if (NT_SUCCESS(Status)) {
  86. Status = Iosb.Status;
  87. }
  88. if (Status == STATUS_JOURNAL_ENTRY_DELETED) {
  89. WsbTrace(OLESTR("WsbCheckUsnJournalForChanges: StartUsn has been deleted\n"));
  90. }
  91. WsbAffirmNtStatus(Status);
  92. ReturnedByteCount = (DWORD)Iosb.Information;
  93. WsbTrace(OLESTR("WsbCheckUsnJournalForChanges: bytes read = %u\n"), ReturnedByteCount);
  94. // Get the next USN start point & and the first
  95. // journal entry
  96. NextUsn = *(USN *)&Buffer;
  97. pUsnRecord = (PUSN_RECORD)((PCHAR)&Buffer + sizeof(USN));
  98. ReturnedByteCount -= sizeof(USN);
  99. // Make sure we actually got some entries
  100. if (0 == ReturnedByteCount) {
  101. WsbTrace(OLESTR("WsbCheckUsnJournalForChanges: no entries, exiting loop\n"), ReturnedByteCount);
  102. break;
  103. }
  104. // Loop over entries in this buffer
  105. while (ReturnedByteCount != 0) {
  106. WsbAffirm(pUsnRecord->RecordLength <= ReturnedByteCount, E_FAIL);
  107. // Skip the first record and check for match on File Id
  108. // (Also skip entries that we created)
  109. if (pUsnRecord->Usn > StartUsn &&
  110. USN_SOURCE_DATA_MANAGEMENT != pUsnRecord->SourceInfo &&
  111. pUsnRecord->FileReferenceNumber == static_cast<ULONGLONG>(FileId)) {
  112. WsbTrace(OLESTR("WsbCheckUsnJournalForChanges: found change record\n"));
  113. WsbTrace(OLESTR( " Reason: %08lx\n"), pUsnRecord->Reason);
  114. *pChanged = TRUE;
  115. break;
  116. } else if (pUsnRecord->Usn == StartUsn) {
  117. // This check is done to make sure the journal is valid -
  118. // StartUsn record must refer to the file in question
  119. if (pUsnRecord->FileReferenceNumber != static_cast<ULONGLONG>(FileId)) {
  120. WsbTraceAlways(
  121. OLESTR("WsbCheckUsnJournalForChanges: StartUsn %I64d for FileId %I64x doesn't match usn journal FileId %I64x\n"),
  122. StartUsn, FileId, pUsnRecord->FileReferenceNumber);
  123. WsbThrow(E_FAIL);
  124. }
  125. }
  126. ReturnedByteCount -= pUsnRecord->RecordLength;
  127. pUsnRecord = (PUSN_RECORD)((PCHAR)pUsnRecord + pUsnRecord->RecordLength);
  128. }
  129. // Make sure we're making progress
  130. WsbAffirm(NextUsn > ReadUsnJournalData.StartUsn, E_FAIL);
  131. }
  132. } WsbCatch( hr );
  133. if (INVALID_HANDLE_VALUE != volHandle) {
  134. CloseHandle(volHandle);
  135. }
  136. WsbTraceOut(OLESTR("WsbCheckUsnJournalForChanges"), OLESTR("Hr = <%ls>, Changed = %ls"),
  137. WsbHrAsString(hr), WsbBoolAsString(*pChanged));
  138. return( hr );
  139. }
  140. HRESULT
  141. WsbGetUsnFromFileHandle(
  142. IN HANDLE hFile,
  143. IN BOOL ForceClose,
  144. OUT LONGLONG* pFileUsn
  145. )
  146. /*++
  147. Routine Description:
  148. Get the current USN Journal number for the open file.
  149. Arguments:
  150. hFile - Handle to the open file
  151. pFileUsn - Pointer to File USN to be returned.
  152. Return Value:
  153. S_OK - success
  154. --*/
  155. {
  156. HRESULT hr = S_OK;
  157. WsbTraceIn(OLESTR("WsbGetUsnFromFileHandle"), OLESTR(""));
  158. try {
  159. char buffer[4096];
  160. IO_STATUS_BLOCK IoStatusBlock;
  161. PUSN_RECORD pUsnInfo;
  162. WsbAffirm(pFileUsn, E_POINTER);
  163. *pFileUsn = 0;
  164. if (TRUE == ForceClose) {
  165. // Get the internal information
  166. WsbAffirmNtStatus(NtFsControlFile( hFile,
  167. NULL,
  168. NULL,
  169. NULL,
  170. &IoStatusBlock,
  171. FSCTL_WRITE_USN_CLOSE_RECORD,
  172. NULL,
  173. 0,
  174. buffer,
  175. sizeof(buffer)));
  176. }
  177. // Get the internal information
  178. WsbAffirmNtStatus(NtFsControlFile( hFile,
  179. NULL,
  180. NULL,
  181. NULL,
  182. &IoStatusBlock,
  183. FSCTL_READ_FILE_USN_DATA,
  184. NULL,
  185. 0,
  186. buffer,
  187. sizeof(buffer)));
  188. pUsnInfo = (PUSN_RECORD) buffer;
  189. WsbTrace(OLESTR("WsbGetUsnFromFileHandle, Usn record version number is %u\n"),
  190. pUsnInfo->MajorVersion);
  191. // Check the version
  192. WsbAffirm(pUsnInfo->MajorVersion == 2, WSB_E_INVALID_DATA);
  193. // Get the USN
  194. *pFileUsn = pUsnInfo->Usn;
  195. } WsbCatchAndDo(hr,
  196. WsbTrace(OLESTR("WsbGetUsnFromFileHandle, GetLastError = %lx\n"),
  197. GetLastError());
  198. );
  199. WsbTraceOut(OLESTR("WsbGetUsnFromFileHandle"), OLESTR("Hr = <%ls>, FileUsn = %I64d"),
  200. WsbHrAsString(hr), *pFileUsn);
  201. return(hr);
  202. }
  203. HRESULT
  204. WsbMarkUsnSource(
  205. HANDLE changeHandle,
  206. OLECHAR* volName
  207. )
  208. /*++
  209. Routine Description:
  210. Mark the source of file changes for this handle as data management. This lets
  211. others, such as content indexing, know that the changes do not affect file content.
  212. Arguments:
  213. changeHandle - Handle to the open file
  214. volName - Volume name (d:\)
  215. Return Value:
  216. S_OK - success
  217. --*/
  218. {
  219. HRESULT hr = S_OK;
  220. HANDLE volHandle = INVALID_HANDLE_VALUE;
  221. NTSTATUS ntStatus;
  222. MARK_HANDLE_INFO sInfo;
  223. IO_STATUS_BLOCK IoStatusBlock;
  224. try {
  225. volHandle = OpenVol(volName);
  226. WsbAffirmHandle(volHandle);
  227. sInfo.UsnSourceInfo = USN_SOURCE_DATA_MANAGEMENT;
  228. sInfo.VolumeHandle = volHandle;
  229. sInfo.HandleInfo = 0;
  230. ntStatus = NtFsControlFile( changeHandle,
  231. NULL,
  232. NULL,
  233. NULL,
  234. &IoStatusBlock,
  235. FSCTL_MARK_HANDLE,
  236. &sInfo,
  237. sizeof(MARK_HANDLE_INFO),
  238. NULL,
  239. 0);
  240. WsbAffirmNtStatus(ntStatus);
  241. CloseHandle(volHandle);
  242. volHandle = INVALID_HANDLE_VALUE;
  243. } WsbCatch( hr );
  244. if (INVALID_HANDLE_VALUE != volHandle) {
  245. CloseHandle(volHandle);
  246. }
  247. return( hr );
  248. }
  249. HRESULT
  250. WsbCreateUsnJournal(
  251. OLECHAR* volName,
  252. ULONGLONG usnSize
  253. )
  254. /*++
  255. Routine Description:
  256. Create the USN journal for the given volume.
  257. Arguments:
  258. volName - Volume name (d:\)
  259. usnSize - Max size of journal
  260. Return Value:
  261. S_OK - success
  262. --*/
  263. {
  264. HRESULT hr = S_OK;
  265. HANDLE volHandle = INVALID_HANDLE_VALUE;
  266. NTSTATUS ntStatus;
  267. IO_STATUS_BLOCK IoStatusBlock;
  268. CREATE_USN_JOURNAL_DATA CreateUsnJournalData;
  269. WsbTraceIn(OLESTR("WsbCreateUsnJournal"), OLESTR("volName = %ls, Size = %I64d"),
  270. volName, usnSize);
  271. try {
  272. volHandle = OpenVol(volName);
  273. WsbAffirmHandle(volHandle);
  274. CreateUsnJournalData.MaximumSize = usnSize;
  275. CreateUsnJournalData.AllocationDelta = usnSize / 32;
  276. ntStatus = NtFsControlFile( volHandle,
  277. NULL,
  278. NULL,
  279. NULL,
  280. &IoStatusBlock,
  281. FSCTL_CREATE_USN_JOURNAL,
  282. &CreateUsnJournalData,
  283. sizeof(CreateUsnJournalData),
  284. NULL,
  285. 0);
  286. WsbTrace(OLESTR("WsbCreateUsnJournal: ntStatus = %lx, iosb.Status = %lx\n"),
  287. ntStatus, IoStatusBlock.Status);
  288. if (STATUS_DISK_FULL == ntStatus) {
  289. WsbThrow(WSB_E_USNJ_CREATE_DISK_FULL);
  290. } else if (!NT_SUCCESS(ntStatus)) {
  291. WsbThrow(WSB_E_USNJ_CREATE);
  292. }
  293. WsbAffirmNtStatus(ntStatus);
  294. } WsbCatch( hr );
  295. if (INVALID_HANDLE_VALUE != volHandle) {
  296. CloseHandle(volHandle);
  297. }
  298. WsbTraceOut(OLESTR("WsbCreateUsnJournal"), OLESTR("Hr = <%ls>"),
  299. WsbHrAsString(hr));
  300. return( hr );
  301. }
  302. HRESULT
  303. WsbGetUsnJournalId(
  304. OLECHAR* volName,
  305. ULONGLONG* usnId
  306. )
  307. /*++
  308. Routine Description:
  309. Get the current USN Journal ID
  310. Arguments:
  311. volName - Volume name (d:\)
  312. usnId - Id is returned here.
  313. Return Value:
  314. S_OK - success
  315. --*/
  316. {
  317. HRESULT hr = S_OK;
  318. HANDLE volHandle = INVALID_HANDLE_VALUE;
  319. NTSTATUS ntStatus;
  320. IO_STATUS_BLOCK IoStatusBlock;
  321. USN_JOURNAL_DATA usnData;
  322. WsbTraceIn(OLESTR("WsbGetUsnJournalId"), OLESTR("volName = %ls"), volName);
  323. try {
  324. WsbAffirmPointer(usnId);
  325. volHandle = OpenVol(volName);
  326. WsbAffirmHandle(volHandle);
  327. *usnId = (ULONGLONG) 0;
  328. ntStatus = NtFsControlFile( volHandle,
  329. NULL,
  330. NULL,
  331. NULL,
  332. &IoStatusBlock,
  333. FSCTL_QUERY_USN_JOURNAL,
  334. NULL,
  335. 0,
  336. &usnData,
  337. sizeof(usnData));
  338. WsbTrace(OLESTR("WsbGetUsnJournalId: ntStatus = %lx, iosb.Status = %lx\n"),
  339. ntStatus, IoStatusBlock.Status);
  340. if (STATUS_JOURNAL_NOT_ACTIVE == ntStatus) {
  341. WsbThrow(WSB_E_NOTFOUND);
  342. }
  343. WsbAffirmNtStatus(ntStatus);
  344. *usnId = usnData.UsnJournalID;
  345. } WsbCatch( hr );
  346. if (INVALID_HANDLE_VALUE != volHandle) {
  347. CloseHandle(volHandle);
  348. }
  349. WsbTraceOut(OLESTR("WsbGetUsnJournalId"), OLESTR("Hr = <%ls>, id = %I64x"),
  350. WsbHrAsString(hr), *usnId);
  351. return( hr );
  352. }
  353. // Local functions
  354. static HANDLE OpenVol(OLECHAR* volName)
  355. {
  356. HRESULT hr = S_OK;
  357. HANDLE volHandle = INVALID_HANDLE_VALUE;
  358. CWsbStringPtr name;
  359. WCHAR *vPtr;
  360. try {
  361. name = volName;
  362. if (name == NULL) {
  363. WsbThrow(E_OUTOFMEMORY);
  364. }
  365. if (name[1] == L':') {
  366. swprintf((OLECHAR*) name, L"%2.2s", volName);
  367. } else {
  368. //
  369. // Must be a volume without a drive letter
  370. // Move to end of PNPVolumeName...
  371. vPtr = name;
  372. vPtr = wcsrchr(vPtr, L'\\');
  373. if (NULL != vPtr) {
  374. *vPtr = L'\0';
  375. }
  376. }
  377. WsbAffirmHr(name.Prepend(OLESTR("\\\\.\\")));
  378. WsbAffirmHandle(volHandle = CreateFile( name,
  379. GENERIC_READ,
  380. FILE_SHARE_READ | FILE_SHARE_WRITE,
  381. NULL,
  382. OPEN_EXISTING,
  383. 0,
  384. NULL ));
  385. } WsbCatchAndDo( hr,
  386. if (INVALID_HANDLE_VALUE != volHandle) {
  387. CloseHandle(volHandle);
  388. }
  389. volHandle = INVALID_HANDLE_VALUE;
  390. )
  391. return(volHandle);
  392. }