示例#1
0
文件: read.go 项目: hugelgupf/ninep
// Reads the content of the directory associated with the File.
// Returns an array of maximum num entries (if num is 0, returns
// all entries from the directory). If the operation fails, returns
// an Error.
func (file *File) Readdir(num int) ([]*ninep.Dir, error) {
	buf := make([]byte, file.fid.Clnt.Msize-ninep.IOHDRSZ)
	var dirs []*ninep.Dir
	pos := 0
	for {
		n, err := file.Read(buf)
		if err != nil && err != io.EOF {
			return dirs[0:pos], err
		}

		if n == 0 {
			return dirs[0:pos], io.EOF
		}

		var d *ninep.Dir
		b := buf[:n]
		for len(b) > 0 {
			var perr error
			d, b, _, perr = ninep.UnpackDir(b, file.Fid().Clnt.Dotu)
			if perr != nil {
				// If we have unpacked anything, it is almost certainly
				// a too-short buffer. So return what we got.
				if pos > 0 {
					return dirs[0:pos], nil
				}
				return nil, perr
			}

			dirs = append(dirs, d)
			pos++
			if num != 0 && pos >= num {
				break
			}
		}
	}
}
示例#2
0
func TestAttachOpenReaddir(t *testing.T) {
	var err error
	clnt, rootfid := setup(9000, t.Fatal)

	dirfid := clnt.FidAlloc()
	if _, err = clnt.Walk(rootfid, dirfid, []string{}); err != nil {
		t.Fatalf("%v", err)
	}

	if err = clnt.Open(dirfid, 0); err != nil {
		t.Fatalf("%v", err)
	}
	var b []byte
	if b, err = clnt.Read(dirfid, 0, 64*1024); err != nil {
		t.Fatalf("%v", err)
	}
	var i, amt int
	var offset uint64
	err = nil
	for err == nil {
		if b, err = clnt.Read(dirfid, offset, 64*1024); err != nil {
			t.Fatalf("%v", err)
		}

		if len(b) == 0 {
			break
		}
		for b != nil && len(b) > 0 {
			if _, b, amt, err = ninep.UnpackDir(b, true); err != nil {
				t.Errorf("UnpackDir returns %v", err)
				break
			} else {
				i++
				offset += uint64(amt)
			}
		}
	}
	if i != len(dirQids) {
		t.Fatalf("Reading: got %d entries, wanted %d, err %v", i, len(dirQids), err)
	}

	t.Logf("-----------------------------> Alternate form, using readdir and File")
	// Alternate form, using readdir and File
	dirfile, err := clnt.FOpen(".", ninep.OREAD)
	if err != nil {
		t.Fatalf("%v", err)
	}
	i, amt, offset = 0, 0, 0
	err = nil

	for err == nil {
		d, err := dirfile.Readdir(64)
		if err != nil && err != io.EOF {
			t.Errorf("%v", err)
		}

		if len(d) == 0 {
			break
		}
		i += len(d)
		if i >= len(dirQids) {
			break
		}
	}
	if i != len(dirQids)-1 {
		t.Fatalf("Readdir: got %d entries, wanted %d", i, len(dirQids)-1)
	}
}
示例#3
0
func TestAttachOpenReaddir(t *testing.T) {
	var err error
	flag.Parse()
	ufs := new(ufs.Ufs)
	ufs.Dotu = false
	ufs.Id = "ufs"
	ufs.Debuglevel = *debug
	ufs.Start(ufs)
	tmpDir, err := ioutil.TempDir("", "go9")
	if err != nil {
		t.Fatal("Can't create temp directory")
	}
	//defer os.RemoveAll(tmpDir)
	ufs.Root = tmpDir

	t.Logf("ufs starting in %v\n", tmpDir)
	// determined by build tags
	//extraFuncs()
	l, err := net.Listen("unix", "")
	if err != nil {
		t.Fatalf("Can not start listener: %v", err)
	}
	srvAddr := l.Addr().String()
	t.Logf("Server is at %v", srvAddr)
	go func() {
		if err = ufs.StartListener(l); err != nil {
			t.Fatalf("Can not start listener: %v", err)
		}
	}()

	user := ninep.OsUsers.Uid2User(os.Geteuid())
	clnt, err := Mount("unix", srvAddr, "/", 8192, user)
	if err != nil {
		t.Fatalf("Connect failed: %v\n", err)
	}
	rootfid := clnt.Root
	clnt.Debuglevel = 0 // *debug
	t.Logf("mounted, rootfid %v\n", rootfid)

	dirfid := clnt.FidAlloc()
	if _, err = clnt.Walk(rootfid, dirfid, []string{"."}); err != nil {
		t.Fatalf("%v", err)
	}

	// Now create a whole bunch of files to test readdir
	for i := 0; i < *numDir; i++ {
		f := fmt.Sprintf(path.Join(tmpDir, fmt.Sprintf("%d", i)))
		if err := ioutil.WriteFile(f, []byte(f), 0600); err != nil {
			t.Fatalf("Create %v: got %v, want nil", f, err)
		}
	}

	if err = clnt.Open(dirfid, 0); err != nil {
		t.Fatalf("%v", err)
	}
	var b []byte
	if b, err = clnt.Read(dirfid, 0, 64*1024); err != nil {
		t.Fatalf("%v", err)
	}
	var i, amt int
	var offset uint64
	err = nil
	found := make([]int, *numDir)
	fail := false
	for err == nil {
		if b, err = clnt.Read(dirfid, offset, 64*1024); err != nil {
			t.Fatalf("%v", err)
		}
		t.Logf("clnt.Read returns [%v,%v]", len(b), err)
		if len(b) == 0 {
			break
		}
		for b != nil && len(b) > 0 {
			var d *ninep.Dir
			if d, b, amt, err = ninep.UnpackDir(b, ufs.Dotu); err != nil {
				t.Errorf("UnpackDir returns %v", err)
				break
			} else {
				if *debug > 128 {
					t.Logf("Entry %d: %v", i, d)
				}
				i++
				offset += uint64(amt)
				ix, err := strconv.Atoi(d.Name)
				if err != nil {
					t.Errorf("File name %v is wrong; %v (dirent %v)", d.Name, err, d)
					continue
				}
				if found[ix] > 0 {
					t.Errorf("Element %d already returned %d times", ix, found[ix])
				}
				found[ix]++
			}
		}
	}
	if i != *numDir {
		t.Fatalf("Reading %v: got %d entries, wanted %d, err %v", tmpDir, i, *numDir, err)
	}
	if fail {
		t.Fatalf("I give up")
	}

	t.Logf("-----------------------------> Alternate form, using readdir and File")
	// Alternate form, using readdir and File
	dirfile, err := clnt.FOpen(".", ninep.OREAD)
	if err != nil {
		t.Fatalf("%v", err)
	}
	i, amt, offset = 0, 0, 0
	err = nil
	passes := 0

	found = make([]int, *numDir)
	fail = false
	for err == nil {
		d, err := dirfile.Readdir(*numDir)
		if err != nil && err != io.EOF {
			t.Errorf("%v", err)
		}

		t.Logf("d is %v", d)
		if len(d) == 0 {
			break
		}
		for _, v := range d {
			ix, err := strconv.Atoi(v.Name)
			if err != nil {
				t.Errorf("File name %v is wrong; %v (dirent %v)", v.Name, err, v)
				continue
			}
			if found[ix] > 0 {
				t.Errorf("Element %d already returned %d times", ix, found[ix])
			}
			found[ix]++
		}
		i += len(d)
		if i >= *numDir {
			break
		}
		if passes > *numDir {
			t.Fatalf("%d iterations, %d read: no progress", passes, i)
		}
		passes++
	}
	if i != *numDir {
		t.Fatalf("Readdir %v: got %d entries, wanted %d", tmpDir, i, *numDir)
	}
}