|
ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
|
Cross-TU prototypes of the VFAT long-name WRITE seam. More...
Go to the source code of this file.
Functions | |
| ra8_fs_name_kind_t | priv_name_classify (const char *leaf, uint16_t *out_units, uint32_t *out_nunits, uint8_t *out83, uint8_t *out_ntres) |
| Decide whether a leaf needs one entry, one entry plus case flags, or a chain. | |
| void | priv_lfn_alias_basis (const uint16_t *leaf, uint32_t n, uint32_t tail, uint8_t *out11) |
| Derive the LONGNA~N.TXT 8.3 alias a long name is filed under. | |
| uint8_t | priv_sfn_checksum (const uint8_t *name83) |
| Compute the 8.3 short-name checksum carried in each LFN directory entry. | |
| void | priv_lfn_fill_slot (uint8_t *ent, const uint16_t *name, uint32_t nlen, uint32_t order, uint8_t is_last, uint8_t csum) |
Fill one 32-byte slot with the order -th group of a long name. | |
| ra8_err_t | priv_dir_find_free_run (const ra8_fs_mount_t *m, const dir_loc_t *loc, uint32_t need, dir_slot_t *out) |
Locate need consecutive free entry slots in a given directory. | |
| ra8_err_t | priv_dir_reserve (const ra8_fs_mount_t *m, const dir_loc_t *loc, const char *leaf, dir_insert_t *out) |
| Decide how a name will be stored and set aside the slots for it. | |
| ra8_err_t | priv_dir_commit (const ra8_fs_mount_t *m, const dir_insert_t *plan, const uint8_t *tmpl, uint64_t *out_lba, uint32_t *out_off) |
| Write a reserved run: the long-name chain, then the 8.3 entry. | |
| ra8_err_t | priv_dir_lookup_any (const ra8_fs_mount_t *m, const dir_loc_t *loc, const char *leaf, uint64_t *out_lba, uint32_t *out_off, uint8_t out_entry[k_ra8_fs_dir_entry_bytes]) |
| Resolve one leaf name by 8.3 first and by long name second. | |
| ra8_err_t | priv_dir_erase_chain (const ra8_fs_mount_t *m, const dir_loc_t *loc, uint64_t lba, uint32_t off, const uint8_t *name83) |
| Delete a directory entry together with its long-name chain. | |
Cross-TU prototypes of the VFAT long-name WRITE seam.
The adapter's general cross-TU prototypes live in the two alphabetical halves ra8_fs_fat_protos_a_internal.h and ra8_fs_fat_protos_b_internal.h. The helpers declared here are kept apart from those because they are one feature rather than one letter range: everything open, mkdir, rename, unlink and rmdir need in order to FILE a name that is not 8.3-representable, find it again, and take it away without leaving the chain behind. Splitting them out also keeps the two halves inside the 1000-line source cap, which they were already close to.
The seam spans three translation units, so the declarations cannot live in any one of them:
Aggregated by the ra8_fs_fat_internal.h umbrella, like the other two.
Definition in file ra8_fs_fat_lfn_write_internal.h.
| ra8_err_t priv_dir_commit | ( | const ra8_fs_mount_t * | m, |
| const dir_insert_t * | plan, | ||
| const uint8_t * | tmpl, | ||
| uint64_t * | out_lba, | ||
| uint32_t * | out_off ) |
Write a reserved run: the long-name chain, then the 8.3 entry.
Fills the slots priv_dir_reserve() set aside. The chain is written back to front – the physically first slot carries the HIGHEST order number with the 0x40 "last logical group" flag – because that is the order a scanner reassembles them in, and every slot carries the checksum of the 8.3 name that closes the run. The 8.3 entry itself is tmpl with its name and DIR_NTRes fields replaced, so the caller decides the attribute, the first cluster and the size, and rename can carry an existing entry across unchanged.
| [in] | m | Mounted FAT12/16/32 volume. |
| [in] | plan | Reservation produced by priv_dir_reserve(). |
| [in] | tmpl | 32-byte entry template; name and NTRes are overwritten. |
| [out] | out_lba | Sector the 8.3 entry landed in. |
| [out] | out_off | Byte offset of the 8.3 entry within that sector. |
| k_ra8_ok | The entry (and any chain) is on disk. |
| k_ra8_err_no_mem | The reserved run ran past the end of the directory. |
| k_ra8_err_* | Backend read/write error. |
tmpl addresses 32 readable bytes. plan came from a priv_dir_reserve() that returned k_ra8_ok, and the directory has not been modified since. Definition at line 374 of file ra8_fs_fat_lfn_write.c.
References dir_walk_t::cur_lba, dir_slot_t::ent, internal_slot_advance(), k_dir_name_field_len, k_dir_off_name, k_dir_off_ntres, k_ra8_fs_dir_entry_bytes, k_ra8_ok, dir_insert_t::lfn_entries, dir_insert_t::name83, dir_insert_t::ntres, dir_insert_t::nunits, priv_byte_copy(), priv_lfn_fill_slot(), priv_read_sector(), priv_sec_walk(), priv_sfn_checksum(), priv_write_sector(), dir_insert_t::start, dir_insert_t::units, and dir_slot_t::w.
Referenced by internal_create_new(), internal_fat_mkdir(), and internal_fat_rename().
| ra8_err_t priv_dir_erase_chain | ( | const ra8_fs_mount_t * | m, |
| const dir_loc_t * | loc, | ||
| uint64_t | lba, | ||
| uint32_t | off, | ||
| const uint8_t * | name83 ) |
Delete a directory entry together with its long-name chain.
Marking only the 8.3 entry 0xE5 – which is all unlink used to do – leaves the attr-0x0F slots in front of it on disk, pointing at a checksum nothing answers to any more. This driver's own reader skips them, but fsck.fat and chkdsk report them as orphaned long-name entries, so the chain is taken away with the entry it belonged to. Only slots that are contiguous with the entry AND carry the checksum of name83 are touched, so an unrelated chain left in front of it by an earlier deletion is not swept up as well.
| [in] | m | Mounted FAT12/16/32 volume. |
| [in] | loc | Directory holding the entry. |
| [in] | lba | Sector of the 8.3 entry. |
| [in] | off | Byte offset of the 8.3 entry within that sector. |
| [in] | name83 | The entry's packed 11-byte name (its checksum source). |
| k_ra8_ok | Entry and chain marked deleted. |
| k_ra8_err_not_found | The walk did not reach (lba, off). |
| k_ra8_err_* | Backend read/write error. |
lba, off) name an entry in loc. name83 is the name field of the entry at (lba, off). loc references that entry. Definition at line 586 of file ra8_fs_fat_lfn_write.c.
References internal_dir_collect_chain(), internal_dir_erase_positions(), k_lfn_erase_max, k_ra8_ok, and priv_sfn_checksum().
Referenced by internal_fat_rename(), internal_fat_rmdir(), and internal_unlink_locked().
| ra8_err_t priv_dir_find_free_run | ( | const ra8_fs_mount_t * | m, |
| const dir_loc_t * | loc, | ||
| uint32_t | need, | ||
| dir_slot_t * | out ) |
Locate need consecutive free entry slots in a given directory.
Walks loc and returns a cursor on the first slot of the first run of need slots whose name field is 0x00 (never used) or 0xE5 (deleted). A long name occupies its chain and its 8.3 entry in one unbroken run, which is why the free slots have to be found together rather than one at a time; need == 1 is the ordinary short-name case and behaves like a first-free-slot search.
| [in] | m | Mount providing geometry and backend. |
| [in] | loc | Directory to search (root or a subdirectory). |
| [in] | need | Consecutive slots required; at least 1. |
| [out] | out | Receives a cursor addressing the run's first slot. |
| k_ra8_ok | Run found; out is positioned on it. |
| k_ra8_err_no_mem | The directory holds no run that long. |
| k_ra8_err_* | Backend error. |
need is at least 1. m is mounted with valid geometry. Definition at line 168 of file ra8_fs_fat_lfn_write.c.
References dir_walk_t::cur_lba, dir_slot_t::ent, internal_slot_is_free(), k_ra8_err_no_mem, k_ra8_fs_dir_entry_bytes, k_ra8_ok, priv_dir_eps(), priv_dir_walk_init_loc(), priv_dir_walk_next_sector(), priv_read_sector(), priv_sec_walk(), and dir_slot_t::w.
Referenced by priv_dir_reserve().
| ra8_err_t priv_dir_lookup_any | ( | const ra8_fs_mount_t * | m, |
| const dir_loc_t * | loc, | ||
| const char * | leaf, | ||
| uint64_t * | out_lba, | ||
| uint32_t * | out_off, | ||
| uint8_t | out_entry[k_ra8_fs_dir_entry_bytes] ) |
Resolve one leaf name by 8.3 first and by long name second.
The two-step every verb has to use, in one place so they cannot drift apart: pack the leaf to 8.3 and look that up, and if it is not representable – or the lookup misses because the file is filed under a generated ~N alias – reassemble the directory's VFAT chains and match the long name instead.
| [in] | m | Mounted FAT12/16/32 volume. |
| [in] | loc | Directory to search. |
| [in] | leaf | Leaf component (no slashes). |
| [out] | out_lba | Sector containing the matched 8.3 entry. |
| [out] | out_off | Byte offset within that sector. |
| [out] | out_entry | 32 bytes of the matched entry. |
| k_ra8_ok | Found; out parameters populated. |
| k_ra8_err_not_found | Neither lookup matched. |
| k_ra8_err_* | Backend error. |
loc names a directory that exists on m. Definition at line 605 of file ra8_fs_fat_lfn_write.c.
References k_max_8_3_name, k_ra8_err_not_found, k_ra8_fs_dir_entry_bytes, priv_dir_find(), priv_dir_find_long(), and priv_path_to_83().
Referenced by internal_enter_subdir(), internal_fat_mkdir(), internal_fat_rename(), internal_rmdir_locate(), internal_unlink_locate(), and priv_open_locked().
| ra8_err_t priv_dir_reserve | ( | const ra8_fs_mount_t * | m, |
| const dir_loc_t * | loc, | ||
| const char * | leaf, | ||
| dir_insert_t * | out ) |
Decide how a name will be stored and set aside the slots for it.
Classifies leaf, generates a unique ~N alias when it needs a long-name chain, and reserves a run of free slots long enough for the chain plus its 8.3 entry – growing the directory by a cluster when no run is long enough, which a FAT12/16 fixed root cannot do. Nothing is written: this is the half that is allowed to fail, so a caller that must allocate something first (mkdir needs a cluster for the new directory) can fail before it does.
| [in] | m | Mounted FAT12/16/32 volume. |
| [in] | loc | Directory the entry is going into. |
| [in] | leaf | Leaf component (no slashes); must outlive the commit. |
| [out] | out | Receives the reservation. |
| k_ra8_ok | Slots reserved; out is ready to commit. |
| k_ra8_err_invalid_arg | leaf is empty, over-long, or illegal. |
| k_ra8_err_no_mem | No run long enough and the directory cannot grow. |
| k_ra8_err_* | Backend or FAT error. |
m is a mounted FAT volume. loc names a directory that exists on m. loc carries out->name83. Definition at line 283 of file ra8_fs_fat_lfn_write.c.
References internal_alias_unique(), internal_dir_grow(), k_lfn_chars_per_ent, k_lfnw_grow_max, k_name_kind_invalid, k_name_kind_long, k_ra8_err_invalid_arg, k_ra8_err_no_mem, k_ra8_ok, dir_insert_t::lfn_entries, dir_insert_t::name83, dir_insert_t::ntres, dir_insert_t::nunits, priv_dir_find_free_run(), priv_name_classify(), dir_insert_t::start, and dir_insert_t::units.
Referenced by internal_create_new(), internal_fat_mkdir(), and internal_fat_rename().
| void priv_lfn_alias_basis | ( | const uint16_t * | leaf, |
| uint32_t | n, | ||
| uint32_t | tail, | ||
| uint8_t * | out11 ) |
Derive the LONGNA~N.TXT 8.3 alias a long name is filed under.
The Microsoft FAT specification's basis-name generation: spaces and all but the last interior dot are dropped, the remainder is upper-cased with anything an 8.3 field cannot hold replaced by _, and the base is truncated to leave room for ~ plus the decimal tail. A leaf that contributes no base characters at all ("...") yields _, because an 8.3 name may not have an empty base.
Every unit above ASCII maps to _, which is what VFAT does with a character its OEM code page cannot express. Working from CODE UNITS rather than UTF-8 bytes is what makes that one underscore per character instead of one per byte.
| [in] | leaf | Long name being filed, as UTF-16 code units. |
| [in] | n | Number of units in leaf. |
| [in] | tail | Sequence number, 1..k_lfn_alias_tail_max. |
| [out] | out11 | Receives the packed, space-padded 11-byte alias. |
leaf and out11 are non-NULL; out11 holds k_max_8_3_name bytes. tail is at least 1 and at most k_lfn_alias_tail_max. out11 is a legal 8.3 character or a space pad. out11 always contains a ~ followed by tail in decimal.Definition at line 769 of file ra8_fs_fat_name.c.
References internal_alias_collect(), internal_alias_digits(), internal_alias_ext_dot(), k_alias_radix, k_filename_base_len, k_filename_ext_len, and k_max_8_3_name.
Referenced by internal_alias_unique().
| void priv_lfn_fill_slot | ( | uint8_t * | ent, |
| const uint16_t * | name, | ||
| uint32_t | nlen, | ||
| uint32_t | order, | ||
| uint8_t | is_last, | ||
| uint8_t | csum ) |
Fill one 32-byte slot with the order -th group of a long name.
Writes the thirteen UTF-16LE code units of group order into the three character runs of an attr-0x0F entry, exactly as priv_lfn_add() reads them back. The group that ends the name carries the NUL terminator immediately after its last character and 0xFFFF in every slot past it – the padding a scanner uses to know the name stopped short of the group boundary. A name whose length is an exact multiple of thirteen therefore carries no terminator at all, which is what the specification requires and what the reassembler already handles by running out of groups.
| [out] | ent | 32-byte slot to fill; zeroed by this function first. |
| [in] | name | The long name, as UTF-16LE code units. |
| [in] | nlen | Its length in code units. |
| [in] | order | 1-based group index (1 = the first thirteen characters). |
| [in] | is_last | Non-zero for the LAST logical group, which is the physically FIRST slot and carries k_lfn_seq_last. |
| [in] | csum | priv_sfn_checksum() of the 8.3 entry closing the chain. |
ent and name are non-NULL; ent addresses 32 writable bytes. order is at least 1 and (order - 1) * 13 is at most nlen. ent outside the 32-byte slot is written.ent; trivially so otherwise.Definition at line 98 of file ra8_fs_fat_lfn.c.
References k_dir_off_attr, k_lfn_chars_per_ent, k_lfn_off_checksum, k_lfn_off_clus_lo, k_lfn_off_seq, k_lfn_off_type, k_lfn_seq_last, k_lfn_unicode_pad, k_ra8_fs_attr_lfn, k_ra8_fs_dir_entry_bytes, priv_wr16(), and s_lfn_char_off.
Referenced by priv_dir_commit().
| ra8_fs_name_kind_t priv_name_classify | ( | const char * | leaf, |
| uint16_t * | out_units, | ||
| uint32_t * | out_nunits, | ||
| uint8_t * | out83, | ||
| uint8_t * | out_ntres ) |
Decide whether a leaf needs one entry, one entry plus case flags, or a chain.
Decodes leaf from UTF-8 into the code units the on-disk chain carries, which is where a malformed encoding is refused – an over-long form, a raw surrogate, a truncated sequence – and then rejects anything a long name may not hold at all (an empty leaf, one longer than k_lfn_write_max CODE UNITS, a control character, or one of the FAT specification's illegal characters). Characters above ASCII are legal: the slots are UTF-16 and the reader returns them as such. What is left is an 8.3 name if it has a 1..8 character base, a 0 or 1..3 character extension, at most one dot, and no character an 8.3 field cannot hold – a space and a second dot are both enough to disqualify it however short it is. An 8.3 name whose base or extension is all one case round-trips through DIR_NTRes; one that MIXES cases in either half does not, and is reported as needing a chain.
| [in] | leaf | Leaf component (no slashes), NUL-terminated UTF-8. |
| [out] | out_units | Receives leaf as UTF-16LE code units. |
| [out] | out_nunits | Receives how many units that is. |
| [out] | out83 | Receives the packed 11-byte name on a short verdict. |
| [out] | out_ntres | Receives the DIR_NTRes case flags (0 unless short). |
| k_name_kind_short | out83 and out_ntres are ready to write. |
| k_name_kind_long | A chain plus a generated alias is required. |
| k_name_kind_invalid | Empty, over-long, illegal, or not valid UTF-8. |
out_units addresses k_lfn_write_max writable units and out83 addresses k_max_8_3_name writable bytes. out_ntres and out_nunits are written on every outcome. leaf is not modified.Definition at line 571 of file ra8_fs_fat_name.c.
References internal_name_case_kind(), internal_name_is_83(), internal_unit_is_lfn_legal(), k_lfn_write_max, k_name_kind_invalid, k_name_kind_long, k_ra8_ok, priv_path_to_83(), and priv_utf8_to_utf16().
Referenced by priv_dir_reserve().
| uint8_t priv_sfn_checksum | ( | const uint8_t * | name83 | ) |
Compute the 8.3 short-name checksum carried in each LFN directory entry.
Implements the rotate-right-add algorithm from the Microsoft FAT spec section 7 ("Long File Name Directory Entries"). Each of the eleven bytes of the 8.3 name field is folded into a running sum: the previous sum is rotated right by one bit (preserving the low bit) and the next byte is added. The result binds a set of LFN slots to their trailing 8.3 entry so that a chain cannot alias a different short name.
| [in] | name83 | Pointer to the 11-byte 8.3 name field (DIR_Name in the FAT spec, space-padded, not NUL-terminated). |
| 0..255 | The folded checksum; all values are possible. |
name83 is non-NULL and points to at least 11 valid bytes. name83 are modified (read-only access).Definition at line 87 of file ra8_fs_fat_lfn.c.
References k_dir_name_field_len, and k_sfn_csum_high_bit.
Referenced by priv_dir_commit(), priv_dir_erase_chain(), and priv_lfn_units_for().