Skip to content

File accessUser activity

Tracker / LocalSearch DB: GNOME File Index on Linux

GNOME's Tracker and LocalSearch file index on Linux: SQLite databases listing indexed files, their timestamps and extracted content for a user's home.

Location
~/.cache/tracker3/files/
Proves
Which files existed in indexed folders, with name, size, MAC times and extracted metadata as last seen by the indexer
Timestamps
Unix epoch seconds (UTC) as integers, or ISO 8601 text when an offset or sub-second part must be kept
Access
Any user for own cache; root for other users
Retention
Mirrors the indexed tree; entries removed when the indexer processes a deletion
Collection
UAC, cp -a, tar

What it is

GNOME desktops ship a file indexer that crawls the user's files, extracts metadata and text, and stores the result in a SPARQL triple store backed by SQLite. It powers search in the Files app (Nautilus), the Activities overview and apps such as Music or Photos. The indexer was called Tracker (tracker-miner-fs); in LocalSearch 3.8 (GNOME 47, 2024) the miners were renamed LocalSearch and the database library Tracker SPARQL became TinySPARQL. The on-disk cache directory kept its tracker3 name.

For an investigator it is a second, independent listing of files in the user's home with their timestamps and sizes, sometimes with extracted text, maintained by a process the user rarely thinks about.

Where it lives

GenerationPathNotes
Tracker 3 and LocalSearch~/.cache/tracker3/files/$XDG_CACHE_HOME/tracker3/files/; meta.db plus one database per named graph
Tracker 3 graph fileshttp%3A%2F%2Ftracker.api.gnome.org%2Fontology%2Fv3%2Ftracker%23FileSystem.dbPercent-encoded graph IRI; siblings for Audio, Documents, Pictures, Software, Video
Tracker 3 errors~/.cache/tracker3/files/errors/Records of files the extractor failed on
LocalSearch 3.11+ removable media.localsearch3/ at the root of the deviceOnly when removable indexing is enabled (off by default)
Tracker 2 (older GNOME 3 releases)~/.cache/tracker/meta.dbSingle database; journal and logs under ~/.local/share/tracker/

Paths do not depend on the distribution family. What varies is whether the indexer is installed and running: it is commonly installed with GNOME desktops and usually absent on servers and other desktops. Some sandboxed or Flatpak builds are compiled with a different cache location, so search the whole home for meta.db.

What it proves

  • That a file with a given path, name and size existed in an indexed location when the indexer last processed it.
  • The file's modification, access and (where the filesystem and GLib expose it) creation time as the indexer saw them.
  • Extracted metadata: document titles and authors, EXIF data, audio tags, page counts, and plain text content for supported documents.
  • Which folders were indexing roots and which removable or network volumes were known.

It does not prove that a user opened a file (indexing is automatic), and it is not a history: an entry is updated in place when the file changes. When the indexer sees a deletion, it removes the entry, so a deleted file survives only if the indexer did not process the change (not running, excluded, crash) or as residue in SQLite free pages and -wal files.

Key fields

The store follows the NEPOMUK-based ontology. These properties matter most for files:

PropertyMeaning
nie:urlFile URI (file:///home/...) of the data object
nfo:fileNameFile name
nfo:fileSizeSize in bytes
nfo:fileLastModifiedFile mtime
nfo:fileLastAccessedFile atime
nfo:fileCreatedFile birth time, when GLib and the filesystem expose it
nie:plainTextContentExtracted text of a document (content graphs such as Documents)
nie:title, nfo:pageCount, EXIF and audio propertiesExtracted metadata

In SQLite, each class is stored as a table named after the class (such as nfo:FileDataObject) with one column per single-valued property, and multi-valued properties get Class_property tables. meta.db also holds the Resource table that maps every row ID to its IRI, and the Graph table listing named graphs. Identifiers contain colons, so quote them in SQL, and list the real table names with .tables before querying.

Timestamps

TinySPARQL stores an xsd:dateTime as an integer Unix timestamp (UTC seconds) when that is lossless, and as ISO 8601 text when the value has a UTC offset or microseconds. Expect both forms in the same column and normalise them:

-- adjust the table name to what .tables shows in the graph database
SELECT CASE typeof(v) WHEN 'integer' THEN datetime(v, 'unixepoch') ELSE v END AS utc
FROM (SELECT "nfo:fileLastModified" AS v FROM "nfo:FileDataObject" LIMIT 5);

The time values are the file's own metadata. The database files' mtime only tells you when the indexer last wrote.

Retention

The index tracks the live filesystem: new files are added, changed files updated and deleted files removed as the miner is notified or recrawls on start. localsearch reset (formerly tracker3 reset) or deleting the cache discards everything. Configuration lives in GSettings schema org.freedesktop.Tracker3.Miner.Files:

  • index-recursive-directories: since LocalSearch 3.11 the default is the whole home directory; earlier releases indexed a set of XDG user folders instead.
  • index-removable-devices and index-optical-discs: both default to false.
  • ignored-directories-with-content: folders containing .trackerignore, .git, .hg or .nomedia are skipped.
  • org.freedesktop.Tracker3.Extract max-bytes: at most 1 MiB of UTF-8 text is extracted per file.

Collection

UAC's files/system/tracker.yaml (in ir_triage) copies meta.db* and the graph databases from ~/.cache/tracker3/files for each user. It does not cover Tracker 2 or removable-media databases, so add those by hand. Stop or avoid touching the user session first if you can: the indexer writes continuously.

cd /mnt/evidence
find home root -path '*/.cache/tracker*' \( -name '*.db' -o -name '*.db-wal' -o -name '*.db-shm' -o -name '*.journal' \) \
  -print0 | tar --null -T - -czf tracker.tgz

Always keep the -wal and -shm companions with each database.

Parsing

Work on copies. The supported way to read the store is SPARQL through the TinySPARQL CLI, which opens a database directory read-only unless --update is given:

tinysparql query --database ./tracker3/files \
  'SELECT ?url ?size ?mtime ?atime WHERE {
     ?f a nfo:FileDataObject ; nie:url ?url ; nfo:fileSize ?size ; nfo:fileLastModified ?mtime .
     OPTIONAL { ?f nfo:fileLastAccessed ?atime } } ORDER BY ?mtime'

The files are also ordinary SQLite databases, so sqlite3 works for bulk export and for inspecting free pages; attach the graph databases to meta.db so Resource IDs resolve.

On a live system, localsearch info <file> and localsearch search <term> query the running index.

Investigator tips

  • Compare indexed URLs with a filesystem listing of the image: indexed files that no longer exist point to deletions the indexer missed, and give you name, size and times for them (see ext4 deleted files).
  • Carve SQLite free pages and the -wal file for older row versions of deleted or changed entries.
  • Extracted nie:plainTextContent can hold the first part of a document's text even when the document itself is gone or encrypted later.
  • Removable and network volumes known to the index help tie USB media to a user; correlate with udev and USB logs.
  • Pair with recently-used.xbel: the index shows a file existed, the recent list shows it was opened.
  • A user who disabled indexing (settings or .trackerignore files) leaves a gap, not a clue of wrongdoing by itself.

See also