From 0464a698df620ca6b905a1b5ef742b320ab6b99e Mon Sep 17 00:00:00 2001 From: Antonio Pires Date: Fri, 2 Dec 2022 13:59:02 -0600 Subject: [PATCH 1/3] Handling corner cases around Fat32 MkDir and volume name This patch adds a few things: - Validates volume name a bit closer to the fat spec - (bug) When we're walking a directory for mkdir we compare what we're looking for by directory entry nodes, rather than on a file/directory basis. This leaves the root volume entry as an unhandled case, specially if the volume name matches the name of the file we're trying to create. This patchset skips the the root directory node in this traversal. --- filesystem/fat32/directory.go | 5 + filesystem/fat32/fat32.go | 34 ++++- filesystem/fat32/fat32_test.go | 221 +++++++++++++++++++-------------- 3 files changed, 162 insertions(+), 98 deletions(-) diff --git a/filesystem/fat32/directory.go b/filesystem/fat32/directory.go index bd917b75..0aa25c78 100644 --- a/filesystem/fat32/directory.go +++ b/filesystem/fat32/directory.go @@ -1,6 +1,7 @@ package fat32 import ( + "fmt" "time" ) @@ -72,6 +73,10 @@ func (d *Directory) createEntry(name string, cluster uint32, dir bool) (*directo // createVolumeLabel create a volume label entry in the given directory, and return the handle to it func (d *Directory) createVolumeLabel(name string) (*directoryEntry, error) { + name, err := validateAndFormatVolumeLabel(name) + if err != nil { + return nil, fmt.Errorf("Unable to create a volume label entry: %w", err) + } // allocate a slot for the new filename in the existing directory entry := directoryEntry{ filenameLong: "", diff --git a/filesystem/fat32/fat32.go b/filesystem/fat32/fat32.go index 84961587..494b1b23 100644 --- a/filesystem/fat32/fat32.go +++ b/filesystem/fat32/fat32.go @@ -1,6 +1,7 @@ package fat32 import ( + "bytes" "errors" "fmt" "os" @@ -626,14 +627,36 @@ func (fs *FileSystem) Label() string { return labelEntry.filenameShort + labelEntry.fileExtension } -// SetLabel changes the filesystem label -func (fs *FileSystem) SetLabel(volumeLabel string) error { +// https://learn.microsoft.com/en-us/windows/win32/fileio/naming-a-file#naming-conventions +// https://www.cs.fsu.edu/~cop4610t/assignments/project3/spec/fatspec.pdf +func validateAndFormatVolumeLabel(volumeLabel string) (string, error) { if volumeLabel == "" { volumeLabel = "NO NAME" } + if len(volumeLabel) > 11 { + return "", fmt.Errorf("Volume label |%s| must be less than 11 characters, got %d", volumeLabel, len(volumeLabel)) + } - // ensure the volumeLabel is proper sized - volumeLabel = fmt.Sprintf("%-11.11s", volumeLabel) + // The following characters are not legal in any bytes of DIR_Name: + // • Values less than 0x20 except for the special case of 0x05 in DIR_Name[0] described above. + // TODO + // • 0x22, 0x2A, 0x2B, 0x2C, 0x2E, 0x2F, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x5B, 0x5C, 0x5D, + // and 0x7C. + invalidBytes := string([]byte{0x22, 0x2A, 0x2B, 0x2C, 0x2E, 0x2F, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x5B, 0x5C, 0x5D, 0x7C}) + idx := bytes.IndexAny([]byte(volumeLabel), invalidBytes) + if idx != -1 { + return "", fmt.Errorf("Volume label cannot have invalid character %c", volumeLabel[idx]) + } + + return fmt.Sprintf("%-11.11s", volumeLabel), nil +} + +// SetLabel changes the filesystem label +func (fs *FileSystem) SetLabel(volumeLabel string) error { + volumeLabel, err := validateAndFormatVolumeLabel(volumeLabel) + if err != nil { + return fmt.Errorf("Error validating volume label %w", err) + } // set the label in the superblock bpb := fs.bootSector.biosParameterBlock @@ -827,6 +850,9 @@ func (fs *FileSystem) readDirWithMkdir(p string, doMake bool) (*Directory, []*di // do we have an entry whose name is the same as this name? found := false for _, e := range entries { + if e.isVolumeLabel { + continue + } if e.filenameLong != subp && e.filenameShort != subp && (!e.lowercaseShortname || (e.lowercaseShortname && !strings.EqualFold(e.filenameShort, subp))) { continue } diff --git a/filesystem/fat32/fat32_test.go b/filesystem/fat32/fat32_test.go index 5b1bca19..197b59c2 100644 --- a/filesystem/fat32/fat32_test.go +++ b/filesystem/fat32/fat32_test.go @@ -1,4 +1,4 @@ -package fat32_test +package fat32 /* These tests the exported functions @@ -15,9 +15,6 @@ import ( "testing" "github.com/diskfs/go-diskfs/filesystem" - "github.com/diskfs/go-diskfs/filesystem/fat32" - "github.com/diskfs/go-diskfs/testhelper" - "github.com/diskfs/go-diskfs/util" ) var ( @@ -49,9 +46,9 @@ func tmpFat32(fill bool, embedPre, embedPost int64) (*os.File, error) { } // either copy the contents of the base file over, or make a file of similar size - b, err := os.ReadFile(fat32.Fat32File) + b, err := os.ReadFile(Fat32File) if err != nil { - return nil, fmt.Errorf("Failed to read contents of %s: %v", fat32.Fat32File, err) + return nil, fmt.Errorf("Failed to read contents of %s: %v", Fat32File, err) } if embedPre > 0 { empty := make([]byte, embedPre) @@ -66,10 +63,10 @@ func tmpFat32(fill bool, embedPre, embedPost int64) (*os.File, error) { if fill { written, err := f.Write(b) if err != nil { - return nil, fmt.Errorf("Failed to write contents of %s to %s: %v", fat32.Fat32File, filename, err) + return nil, fmt.Errorf("Failed to write contents of %s to %s: %v", Fat32File, filename, err) } if written != len(b) { - return nil, fmt.Errorf("wrote only %d bytes of %s to %s instead of %d", written, fat32.Fat32File, filename, len(b)) + return nil, fmt.Errorf("wrote only %d bytes of %s to %s instead of %d", written, Fat32File, filename, len(b)) } } else { size := int64(len(b)) @@ -97,7 +94,7 @@ func tmpFat32(fill bool, embedPre, embedPost int64) (*os.File, error) { } func TestFat32Type(t *testing.T) { - fs := &fat32.FileSystem{} + fs := &FileSystem{} fstype := fs.Type() expected := filesystem.TypeFat32 if fstype != expected { @@ -106,90 +103,105 @@ func TestFat32Type(t *testing.T) { } func TestFat32Mkdir(t *testing.T) { - // only do this test if os.Getenv("TEST_IMAGE") contains a real image - if intImage == "" { - return - } - //nolint:thelper // this is not a helper function - runTest := func(t *testing.T, post, pre int64, fatFunc func(util.File, int64, int64, int64) (*fat32.FileSystem, error)) { - // create our directories - tests := []string{ - "/", - "/foo", - "/foo/bar", - "/a/b/c", - } - f, err := tmpFat32(true, pre, post) - if err != nil { - t.Fatal(err) - } - if keepTmpFiles == "" { - defer os.Remove(f.Name()) - } else { - fmt.Println(f.Name()) - } - fileInfo, err := f.Stat() + t.Run("Creating directory at root with the same name as volume", func(t *testing.T) { + f, err := os.CreateTemp("", "*") + label := "boot" + // create an empty filesystem + fs, err := Create(f, 1000000, 0, 512, label) if err != nil { - t.Fatalf("error getting file info for tmpfile %s: %v", f.Name(), err) + t.Fatalf("error creating fat32 filesystem: %v", err) } - fs, err := fatFunc(f, fileInfo.Size()-pre-post, pre, 512) + err = fs.Mkdir("/" + label) if err != nil { - t.Fatalf("error reading fat32 filesystem from %s: %v", f.Name(), err) - } - for _, p := range tests { - err := fs.Mkdir(p) - switch { - case err != nil: - t.Errorf("Mkdir(%s): error %v", p, err) - default: - // check that the directory actually was created - output := new(bytes.Buffer) - mpath := "/file.img" - mounts := map[string]string{ - f.Name(): mpath, - } - err := testhelper.DockerRun(nil, output, false, true, mounts, intImage, "mdir", "-i", fmt.Sprintf("%s@@%d", mpath, pre), fmt.Sprintf("::%s", p)) - if err != nil { - t.Errorf("Mkdir(%s): Unexpected err: %v", p, err) - t.Log(output.String()) - } - } + t.Fatalf("error creating directory with same name as label (%s): %v", label, err) } - } - t.Run("read to Mkdir", func(t *testing.T) { - t.Run("entire image", func(t *testing.T) { - runTest(t, 0, 0, fat32.Read) - }) - t.Run("embedded filesystem", func(t *testing.T) { - runTest(t, 500, 1000, fat32.Read) - }) - }) - t.Run("Create to Mkdir", func(t *testing.T) { - // This is to enable Create "fit" into the common testing logic - createShim := func(file util.File, size int64, start int64, blocksize int64) (*fat32.FileSystem, error) { - return fat32.Create(file, size, start, blocksize, "") - } - t.Run("entire image", func(t *testing.T) { - runTest(t, 0, 0, createShim) - }) - t.Run("embedded filesystem", func(t *testing.T) { - runTest(t, 500, 1000, createShim) - }) }) + + // only do this test if os.Getenv("TEST_IMAGE") contains a real image + // if intImage == "" { + // return + // } + // //nolint:thelper // this is not a helper function + // runTest := func(t *testing.T, post, pre int64, fatFunc func(util.File, int64, int64, int64) (*FileSystem, error)) { + // // create our directories + // tests := []string{ + // "/", + // "/foo", + // "/foo/bar", + // "/a/b/c", + // } + // f, err := tmpFat32(true, pre, post) + // 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 := fatFunc(f, fileInfo.Size()-pre-post, pre, 512) + // if err != nil { + // t.Fatalf("error reading fat32 filesystem from %s: %v", f.Name(), err) + // } + // for _, p := range tests { + // err := fs.Mkdir(p) + // switch { + // case err != nil: + // t.Errorf("Mkdir(%s): error %v", p, err) + // default: + // // check that the directory actually was created + // output := new(bytes.Buffer) + // mpath := "/file.img" + // mounts := map[string]string{ + // f.Name(): mpath, + // } + // err := testhelper.DockerRun(nil, output, false, true, mounts, intImage, "mdir", "-i", fmt.Sprintf("%s@@%d", mpath, pre), fmt.Sprintf("::%s", p)) + // if err != nil { + // t.Errorf("Mkdir(%s): Unexpected err: %v", p, err) + // t.Log(output.String()) + // } + // } + // } + // } + // t.Run("read to Mkdir", func(t *testing.T) { + // t.Run("entire image", func(t *testing.T) { + // runTest(t, 0, 0, Read) + // }) + // t.Run("embedded filesystem", func(t *testing.T) { + // runTest(t, 500, 1000, Read) + // }) + // }) + // t.Run("Create to Mkdir", func(t *testing.T) { + // // This is to enable Create "fit" into the common testing logic + // createShim := func(file util.File, size int64, start int64, blocksize int64) (*FileSystem, error) { + // return Create(file, size, start, blocksize, "") + // } + // t.Run("entire image", func(t *testing.T) { + // runTest(t, 0, 0, createShim) + // }) + // t.Run("embedded filesystem", func(t *testing.T) { + // runTest(t, 500, 1000, createShim) + // }) + // }) + } func TestFat32Create(t *testing.T) { tests := []struct { blocksize int64 filesize int64 - fs *fat32.FileSystem + fs *FileSystem err error }{ {500, 6000, nil, fmt.Errorf("blocksize for FAT32 must be")}, {513, 6000, nil, fmt.Errorf("blocksize for FAT32 must be")}, - {512, fat32.Fat32MaxSize + 100000, nil, fmt.Errorf("requested size is larger than maximum allowed FAT32")}, + {512, Fat32MaxSize + 100000, nil, fmt.Errorf("requested size is larger than maximum allowed FAT32")}, {512, 0, nil, fmt.Errorf("requested size is smaller than minimum allowed FAT32")}, - {512, 10000000, &fat32.FileSystem{}, nil}, + {512, 10000000, &FileSystem{}, nil}, } //nolint:thelper // this is not a helper function runTest := func(t *testing.T, pre, post int64) { @@ -203,7 +215,7 @@ func TestFat32Create(t *testing.T) { } defer os.Remove(f.Name()) // create the filesystem - fs, err := fat32.Create(f, tt.filesize-pre-post, pre, tt.blocksize, "") + fs, err := Create(f, tt.filesize-pre-post, pre, tt.blocksize, "") switch { case (err == nil && tt.err != nil) || (err != nil && tt.err == nil) || (err != nil && tt.err != nil && !strings.HasPrefix(err.Error(), tt.err.Error())): t.Errorf("Create(%s, %d, %d, %d): mismatched errors\nactual %v\nexpected %v", f.Name(), tt.filesize, 0, tt.blocksize, err, tt.err) @@ -233,15 +245,15 @@ func TestFat32Read(t *testing.T) { blocksize int64 filesize int64 bytechange int64 - fs *fat32.FileSystem + fs *FileSystem err error }{ {500, 6000, -1, nil, fmt.Errorf("blocksize for FAT32 must be")}, {513, 6000, -1, nil, fmt.Errorf("blocksize for FAT32 must be")}, - {512, fat32.Fat32MaxSize + 10000, -1, nil, fmt.Errorf("requested size is larger than maximum allowed FAT32 size")}, + {512, Fat32MaxSize + 10000, -1, nil, fmt.Errorf("requested size is larger than maximum allowed FAT32 size")}, {512, 0, -1, nil, fmt.Errorf("requested size is smaller than minimum allowed FAT32 size")}, {512, 10000000, 512, nil, fmt.Errorf("error reading FileSystem Information Sector")}, - {512, 10000000, -1, &fat32.FileSystem{}, nil}, + {512, 10000000, -1, &FileSystem{}, nil}, } //nolint:thelper // this is not a helper function runTest := func(t *testing.T, pre, post int64) { @@ -263,7 +275,7 @@ func TestFat32Read(t *testing.T) { corrupted = fmt.Sprintf("corrupted %d", tt.bytechange+pre) } // create the filesystem - fs, err := fat32.Read(f, tt.filesize-pre-post, pre, tt.blocksize) + fs, err := Read(f, tt.filesize-pre-post, pre, tt.blocksize) switch { case (err == nil && tt.err != nil) || (err != nil && tt.err == nil) || (err != nil && tt.err != nil && !strings.HasPrefix(err.Error(), tt.err.Error())): t.Errorf("read(%s, %d, %d, %d) %s: mismatched errors, actual %v expected %v", f.Name(), tt.filesize, 0, tt.blocksize, corrupted, err, tt.err) @@ -326,7 +338,7 @@ func TestFat32ReadDir(t *testing.T) { if err != nil { t.Fatalf("error getting file info for tmpfile %s: %v", f.Name(), err) } - fs, err := fat32.Read(f, fileInfo.Size()-pre-post, pre, 512) + fs, err := Read(f, fileInfo.Size()-pre-post, pre, 512) if err != nil { t.Fatalf("error reading fat32 filesystem from %s: %v", f.Name(), err) } @@ -395,7 +407,7 @@ func TestFat32OpenFile(t *testing.T) { if err != nil { t.Fatalf("error getting file info for tmpfile %s: %v", f.Name(), err) } - fs, err := fat32.Read(f, fileInfo.Size()-pre-post, pre, 512) + fs, err := Read(f, fileInfo.Size()-pre-post, pre, 512) if err != nil { t.Fatalf("error reading fat32 filesystem from %s: %v", f.Name(), err) } @@ -475,7 +487,7 @@ func TestFat32OpenFile(t *testing.T) { if err != nil { t.Fatalf("error getting file info for tmpfile %s: %v", f.Name(), err) } - fs, err := fat32.Read(f, fileInfo.Size()-pre-post, pre, 512) + fs, err := Read(f, fileInfo.Size()-pre-post, pre, 512) if err != nil { t.Fatalf("error reading fat32 filesystem from %s: %v", f.Name(), err) } @@ -551,7 +563,7 @@ func TestFat32OpenFile(t *testing.T) { if err != nil { t.Fatalf("error getting file info for tmpfile %s: %v", f.Name(), err) } - fs, err := fat32.Create(f, fileInfo.Size()-pre-post, pre, 512, " NO NAME") + fs, err := Create(f, fileInfo.Size()-pre-post, pre, 512, " NO NAME") if err != nil { t.Fatalf("error reading fat32 filesystem from %s: %v", f.Name(), err) } @@ -620,7 +632,7 @@ func TestFat32OpenFile(t *testing.T) { if err != nil { t.Fatalf("error getting file info for tmpfile %s: %v", f.Name(), err) } - fs, err := fat32.Read(f, fileInfo.Size()-pre-post, pre, 512) + fs, err := Read(f, fileInfo.Size()-pre-post, pre, 512) if err != nil { t.Fatalf("error reading fat32 filesystem from %s: %v", f.Name(), err) } @@ -680,7 +692,7 @@ func TestFat32OpenFile(t *testing.T) { 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) + fs, err := Read(f, fileInfo.Size(), 0, 512) if err != nil { t.Fatalf("error reading fat32 filesystem from %s: %v", f.Name(), err) } @@ -747,7 +759,7 @@ func TestFat32OpenFile(t *testing.T) { if err != nil { t.Fatalf("error getting file info for tmpfile %s: %v", f.Name(), err) } - fs, err := fat32.Read(f, fileInfo.Size()-pre-post, pre, 512) + fs, err := Read(f, fileInfo.Size()-pre-post, pre, 512) if err != nil { t.Fatalf("error reading fat32 filesystem from %s: %v", f.Name(), err) } @@ -806,6 +818,27 @@ func TestFat32OpenFile(t *testing.T) { } func TestFat32Label(t *testing.T) { + t.Run("validate labels", func(t *testing.T) { + label, err := validateAndFormatVolumeLabel("foo") + if err != nil { + t.Fatal(err) + } + if label != "foo " { + t.Fatal("invalid format") + } + + label, err = validateAndFormatVolumeLabel("ahfkjsdhfkjshdkjfhkhsdf") + if err == nil { + t.Fatal("expected error validating input over accepted length") + } + + label, err = validateAndFormatVolumeLabel("*") + if err == nil { + t.Fatal("expected error validating input with bad character") + } + + }) + t.Run("read-label", func(t *testing.T) { // get a mock filesystem image f, err := tmpFat32(true, 0, 0) @@ -825,7 +858,7 @@ func TestFat32Label(t *testing.T) { } // read the filesystem - fs, err := fat32.Read(f, fileInfo.Size(), 0, 512) + fs, err := Read(f, fileInfo.Size(), 0, 512) if err != nil { t.Fatalf("error reading fat32 filesystem from %s: %v", f.Name(), err) } @@ -856,7 +889,7 @@ func TestFat32Label(t *testing.T) { } // create an empty filesystem - fs, err := fat32.Create(f, fileInfo.Size(), 0, 512, "go-diskfs") + fs, err := Create(f, fileInfo.Size(), 0, 512, "go-diskfs") if err != nil { t.Fatalf("error creating fat32 filesystem: %v", err) } @@ -877,7 +910,7 @@ func TestFat32Label(t *testing.T) { } // read the filesystem - fs, err = fat32.Read(f, fileInfo.Size(), 0, 512) + fs, err = Read(f, fileInfo.Size(), 0, 512) if err != nil { t.Fatalf("error reading fat32 filesystem from %s: %v", f.Name(), err) } @@ -908,7 +941,7 @@ func TestFat32Label(t *testing.T) { } // create an empty filesystem - fs, err := fat32.Create(f, fileInfo.Size(), 0, 512, "go-diskfs") + fs, err := Create(f, fileInfo.Size(), 0, 512, "go-diskfs") if err != nil { t.Fatalf("error creating fat32 filesystem: %v", err) } @@ -935,7 +968,7 @@ func TestFat32Label(t *testing.T) { } // read the filesystem - fs, err = fat32.Read(f, fileInfo.Size(), 0, 512) + fs, err = Read(f, fileInfo.Size(), 0, 512) if err != nil { t.Fatalf("error reading fat32 filesystem from %s: %v", f.Name(), err) } From a236c934b9cde453be9922825f3626e7b0523e3b Mon Sep 17 00:00:00 2001 From: Antonio Pires Date: Fri, 2 Dec 2022 14:10:33 -0600 Subject: [PATCH 2/3] mend --- filesystem/fat32/fat32_test.go | 221 ++++++++++++++------------------- 1 file changed, 94 insertions(+), 127 deletions(-) diff --git a/filesystem/fat32/fat32_test.go b/filesystem/fat32/fat32_test.go index 197b59c2..5b1bca19 100644 --- a/filesystem/fat32/fat32_test.go +++ b/filesystem/fat32/fat32_test.go @@ -1,4 +1,4 @@ -package fat32 +package fat32_test /* These tests the exported functions @@ -15,6 +15,9 @@ import ( "testing" "github.com/diskfs/go-diskfs/filesystem" + "github.com/diskfs/go-diskfs/filesystem/fat32" + "github.com/diskfs/go-diskfs/testhelper" + "github.com/diskfs/go-diskfs/util" ) var ( @@ -46,9 +49,9 @@ func tmpFat32(fill bool, embedPre, embedPost int64) (*os.File, error) { } // either copy the contents of the base file over, or make a file of similar size - b, err := os.ReadFile(Fat32File) + b, err := os.ReadFile(fat32.Fat32File) if err != nil { - return nil, fmt.Errorf("Failed to read contents of %s: %v", Fat32File, err) + return nil, fmt.Errorf("Failed to read contents of %s: %v", fat32.Fat32File, err) } if embedPre > 0 { empty := make([]byte, embedPre) @@ -63,10 +66,10 @@ func tmpFat32(fill bool, embedPre, embedPost int64) (*os.File, error) { if fill { written, err := f.Write(b) if err != nil { - return nil, fmt.Errorf("Failed to write contents of %s to %s: %v", Fat32File, filename, err) + return nil, fmt.Errorf("Failed to write contents of %s to %s: %v", fat32.Fat32File, filename, err) } if written != len(b) { - return nil, fmt.Errorf("wrote only %d bytes of %s to %s instead of %d", written, Fat32File, filename, len(b)) + return nil, fmt.Errorf("wrote only %d bytes of %s to %s instead of %d", written, fat32.Fat32File, filename, len(b)) } } else { size := int64(len(b)) @@ -94,7 +97,7 @@ func tmpFat32(fill bool, embedPre, embedPost int64) (*os.File, error) { } func TestFat32Type(t *testing.T) { - fs := &FileSystem{} + fs := &fat32.FileSystem{} fstype := fs.Type() expected := filesystem.TypeFat32 if fstype != expected { @@ -103,105 +106,90 @@ func TestFat32Type(t *testing.T) { } func TestFat32Mkdir(t *testing.T) { - t.Run("Creating directory at root with the same name as volume", func(t *testing.T) { - f, err := os.CreateTemp("", "*") - label := "boot" - // create an empty filesystem - fs, err := Create(f, 1000000, 0, 512, label) + // only do this test if os.Getenv("TEST_IMAGE") contains a real image + if intImage == "" { + return + } + //nolint:thelper // this is not a helper function + runTest := func(t *testing.T, post, pre int64, fatFunc func(util.File, int64, int64, int64) (*fat32.FileSystem, error)) { + // create our directories + tests := []string{ + "/", + "/foo", + "/foo/bar", + "/a/b/c", + } + f, err := tmpFat32(true, pre, post) if err != nil { - t.Fatalf("error creating fat32 filesystem: %v", err) + t.Fatal(err) + } + if keepTmpFiles == "" { + defer os.Remove(f.Name()) + } else { + fmt.Println(f.Name()) } - err = fs.Mkdir("/" + label) + fileInfo, err := f.Stat() + if err != nil { + t.Fatalf("error getting file info for tmpfile %s: %v", f.Name(), err) + } + fs, err := fatFunc(f, fileInfo.Size()-pre-post, pre, 512) if err != nil { - t.Fatalf("error creating directory with same name as label (%s): %v", label, err) + t.Fatalf("error reading fat32 filesystem from %s: %v", f.Name(), err) + } + for _, p := range tests { + err := fs.Mkdir(p) + switch { + case err != nil: + t.Errorf("Mkdir(%s): error %v", p, err) + default: + // check that the directory actually was created + output := new(bytes.Buffer) + mpath := "/file.img" + mounts := map[string]string{ + f.Name(): mpath, + } + err := testhelper.DockerRun(nil, output, false, true, mounts, intImage, "mdir", "-i", fmt.Sprintf("%s@@%d", mpath, pre), fmt.Sprintf("::%s", p)) + if err != nil { + t.Errorf("Mkdir(%s): Unexpected err: %v", p, err) + t.Log(output.String()) + } + } } + } + t.Run("read to Mkdir", func(t *testing.T) { + t.Run("entire image", func(t *testing.T) { + runTest(t, 0, 0, fat32.Read) + }) + t.Run("embedded filesystem", func(t *testing.T) { + runTest(t, 500, 1000, fat32.Read) + }) + }) + t.Run("Create to Mkdir", func(t *testing.T) { + // This is to enable Create "fit" into the common testing logic + createShim := func(file util.File, size int64, start int64, blocksize int64) (*fat32.FileSystem, error) { + return fat32.Create(file, size, start, blocksize, "") + } + t.Run("entire image", func(t *testing.T) { + runTest(t, 0, 0, createShim) + }) + t.Run("embedded filesystem", func(t *testing.T) { + runTest(t, 500, 1000, createShim) + }) }) - - // only do this test if os.Getenv("TEST_IMAGE") contains a real image - // if intImage == "" { - // return - // } - // //nolint:thelper // this is not a helper function - // runTest := func(t *testing.T, post, pre int64, fatFunc func(util.File, int64, int64, int64) (*FileSystem, error)) { - // // create our directories - // tests := []string{ - // "/", - // "/foo", - // "/foo/bar", - // "/a/b/c", - // } - // f, err := tmpFat32(true, pre, post) - // 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 := fatFunc(f, fileInfo.Size()-pre-post, pre, 512) - // if err != nil { - // t.Fatalf("error reading fat32 filesystem from %s: %v", f.Name(), err) - // } - // for _, p := range tests { - // err := fs.Mkdir(p) - // switch { - // case err != nil: - // t.Errorf("Mkdir(%s): error %v", p, err) - // default: - // // check that the directory actually was created - // output := new(bytes.Buffer) - // mpath := "/file.img" - // mounts := map[string]string{ - // f.Name(): mpath, - // } - // err := testhelper.DockerRun(nil, output, false, true, mounts, intImage, "mdir", "-i", fmt.Sprintf("%s@@%d", mpath, pre), fmt.Sprintf("::%s", p)) - // if err != nil { - // t.Errorf("Mkdir(%s): Unexpected err: %v", p, err) - // t.Log(output.String()) - // } - // } - // } - // } - // t.Run("read to Mkdir", func(t *testing.T) { - // t.Run("entire image", func(t *testing.T) { - // runTest(t, 0, 0, Read) - // }) - // t.Run("embedded filesystem", func(t *testing.T) { - // runTest(t, 500, 1000, Read) - // }) - // }) - // t.Run("Create to Mkdir", func(t *testing.T) { - // // This is to enable Create "fit" into the common testing logic - // createShim := func(file util.File, size int64, start int64, blocksize int64) (*FileSystem, error) { - // return Create(file, size, start, blocksize, "") - // } - // t.Run("entire image", func(t *testing.T) { - // runTest(t, 0, 0, createShim) - // }) - // t.Run("embedded filesystem", func(t *testing.T) { - // runTest(t, 500, 1000, createShim) - // }) - // }) - } func TestFat32Create(t *testing.T) { tests := []struct { blocksize int64 filesize int64 - fs *FileSystem + fs *fat32.FileSystem err error }{ {500, 6000, nil, fmt.Errorf("blocksize for FAT32 must be")}, {513, 6000, nil, fmt.Errorf("blocksize for FAT32 must be")}, - {512, Fat32MaxSize + 100000, nil, fmt.Errorf("requested size is larger than maximum allowed FAT32")}, + {512, fat32.Fat32MaxSize + 100000, nil, fmt.Errorf("requested size is larger than maximum allowed FAT32")}, {512, 0, nil, fmt.Errorf("requested size is smaller than minimum allowed FAT32")}, - {512, 10000000, &FileSystem{}, nil}, + {512, 10000000, &fat32.FileSystem{}, nil}, } //nolint:thelper // this is not a helper function runTest := func(t *testing.T, pre, post int64) { @@ -215,7 +203,7 @@ func TestFat32Create(t *testing.T) { } defer os.Remove(f.Name()) // create the filesystem - fs, err := Create(f, tt.filesize-pre-post, pre, tt.blocksize, "") + fs, err := fat32.Create(f, tt.filesize-pre-post, pre, tt.blocksize, "") switch { case (err == nil && tt.err != nil) || (err != nil && tt.err == nil) || (err != nil && tt.err != nil && !strings.HasPrefix(err.Error(), tt.err.Error())): t.Errorf("Create(%s, %d, %d, %d): mismatched errors\nactual %v\nexpected %v", f.Name(), tt.filesize, 0, tt.blocksize, err, tt.err) @@ -245,15 +233,15 @@ func TestFat32Read(t *testing.T) { blocksize int64 filesize int64 bytechange int64 - fs *FileSystem + fs *fat32.FileSystem err error }{ {500, 6000, -1, nil, fmt.Errorf("blocksize for FAT32 must be")}, {513, 6000, -1, nil, fmt.Errorf("blocksize for FAT32 must be")}, - {512, Fat32MaxSize + 10000, -1, nil, fmt.Errorf("requested size is larger than maximum allowed FAT32 size")}, + {512, fat32.Fat32MaxSize + 10000, -1, nil, fmt.Errorf("requested size is larger than maximum allowed FAT32 size")}, {512, 0, -1, nil, fmt.Errorf("requested size is smaller than minimum allowed FAT32 size")}, {512, 10000000, 512, nil, fmt.Errorf("error reading FileSystem Information Sector")}, - {512, 10000000, -1, &FileSystem{}, nil}, + {512, 10000000, -1, &fat32.FileSystem{}, nil}, } //nolint:thelper // this is not a helper function runTest := func(t *testing.T, pre, post int64) { @@ -275,7 +263,7 @@ func TestFat32Read(t *testing.T) { corrupted = fmt.Sprintf("corrupted %d", tt.bytechange+pre) } // create the filesystem - fs, err := Read(f, tt.filesize-pre-post, pre, tt.blocksize) + fs, err := fat32.Read(f, tt.filesize-pre-post, pre, tt.blocksize) switch { case (err == nil && tt.err != nil) || (err != nil && tt.err == nil) || (err != nil && tt.err != nil && !strings.HasPrefix(err.Error(), tt.err.Error())): t.Errorf("read(%s, %d, %d, %d) %s: mismatched errors, actual %v expected %v", f.Name(), tt.filesize, 0, tt.blocksize, corrupted, err, tt.err) @@ -338,7 +326,7 @@ func TestFat32ReadDir(t *testing.T) { if err != nil { t.Fatalf("error getting file info for tmpfile %s: %v", f.Name(), err) } - fs, err := Read(f, fileInfo.Size()-pre-post, pre, 512) + fs, err := fat32.Read(f, fileInfo.Size()-pre-post, pre, 512) if err != nil { t.Fatalf("error reading fat32 filesystem from %s: %v", f.Name(), err) } @@ -407,7 +395,7 @@ func TestFat32OpenFile(t *testing.T) { if err != nil { t.Fatalf("error getting file info for tmpfile %s: %v", f.Name(), err) } - fs, err := Read(f, fileInfo.Size()-pre-post, pre, 512) + fs, err := fat32.Read(f, fileInfo.Size()-pre-post, pre, 512) if err != nil { t.Fatalf("error reading fat32 filesystem from %s: %v", f.Name(), err) } @@ -487,7 +475,7 @@ func TestFat32OpenFile(t *testing.T) { if err != nil { t.Fatalf("error getting file info for tmpfile %s: %v", f.Name(), err) } - fs, err := Read(f, fileInfo.Size()-pre-post, pre, 512) + fs, err := fat32.Read(f, fileInfo.Size()-pre-post, pre, 512) if err != nil { t.Fatalf("error reading fat32 filesystem from %s: %v", f.Name(), err) } @@ -563,7 +551,7 @@ func TestFat32OpenFile(t *testing.T) { if err != nil { t.Fatalf("error getting file info for tmpfile %s: %v", f.Name(), err) } - fs, err := Create(f, fileInfo.Size()-pre-post, pre, 512, " NO NAME") + fs, err := fat32.Create(f, fileInfo.Size()-pre-post, pre, 512, " NO NAME") if err != nil { t.Fatalf("error reading fat32 filesystem from %s: %v", f.Name(), err) } @@ -632,7 +620,7 @@ func TestFat32OpenFile(t *testing.T) { if err != nil { t.Fatalf("error getting file info for tmpfile %s: %v", f.Name(), err) } - fs, err := Read(f, fileInfo.Size()-pre-post, pre, 512) + fs, err := fat32.Read(f, fileInfo.Size()-pre-post, pre, 512) if err != nil { t.Fatalf("error reading fat32 filesystem from %s: %v", f.Name(), err) } @@ -692,7 +680,7 @@ func TestFat32OpenFile(t *testing.T) { if err != nil { t.Fatalf("error getting file info for tmpfile %s: %v", f.Name(), err) } - fs, err := Read(f, fileInfo.Size(), 0, 512) + fs, err := fat32.Read(f, fileInfo.Size(), 0, 512) if err != nil { t.Fatalf("error reading fat32 filesystem from %s: %v", f.Name(), err) } @@ -759,7 +747,7 @@ func TestFat32OpenFile(t *testing.T) { if err != nil { t.Fatalf("error getting file info for tmpfile %s: %v", f.Name(), err) } - fs, err := Read(f, fileInfo.Size()-pre-post, pre, 512) + fs, err := fat32.Read(f, fileInfo.Size()-pre-post, pre, 512) if err != nil { t.Fatalf("error reading fat32 filesystem from %s: %v", f.Name(), err) } @@ -818,27 +806,6 @@ func TestFat32OpenFile(t *testing.T) { } func TestFat32Label(t *testing.T) { - t.Run("validate labels", func(t *testing.T) { - label, err := validateAndFormatVolumeLabel("foo") - if err != nil { - t.Fatal(err) - } - if label != "foo " { - t.Fatal("invalid format") - } - - label, err = validateAndFormatVolumeLabel("ahfkjsdhfkjshdkjfhkhsdf") - if err == nil { - t.Fatal("expected error validating input over accepted length") - } - - label, err = validateAndFormatVolumeLabel("*") - if err == nil { - t.Fatal("expected error validating input with bad character") - } - - }) - t.Run("read-label", func(t *testing.T) { // get a mock filesystem image f, err := tmpFat32(true, 0, 0) @@ -858,7 +825,7 @@ func TestFat32Label(t *testing.T) { } // read the filesystem - fs, err := Read(f, fileInfo.Size(), 0, 512) + fs, err := fat32.Read(f, fileInfo.Size(), 0, 512) if err != nil { t.Fatalf("error reading fat32 filesystem from %s: %v", f.Name(), err) } @@ -889,7 +856,7 @@ func TestFat32Label(t *testing.T) { } // create an empty filesystem - fs, err := Create(f, fileInfo.Size(), 0, 512, "go-diskfs") + fs, err := fat32.Create(f, fileInfo.Size(), 0, 512, "go-diskfs") if err != nil { t.Fatalf("error creating fat32 filesystem: %v", err) } @@ -910,7 +877,7 @@ func TestFat32Label(t *testing.T) { } // read the filesystem - fs, err = Read(f, fileInfo.Size(), 0, 512) + fs, err = fat32.Read(f, fileInfo.Size(), 0, 512) if err != nil { t.Fatalf("error reading fat32 filesystem from %s: %v", f.Name(), err) } @@ -941,7 +908,7 @@ func TestFat32Label(t *testing.T) { } // create an empty filesystem - fs, err := Create(f, fileInfo.Size(), 0, 512, "go-diskfs") + fs, err := fat32.Create(f, fileInfo.Size(), 0, 512, "go-diskfs") if err != nil { t.Fatalf("error creating fat32 filesystem: %v", err) } @@ -968,7 +935,7 @@ func TestFat32Label(t *testing.T) { } // read the filesystem - fs, err = Read(f, fileInfo.Size(), 0, 512) + fs, err = fat32.Read(f, fileInfo.Size(), 0, 512) if err != nil { t.Fatalf("error reading fat32 filesystem from %s: %v", f.Name(), err) } From a6d242606075e1547fa1bf0656a3bcf5f6437a6b Mon Sep 17 00:00:00 2001 From: Antonio Pires Date: Fri, 2 Dec 2022 14:12:46 -0600 Subject: [PATCH 3/3] mend --- filesystem/fat32/fat32_internal_test.go | 21 +++++++++++++++++++++ filesystem/fat32/fat32_test.go | 14 ++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/filesystem/fat32/fat32_internal_test.go b/filesystem/fat32/fat32_internal_test.go index 4b300061..da19b8f2 100644 --- a/filesystem/fat32/fat32_internal_test.go +++ b/filesystem/fat32/fat32_internal_test.go @@ -348,3 +348,24 @@ func TestFat32ReadDirWithMkdir(t *testing.T) { } } } + +func TestFat32ValidateAndFormatVolumeLabel(t *testing.T) { + label, err := validateAndFormatVolumeLabel("foo") + if err != nil { + t.Fatal(err) + } + if label != "foo " { + t.Fatal("invalid format") + } + + label, err = validateAndFormatVolumeLabel("ahfkjsdhfkjshdkjfhkhsdf") + if err == nil { + t.Fatal("expected error validating input over accepted length") + } + + label, err = validateAndFormatVolumeLabel("*") + if err == nil { + t.Fatal("expected error validating input with bad character") + } + +} diff --git a/filesystem/fat32/fat32_test.go b/filesystem/fat32/fat32_test.go index 5b1bca19..226dff96 100644 --- a/filesystem/fat32/fat32_test.go +++ b/filesystem/fat32/fat32_test.go @@ -106,6 +106,20 @@ func TestFat32Type(t *testing.T) { } func TestFat32Mkdir(t *testing.T) { + t.Run("Creating directory at root with the same name as volume", func(t *testing.T) { + f, err := os.CreateTemp("", "*") + label := "boot" + // create an empty filesystem + fs, err := fat32.Create(f, 1000000, 0, 512, label) + if err != nil { + t.Fatalf("error creating fat32 filesystem: %v", err) + } + err = fs.Mkdir("/" + label) + if err != nil { + t.Fatalf("error creating directory with same name as label (%s): %v", label, err) + } + }) + // only do this test if os.Getenv("TEST_IMAGE") contains a real image if intImage == "" { return