Schema version 3. A scan directory holds manifest.json and a directory of part files per table; DuckDB reads each table's parts with a glob such as entries/.
Types are as DuckDB reads them from Parquet. In CSV and JSON Lines, byte columns are base64 text under their text name, and timestamps are ISO-8601 UTC text (or epoch seconds with --time-format epoch).
Integer columns are signed and wide enough for every value, so they work in tools and databases without unsigned types (PostgreSQL, Spark). The exceptions are dev, ino, and rdev: opaque 64-bit identifiers whose top bit can be set, so they're unsigned (UBIGINT). Byte totals and counts above the signed 64-bit maximum (8 EiB) would be capped, not wrapped.
entries#
One row per file, directory, or other entry.
| Column | Type | Null | Description |
|---|---|---|---|
path |
VARCHAR | Full path. Always valid UTF-8: bytes that aren't valid UTF-8 appear as \xNN, and in CSV, control characters are escaped (\n, \t, \xNN). |
|
parent_path |
VARCHAR | Path of the containing directory; empty for /. |
|
name |
VARCHAR | Final path component. For a scan root, the root's own name. | |
extension |
VARCHAR | yes | Lowercased text after the last . of a name that isn't a directory. None for names starting or ending with . or extensions longer than 32 bytes. |
path_raw (text: path_b64) |
BLOB | yes | Exact path bytes, when path differs from them (every row with --raw-paths always). Base64 in CSV and JSON Lines, as path_b64. Exact bytes for any row: coalesce(. |
name_flags |
INTEGER | Bitmask of name properties that cause trouble; see Name flags. | |
kind |
VARCHAR | Entry type; see Kinds. | |
depth |
INTEGER | Levels below the scan root; 0 for the root. | |
dir_id |
BIGINT | yes | For directories, an ID assigned by the scan, unique within it. |
parent_id |
BIGINT | dir_id of the containing directory; 0 for a root. |
|
dev |
UBIGINT | Device of the file system holding the entry (st_dev). Not stable across hosts or remounts. |
|
ino |
UBIGINT | Inode number. Entries with the same (dev, ino) are hard links to one file. |
|
nlink |
BIGINT | Number of hard links. | |
uid |
BIGINT | Owner user ID. | |
gid |
BIGINT | Owner group ID. | |
mode |
INTEGER | Full st_mode: file type and permission bits. |
|
size |
BIGINT | yes | Logical size in bytes. Null when skipped with --fields. |
alloc_bytes |
BIGINT | yes | Space allocated on disk (st_blocks × 512). Smaller than size for sparse, compressed, or tiered files. Null when skipped with --fields. |
atime |
TIMESTAMPTZ | yes | Last access. Null when skipped with --fields. |
mtime |
TIMESTAMPTZ | yes | Last change to the contents. Copies and restores often preserve it. Null when skipped with --fields. |
ctime |
TIMESTAMPTZ | yes | Last change to the contents or metadata. Not creation time. Users can't set it, so it's the reliable signal of recent change. Null when skipped with --fields. |
btime |
TIMESTAMPTZ | yes | Creation (birth) time, when the platform and file system provide it and it isn't skipped with --fields. |
rdev |
UBIGINT | yes | Device number, for character and block devices. |
dir_entries |
BIGINT | yes | For directories that were read: number of immediate children. A subdirectory deleted after it was listed but before it was read is counted, though it has no row. |
dir_files |
BIGINT | yes | For directories that were read: immediate children that aren't directories. |
dir_subdirs |
BIGINT | yes | For directories that were read: immediate subdirectories. |
dir_bytes |
BIGINT | yes | For directories that were read: sum of size over immediate children that aren't directories. |
dir_alloc_bytes |
BIGINT | yes | For directories that were read: sum of alloc_bytes over immediate children that aren't directories. |
is_mount_point |
BOOLEAN | True when this directory is on a different device from its parent. | |
time_flags |
INTEGER | Bitmask of timestamps that couldn't be represented and were clamped: 1 atime, 2 mtime, 4 ctime, 8 btime. |
|
error |
VARCHAR | yes | For directories that couldn't be fully read: the failed operation and error, such as open: EACCES. With --detect-cycles, revisit: already visited through another path marks a directory that was reached again and not re-read. With --stall-timeout, stall: ... marks a directory the scan gave up on. |
symlink_target |
VARCHAR | yes | Where a symlink points, with --symlink-targets, rendered like path; null otherwise. Added in schema version 3, and last so that older CSV readers can ignore it. |
symlink_target_raw (text: symlink_target_b64) |
BLOB | yes | Exact target bytes, when symlink_target differs from them (every symlink with --raw-paths always). Base64 in CSV and JSON Lines, as symlink_target_b64. |
errors#
One row per failed operation. Present only if there were any.
| Column | Type | Null | Description |
|---|---|---|---|
path |
VARCHAR | Path of the entry the operation was on, rendered like entries.path. |
|
path_raw (text: path_b64) |
BLOB | yes | Exact path bytes, when path differs from them. Base64 in CSV and JSON Lines, as path_b64. |
op |
VARCHAR | The failed operation: open, readdir, stat, verify (the directory was replaced during the scan), stall (no progress for --stall-timeout, so the scan gave up on the directory), readlink (reading a symlink's target, with --symlink-targets), or internal. |
|
errno |
INTEGER | yes | The OS error number, when there is one. |
errno_name |
VARCHAR | yes | Symbolic name of errno, such as EACCES. |
message |
VARCHAR | Human-readable description. | |
time |
TIMESTAMPTZ | When the error happened. |
users#
With --resolve-ids: one row per user ID in entries.uid, with its name. Written when the scan finishes.
| Column | Type | Null | Description |
|---|---|---|---|
uid |
BIGINT | A user ID that owns at least one entry. | |
name |
VARCHAR | yes | The user's name, as the scanning host looked it up when the scan finished; null when no account has that ID (such as a deleted user). |
groups#
With --resolve-ids: one row per group ID in entries.gid, with its name. Written when the scan finishes.
| Column | Type | Null | Description |
|---|---|---|---|
gid |
BIGINT | A group ID that owns at least one entry. | |
name |
VARCHAR | yes | The group's name, as the scanning host looked it up when the scan finished; null when no group has that ID. |
rollup#
Written by fs-inventory rollup: one row per directory with totals over its whole subtree. Parquet only.
| Column | Type | Null | Description |
|---|---|---|---|
dir_id |
BIGINT | The directory's dir_id in entries. |
|
parent_id |
BIGINT | dir_id of the containing directory; 0 for a root. |
|
depth |
INTEGER | Levels below the scan root; 0 for the root. | |
path |
VARCHAR | Full path, rendered like entries.path. |
|
path_raw (text: path_b64) |
BLOB | yes | Exact path bytes, when path differs from them. |
entries |
BIGINT | Entries anywhere below this directory, not counting the directory itself. | |
files |
BIGINT | Entries below this directory that aren't directories. | |
dirs |
BIGINT | Directories below this directory. | |
bytes |
BIGINT | Sum of size over entries below this directory that aren't directories. |
|
alloc_bytes |
BIGINT | Sum of alloc_bytes over entries below this directory that aren't directories. |
|
oldest_mtime |
TIMESTAMPTZ | yes | Oldest mtime below this directory, over entries that aren't directories. Null when there are none. |
newest_mtime |
TIMESTAMPTZ | yes | Newest mtime below this directory, over entries that aren't directories. |
newest_ctime |
TIMESTAMPTZ | yes | Newest ctime below this directory, over entries that aren't directories. |
newest_atime |
TIMESTAMPTZ | yes | Newest atime below this directory, over entries that aren't directories. |
incomplete_dirs |
BIGINT | Directories in this subtree, including this one, that weren't read completely: errors, mount points not entered, or --max-depth. When it isn't 0, the totals are lower bounds. |
rollup_ages#
Written by fs-inventory rollup: file counts and bytes by age for each directory down to --age-depth, measured from the scan's start time. Parquet only.
| Column | Type | Null | Description |
|---|---|---|---|
dir_id |
BIGINT | The directory's dir_id; join with rollup or entries for its path. |
|
time |
VARCHAR | Which timestamp the age is measured from: mtime, ctime, or atime. |
|
bucket |
INTEGER | Age bucket, in order: 0 is future (newer than the scan), then increasing age. |
|
label |
VARCHAR | The bucket's label, such as <30d, 1y-2y, or >=10y, from --age-buckets. |
|
files |
BIGINT | Entries below the directory in this bucket that aren't directories. Only buckets with files have rows. | |
bytes |
BIGINT | Sum of size over those entries. |
Name flags#
Bits of name_flags. Decode them in DuckDB with fs_name_flags( from sql/.
| Bit | Name | Meaning |
|---|---|---|
| 1 | invalid_utf8 |
Not valid UTF-8: a legacy encoding (Latin-1, Shift-JIS, ...) or corruption |
| 2 | c0_control |
Contains an ASCII control character, such as a newline or tab |
| 4 | c1_control |
Contains a C1 control character (U+0080 to U+009F) |
| 8 | del |
Contains DEL (U+007F) |
| 16 | bidi_control |
Contains a bidirectional formatting character that can disguise how a name displays |
| 32 | not_nfc |
Valid UTF-8 but not in Unicode Normalization Form C (common from macOS) |
| 64 | leading_trailing_space |
Starts or ends with a space |
| 128 | leading_dash |
Starts with -, which tools can mistake for an option |
| 256 | trailing_dot |
Ends with ., which Windows strips |
| 512 | windows_reserved |
Contains a character Windows forbids (<>:"|?*\) or is a device name such as CON |
| 1024 | long_name |
Longer than 255 bytes |
| 2048 | long_path |
The full path is at least 4,096 bytes |
Kinds#
Values of kind.
| Kind | Meaning |
|---|---|
file |
Regular file |
dir |
Directory |
symlink |
Symbolic link (never followed) |
fifo |
Named pipe |
socket |
Unix domain socket |
char |
Character device |
block |
Block device |
unknown |
Any other type |