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