// 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 } } } }
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) } }
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) } }