// 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) ([]*p.Dir, error) { buf := make([]byte, file.fid.Clnt.Msize-p.IOHDRSZ) var dirs []*p.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 *p.Dir b := buf[:n] for len(b) > 0 { var perr error d, b, _, perr = p.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 } } } return dirs[0:pos], nil }
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) } }() var conn net.Conn if conn, err = net.Dial("unix", srvAddr); err != nil { t.Fatalf("%v", err) } else { t.Logf("Got a conn, %v\n", conn) } clnt := NewClnt(conn, 8192, false) // packet debugging on clients is broken. clnt.Debuglevel = 0 // *debug user := p.OsUsers.Uid2User(os.Geteuid()) rootfid, err := clnt.Attach(nil, user, "/") if err != nil { t.Fatalf("%v", err) } t.Logf("attached, 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 *p.Dir if d, b, amt, err = p.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(".", p.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) } }