Expand description
Per-file Unix timestamps shared across the create / import / export paths, plus the format-specific encoders every non-Unix driver needs to write those same times into its own on-disk shape.
The goal is date-preservation on copy: when rb-cli copies a file from a host
folder, a tar archive, or another disk image into a filesystem, the
destination should record the source’s mtime, not “now”. And a
tar_export (or any host-side extract) of that image should carry the same
mtime back out.
§The rule
create_file / create_directory / create_symlink use these times when
options.unix_times.is_some(); otherwise they stamp now. So:
- Genuine new file (user typed
put, GUI created a blank file) — caller leavesunix_times = None, driver stampsnow. - Copy / extract / import — caller (dir_import / tar_import / Commander stage_copy) captures the source’s mtime and passes it through; the destination inode records it verbatim.
§Why per-field Options
Different sources carry different subsets: a tar Header has only mtime,
an HFS entry has creation + modification + backup dates, an EFS inode has
all three (atime/mtime/ctime). Missing fields aren’t fabricated — the
driver falls back to now (or mtime where sensible) for each.
Values are u64 seconds since UNIX epoch 1970-01-01. Sub-second precision is intentionally dropped: FAT is 2-second granular, EFS/AFFS/PFS3 are 1- second, only ext/xfs/jfs carry nanoseconds — and the tar exporter only writes seconds anyway, so nanos wouldn’t round-trip end-to-end.
§Format encoders
Every filesystem below rusty-backup edits carries dates in some shape:
DOS packed (FAT / exFAT / Human68k), NTFS FILETIME, Mac epoch (HFS /
HFS+ / MFS), ProDOS packed, UCSD packed, ADFS 40-bit centiseconds, OS-9
Y-M-D bytes, QDOS 1961 epoch. Each encoder in this module turns a Unix
u64 seconds value into that shape; each decoder is the inverse and
returns None on the format’s “no date set” sentinel (usually a
literal zero on disk).
Encoders clamp to the format’s earliest representable date rather than
underflowing — a FAT file dated 1975 becomes 1980-01-01, not garbage.
Decoders return None for zero and for values that would land before
1970, so a modified_unix never carries a suspicious 1969 / 1970-01-01
for what is on disk actually “no timestamp”.
Structs§
- Unix
Times - A snapshot of a file’s Unix timestamps, in seconds since 1970-01-01.
Constants§
- EXFAT_
UTC_ OFFSET_ VALID - exFAT UtcOffset bit 7: the low 7 bits hold a valid offset in 15-minute steps.
Functions§
- adfs_
time_ to_ unix - Decode an ADFS (load_addr, exec_addr) pair to Unix seconds. Returns
Nonewhen load_addr’s high 12 bits aren’t0xFFF(which means the pair is a real load/exec address, not a datestamp) or when the resulting timestamp would land before 1970. - dos_
datetime_ to_ unix - Decode a FAT (date, time) pair back to Unix seconds. Returns
Nonefor a zerodate(the “no date set” sentinel every DOS filesystem tool uses) or for a date field whose components don’t make sense (month 0, day 0, day > days-in-month, etc). Raw and zone-less: the words are read as UTC. FAT stores local wall-clock time, so drivers usedos_local_to_unix. - dos_
local_ now - The current wall clock as FAT (date, time) words.
- dos_
local_ to_ unix - FAT’s local wall-clock (date, time) words back to Unix seconds (UTC).
- exfat_
local_ now - The current wall clock as an exFAT (timestamp, UtcOffset) pair.
- exfat_
local_ to_ unix - An exFAT (timestamp, UtcOffset) pair back to Unix seconds. With no valid offset the stamp is the local wall clock of an unknown zone, read as this host’s (as Linux does).
- exfat_
timestamp_ to_ unix - Inverse of
unix_to_exfat_timestamp. Raw and zone-less like the DOS pair; drivers useexfat_local_to_unix, which honours the UtcOffset byte. - filetime_
to_ unix - Decode an NTFS FILETIME back to Unix seconds. Returns
Nonefor a zero FILETIME (NTFS’s “unset” sentinel) or for a FILETIME that would land before 1970 (the tar oracle would render those as 1969 either way, and no real NTFS volume dates a file before 1970). - local_
utc_ offset_ secs - Seconds this host’s local time is ahead of UTC, for the filesystems that store wall-clock time with no zone (HFS, MFS, FAT, Human68k, ProDOS). The current offset, not the date’s.
- mac_
epoch_ to_ unix - Decode a Mac epoch u32 back to Unix seconds. Mirrors
hfs_common::mac_date_to_unix— returnsNonefor zero (the “no date” sentinel) and for pre-1970 Mac dates (which would tar out as 1969). - mac_
local_ now - The current wall clock as a classic-Mac local-time stamp.
- mac_
local_ to_ unix - A classic-Mac local-time stamp back to Unix seconds (UTC).
- now
- Current wall-clock time as seconds since UNIX epoch. Clamped to 0 on the
(impossible) pre-1970 system clock. Replaces every driver’s
SystemTime::now().duration_since(UNIX_EPOCH).unwrap_or_default().as_secs()dance with one function. - now_u32
now()clamped into a u32 (used by drivers with 32-bit time fields — EFS, UFS-v1, XFS-v4, FAT/exFAT date halves). u32 overflows in 2106; we document but do not guard against it (no user has a 2106-vintage disk).- os9_
dat_ to_ unix - Decode an OS-9 FD.DAT to Unix seconds. Returns
Nonefor all-zero (unwritten) or nonsensical component values. - os9_
dcr_ to_ unix - Decode an OS-9 FD.DCR (creation date only) to Unix seconds. Returns
Nonefor all-zero or pre-1970 dates. - prodos_
datetime_ to_ unix - Decode a ProDOS (date, time) pair back to Unix seconds. Returns
Nonefor a zerodate(“no date set” — ProDOS Technical Note #28 formalises this). Raw and zone-less; drivers useprodos_local_to_unix. - prodos_
local_ now - The current wall clock as a ProDOS (date, time) pair.
- prodos_
local_ to_ unix - A ProDOS local wall-clock (date, time) pair back to Unix seconds (UTC).
- qdos_
date_ to_ unix - Decode a QDOS timestamp to Unix seconds. Returns
Nonefor zero (the “no date set” sentinel) or for QDOS values that would land before 1970. - resolve_
or_ now - The
now-fallback rule the drivers use in one place: return the givenUnixTimesif any field is set, otherwise a fresh all-fieldsnow. - ucsd_
date_ to_ unix - Decode a UCSD Pascal packed date to Unix seconds (00:00:00 of that day).
Returns
Nonefor zero, and for pre-1970 dates (which would round-trip through tar as 1969 anyway; the year field’s 1900..1999 range means any UCSD-native date can be pre-1970, so this guard matters). - unix_
to_ adfs_ time - Encode Unix seconds as an ADFS timestamped (load_addr, exec_addr)
pair carrying the given RISC OS filetype (12 bits: 0xFFF = Data,
0xFEB = Obey, etc.).
load_addr = 0xFFF_00000 | ((ft & 0xFFF) << 8) | ((cs40 >> 32) as u8);exec_addr = cs40 as u32. The 0xFFF-in- high-12-bits pattern is the “this is a datestamp, not a load address” marker every RISC OS tool checks for. - unix_
to_ dos_ datetime - Encode Unix seconds as (fat_date, fat_time) — the two 16-bit words FAT
dirent slots hold.
fat_datelayout:year_since_1980 (7) | month (4) | day (5);fat_timelayout:hour (5) | minute (6) | second/2 (5). - unix_
to_ dos_ local - Unix seconds to FAT’s (date, time) words as the local wall clock, as DOS and Windows write them.
- unix_
to_ exfat_ local - Unix seconds to an exFAT (timestamp, UtcOffset) pair: local time tagged with the host offset. A host offset exFAT cannot express (not whole quarter hours) is written as UTC, offset 0.
- unix_
to_ exfat_ timestamp - exFAT packs the two 16-bit DOS words into a single u32 (date in the
upper half, time in the lower). Layer over
unix_to_dos_datetime. - unix_
to_ filetime - Encode Unix seconds as an NTFS FILETIME (100-nanosecond intervals since 1601-01-01). Sub-second precision is lost, which is fine — every other source in the import chain (host stat, tar Header, cross-fs copy) is second-granular anyway.
- unix_
to_ lif_ bcd - Encode Unix seconds as HP LIF’s 6-byte BCD
YYMMDDhhmmss; years outside 1970-2069 clamp. - unix_
to_ mac_ epoch - Encode Unix seconds as a Mac epoch u32, clamping at both ends: a bogus future mtime on an extracted archive used to wrap into 1904..1970.
- unix_
to_ mac_ local - Unix seconds to a classic-Mac local-time stamp: the wall clock the Mac shows.
- unix_
to_ os9_ dat - Encode Unix seconds as OS-9 FD.DAT (5 bytes: year-1900, month, day, hour, minute). OS-9’s year is a single unsigned byte — 1900..2155 representable. Pre-1900 clamps to 1900-01-01; post-2155 clamps to 2155-12-31.
- unix_
to_ os9_ dcr - Encode Unix seconds as OS-9 FD.DCR (3 bytes: year-1900, month, day).
- unix_
to_ prodos_ datetime - Encode Unix seconds as a ProDOS (date, time) pair. Date layout:
year (7) | month (4) | day (5)where year isyear - 2000when < 40 elseyear - 1900(ProDOS’s own two-digit convention — years 40..99 mean 1940..1999, years 0..39 mean 2000..2039). Time layout:hour (5) | minute (6)(no seconds — ProDOS is minute-granular). - unix_
to_ prodos_ local - Unix seconds to a ProDOS (date, time) pair on the local wall clock an Apple II clock card keeps.
- unix_
to_ qdos_ date - Encode Unix seconds as a QDOS timestamp (u32 seconds since 1961-01-01, big-endian on disk — but the encoding is byte-order-agnostic here). Pre-1961 clamps to 0 (1961-01-01); post-2097-02-06 truncates by u32 wraparound. No QDOS tool guards against either.
- unix_
to_ ucsd_ date - Encode Unix seconds as a UCSD Pascal packed date. Layout (little-endian
as it sits in the dirent, but treated here as a plain u16):
year (7) | month (4) | day (5)— years are 2-digit like ProDOS, but UCSD’s convention is different: 0..99 all map to 1900..1999.