Skip to main content

Module times

Module times 

Source
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 leaves unix_times = None, driver stamps now.
  • 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§

UnixTimes
A snapshot of a file’s Unix timestamps, in seconds since 1970-01-01.

Functions§

adfs_time_to_unix
Decode an ADFS (load_addr, exec_addr) pair to Unix seconds. Returns None when load_addr’s high 12 bits aren’t 0xFFF (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 None for a zero date (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). Values are treated as UTC — FAT stores wall-clock time with no timezone, and every tool we round-trip against does the same.
exfat_timestamp_to_unix
Inverse of unix_to_exfat_timestamp.
filetime_to_unix
Decode an NTFS FILETIME back to Unix seconds. Returns None for 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 (classic HFS, MFS).
mac_epoch_to_unix
Decode a Mac epoch u32 back to Unix seconds. Mirrors hfs_common::mac_date_to_unix — returns None for 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 None for all-zero (unwritten) or nonsensical component values.
os9_dcr_to_unix
Decode an OS-9 FD.DCR (creation date only) to Unix seconds. Returns None for all-zero or pre-1970 dates.
prodos_datetime_to_unix
Decode a ProDOS (date, time) pair back to Unix seconds. Returns None for a zero date (“no date set” — ProDOS Technical Note #28 formalises this).
qdos_date_to_unix
Decode a QDOS timestamp to Unix seconds. Returns None for 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 given UnixTimes if any field is set, otherwise a fresh all-fields now.
ucsd_date_to_unix
Decode a UCSD Pascal packed date to Unix seconds (00:00:00 of that day). Returns None for 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_date layout: year_since_1980 (7) | month (4) | day (5); fat_time layout: hour (5) | minute (6) | second/2 (5).
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 is year - 2000 when < 40 else year - 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_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.