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

Writing VFAT long names: reserve the slots, build the chain, take it away again. More...

#include <stddef.h>
#include <stdint.h>
#include "ra8_attributes.h"
#include "ra8_fs.h"
#include "ra8_fs_fat_internal.h"
Include dependency graph for ra8_fs_fat_lfn_write.c:

Go to the source code of this file.

Enumerations

enum  ra8_fs_lfnw_local_t : uint32_t { k_lfnw_grow_max = 3U }
 Bounds used only by this translation unit's directory manipulation. More...

Functions

static ra8_err_t internal_alias_unique (const ra8_fs_mount_t *m, const dir_loc_t *loc, const uint16_t *leaf, uint32_t n, uint8_t *out11)
 Pick the lowest ~N alias the directory does not already hold.
static uint8_t internal_slot_is_free (const uint8_t *ent)
 Is this 32-byte slot available for a new entry?
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.
static ra8_err_t internal_dir_grow (const ra8_fs_mount_t *m, const dir_loc_t *loc)
 Append one zeroed cluster to a directory's chain.
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.
static ra8_err_t internal_slot_advance (const ra8_fs_mount_t *m, dir_slot_t *cur, uint8_t *buf, uint64_t *lba_io)
 Step a slot cursor forward one entry, flushing across sector edges.
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.
static void internal_run_push (dir_pos_t *run, uint32_t *len_io, uint64_t lba, uint32_t off)
 Record one long-name slot address, keeping the newest on overflow.
static ra8_err_t internal_dir_collect_chain (const ra8_fs_mount_t *m, const dir_loc_t *loc, uint64_t tlba, uint32_t toff, uint8_t csum, dir_pos_t *run, uint32_t *out_len)
 Collect the long-name slots that belong to one 8.3 entry.
static ra8_err_t internal_dir_erase_positions (const ra8_fs_mount_t *m, const dir_pos_t *pos, uint32_t count)
 Mark every listed slot deleted, one sector read-modify-write at a time.
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.
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.

Detailed Description

Writing VFAT long names: reserve the slots, build the chain, take it away again.

ra8_fs_fat_lfn.c has always been able to READ a long name – reassemble a run of attr-0x0F entries, check the checksum against the 8.3 entry behind them, and match it. This file is the other direction, and with it the filesystem can finally store the name the caller asked for instead of refusing it: ra8_fs_open(), ra8_fs_mkdir() and ra8_fs_rename() used to answer k_ra8_err_invalid_arg for anything that was not 8.3-representable.

Three pieces, in the order a create runs them:

  1. An alias nothing else answers to. A long name still needs an 8.3 entry, because that is where the size, the attributes and the first cluster live. priv_lfn_alias_basis() derives LONGNA~1.TXT from Long Name.txt, and ::priv_alias_unique() keeps raising the tail until the directory does not already hold that name.
  2. A run of consecutive free slots. A chain is only a chain because its entries physically precede their 8.3 entry, so the slots have to be found together rather than one at a time – and when the directory has no run that long, it grows by a cluster (a FAT12/16 root cannot, and says so).
  3. The chain itself, written back-to-front with the 0x40 flag on the physically-first entry, each slot carrying the checksum of the alias.

The fourth piece runs in the other direction. priv_dir_erase_chain() is what stops unlink and rename leaving ORPHANS: clearing only the 8.3 entry left the whole attr-0x0F run on disk with a checksum that now matched nothing, which in-tree readers skip but fsck.fat and chkdsk both report. It walks forward to the doomed entry keeping the run of long-name slots that immediately precede it AND carry its checksum, then 0xE5s all of them together with it.

Since
0.1.0

Definition in file ra8_fs_fat_lfn_write.c.

Enumeration Type Documentation

◆ ra8_fs_lfnw_local_t

enum ra8_fs_lfnw_local_t : uint32_t

Bounds used only by this translation unit's directory manipulation.

k_lfnw_grow_max is the loop bound that keeps the "no run this long -- grow and look again" retry finite (NASA Power of 10 Rule 2). Two grows always suffice: the longest run this code ever asks for is k_lfn_erase_max + 1 = 21 slots, and the smallest cluster this driver mounts is one 512-byte sector = 16 slots, so a run can need at most one fresh cluster beyond a completely full one. The third attempt is slack, not a requirement.

Invariant
k_lfnw_grow_max is at least 2.
See also
priv_dir_reserve()
Since
0.1.0
Enumerator
k_lfnw_grow_max 

Cluster-growth retries before reporting no_mem.

Definition at line 63 of file ra8_fs_fat_lfn_write.c.

Function Documentation

◆ internal_alias_unique()

ra8_err_t internal_alias_unique ( const ra8_fs_mount_t * m,
const dir_loc_t * loc,
const uint16_t * leaf,
uint32_t n,
uint8_t * out11 )
static

Pick the lowest ~N alias the directory does not already hold.

Generates the basis name for N = 1, 2, 3 ... and looks each one up by its packed 8.3 form, stopping at the first miss. Looking the alias up (rather than only the long name) is the point: two different long names routinely produce the same basis, and an alias collision would give one file two 8.3 entries with the same name.

Parameters
[in]mMounted FAT12/16/32 volume.
[in]locDirectory the entry is going into.
[in]leafLong name being filed, as UTF-16 code units.
[in]nNumber of units in leaf.
[out]out11Receives the packed 11-byte alias.
Returns
Error code.
Return values
k_ra8_okAn unused alias was found; out11 holds it.
k_ra8_err_no_memEvery alias in the supported range is taken.
k_ra8_err_*Backend read error while probing.
Precondition
All pointers are non-NULL; out11 addresses k_max_8_3_name bytes.
leaf is the unit array priv_name_classify() filled, and it reported k_name_kind_long for it.
Postcondition
On success no entry in loc carries the name in out11.
No on-disk state is modified.
Note
Bounded by k_lfn_alias_tail_max probes (NASA Power of 10 Rule 2).
Since
0.1.0

Definition at line 103 of file ra8_fs_fat_lfn_write.c.

References k_lfn_alias_tail_max, k_ra8_err_no_mem, k_ra8_err_not_found, k_ra8_fs_dir_entry_bytes, k_ra8_ok, priv_dir_find(), and priv_lfn_alias_basis().

Referenced by priv_dir_reserve().

◆ internal_dir_collect_chain()

ra8_err_t internal_dir_collect_chain ( const ra8_fs_mount_t * m,
const dir_loc_t * loc,
uint64_t tlba,
uint32_t toff,
uint8_t csum,
dir_pos_t * run,
uint32_t * out_len )
static

Collect the long-name slots that belong to one 8.3 entry.

Walks the directory to the entry at (tlba, toff), keeping the run of attr-0x0F slots that immediately precede it AND carry csum. Any live entry, any deleted slot, or a long-name slot with a different checksum resets the run – so a stale chain left in front of this file by some earlier deletion is not swept up with it.

Parameters
[in]mMounted FAT12/16/32 volume.
[in]locDirectory holding the entry.
[in]tlbaSector of the target 8.3 entry.
[in]toffByte offset of the target within that sector.
[in]csumChecksum of the target's packed 8.3 name.
[out]runReceives up to k_lfn_erase_max slot addresses.
[out]out_lenReceives how many of run were filled.
Returns
Error code.
Return values
k_ra8_okThe target was reached; run/out_len valid.
k_ra8_err_not_foundThe walk ended without reaching the target.
k_ra8_err_*Backend read error.
Precondition
All pointers are non-NULL; run holds k_lfn_erase_max entries.
(tlba, toff) came from a lookup in this same directory.
Postcondition
On success run holds only slots that precede the target.
No on-disk state is modified.
Note
Not thread-safe; callers serialise directory access.
Since
0.1.0

Definition at line 492 of file ra8_fs_fat_lfn_write.c.

References dir_walk_t::cur_lba, internal_run_push(), k_dir_marker_free_used, k_dir_off_attr, k_dir_off_name, k_lfn_off_checksum, k_ra8_err_not_found, k_ra8_fs_attr_lfn, 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(), and priv_sec_walk().

Referenced by priv_dir_erase_chain().

◆ internal_dir_erase_positions()

ra8_err_t internal_dir_erase_positions ( const ra8_fs_mount_t * m,
const dir_pos_t * pos,
uint32_t count )
static

Mark every listed slot deleted, one sector read-modify-write at a time.

The addresses arrive in increasing order, so a single sector buffer is enough: it is written back only when the next address moves to a different sector, which for the usual chain means one read and one write for the whole deletion.

Parameters
[in]mMounted FAT12/16/32 volume.
[in]posSlot addresses, in increasing sector order.
[in]countHow many; at least 1.
Returns
Error code.
Return values
k_ra8_okEvery listed slot now reads 0xE5.
k_ra8_err_*Backend read/write error.
Precondition
m and pos are non-NULL; count is at least 1.
The addresses are sorted by sector.
Postcondition
On success no listed slot is reachable by a directory scan.
On failure an earlier sector may already have been updated.
Note
Not thread-safe; callers serialise directory access.
Since
0.1.0

Definition at line 560 of file ra8_fs_fat_lfn_write.c.

References k_dir_marker_free_used, k_dir_off_name, k_ra8_ok, dir_pos_t::lba, dir_pos_t::off, priv_read_sector(), priv_sec_walk(), and priv_write_sector().

Referenced by priv_dir_erase_chain().

◆ internal_dir_grow()

ra8_err_t internal_dir_grow ( const ra8_fs_mount_t * m,
const dir_loc_t * loc )
static

Append one zeroed cluster to a directory's chain.

Walks to the chain's last cluster with the shared directory iterator, allocates a fresh cluster, zeroes every sector of it so it reads as end-of-directory, and only then links it in – a directory is never visible in a half-initialised state. A FAT12/16 volume root has no chain to extend and is refused.

Parameters
[in]mMounted FAT12/16/32 volume.
[in]locDirectory to extend.
Returns
Error code.
Return values
k_ra8_okThe directory is one cluster longer.
k_ra8_err_no_memA FAT12/16 fixed root, or the volume is full.
k_ra8_err_protocol_errorThe existing chain revisits a cluster.
k_ra8_err_*Backend or FAT error.
Precondition
m and loc are non-NULL; m is a mounted FAT volume.
loc names a directory that exists on m.
Postcondition
On success the new cluster is zeroed and linked at the chain's end.
On failure no cluster is left allocated but unreferenced.
Note
Not thread-safe; callers serialise directory access.
Since
0.1.0

Definition at line 235 of file ra8_fs_fat_lfn_write.c.

References dir_walk_t::cluster, dir_loc_t::is_root, k_ra8_err_no_mem, k_ra8_fs_type_fat32, k_ra8_ok, k_zero_sector, priv_alloc_eoc_cluster(), priv_cluster_to_lba(), priv_dir_walk_init_loc(), priv_dir_walk_next_sector(), priv_fat_set(), priv_free_chain(), priv_write_sector(), ra8_fs_mount_t::sectors_per_cluster, and ra8_fs_mount_t::type.

Referenced by priv_dir_reserve().

◆ internal_run_push()

void internal_run_push ( dir_pos_t * run,
uint32_t * len_io,
uint64_t lba,
uint32_t off )
static

Record one long-name slot address, keeping the newest on overflow.

A legal chain is at most k_lfn_erase_max entries, so the shift only runs on a corrupt directory. Keeping the entries CLOSEST to the 8.3 entry is the safe choice there: those are the ones the checksum test has most recently confirmed belong to it.

Parameters
[in,out]runArray of at least k_lfn_erase_max positions.
[in,out]len_ioCurrent length; incremented until the cap is reached.
[in]lbaSector of the slot to record.
[in]offByte offset of the slot within that sector.
Returns
Nothing.
Precondition
run and len_io are non-NULL; *len_io is at most the cap.
off is a valid entry offset inside one sector.
Postcondition
*len_io never exceeds k_lfn_erase_max.
The last recorded position is always run[*len_io - 1].
Note
Bounded shift (NASA Power of 10 Rule 2).
Since
0.1.0

Definition at line 446 of file ra8_fs_fat_lfn_write.c.

References k_lfn_erase_max.

Referenced by internal_dir_collect_chain().

◆ internal_slot_advance()

ra8_err_t internal_slot_advance ( const ra8_fs_mount_t * m,
dir_slot_t * cur,
uint8_t * buf,
uint64_t * lba_io )
static

Step a slot cursor forward one entry, flushing across sector edges.

The write buffer holds one sector; crossing into the next one means committing what is in it first, because the run being written may already have modified this sector's earlier slots.

Parameters
[in]mMounted FAT12/16/32 volume.
[in,out]curCursor to advance.
[in,out]bufSector buffer; written out and reloaded on a crossing.
[in,out]lba_ioHolds the buffer's LBA; updated on a crossing.
Returns
Error code.
Return values
k_ra8_okThe cursor addresses the next slot.
k_ra8_err_no_memThe directory ended mid-run (corrupt reservation).
k_ra8_err_*Backend read/write error.
Precondition
All pointers are non-NULL; buf holds the sector at *lba_io.
cur is positioned inside the reserved run.
Postcondition
On success buf holds the sector cur now points into.
On failure the run is left partially written.
Note
Not thread-safe; callers serialise directory access.
Since
0.1.0

Definition at line 350 of file ra8_fs_fat_lfn_write.c.

References dir_walk_t::cur_lba, dir_slot_t::ent, k_ra8_err_no_mem, k_ra8_ok, priv_dir_eps(), priv_dir_walk_next_sector(), priv_read_sector(), priv_write_sector(), and dir_slot_t::w.

Referenced by priv_dir_commit().

◆ internal_slot_is_free()

uint8_t internal_slot_is_free ( const uint8_t * ent)
static

Is this 32-byte slot available for a new entry?

Both free markers count: 0xE5 is a slot whose entry was deleted, and 0x00 is the end-of-directory marker, past which every slot in the allocated directory space is unused. Writing into a run that starts at 0x00 is safe because the slot after the run keeps its own 0x00, which is what still terminates the directory.

Parameters
[in]ent32-byte directory slot.
Returns
Availability flag.
Return values
1UThe slot may be overwritten.
0UThe slot holds a live entry.
Precondition
ent addresses 32 readable bytes.
ent was loaded from a directory sector.
Postcondition
No state is modified.
The verdict depends only on DIR_Name[0].
Note
Pure function; trivially thread-safe.
Since
0.1.0

Definition at line 158 of file ra8_fs_fat_lfn_write.c.

References k_dir_marker_free_perm, k_dir_marker_free_used, and k_dir_off_name.

Referenced by priv_dir_find_free_run().

◆ priv_dir_commit()

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.

Parameters
[in]mMounted FAT12/16/32 volume.
[in]planReservation produced by priv_dir_reserve().
[in]tmpl32-byte entry template; name and NTRes are overwritten.
[out]out_lbaSector the 8.3 entry landed in.
[out]out_offByte offset of the 8.3 entry within that sector.
Returns
Error code.
Return values
k_ra8_okThe entry (and any chain) is on disk.
k_ra8_err_no_memThe reserved run ran past the end of the directory.
k_ra8_err_*Backend read/write error.
Precondition
All pointers are non-NULL; 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.
Postcondition
On success a scan of the directory finds the new name.
On a mid-run failure the directory may hold a partial chain, which a scanner skips because it is not closed by a matching 8.3 entry.
Note
A run that fits inside one sector – which is every name of 15 groups or fewer that does not straddle a boundary, so nearly all of them – reaches the backend as a SINGLE write. The chain and the entry that closes it then appear together or not at all, which is the best any FAT directory update can do: the format has no journal, and a run spanning two sectors is two writes with a window between them.
Not thread-safe; callers serialise directory access.
Since
0.1.0

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().

◆ priv_dir_erase_chain()

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.

Parameters
[in]mMounted FAT12/16/32 volume.
[in]locDirectory holding the entry.
[in]lbaSector of the 8.3 entry.
[in]offByte offset of the 8.3 entry within that sector.
[in]name83The entry's packed 11-byte name (its checksum source).
Returns
Error code.
Return values
k_ra8_okEntry and chain marked deleted.
k_ra8_err_not_foundThe walk did not reach (lba, off).
k_ra8_err_*Backend read/write error.
Precondition
All pointers are non-NULL; (lba, off) name an entry in loc.
name83 is the name field of the entry at (lba, off).
Postcondition
On success no long-name slot in loc references that entry.
The entry's cluster chain is NOT touched; freeing it is the caller's job.
Note
Not thread-safe; callers serialise directory access.
Since
0.1.0

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().

◆ priv_dir_find_free_run()

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.

Parameters
[in]mMount providing geometry and backend.
[in]locDirectory to search (root or a subdirectory).
[in]needConsecutive slots required; at least 1.
[out]outReceives a cursor addressing the run's first slot.
Returns
Error code.
Return values
k_ra8_okRun found; out is positioned on it.
k_ra8_err_no_memThe directory holds no run that long.
k_ra8_err_*Backend error.
Precondition
All pointers are non-NULL and need is at least 1.
m is mounted with valid geometry.
Postcondition
On success every slot of the run is free.
No on-disk state is modified.
Note
Thread-safety inherited from the backend.
Since
0.1.0

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().

◆ priv_dir_lookup_any()

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.

Parameters
[in]mMounted FAT12/16/32 volume.
[in]locDirectory to search.
[in]leafLeaf component (no slashes).
[out]out_lbaSector containing the matched 8.3 entry.
[out]out_offByte offset within that sector.
[out]out_entry32 bytes of the matched entry.
Returns
Error code.
Return values
k_ra8_okFound; out parameters populated.
k_ra8_err_not_foundNeither lookup matched.
k_ra8_err_*Backend error.
Precondition
All pointers are non-NULL.
loc names a directory that exists on m.
Postcondition
On success the out parameters identify one on-disk 8.3 entry.
No on-disk state is modified.
Note
Not thread-safe; callers serialise directory access.
Since
0.1.0

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().

◆ priv_dir_reserve()

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.

Parameters
[in]mMounted FAT12/16/32 volume.
[in]locDirectory the entry is going into.
[in]leafLeaf component (no slashes); must outlive the commit.
[out]outReceives the reservation.
Returns
Error code.
Return values
k_ra8_okSlots reserved; out is ready to commit.
k_ra8_err_invalid_argleaf is empty, over-long, or illegal.
k_ra8_err_no_memNo run long enough and the directory cannot grow.
k_ra8_err_*Backend or FAT error.
Precondition
All pointers are non-NULL; m is a mounted FAT volume.
loc names a directory that exists on m.
Postcondition
On success no other entry in loc carries out->name83.
On failure no directory entry has been written.
Note
Not thread-safe; callers serialise directory access.
Since
0.1.0

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().