ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
ra8_fs_fat_time_internal.h File Reference

On-disk timestamp field offsets, packing constants, and stampers. More...

#include <stdint.h>
#include "ra8_attributes.h"
#include "ra8_fs.h"
Include dependency graph for ra8_fs_fat_time_internal.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Enumerations

enum  ra8_fs_time_off_t : uint8_t {
  k_dir_off_crt_time_tenth = 13 ,
  k_dir_off_crt_time = 14 ,
  k_dir_off_crt_date = 16 ,
  k_dir_off_lst_acc_date = 18 ,
  k_dir_off_wrt_time = 22 ,
  k_dir_off_wrt_date = 24
}
 Byte offsets of the timestamp fields in a 32-byte FAT directory entry. More...
enum  ra8_fs_exfat_time_off_t : uint8_t {
  k_exfat_off_file_ctime = 8 ,
  k_exfat_off_file_mtime = 12 ,
  k_exfat_off_file_atime = 16 ,
  k_exfat_off_file_c10ms = 20 ,
  k_exfat_off_file_m10ms = 21 ,
  k_exfat_off_file_cutc = 22 ,
  k_exfat_off_file_mutc = 23 ,
  k_exfat_off_file_autc = 24
}
 Byte offsets of the timestamp fields in an exFAT File entry (0x85). More...
enum  ra8_fs_time_pack_t : uint32_t {
  k_fs_time_epoch_year = 1980U ,
  k_fs_time_year_max = 2107U ,
  k_fs_time_month_min = 1U ,
  k_fs_time_month_max = 12U ,
  k_fs_time_day_min = 1U ,
  k_fs_time_day_max = 31U ,
  k_fs_time_hour_max = 23U ,
  k_fs_time_minute_max = 59U ,
  k_fs_time_second_max = 59U ,
  k_fs_time_centi_max = 99U ,
  k_fs_date_shift_year = 9U ,
  k_fs_date_shift_month = 5U ,
  k_fs_time_shift_hour = 11U ,
  k_fs_time_shift_minute = 5U ,
  k_fs_time_second_div = 2U ,
  k_fs_xf_shift_date = 16U ,
  k_fs_xf_shift_month = 5U ,
  k_fs_xf_shift_year = 9U ,
  k_fs_centi_per_second = 100U ,
  k_fs_utc_step_min = 15U ,
  k_fs_utc_valid_bit = 0x80U ,
  k_fs_utc_field_mask = 0x7FU ,
  k_fs_utc_unknown = 0x00U ,
  k_fs_time_epoch_fat_date = 0x0021U
}
 Bit positions, field ranges, and epoch constants for both packings. More...
enum  ra8_fs_utc_span_t : int16_t {
  k_fs_utc_span_min = -720 ,
  k_fs_utc_span_max = 840
}
 The signed range of UTC offsets exFAT's 7-bit field can express. More...

Functions

void priv_fat_entry_stamp_create (uint8_t *entry)
 Stamp a fresh FAT directory entry's create, write, and access fields.
void priv_fat_entry_stamp_write (uint8_t *entry)
 Advance a FAT directory entry's modification time and access date.
void priv_fat_entry_stamp_access (uint8_t *entry)
 Advance only a FAT directory entry's last-access date.
void priv_exfat_file_stamp_create (uint8_t *file_entry)
 Stamp a fresh exFAT File entry's create, modify, and access fields.
void priv_exfat_file_stamp_access (uint8_t *file_entry)
 Advance only an exFAT File entry's last-accessed stamp.
void priv_fat_entry_set_times (uint8_t *entry, const ra8_fs_datetime_t *create, const ra8_fs_datetime_t *modify, const ra8_fs_datetime_t *access)
 Set chosen FAT directory-entry timestamps from caller-supplied readings.
void priv_exfat_file_set_times (uint8_t *file_entry, const ra8_fs_datetime_t *create, const ra8_fs_datetime_t *modify, const ra8_fs_datetime_t *access)
 Set chosen exFAT File-entry timestamps from caller-supplied readings.
void priv_exfat_file_stamp_write (uint8_t *file_entry)
 Advance an exFAT File entry's modification (and access) stamps.

Detailed Description

On-disk timestamp field offsets, packing constants, and stampers.

The module-private half of the wall-clock seam (ra8_fs_set_clock()). It carries the byte offsets of the timestamp fields inside a 32-byte FAT directory entry and inside an exFAT File entry, the bit layout both formats pack a date and a time into, and the five stamping helpers the create / write / rename paths call.

The stampers deliberately take a raw entry pointer rather than a mount or a file handle: a timestamp is a property of the 32 bytes being assembled, and keeping it that way means the helper can be applied to an entry that is still in a stack buffer (a fresh directory slot, a "." link, an exFAT entry set being built) as easily as to one just read back off the volume.

Pulled in by the ra8_fs_fat_internal.h umbrella, so every ra8_fs_fat*.c file sees it; included by nothing outside this module.

References (every shorthand citation in this file):

  • "MS FAT spec" = Microsoft Corp., "FAT: General Overview of On-Disk Format", v1.03, December 6 2000.
  • "exFAT spec" = Microsoft Corp., "exFAT file system specification", revision 1.00, section 7.4 "File Directory Entry".
Since
0.1.0

Definition in file ra8_fs_fat_time_internal.h.

Enumeration Type Documentation

◆ ra8_fs_exfat_time_off_t

enum ra8_fs_exfat_time_off_t : uint8_t

Byte offsets of the timestamp fields in an exFAT File entry (0x85).

exFAT spec sec 7.4. The three 32-bit stamps share one packed layout (ra8_fs_time_pack_t); the 10ms fields recover the odd second and the hundredths that the 2-second stamp granularity throws away; the UtcOffset bytes say which zone the civil time in the stamp belongs to.

Invariant
Every offset addresses a field wholly inside one 32-byte entry.
See also
priv_exfat_file_stamp_create()
Since
0.1.0
Enumerator
k_exfat_off_file_ctime 

exFAT spec sec 7.4.8 "CreateTimestamp".

k_exfat_off_file_mtime 

exFAT spec sec 7.4.9 "LastModifiedTimestamp".

k_exfat_off_file_atime 

exFAT spec sec 7.4.10 "LastAccessedTimestamp".

k_exfat_off_file_c10ms 

exFAT spec sec 7.4.11 "Create10msIncrement".

k_exfat_off_file_m10ms 

exFAT spec sec 7.4.12 "LastModified10ms".

k_exfat_off_file_cutc 

exFAT spec sec 7.4.13 "CreateUtcOffset".

k_exfat_off_file_mutc 

exFAT spec sec 7.4.14 "LastModifiedUtcOffset".

k_exfat_off_file_autc 

exFAT spec sec 7.4.15 "LastAccessedUtcOffset".

Definition at line 76 of file ra8_fs_fat_time_internal.h.

◆ ra8_fs_time_off_t

enum ra8_fs_time_off_t : uint8_t

Byte offsets of the timestamp fields in a 32-byte FAT directory entry.

MS FAT spec sec 6, table "Directory Entry". These are the fields priv_write_new_dir_entry() used to leave as zeros: a zero DIR_CrtDate / DIR_WrtDate encodes month 0 and day 0, and both are 1-based, so it is not a date any host can agree on.

Invariant
Every offset addresses a field wholly inside one 32-byte entry.
See also
priv_fat_entry_stamp_create()
Since
0.1.0
Enumerator
k_dir_off_crt_time_tenth 

MS FAT spec sec 6 "DIR_CrtTimeTenth".

k_dir_off_crt_time 

MS FAT spec sec 6 "DIR_CrtTime".

k_dir_off_crt_date 

MS FAT spec sec 6 "DIR_CrtDate".

k_dir_off_lst_acc_date 

MS FAT spec sec 6 "DIR_LstAccDate".

k_dir_off_wrt_time 

MS FAT spec sec 6 "DIR_WrtTime".

k_dir_off_wrt_date 

MS FAT spec sec 6 "DIR_WrtDate".

Definition at line 53 of file ra8_fs_fat_time_internal.h.

◆ ra8_fs_time_pack_t

enum ra8_fs_time_pack_t : uint32_t

Bit positions, field ranges, and epoch constants for both packings.

FAT splits the stamp across two 16-bit words (MS FAT spec sec 6): date = year-1980 << 9 | month << 5 | day, time = hour << 11 | minute << 5 | second/2. exFAT packs the same six fields into one 32-bit word (exFAT spec sec 7.4.8) with the time in the low half and the date in the high half, which is why the two share the sub-field shifts below.

Invariant
The epoch is 1980 in both formats; the year field is 7 bits, so 2107 is the last representable year.
See also
priv_fat_entry_stamp_create()
Since
0.1.0
Enumerator
k_fs_time_epoch_year 

Year 0 of both on-disk formats.

k_fs_time_year_max 

1980 + 127: last representable year.

k_fs_time_month_min 

Month is 1-based on disk.

k_fs_time_month_max 

Highest month.

k_fs_time_day_min 

Day is 1-based on disk.

k_fs_time_day_max 

Highest day the field can express.

k_fs_time_hour_max 

Highest hour.

k_fs_time_minute_max 

Highest minute.

k_fs_time_second_max 

Highest second.

k_fs_time_centi_max 

Highest hundredth within a second.

k_fs_date_shift_year 

FAT date: year field position.

k_fs_date_shift_month 

FAT date: month field position.

k_fs_time_shift_hour 

FAT time: hour field position.

k_fs_time_shift_minute 

FAT time: minute field position.

k_fs_time_second_div 

FAT/exFAT store seconds/2.

k_fs_xf_shift_date 

exFAT stamp: date half position.

k_fs_xf_shift_month 

exFAT date half: month field position.

k_fs_xf_shift_year 

exFAT date half: year field position.

k_fs_centi_per_second 

Hundredths in one second.

k_fs_utc_step_min 

exFAT UtcOffset granularity, minutes.

k_fs_utc_valid_bit 

exFAT UtcOffset bit 7 = OffsetValid.

k_fs_utc_field_mask 

exFAT UtcOffset bits 6:0 = the offset.

k_fs_utc_unknown 

OffsetValid clear: zone not recorded.

k_fs_time_epoch_fat_date 

1980-01-01 packed: month 1, day 1.

Definition at line 103 of file ra8_fs_fat_time_internal.h.

◆ ra8_fs_utc_span_t

enum ra8_fs_utc_span_t : int16_t

The signed range of UTC offsets exFAT's 7-bit field can express.

Kept apart from ra8_fs_time_pack_t because these are the only negative constants in the timestamp layer and that enum's underlying type is unsigned. UTC-12:00 and UTC+14:00 are the real extremes of civil time on Earth, and both land inside the 7-bit two's-complement field (-48 and +56 fifteen-minute steps).

Invariant
Both bounds are whole multiples of k_fs_utc_step_min.
See also
priv_exfat_file_stamp_create()
Since
0.1.0
Enumerator
k_fs_utc_span_min 

UTC-12:00 expressed in minutes.

k_fs_utc_span_max 

UTC+14:00 expressed in minutes.

Definition at line 144 of file ra8_fs_fat_time_internal.h.

Function Documentation

◆ priv_exfat_file_set_times()

void priv_exfat_file_set_times ( uint8_t * file_entry,
const ra8_fs_datetime_t * create,
const ra8_fs_datetime_t * modify,
const ra8_fs_datetime_t * access )

Set chosen exFAT File-entry timestamps from caller-supplied readings.

The exFAT counterpart of priv_fat_entry_set_times, with the two side fields exFAT carries: create and modify each write their 32-bit timestamp, their 10 ms increment and their UtcOffset byte; access writes LastAccessedTimestamp and its UtcOffset (exFAT has no last-accessed 10 ms field). Every non-NULL reading is treated as a real instant, so its UtcOffset is honoured (OffsetValid set when the offset is a whole 15-minute step in UTC-12:00..UTC+14:00, else recorded unknown). Each reading is clamped before packing.

Parameters
[in,out]file_entry32-byte exFAT File (0x85) entry to patch in place.
[in]createCreate stamp, or NULL to leave it unchanged.
[in]modifyModify stamp, or NULL to leave it unchanged.
[in]accessAccess stamp, or NULL to leave it unchanged.
Returns
Nothing.
Precondition
file_entry is non-NULL and addresses 32 writable bytes.
file_entry is a File entry; the caller recomputes SetChecksum after.
Postcondition
Each non-NULL reading's fields hold that (clamped) instant.
No timestamp whose argument was NULL is modified.
Warning
The entry set's SetChecksum covers these bytes – recompute it after patching or the volume fails a host fsck.
Note
Callers serialise filesystem operations.
Since
0.1.0

Definition at line 573 of file ra8_fs_fat_time.c.

References exfat_stamp_t::inc10, internal_clamp_datetime(), internal_exfat_pack(), k_exfat_off_file_atime, k_exfat_off_file_autc, k_exfat_off_file_c10ms, k_exfat_off_file_ctime, k_exfat_off_file_cutc, k_exfat_off_file_m10ms, k_exfat_off_file_mtime, k_exfat_off_file_mutc, priv_wr32(), exfat_stamp_t::stamp, and exfat_stamp_t::utc.

Referenced by internal_utime_exfat().

◆ priv_exfat_file_stamp_access()

void priv_exfat_file_stamp_access ( uint8_t * file_entry)

Advance only an exFAT File entry's last-accessed stamp.

The exFAT counterpart of priv_fat_entry_stamp_access, taken by the rename path for the same reason: the name changed, the bytes did not. Writes LastAccessedTimestamp and its UtcOffset byte; exFAT has no last-accessed 10ms field, so there is none to write.

Parameters
[in,out]file_entry32-byte exFAT File (0x85) entry to stamp in place.
Returns
Nothing.
Precondition
file_entry is non-NULL and addresses 32 writable bytes.
file_entry was read back from the volume as part of an entry set.
Postcondition
LastAccessedTimestamp and LastAccessedUtcOffset hold the current stamp.
The create and modify fields are unchanged.
Warning
The entry set's SetChecksum covers these bytes – recompute it after.
Note
Not thread-safe against ra8_fs_set_clock; install the clock first.
Since
0.1.0

Definition at line 532 of file ra8_fs_fat_time.c.

References internal_exfat_stamp_now(), k_exfat_off_file_atime, k_exfat_off_file_autc, priv_wr32(), exfat_stamp_t::stamp, and exfat_stamp_t::utc.

Referenced by internal_exfat_build_rename_set().

◆ priv_exfat_file_stamp_create()

void priv_exfat_file_stamp_create ( uint8_t * file_entry)

Stamp a fresh exFAT File entry's create, modify, and access fields.

The exFAT counterpart of priv_fat_entry_stamp_create, and it has three more fields to get right than FAT does: the 10ms increments that recover the odd second the 2-second stamp granularity drops, and the UtcOffset bytes that say which zone the civil time belongs to. An offset the format cannot express (not a whole 15-minute step, or outside UTC-12:00..UTC+14:00) is recorded as k_fs_utc_unknown – OffsetValid clear – rather than guessed.

Parameters
[in,out]file_entry32-byte exFAT File (0x85) entry to stamp in place.
Returns
Nothing.
Precondition
file_entry is non-NULL and addresses 32 writable bytes.
file_entry is a File entry; the caller recomputes SetChecksum after.
Postcondition
All three stamps, both 10ms fields, and all three UtcOffset bytes are set.
No byte outside offsets 8..24 is modified.
Warning
The entry set's SetChecksum covers these bytes – recompute it after stamping or the volume fails a host fsck.
Note
Not thread-safe against ra8_fs_set_clock; install the clock first.
Since
0.1.0

Definition at line 505 of file ra8_fs_fat_time.c.

References exfat_stamp_t::inc10, internal_exfat_stamp_now(), k_exfat_off_file_atime, k_exfat_off_file_autc, k_exfat_off_file_c10ms, k_exfat_off_file_ctime, k_exfat_off_file_cutc, k_exfat_off_file_m10ms, k_exfat_off_file_mtime, k_exfat_off_file_mutc, priv_wr32(), exfat_stamp_t::stamp, and exfat_stamp_t::utc.

Referenced by internal_exfat_build_dir_set(), and internal_exfat_build_set().

◆ priv_exfat_file_stamp_write()

void priv_exfat_file_stamp_write ( uint8_t * file_entry)

Advance an exFAT File entry's modification (and access) stamps.

The exFAT counterpart of priv_fat_entry_stamp_write, taken by every flush of a streaming write. It moves LastModifiedTimestamp, its 10 ms increment and its UtcOffset – the three fields that together say WHEN the bytes on the card were put there – and LastAccessedTimestamp with them, because a write is an access. The creation fields are deliberately untouched: a truncate-in-place keeps a file's identity, and its birthday is part of that.

Parameters
[in,out]file_entry32-byte exFAT File (0x85) entry to stamp in place.
Returns
Nothing.
Precondition
file_entry is non-NULL and addresses 32 writable bytes.
file_entry was read back from the volume as part of an entry set.
Postcondition
The modified and accessed stamps name the current instant.
CreateTimestamp, Create10msIncrement and CreateUtcOffset are unchanged.
Warning
The entry set's SetChecksum covers these bytes – recompute it after stamping or the volume fails a host fsck.
Note
Not thread-safe against ra8_fs_set_clock; install the clock first.
Since
0.1.0

Definition at line 520 of file ra8_fs_fat_time.c.

References exfat_stamp_t::inc10, internal_exfat_stamp_now(), k_exfat_off_file_atime, k_exfat_off_file_autc, k_exfat_off_file_m10ms, k_exfat_off_file_mtime, k_exfat_off_file_mutc, priv_wr32(), exfat_stamp_t::stamp, and exfat_stamp_t::utc.

Referenced by priv_exfat_flush_set().

◆ priv_fat_entry_set_times()

void priv_fat_entry_set_times ( uint8_t * entry,
const ra8_fs_datetime_t * create,
const ra8_fs_datetime_t * modify,
const ra8_fs_datetime_t * access )

Set chosen FAT directory-entry timestamps from caller-supplied readings.

The utime primitive (ra8_fs_utime()): each non-NULL argument overwrites its timestamp fields, each NULL one leaves them exactly as they are. create writes DIR_CrtTimeTenth / DIR_CrtTime / DIR_CrtDate; modify writes DIR_WrtTime / DIR_WrtDate; access writes DIR_LstAccDate (FAT has no last-access time). Unlike the clock-driven stampers this takes explicit readings, so a backup/restore can put an original create/modify time back rather than the moment of the restore. Each reading is clamped into the on-disk range before packing, so an out-of-range field degrades to the nearest legal one and never fails the call.

Parameters
[in,out]entry32-byte directory entry to patch in place.
[in]createCreate stamp to write, or NULL to leave it unchanged.
[in]modifyModify stamp to write, or NULL to leave it unchanged.
[in]accessAccess stamp to write, or NULL to leave it unchanged.
Returns
Nothing.
Precondition
entry is non-NULL and addresses 32 writable bytes.
A non-NULL reading argument points at a readable ra8_fs_datetime_t.
Postcondition
Each non-NULL reading's fields hold that (clamped) instant.
No timestamp whose argument was NULL is modified, nor any non-time byte.
Note
Not thread-safe against ra8_fs_set_clock is irrelevant here – this reads no clock; callers still serialise filesystem operations.
Since
0.1.0

Definition at line 541 of file ra8_fs_fat_time.c.

References fat_stamp_t::date, internal_clamp_datetime(), internal_fat_pack(), k_dir_off_crt_date, k_dir_off_crt_time, k_dir_off_crt_time_tenth, k_dir_off_lst_acc_date, k_dir_off_wrt_date, k_dir_off_wrt_time, priv_wr16(), fat_stamp_t::tenth, and fat_stamp_t::time.

Referenced by internal_utime_fat().

◆ priv_fat_entry_stamp_access()

void priv_fat_entry_stamp_access ( uint8_t * entry)

Advance only a FAT directory entry's last-access date.

What a rename gets. A rename changes the name, not the bytes, so advancing DIR_WrtDate would tell every rsync, backup and OTA "newest image" heuristic that the contents changed – the exact class of false positive #601 exists to remove, only inverted. FAT has no separate metadata-change field, so the honest record of "this entry was touched" is the access date, which is also the only access field FAT has (there is no last-access TIME).

Parameters
[in,out]entry32-byte directory entry to stamp in place.
Returns
Nothing.
Precondition
entry is non-NULL and addresses 32 writable bytes.
entry was read back from the volume.
Postcondition
DIR_LstAccDate holds today's packed date.
Every other byte of entry is unchanged.
Note
Not thread-safe against ra8_fs_set_clock; install the clock first.
Since
0.1.0

Definition at line 497 of file ra8_fs_fat_time.c.

References fat_stamp_t::date, internal_fat_stamp_now(), k_dir_off_lst_acc_date, and priv_wr16().

Referenced by internal_fat_rename().

◆ priv_fat_entry_stamp_create()

void priv_fat_entry_stamp_create ( uint8_t * entry)

Stamp a fresh FAT directory entry's create, write, and access fields.

Reads the installed clock once (or falls back to the FAT epoch) and writes DIR_CrtTimeTenth, DIR_CrtTime, DIR_CrtDate, DIR_LstAccDate, DIR_WrtTime and DIR_WrtDate from that single reading, so a newly created file's three dates agree with each other instead of straddling a clock tick.

Parameters
[in,out]entry32-byte directory entry to stamp in place.
Returns
Nothing.
Precondition
entry is non-NULL and addresses 32 writable bytes.
The other fields of entry (name, attribute, cluster) are already set or will be set without disturbing offsets 13..25.
Postcondition
Every timestamp field of entry holds a legal calendar value.
No field outside offsets 13..25 is modified.
Note
Not thread-safe against ra8_fs_set_clock; install the clock first.
Since
0.1.0

Definition at line 474 of file ra8_fs_fat_time.c.

References fat_stamp_t::date, internal_fat_stamp_now(), k_dir_off_crt_date, k_dir_off_crt_time, k_dir_off_crt_time_tenth, k_dir_off_lst_acc_date, k_dir_off_wrt_date, k_dir_off_wrt_time, priv_wr16(), fat_stamp_t::tenth, and fat_stamp_t::time.

Referenced by internal_create_new(), internal_fat_mkdir(), internal_fat_put_vol_id(), and internal_pack_dot_entry().

◆ priv_fat_entry_stamp_write()

void priv_fat_entry_stamp_write ( uint8_t * entry)

Advance a FAT directory entry's modification time and access date.

The write half: DIR_WrtTime / DIR_WrtDate (what every host shows as "date modified" and what every backup and sync tool keys on) plus DIR_LstAccDate, because writing is also accessing. The create fields are left exactly as they are – a file created on a PC keeps the PC's creation date.

Parameters
[in,out]entry32-byte directory entry to stamp in place.
Returns
Nothing.
Precondition
entry is non-NULL and addresses 32 writable bytes.
entry was read back from the volume (or is being assembled for it).
Postcondition
DIR_WrtTime, DIR_WrtDate and DIR_LstAccDate hold the current stamp.
The create fields at offsets 13..17 are unchanged.
Note
Not thread-safe against ra8_fs_set_clock; install the clock first.
Since
0.1.0

Definition at line 487 of file ra8_fs_fat_time.c.

References fat_stamp_t::date, internal_fat_stamp_now(), k_dir_off_lst_acc_date, k_dir_off_wrt_date, k_dir_off_wrt_time, priv_wr16(), and fat_stamp_t::time.

Referenced by internal_close_stamp(), internal_fat_put_vol_id(), internal_fat_trunc_commit(), and internal_truncate_existing().