Figure 1   The USN_JOURNAL_DATA Structure
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)
      }
   }
}