func asAFile(t Fataler, rws []Object, nops, maxoff, maxsz int) { rw := rws[0] fd, err := ioutil.TempFile("", "rwtest") if err != nil { t.Fatalf("temp file: %s", err) } defer fd.Close() opc := make(chan int) rrw, ok := rw.(Resizeable) nrsz := 0 if ok { nrsz = nops / 10 nops -= nrsz } nrd := nops/2 nwr := nops - nrd defer t.Logf("%d reads, %d writes, %d resizes\n", nrd, nwr, nrsz) go func() { for i := 0; i < nrd; i++ { if ok := opc <- 0; !ok { break } } }() go func() { for i := 0; i < nwr; i++ { if ok := opc <- 1; !ok { break } } }() go func() { for i := 0; i < nrsz; i++ { if ok := opc <- 2; !ok { break } } }() defer func() { close(opc, "done") }() wdata := make([]byte, maxsz) for i := 0; i < maxsz; i++ { wdata[i] = byte(i) } xrw, ok := rw.(FullyReadable) for i := 0; i < nops; i++ { off := rand.Intn(maxoff) sz := rand.Intn(maxsz) rw = pick(rws) switch <-opc { case 0: dataf:= make([]byte, sz) datarw:= make([]byte, sz) nf, errf := fd.ReadAt(dataf, int64(off)) nrw, errrw := rw.ReadAt(datarw, int64(off)) if nf != nrw { t.Fatalf("didn't read the same") } if errf == io.EOF { errf = nil } if errrw == io.EOF { errrw = nil } if errf != nil && errrw == nil || errf == nil && errrw != nil { t.Logf("file sts %v", errf) t.Logf("rw sts %v", errrw) t.Fatalf("didn't fail the same in read") } if bytes.Compare(dataf[:nf], datarw[:nrw]) != 0 { s1 := dbg.HexStr(dataf[:nf], 32) s2 := dbg.HexStr(datarw[:nrw], 32) t.Logf("os %d bytes: %s", nf, s1) t.Logf("rw %d bytes: %s", nrw, s2) t.Fatalf("didn't read the same content") } case 1: if sz == 0 { sz++ } nf, errf := fd.WriteAt(wdata[:sz], int64(off)) nrw, errrw := rw.WriteAt(wdata[:sz], int64(off)) if nf != nrw { t.Fatalf("didn't write the same") } if errf != nil && errrw == nil || errf == nil && errrw != nil { t.Fatalf("didn't fail the same in write") } if ok { compare(t, xrw, fd) } case 2: if err := fd.Truncate(int64(off)); err != nil { t.Fatalf("file resize: %s", err) } if err := rrw.Truncate(int64(off)); err != nil { t.Fatalf("user resize: %s", err) } if ok { compare(t, xrw, fd) } } } if !ok { return } // Now compare everything. compare(t, xrw, fd) } func compare(t Fataler, rw, fd FullyReadable) { fdata, err := readall(fd) if err != nil { t.Fatalf("read all fd: %s", err) } rwdata, err := readall(rw) if err != nil { t.Fatalf("read all rw: %s", err) } if bytes.Compare(fdata, rwdata) != 0 { t.Logf("file %d bytes: %s\n", len(fdata), dbg.HexStr(fdata, 32)) t.Logf("rw %d bytes: %s\n", len(rwdata), dbg.HexStr(rwdata, 32)) for i := 0; i < len(fdata) && i < len(rwdata); i++ { if fdata[i] != rwdata[i] { t.Logf("[%d] file %x rw %x\n", i, fdata[i], rwdata[i]) break } } t.Fatalf("files do not match") } } func readall(rw FullyReadable) ([]byte, error) { old, err := rw.Seek(0, 1) if err != nil { return nil, err } n, err := rw.Seek(0, 0) if n != 0 || err != nil { return nil, err } data, err := ioutil.ReadAll(rw) if err != nil { return nil, err } _, err = rw.Seek(old, 0) if err != nil { return nil, err } return data, nil }
func (t *Fs) Get(rid string, off, count int64, pred string) <-chan []byte { n := atomic.AddInt32(&t.nb, 1) t.printf("->get[%d] %s %d %d '%s'", n, rid, off, count, pred) dc := make(chan []byte) go func(){ xc := t.fs.Get(rid, off, count, pred) nb, nm := 0, 0 for d := range xc { s := dbg.HexStr(d, 16) t.vprintf("<-get[%d] %d bytes %s", n, len(d), s) if ok := dc <- d; !ok { close(xc, "client gone") } nb += len(d) nm++ } err := cerror(xc) t.printf("<-get[%d] %d bytes %d msgs sts %v", n, nb, nm, err) close(dc, err) }() return dc } func (t *Fs) Put(rid string, d zx.Dir, off int64, dc <-chan []byte, pred string) chan zx.Dir { n := atomic.AddInt32(&t.nb, 1) t.printf("->put[%d] %s %s %d '%s'", n, rid, d, off, pred) rc := make(chan zx.Dir, 1) datc := make(chan []byte) if dc == nil { datc = nil } else { go func() { for d := range dc { s := dbg.HexStr(d, 16) t.vprintf("->put[%d] %d bytes %s", n, len(d), s) if ok := datc <- d; !ok { close(dc, cerror(datc)) break } } err := cerror(dc) t.vprintf("->put[%d] sts %v", n, err) close(datc, err) }() } go func() { xc := t.fs.Put(rid, d, off, datc, pred) d := <-xc err := cerror(xc) if err != nil { close(datc, err) } t.printf("<-put[%d] %s sts %v", n, d, err) rc <-d close(rc, err) }() return rc } func (t *Fs) Mkdir(rid string, d zx.Dir) chan error { n := atomic.AddInt32(&t.nb, 1) t.printf("->mkdir[%d] %s %s", n, rid, d) dc := make(chan error, 1) go func() { xc := t.fs.Mkdir(rid, d) err := <- xc t.printf("<-mkdir[%d] sts %v", n, err) dc <- err close(dc, cerror(xc)) }() return dc } func (t *Fs) Wstat(rid string, d zx.Dir) chan error { n := atomic.AddInt32(&t.nb, 1) t.printf("->wstat[%d] %s %s", n, rid, d) dc := make(chan error, 1) go func() { xc := t.fs.Wstat(rid, d) err := <- xc t.printf("<-wstat[%d] sts %v", n, err) dc <- err close(dc, cerror(xc)) }() return dc } func (t *Fs) Move(from, to string) chan error { n := atomic.AddInt32(&t.nb, 1) t.printf("->move[%d] %s %s", n, from, to) dc := make(chan error, 1) go func() { xc := t.fs.Move(from, to) err := <- xc t.printf("<-move[%d] sts %v", n, err) dc <- err close(dc, cerror(xc)) }() return dc } func (t *Fs) Remove(rid string) chan error { n := atomic.AddInt32(&t.nb, 1) t.printf("->remove[%d] %s", n, rid) dc := make(chan error, 1) go func() { xc := t.fs.Remove(rid) err := <- xc t.printf("<-remove[%d] sts %v", n, err) dc <- err close(dc, cerror(xc)) }() return dc } func (t *Fs) RemoveAll(rid string) chan error { n := atomic.AddInt32(&t.nb, 1) t.printf("->removeall[%d] %s", n, rid) dc := make(chan error, 1) go func() { xc := t.fs.RemoveAll(rid) err := <- xc t.printf("<-removeall[%d] sts %v", n, err) dc <- err close(dc, cerror(xc)) }() return dc } func (t *Fs) Fsys(name string) <-chan error { n := atomic.AddInt32(&t.nb, 1) t.printf("->fsys[%d] %s", n, name) dc := make(chan error, 1) go func() { var xc <-chan error if fnd, ok := t.fs.(zx.Finder); ok { xc = fnd.Fsys(name) } else { xx := make(chan error, 1) xx <- dbg.ErrBug close(xx, dbg.ErrBug) xc = xx } err := <- xc t.printf("<-fsys[%d] sts %v", n, err) dc <- err close(dc, cerror(xc)) }() return dc } func (t *Fs) Find(rid, fpred, spref, dpref string, depth int) <-chan zx.Dir { n := atomic.AddInt32(&t.nb, 1) t.printf("->find[%d] %s '%s' '%s' '%s' %d", n, rid, fpred, spref, dpref, depth) dc := make(chan zx.Dir, 1) go func() { xc := t.fs.Find(rid, fpred, spref, dpref, depth) nm := 0 for d := range xc { nm++ t.vprintf("<-find[%d] %s", n, d) dc <- d } err := cerror(xc) t.printf("<-find[%d] %d msgs sts %v", n, nm, err) close(dc, err) }() return dc } func (t *Fs) FindGet(rid, fpred, spref, dpref string, depth int) <-chan zx.DirData { n := atomic.AddInt32(&t.nb, 1) t.printf("->findget[%d] %s '%s' '%s' '%s' %d", n, rid, fpred, spref, dpref, depth) dc := make(chan zx.DirData) go func() { xc := t.fs.FindGet(rid, fpred, spref, dpref, depth) nm := 0 for d := range xc { nm++ t.vprintf("<-findget[%d] %s", n, d) if ok := dc <- d; !ok { close(xc, "client gone") } } err := cerror(xc) t.printf("<-findget[%d] %d msgs sts %v", n, nm, err) close(dc, err) }() return dc } // Ask the tree to perform auth checks on behalf of ai. func (t *Fs) AuthFor(ai *auth.Info) (zx.Tree, error) { nfs := &Fs{} *nfs = *t if afs, ok := t.ufs.(zx.AuthTree); ok { x, err := afs.AuthFor(ai) if err == nil { nfs.ufs = x nfs.fs = zx.RWTreeFor(nfs.ufs) return nfs, nil } return nil, err } return nil, errors.New("no auth") } func (t *Fs) Dump(w io.Writer) { if dfs, ok := t.fs.(zx.Dumper); ok { dfs.Dump(w) } else { fmt.Fprintf(w, "no dumps for %s\n", t) } } func (t *Fs) Stats() *zx.IOstats { if dfs, ok := t.fs.(zx.StatTree); ok { return dfs.Stats() } return nil }