typedef struct {
DWORDLONG UsnJournalID;
USN FirstUsn;
USN NextUsn;
USN LowestValidUsn;
USN MaxUsn;
DWORDLONG MaximumSize;
DWORDLONG AllocationDelta;
} USN_JOURNAL_DATA, *PUSN_JOURNAL_DATA;
Members
|
Description
|
UsnJournalID
|
64-bit unique journal identifier.
|
FirstUsn
|
Identifies the first USN actually in the journal. All USNs below this value have been purged.
|
NextUsn
|
The USN that will be assigned to the next record appended to the journal.
|
LowestValidUsn
|
The lowest USN that is valid for this journal. On some occasions, the lowest USN number may not be zero. All changes with this USN or higher have been reported in the Change Journal.
|
MaxUsn
|
The largest USN that will ever be issued in this journal. USNs cannot make use of the entire 64-bit address space-they are limited by the maximum logical size of a sparse file on an NTFS volume. Administrators are responsible for watching this number and deleting the journal if the NextUsn member approaches this value.
|
MaximumSize
|
The maximum size in bytes that the journal should use on the volume.
|
AllocationDelta
|
Size to grow the journal when needed, and size to purge from the start of the journal if it grows past MaximumSize.
|
Figure 2 Failing a DeviceIoControl
Code
|
Description
|
ERROR_INVALID_DEVICE_STATE
|
The volume does not support Change Journals.
|
ERROR_JOURNAL_NOT_ACTIVE
|
The volume supports journals, but the journal is not currently active. Use FSCTL_CREATE_USN_ JOURNAL to activate the journal.
|
ERROR_JOURNAL_DELETE_IN_PROGRESS
|
A journal is in the process of being disabled. Use FSCTL_DELETE_USN_JOURNAL to set up a notification that will tell you when the delete is complete.
|
Figure 3 Version 2.3 USN_RECORD Structure
// HYPOTHETICAL Version 2.3 USN_RECORD structure
typedef struct {
DWORD RecordLength;
WORD MajorVersion;
WORD MinorVersion;
DWORDLONG FileReferenceNumber;
DWORDLONG ParentFileReferenceNumber;
USN Usn;
LARGE_INTEGER TimeStamp;
DWORD Reason;
DWORD SourceInfo;
DWORD SecurityId;
DWORD FileAttributes;
WORD FileNameLength;
WORD FileNameOffset; // penultimate of original version 2.0
DWORD ExtraInfo1; // Hypothetically added in version 2.1
DWORD ExtraInfo2; // Hypothetically added in version 2.2
DWORD ExtraInfo3; // Hypothetically added in version 2.3
WCHAR FileName[1]; // variable length always at the end
} USN_RECORD, *PUSN_RECORD;
Description
Figure 4 File Name of a USN Record
Member
|
Description
|
FileNameOffset
|
The number of bytes from the start of the record to the start of the file or directory name.
|
FileNameLength
|
The number of bytes in the file name. The file name will always be stored in Unicode, so the number of characters in the file name will be FileNameLength/sizeof(WCHAR). This value does not include a zero terminating character, and you cannot rely on the name being zero-terminated in the record.
|
FileName
|
Never use this member directly. At runtime, the location of the file or directory name may not start at this member. Use the FileNameOffset and FileNameLength members instead.
|
Figure 5 Change Journal Reason Codes
Reason Code
|
Description
|
USN_REASON_BASIC_INFO_CHANGE
|
A user has either changed one or more file or directory attributes (such as read-only, hidden, system, archive, or sparse attribute), or one or more time stamps.
|
USN_REASON_CLOSE
|
The file or directory was closed.
|
USN_REASON_COMPRESSION_CHANGE
|
The compression state of the file or directory was changed.
|
USN_REASON_DATA_EXTEND
|
The file’s unnamed stream had data
appended to it.
|
USN_REASON_DATA_OVERWRITE
|
The unnamed stream in the file or directory had its data overwritten.
|
USN_REASON_DATA_TRUNCATION
|
The file’s unnamed stream was truncated.
|
USN_REASON_EA_CHANGE
|
The user made a change to the file or directory extended attributes. These NTFS attributes are not accessible to Win32-based
applications.
|
USN_REASON_ENCRYPTION_CHANGE
|
The file or directory was encrypted or
decrypted.
|
USN_REASON_FILE_CREATE
|
The file or directory was created.
|
USN_REASON_FILE_DELETE
|
The file or directory was deleted.
|
USN_REASON_HARD_LINK_CHANGE
|
An NTFS hard link was added to or removed from the file.
|
USN_REASON_INDEXABLE_CHANGE
|
A user changed the FILE_ATTRIBUTE_ NOT_CONTENT_INDEXED attribute. That is, the user changed the file or directory from one that should be content indexed to one that should not, or vice versa.
|
USN_REASON_NAMED_DATA_EXTEND
|
The named stream in the file or directory had data appended to it.
|
USN_REASON_NAMED_DATA_OVERWRITE
|
The named stream in the file or directory had its data overwritten.
|
USN_REASON_NAMED_DATA_TRUNCATION
|
The named stream in the file or directory was truncated.
|
USN_REASON_OBJECT_ID_CHANGE
|
The object identifier of the file or directory was changed.
|
USN_REASON_RENAME_NEW_NAME
|
The file or directory was renamed, and the file name in this USN_RECORD structure is the new name.
|
USN_REASON_RENAME_OLD_NAME
|
The file or directory was renamed, and the file name in this USN_RECORD structure is the old name
|
USN_REASON_REPARSE_POINT_CHANGE
|
The file or directory reparse point attribute was added, changed, or deleted.
|
USN_REASON_SECURITY_CHANGE
|
A change was made in the access rights to the file or directory.
|
USN_REASON_STREAM_CHANGE
|
A named stream has been added, renamed, or removed from the file or directory.
|
Figure 6 Processing Reason Codes
Order of Actions
|
Journal Records Created
(with short name of reason codes) |
Open Existing File
|
None
|
Overwrite Some Data
|
Data Overwrite
|
Seek to End
|
None
|
Append Some Data
|
Data Overwrite | Data Extend
|
Seek to Start
|
None
|
Overwrite Some Data
|
None (we already know about Data Overwrite)
|
Change Time-stamp
|
Data Overwrite | Data Extend | Basic Info Changed
|
Close File
|
Data Overwrite | Data Extend | Basic Info Changed | Close
|
Open File Again
|
None
|
Overwrite Some Data
|
Data Overwrite
|
Close File
|
Data Overwrite | Close
|
Figure 7 SourceInfo Flags
Flag
|
Description
|
USN_SOURCE_DATA_MANAGEMENT
|
The source (application) has not modified the external view of the file or directory. For example, Windows 2000 provides a service that transparently moves unused files to tape and restores them if access is attempted. Records will be added when the file is removed or restored, but they can be ignored since the change does not affect what an application reads from the file.
|
USN_SOURCE_AUXILIARY_DATA
|
The source has not modified the external view of the file with regard to the application that created this file. For example, a virus program can specify this when cleaning a document, or a thumbnail viewer might store preview data in a private named stream.
|
USN_SOURCE_REPLICATION_MANAGEMENT
|
The source is modifying the file to match the contents of the same file, which exists in another member of the replica set.
|
Figure 8 Return Record
// This function will return TRUE if it meets the filter
// criteria specified by the ReasonMask and ReturnOnlyOnClose
// members of the READ_USN_JOURNAL_DATA structure
BOOL ReturnRecord (PREAD_USN_JOURNAL_DATA prujd,
PUSN_RECORD precord) {
BOOL bReturnToUser = FALSE;
// Test the ReasonMask
// The user is interested only in records with at least one
// of the codes specified by ReasonMask
if ((prujd->ReasonMask & precord->Reason) != 0)
bReturnToUser = TRUE;
// Test ReturnOnlyOnClose
// If we passed the ReasonMask test
// 'and' the caller only wants records with USN_REASON_CLOSE
// 'and' this record does not have USN_REASON_CLOSE
// then set bReturnToUser to FALSE
if (bReturnToUser && prujd->ReturnOnlyOnClose &&
((precord->Reason & USN_REASON_CLOSE) == 0))_
bReturnToUser = FALSE
return bReturnToUser;
}
Figure 10 Reading USN Data
// Read the raw data for USNs from usnStart up to but not including usnEnd
// This can be used to read all available records by using
// the USN_JOURNAL_DATA members FirstUsn and NextUsn
void GetRawRecordData(HANDLE hcj, DWORDLONG journalId,
USN usnStart, USN usnEnd){
READ_USN_JOURNAL_DATA rujd;
rujd.StartUsn = usnStart;
rujd.ReasonMask = 0x"#ffffff"FF; // All bits
rujd.ReturnOnlyOnClose = FALSE; // All entries
rujd.Timeout = 0; // No timeout
rujd.BytesToWaitFor = 0; // Do not wait if no records
rujd.UsnJournalID = journalId; // The journal we expect to read from
while (rujd.StartUsn < usnEnd) {
DWORD cbRead;
BYTE pData[8192 + sizeof(USN)]; // read in 8 KB chunks
BOOL fOk = DeviceIoControl(hcj, FSCTL_READ_USN_JOURNAL,
&rujd, sizeof(rujd),
pData, sizeof(pdata), &cbRead, NULL);
if (!fOk)
break; // handle error
// Get first USN to request next time
rujd.StartUsn = * ((PUSN) pData);
PUSN_RECORD pRecord = (PUSN_RECORD) &pData[sizeof(USN)];
while ((PBYTE) pRecord < (pData + cbRead)) {
// ... do something with the record ...
pRecord = (PUSN_RECORD)((PBYTE) pRecord + pRecord->RecordLength)
}
}
}