Commit 1989e683 authored by Han-Wen Nienhuys's avatar Han-Wen Nienhuys

Fix bug with dirent padding.

Add test case with random filename lengths.
parent a9d18e32
...@@ -45,7 +45,7 @@ type MountState struct { ...@@ -45,7 +45,7 @@ type MountState struct {
// Run each operation in its own Go-routine. // Run each operation in its own Go-routine.
threaded bool threaded bool
// Dump debug info onto stdout. // Dump debug info onto stdout.
Debug bool Debug bool
} }
...@@ -97,7 +97,7 @@ func (self *MountState) UnregisterDir(handle uint64) { ...@@ -97,7 +97,7 @@ func (self *MountState) UnregisterDir(handle uint64) {
// If threaded is set, each filesystem operation executes in a // If threaded is set, each filesystem operation executes in a
// separate goroutine, and errors and writes are done asynchronously // separate goroutine, and errors and writes are done asynchronously
// using channels. // using channels.
// //
// TODO - error handling should perhaps be user-serviceable. // TODO - error handling should perhaps be user-serviceable.
func (self *MountState) Mount(mountPoint string, threaded bool) os.Error { func (self *MountState) Mount(mountPoint string, threaded bool) os.Error {
file, mp, err := mount(mountPoint) file, mp, err := mount(mountPoint)
...@@ -355,7 +355,7 @@ func dispatch(state *MountState, h *InHeader, arg *bytes.Buffer) (outBytes [][]b ...@@ -355,7 +355,7 @@ func dispatch(state *MountState, h *InHeader, arg *bytes.Buffer) (outBytes [][]b
case FUSE_CREATE: case FUSE_CREATE:
out, status = doCreate(state, h, input.(*CreateIn), filename) out, status = doCreate(state, h, input.(*CreateIn), filename)
// TODO - implement file locking. // TODO - implement file locking.
// case FUSE_SETLK // case FUSE_SETLK
// case FUSE_SETLKW // case FUSE_SETLKW
case FUSE_BMAP: case FUSE_BMAP:
...@@ -404,7 +404,7 @@ func serialize(h *InHeader, res Status, out interface{}, debug bool) (data [][]b ...@@ -404,7 +404,7 @@ func serialize(h *InHeader, res Status, out interface{}, debug bool) (data [][]b
if len(val) > max { if len(val) > max {
val = val[:max] + fmt.Sprintf(" ...trimmed (response size %d)", len(b.Bytes())) val = val[:max] + fmt.Sprintf(" ...trimmed (response size %d)", len(b.Bytes()))
} }
log.Printf("Serialize: %v code: %v value: %v\n", log.Printf("Serialize: %v code: %v value: %v\n",
operationName(h.Opcode), errorString(res), val) operationName(h.Opcode), errorString(res), val)
} }
...@@ -542,7 +542,6 @@ func (de *DEntryList) AddString(name string, inode uint64, mode uint32) { ...@@ -542,7 +542,6 @@ func (de *DEntryList) AddString(name string, inode uint64, mode uint32) {
func (de *DEntryList) Add(name []byte, inode uint64, mode uint32) { func (de *DEntryList) Add(name []byte, inode uint64, mode uint32) {
de.offset++ de.offset++
dirent := new(Dirent) dirent := new(Dirent)
dirent.Off = de.offset dirent.Off = de.offset
dirent.Ino = inode dirent.Ino = inode
...@@ -553,11 +552,11 @@ func (de *DEntryList) Add(name []byte, inode uint64, mode uint32) { ...@@ -553,11 +552,11 @@ func (de *DEntryList) Add(name []byte, inode uint64, mode uint32) {
if err != nil { if err != nil {
panic("Serialization of Dirent failed") panic("Serialization of Dirent failed")
} }
de.buf.Write([]byte(name)) de.buf.Write(name)
de.buf.WriteByte(0)
n := (len(name) + 1) % 8 // padding padding := 8 - len(name)&7
if n != 0 { if padding < 8 {
de.buf.Write(make([]byte, 8-n)) de.buf.Write(make([]byte, padding))
} }
} }
......
...@@ -9,6 +9,7 @@ import ( ...@@ -9,6 +9,7 @@ import (
"strings" "strings"
"testing" "testing"
"syscall" "syscall"
"rand"
) )
var _ = strings.Join var _ = strings.Join
...@@ -152,7 +153,7 @@ func (self *testCase) testReadThroughFuse() { ...@@ -152,7 +153,7 @@ func (self *testCase) testReadThroughFuse() {
self.tester.Errorf("Wrong mode %o != %o", fi.Mode, mode) self.tester.Errorf("Wrong mode %o != %o", fi.Mode, mode)
} }
// Open (for read), read. // Open (for read), read.
fmt.Println("Testing open.") fmt.Println("Testing open.")
f, err := os.Open(self.mountFile, os.O_RDONLY, 0) f, err := os.Open(self.mountFile, os.O_RDONLY, 0)
if err != nil { if err != nil {
...@@ -188,7 +189,7 @@ func (self *testCase) testRemove() { ...@@ -188,7 +189,7 @@ func (self *testCase) testRemove() {
} }
func (self *testCase) testWriteThroughFuse() { func (self *testCase) testWriteThroughFuse() {
// Create (for write), write. // Create (for write), write.
fmt.Println("Testing create.") fmt.Println("Testing create.")
f, err := os.Open(self.mountFile, os.O_WRONLY|os.O_CREATE, 0644) f, err := os.Open(self.mountFile, os.O_WRONLY|os.O_CREATE, 0644)
if err != nil { if err != nil {
...@@ -450,12 +451,12 @@ func (self *testCase) testLargeRead() { ...@@ -450,12 +451,12 @@ func (self *testCase) testLargeRead() {
if err != nil { if err != nil {
self.tester.Errorf("write err %v %v", err, n) self.tester.Errorf("write err %v %v", err, n)
} }
err = f.Close() err = f.Close()
if err != nil { if err != nil {
self.tester.Errorf("close err %v", err) self.tester.Errorf("close err %v", err)
} }
// Read in one go. // Read in one go.
g, err := os.Open(path.Join(self.mountPoint, "large"), os.O_RDONLY, 0) g, err := os.Open(path.Join(self.mountPoint, "large"), os.O_RDONLY, 0)
if err != nil { if err != nil {
...@@ -472,7 +473,7 @@ func (self *testCase) testLargeRead() { ...@@ -472,7 +473,7 @@ func (self *testCase) testLargeRead() {
break break
} }
} }
if err != nil { if err != nil {
self.tester.Errorf("read mismatch %v", err) self.tester.Errorf("read mismatch %v", err)
} }
...@@ -484,7 +485,7 @@ func (self *testCase) testLargeRead() { ...@@ -484,7 +485,7 @@ func (self *testCase) testLargeRead() {
self.tester.Errorf("open err %v", err) self.tester.Errorf("open err %v", err)
} }
readSlice = make([]byte, 4096) readSlice = make([]byte, 4096)
total := 0 total := 0
for { for {
m, err := g.Read(readSlice) m, err := g.Read(readSlice)
if m == 0 && err == os.EOF { if m == 0 && err == os.EOF {
...@@ -494,29 +495,48 @@ func (self *testCase) testLargeRead() { ...@@ -494,29 +495,48 @@ func (self *testCase) testLargeRead() {
self.tester.Errorf("read err %v %v", err, m) self.tester.Errorf("read err %v %v", err, m)
break break
} }
total += m total += m
} }
if total != len(slice) { if total != len(slice) {
self.tester.Errorf("slice error %d", total) self.tester.Errorf("slice error %d", total)
} }
g.Close() g.Close()
os.Remove(name) os.Remove(name)
} }
func randomLengthString(length int) string {
r := rand.Intn(length)
j := 0
b := make([]byte, r)
for i := 0; i < r; i++ {
j = (j + 1) % 10
b[i] = byte(j) + byte('0')
}
return string(b)
}
func (self *testCase) testLargeDirRead() { func (self *testCase) testLargeDirRead() {
count := 100 created := 100
names := make([]string, count) names := make([]string, created)
subdir := path.Join(self.origDir, "readdirSubdir") subdir := path.Join(self.origDir, "readdirSubdir")
os.Mkdir(subdir, 0700) os.Mkdir(subdir, 0700)
longname := "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
for i := 0; i < count; i++ { nameSet := make(map[string]bool)
for i := 0; i < created; i++ {
// Should vary file name length. // Should vary file name length.
name := path.Join(subdir, fmt.Sprintf("file%d", i)) base := fmt.Sprintf("file%d%s", i,
randomLengthString(len(longname)))
name := path.Join(subdir, base)
nameSet[base] = true
f, err := os.Open(name, os.O_WRONLY | os.O_CREATE, 0777) f, err := os.Open(name, os.O_WRONLY | os.O_CREATE, 0777)
if err != nil { if err != nil {
self.tester.Errorf("open write err %v", err) self.tester.Errorf("open write err %v", err)
...@@ -534,22 +554,34 @@ func (self *testCase) testLargeDirRead() { ...@@ -534,22 +554,34 @@ func (self *testCase) testLargeDirRead() {
} }
// Chunked read. // Chunked read.
total := 0 total := 0
readSet := make(map[string] bool)
for { for {
namesRead, err := dir.Readdirnames(20) namesRead, err := dir.Readdirnames(20)
if err != nil { if err != nil {
self.tester.Errorf("readdir err %v %v", err, namesRead) self.tester.Errorf("readdir err %v %v", err, namesRead)
} }
if len(namesRead) == 0 { if len(namesRead) == 0 {
break break
} }
for _, v := range(namesRead) {
readSet[v] = true
}
total += len(namesRead) total += len(namesRead)
} }
if total != count { if total != created {
self.tester.Errorf("readdir mismatch %v %v", total, count) self.tester.Errorf("readdir mismatch got %v wanted %v", total, created)
} }
for k, _ := range(nameSet) {
_, ok := readSet[k]
if !ok {
self.tester.Errorf("Name %v not found", k)
}
}
dir.Close() dir.Close()
os.RemoveAll(subdir) os.RemoveAll(subdir)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment