Skip to content

USN change journal

This source reads the NTFS USN change journal of each fixed NTFS volume. It records that a file changed and why (the reason bitmask), but not which process made the change. Use it together with file ETW. USN is durable and resumes from a stored cursor. File ETW gives process attribution.

Collector ID freedr.usn (health: usn)
Windows mechanism FSCTL_READ_USN_JOURNAL (non-blocking, 256 KiB buffer, V2 records only, all 24 reason bits)
Hunt events view, event_type = 'usn.change'
Rule SQL source name usn
Hot table usn_v3
Code crates/freedr-collect-usn

Volumes

Rule Detail
Eligible Mounted volumes with a fixed-drive mount and the NTFS file system
Excluded Removable, network, ReFS/FAT and unmounted volumes (reported as unsupported_volumes or unavailable_volumes)
Limit 32 active volumes, chosen in volume GUID order
Isolation Each volume has its own state, cursor and failure domain
Polling Re-discovers volumes each loop. Sleeps 500 ms only when all volumes are caught up.

Event type

There is exactly one event type: usn.change. The reason column holds the raw USN_REASON_* bitmask, for example:

Bit Name
0x1 / 0x2 / 0x4 DATA_OVERWRITE / DATA_EXTEND / DATA_TRUNCATION
0x100 FILE_CREATE
0x200 FILE_DELETE
0x800 SECURITY_CHANGE
0x1000 / 0x2000 RENAME_OLD_NAME / RENAME_NEW_NAME
0x8000 BASIC_INFO_CHANGE
0x200000 STREAM_CHANGE
0x80000000 CLOSE

Filter with bitwise SQL, for example reason & 256 <> 0 for creates.

Columns

Column Notes
volume_serial Volume serial number
journal_id, usn Journal instance and record position
file_id 8-byte file reference number (FRN)
reason Raw reason bitmask
path Resolved path (see below)

The volume GUID, parent FRN, source info, security ID and file attributes are not stored.

Path resolution

  1. Open by file ID. FreeDR calls OpenFileById and then GetFinalPathNameByHandleW. This gives the file's current path when the journal is read (form \\?\C:\…), which may be newer than the name at the time of the change.
  2. Parent + leaf fallback. If the file is gone (for example, deleted), the path is built from the parent directory's FRN and the record's file name. For RENAME_OLD_NAME the parent is tried first. A 1,024-entry parent cache per volume is cleared when a directory is renamed or deleted.
  3. Unresolvable. If neither the file nor its parent resolves, the record is dropped (path_unresolved_dropped). This happens, for example, when a whole directory tree was deleted.

USN does not use the Live MFT reader. Live MFT is a separate on-demand lookup (up to 64 exact paths or FRNs) used from Hunt, not an event source.

Cursor, restart and gaps

Situation Behaviour
First install Starts at the journal's current end (NextUsn). History is not imported.
Commit Batches of at most 256 events / 8 MiB. The per-volume cursor (journal_id, next USN) is stored in the same transaction as the rows.
Agent restart Downtime is not replayed. The source starts again at NextUsn and records the jump as a coverage gap.
Journal overrun while running Resumes at the oldest retained record (FirstUsn), records a gap, and counts a read_failures
Journal deleted or recreated journal_resets +1
Malformed page Skipped as a gap if the next position is valid. Otherwise the volume is marked faulted.
Filtered records Still advance the cursor

Coverage gaps appear only in health counters. No row is written for them.

Noise controls

Control Detail Counter
Close-only records A record whose only reason is CLOSE is dropped filtered_close_only
First-only per minute Key (file reference number, reason mask), 60 s window, 4,096 keys per volume, in memory repeated_records
Fixed paths C:\ProgramData\FreeDR\…, CBS.log, EdgeUpdate Download/Install/Log, Edge Temp, msedge_installer.log
OS maintenance paths Everything under C:\$WinREAgent\, SoftwareDistribution\Download\, WinSxS\Manifests\, WinSxS\FileMaps\, DriverStore\FileRepository\, assembly\NativeImages_*; INF\setupapi.*.log; Prefetch\*.pf; .NET ngen*.log
Generated directories CbsTemp transactions, WinSxS component directories, WindowsApps\<package> and WindowsApps\Deleted, AppRepository, versioned Edge / EdgeCore / EdgeWebView application directories
Measured pairs (ADR-0028) SoftwareDistribution\Download\*.manifest; WinSxS\Temp\PendingRenames\*.cdf-ms and *.manifest; servicing\Packages\*.cat and *.mum; WinSxS\Catalogs\*.cat; local AppData Microsoft\OneDrive *.js/*.svg/*.css/*.json/*.png; System32\catroot2\dberr.txt

Warning

These exclusions remove real evidence, including WinSxS, WindowsApps and Prefetch .pf changes. ADR-0028 states that they are not lossless.

Artifact triggers

Every retained USN record queues its path for artifact acquisition. For an already-inventoried path, only content-changing reasons trigger a new collection: data overwrite, extend or truncation (including named streams), file create and stream change.

Health counters

Counters: reads, decoded_records, retained_records, filtered_close_only, repeated_records, path_unresolved_dropped, commit_acknowledgements, journal_resets, coverage_gaps, read_failures, decode_failures, checkpoint_failures, backpressure_pauses, integration_failures, fatal_worker_failures, commit_* failure counters. (replays exists but is always 0.)

Gauges: active_volumes, unavailable_volumes, unsupported_volumes, pending_volumes, faulted_volumes, failed_workers, cursor_lag_usn.

The source is degraded while the worker has failed or faulted_volumes or failed_workers is non-zero, and whenever the lifetime total of read_failures, decode_failures, checkpoint_failures and integration_failures grows. Like every collector, it then stays degraded for 30 minutes after its last fault, clears on its own, and counts degraded_episodes. See Storage & health.

Known gaps

  • No process attribution.
  • Changes made while FreeDR is stopped, and history from before installation, are not collected.
  • A journal overrun loses records older than FirstUsn.
  • Paths reflect the name when the journal is read, not when the change happened.
  • A delete is lost when its parent directory is also gone.
  • Only fixed NTFS volumes are read, at most 32.