Skip to content

Commit

Permalink
writer: fix writing directories with many entries
Browse files Browse the repository at this point in the history
This fixes writing out (for example) device tree overlay directory.

We now write the directory entries twice:
Once for figuring out the correct firstCluster values,
then again for writing out the correct firstCluster values.

related to gokrazy/gokrazy#216
related to gokrazy/tools#67
  • Loading branch information
stapelberg committed Dec 15, 2023
1 parent a645001 commit cb94242
Showing 1 changed file with 32 additions and 15 deletions.
47 changes: 32 additions & 15 deletions fat/writer.go
Original file line number Diff line number Diff line change
Expand Up @@ -552,36 +552,52 @@ func (fw *Writer) writeDirEntries(w io.Writer, d *directory) error {
}

func (fw *Writer) writeDir(d *directory) error {
d.firstCluster = fw.currentCluster()
// TODO: calculate how many clusters we will need for all directory entries

// Allocate 1 self-standing cluster (for now) in the FAT:
fw.fat = append(fw.fat, endOfChain)
oldFat := fw.fat
offset, err := fw.dataTmp.Seek(0, io.SeekCurrent)
if err != nil {
return err
}
// Write the directory entries to populate d.firstCluster
if err := fw.writeDir1(d); err != nil {
return err
}

clusterOffset := (int64(d.firstCluster) - int64(unusableClusters)) * int64(clusterSize)
// Reset the FAT to before the write and write the directory entries again,
// this time with the correct d.firstCluster.
if _, err := fw.dataTmp.Seek(offset, io.SeekStart); err != nil {
return err
}
fw.fat = oldFat
if err := fw.writeDir1(d); err != nil {
return err
}
return nil
}

func (fw *Writer) writeDir1(d *directory) error {
for _, e := range d.entries {
if e.Attr() != attrDirectory {
continue
}
if err := fw.writeDir(e.(*directory)); err != nil {
if err := fw.writeDir1(e.(*directory)); err != nil {
return err
}
}

if _, err := fw.dataTmp.Seek(clusterOffset, io.SeekStart); err != nil {
return err
}
d.firstCluster = fw.currentCluster()

pw := &paddingWriter{
w: fw.dataTmp,
padTo: clusterSize,
fuw := &fatUpdatingWriter{
fw: fw,
pw: &paddingWriter{
w: fw.dataTmp,
padTo: clusterSize,
},
}

if err := fw.writeDirEntries(pw, d); err != nil {
if err := fw.writeDirEntries(fuw, d); err != nil {
return err
}
if err := pw.Flush(); err != nil {
if err := fuw.Close(); err != nil {
return err
}

Expand Down Expand Up @@ -632,6 +648,7 @@ func (fw *Writer) Flush() error {
fw.fat = append(fw.fat, pad...)
}

// TODO: why fullSectors, the FAT is in clusters?!
fatSectors := fullSectors(len(fw.fat) * 2)

// We only need to reserve the boot sector, but the number of reserved
Expand Down

0 comments on commit cb94242

Please sign in to comment.