// Facade that serves t at the given address by using the ds // to serve and calling Serve for each client. func Server(t zx.Tree, addr string) { dbg.Warn("serve %s at %s...", t.Name(), addr) cc, ec, err := ds.Serve(os.Args[0], addr) if err != nil { dbg.Warn("serve: %s", err) return } go func() { for c := range cc { if c != nil { go serveFor(t, *c) } } if err := cerror(cc); err != nil { dbg.Warn("serve: %s", err) } close(ec, "done") }() }
func mkfs(addr string) (zx.Tree, func(), error) { if len(addr) == 0 { opts.Usage(os.Stderr) dbg.Fatal("usage") } var fs zx.Tree var st *zx.IOstats var err error if _, err := os.Stat(addr); err == nil { fs, st, err = mklfs(addr) } else { fs, st, err = mkrfs(addr) } if err != nil { return nil, nil, err } fn := func() {} if sflag { fn = func() { st.Averages() dbg.Warn("%s iostats:\n%s\n", fs.Name(), st) } } if mfscfs { dbg.Warn("%s: mfs cache", addr) return mfscache(fs, fn) } if lfsdir != "" { dbg.Warn("%s: lfs cache", addr) return lfscache(fs, fn) } if !nocaching && !delayed { dbg.Warn("%s: old cache", addr) return cache(fs, fn) } dbg.Warn("%s: uncached", addr) return fs, fn, nil }
func chkok(fs zx.Tree, attr string) error { d, err := zx.Stat(fs, "/") if err != nil { return fmt.Errorf("%s: %s", fs.Name(), err) } rwfs, ok := fs.(zx.RWTree) if !ok { return nil } if err := <-rwfs.Wstat("/", zx.Dir{attr: "666"}); err != nil { return err } d, err = zx.Stat(fs, "/") if err != nil { return fmt.Errorf("%s: %s", fs.Name(), err) } if d[attr] != "666" { return fmt.Errorf("%s: does not preserve %s", fs.Name(), attr) } if err := <-rwfs.Wstat("/", zx.Dir{attr: ""}); err != nil { return err } return nil }
// Create a new cfs given a local tree used as a cache of a remote one. // Operations are performed on behalf of each file owner. // The lfs tree must have permission checking disabled // (cfs will want to update everything in it no matter the user who makes the requests) func New(tag string, lfs zx.RWTree, rfs zx.Tree, rdonly bool) (*Cfs, error) { if lfs == nil || rfs == nil { return nil, errors.New("no lfs or rfs") } rwrfs, ok := rfs.(zx.RWTree) if !ok && !rdonly { rdonly = true rwrfs = zx.ROTreeFor(rfs) dbg.Warn("remote %T not rw: rdonly set", rfs) } if !rdonly { if err := chkok(lfs, "Rtime"); err != nil { return nil, err } } if tag == "" { tag = "cfs!" + rfs.Name() } fs := &Cfs { Tag: tag, lfs: lfs, cfs: lfs, // but will keep its ai as nil to wstat uids rfs: rwrfs, rdonly: rdonly, noinvalproto: NoInvalProto, Flags: &zx.Flags{Dbg: Debug}, cUsers: &cUsers { who: make(map[string]time.Time), }, cache: cache.New(), closedc: make(chan bool), polldonec: make(chan bool), } if DebugLocks { fs.lktrz = &lockTrzs{} } fs.cache.Tag = tag fs.cache.Dbg = &fs.Flags.Dbg fs.tpath = fmt.Sprintf("cfs%p", fs) if fs.noinvalproto { fs.invalQ, _ = newInvalQ(tag, &fs.Flags.Dbg, nil) close(fs.polldonec) } else { var mustpoll bool fs.invalQ, mustpoll = newInvalQ(tag, &fs.Flags.Dbg, fs.rfs) if mustpoll { dbg.Warn("%s: polling %s for external changes", tag, fs.rfs) // runs with no ai go fs.pollproc() } else { close(fs.polldonec) } } go fs.invalproc() fs.Flags.Add("verbsync", &fs.cache.Verb) fs.Flags.Add("debug", &fs.Flags.Dbg) if d, ok := lfs.(zx.Debugger); ok { fs.Flags.Add("ldebug", d.Debug()) } if d, ok := rfs.(zx.Debugger); ok { fs.Flags.Add("rdebug", d.Debug()) } fs.Flags.AddRO("rdonly", &fs.rdonly) fs.Flags.AddRO("noperm", &fs.NoPermCheck) fs.Flags.Add("clear", func(...string)error{ fs.IOstats.Clear() return nil }) return fs, nil }
func dump(dir string, t zx.Tree, ec chan bool) { defer func() { ec <- true }() name := t.Name() data := zx.Path(dir, "data") doskip := Skip for { if doskip { waitDumpTime(name) doskip = false continue } dbg.Warn("snap %s...", name) if err := os.MkdirAll(data, 0750); err != nil { dbg.Warn("%s: %s", data, err) return } rd, err := zx.Stat(t, "/") if err != nil { dbg.Warn("%s: %s", name, err) continue } // make sure it's not empty ds, err := zx.GetDir(t, "/") if err != nil { dbg.Warn("%s: %s", name, err) continue } if len(ds) == 0 { dbg.Warn("%s: file system is empty. ignored.", name) continue } s, err := dumpDir(data, name, zx.File{t, rd}) if err != nil { dbg.Warn("%s: %s", name, err) } ts := time.Now().Format("2006/0102") tree := strings.Replace(name, "/", ".", -1) tspath0 := zx.Path(dir, tree, ts) os.MkdirAll(path.Dir(tspath0), 0755) spath := zx.Path(data, s) tspath := tspath0 for i := 1; ; i++ { fi, _ := os.Stat(tspath) if fi == nil { break } tspath = fmt.Sprintf("%s.%d", tspath0, i) } os.MkdirAll(path.Dir(tspath), 0755) if err := os.Symlink(spath, tspath); err != nil { dbg.Warn("%s: %s", name, err) } dbg.Warn("snap %s %s", tspath, s) if Once { break } waitDumpTime(name) } }