Skip to content

Commit

Permalink
Merge pull request #251 from jsando/fat32-case-fixes
Browse files Browse the repository at this point in the history
Closes #250: fat32 8.3 lowercase names, make fs.OpenFile case insensitive for 8.3 and long filenames
  • Loading branch information
deitch authored Sep 3, 2024
2 parents 32280aa + 28cd047 commit 183295d
Show file tree
Hide file tree
Showing 4 changed files with 90 additions and 5 deletions.
4 changes: 2 additions & 2 deletions filesystem/fat32/directoryentry.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ func (de *directoryEntry) toBytes() ([]byte, error) {
}

if de.lowercaseExtension {
dosBytes[12] |= 0x04
dosBytes[12] |= 0x10
}
if de.lowercaseShortname {
dosBytes[12] |= 0x08
Expand Down Expand Up @@ -161,7 +161,7 @@ byteLoop:
isArchiveDirty := b[i+11]&0x20 == 0x20
isVolumeLabel := b[i+11]&0x08 == 0x08
lowercaseShortname := b[i+12]&0x08 == 0x08
lowercaseExtension := b[i+12]&0x04 == 0x04
lowercaseExtension := b[i+12]&0x10 == 0x10

entry := directoryEntry{
filenameLong: lfn,
Expand Down
6 changes: 3 additions & 3 deletions filesystem/fat32/fat32.go
Original file line number Diff line number Diff line change
Expand Up @@ -511,7 +511,7 @@ func (fs *FileSystem) ReadDir(p string) ([]os.FileInfo, error) {
}
fileExtension := e.fileExtension
if e.lowercaseExtension {
shortName = strings.ToLower(fileExtension)
fileExtension = strings.ToLower(fileExtension)
}
if fileExtension != "" {
shortName = fmt.Sprintf("%s.%s", shortName, fileExtension)
Expand Down Expand Up @@ -553,7 +553,7 @@ func (fs *FileSystem) OpenFile(p string, flag int) (filesystem.File, error) {
if e.fileExtension != "" {
shortName += "." + e.fileExtension
}
if e.filenameLong != filename && shortName != filename {
if !strings.EqualFold(e.filenameLong, filename) && !strings.EqualFold(shortName, filename) {
continue
}
// cannot do anything with directories
Expand Down Expand Up @@ -840,7 +840,7 @@ func (fs *FileSystem) readDirWithMkdir(p string, doMake bool) (*Directory, []*di
// match is determined by any one of:
// - long filename == provided name
// - uppercase(short filename) == uppercase(provided name)
if e.filenameLong != subp && !strings.EqualFold(e.filenameShort, subp) {
if !strings.EqualFold(e.filenameLong, subp) && !strings.EqualFold(e.filenameShort, subp) {
continue
}
if !e.isSubdirectory {
Expand Down
81 changes: 81 additions & 0 deletions filesystem/fat32/fat32_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -977,3 +977,84 @@ func TestFat32MkdirCases(t *testing.T) {
t.Fatalf("expected 1 file, found %d", len(files))
}
}

func Test83Lowercase(t *testing.T) {
// get a temporary working file
f, err := tmpFat32(true, 0, 0)
if err != nil {
t.Fatal(err)
}
if keepTmpFiles == "" {
defer os.Remove(f.Name())
} else {
fmt.Println(f.Name())
}
fileInfo, err := f.Stat()
if err != nil {
t.Fatalf("error getting file info for tmpfile %s: %v", f.Name(), err)
}
fs, err := fat32.Read(f, fileInfo.Size(), 0, 512)
if err != nil {
t.Fatalf("error reading fat32 filesystem from %s: %v", f.Name(), err)
}

// Ensure using correct masks for lowercase shortname and extension (bits 3 and 4, zero-based)
files, err := fs.ReadDir("/lower83")
if err != nil {
t.Fatal(err)
}
expected := []string{"lower.low", "lower.UPP", "UPPER.low"}
i := 0
for _, file := range files {
if file.Name() == "." || file.Name() == ".." {
continue
}
if file.Name() != expected[i] {
t.Errorf("got %q, expected %q", file.Name(), expected[i])
}
i++
}
}

func TestOpenFileCaseInsensitive(t *testing.T) {
// get a temporary working file
f, err := tmpFat32(true, 0, 0)
if err != nil {
t.Fatal(err)
}
if keepTmpFiles == "" {
defer os.Remove(f.Name())
} else {
fmt.Println(f.Name())
}
fileInfo, err := f.Stat()
if err != nil {
t.Fatalf("error getting file info for tmpfile %s: %v", f.Name(), err)
}
fs, err := fat32.Read(f, fileInfo.Size(), 0, 512)
if err != nil {
t.Fatalf("error reading fat32 filesystem from %s: %v", f.Name(), err)
}

// Ensure openfile is case-insensitive for the 8.3 name as well as the long name
paths := []string{
// The actual name
"/lower83/lower.low",
// Same name but different extension case
"/lower83/lower.LOW",
// Same name but different base case
"/lower83/LOWER.LOW",
// Actual name/case of non-8.3 file
"/tercer_archivo",
// Same name but uppercase
"/TERCER_ARCHIVO",
}
for _, path := range paths {
file, err := fs.OpenFile(path, os.O_RDONLY)
if err != nil {
t.Errorf("error opening %s: %v\n", path, err)
} else {
file.Close()
}
}
}
4 changes: 4 additions & 0 deletions filesystem/fat32/testdata/mkfat32.sh
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ mcopy -i /data/fat32.img /CORTO1.TXT ::/
mcopy -i /data/fat32.img '/Un archivo con nombre largo.dat' ::/
mcopy -i /data/fat32.img '/tercer_archivo' ::/
mcopy -i /data/fat32.img '/some_long_embedded_nameא' ::/foo/bar
mmd -i /data/fat32.img ::/lower83
mcopy -i /data/fat32.img /CORTO1.TXT ::/lower83/lower.low
mcopy -i /data/fat32.img /CORTO1.TXT ::/lower83/lower.UPP
mcopy -i /data/fat32.img /CORTO1.TXT ::/lower83/UPPER.low
i=0
until [ $i -gt 75 ]; do mmd -i /data/fat32.img ::/foo/dir${i}; i=$(( $i+1 )); done
Expand Down

0 comments on commit 183295d

Please sign in to comment.