Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closes #250: fat32 8.3 lowercase names, make fs.OpenFile case insensitive for 8.3 and long filenames #251

Merged
merged 1 commit into from
Sep 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading