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.

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