func statNode(ctx context.Context, config libkbfs.Config, nodePathStr string) error { p, err := makeKbfsPath(nodePathStr) if err != nil { return err } n, ei, err := p.getNode(ctx, config) if err != nil { return err } // If n is non-nil, ignore the EntryInfo returned by // p.getNode() so we can exercise the Stat() codepath. We // can't compare the two, since they might legitimately differ // due to races. if n != nil { ei, err = config.KBFSOps().Stat(ctx, n) if err != nil { return err } } var symPathStr string if ei.Type == libkbfs.Sym { symPathStr = fmt.Sprintf("SymPath: %s, ", ei.SymPath) } mtimeStr := time.Unix(0, ei.Mtime).String() ctimeStr := time.Unix(0, ei.Ctime).String() fmt.Printf("{Type: %s, Size: %d, %sMtime: %s, Ctime: %s}\n", ei.Type, ei.Size, symPathStr, mtimeStr, ctimeStr) return nil }
// GetEncodedMetrics returns metrics encoded as bytes for metrics file. func GetEncodedMetrics(config libkbfs.Config) func(context.Context) ([]byte, time.Time, error) { return func(context.Context) ([]byte, time.Time, error) { if registry := config.MetricsRegistry(); registry != nil { b := bytes.NewBuffer(nil) metricsutil.WriteMetrics(registry, b) return b.Bytes(), time.Time{}, nil } return []byte("Metrics have been turned off.\n"), time.Time{}, nil } }
// NewFS creates an FS func NewFS(config libkbfs.Config, conn *fuse.Conn, debug bool) *FS { log := config.MakeLogger("kbfsfuse") // We need extra depth for errors, so that we can report the line // number for the caller of reportErr, not reportErr itself. errLog := log.CloneWithAddedDepth(1) if debug { // Turn on debugging. TODO: allow a proper log file and // style to be specified. log.Configure("", true, "") errLog.Configure("", true, "") } fs := &FS{config: config, conn: conn, log: log, errLog: errLog} return fs }
func (r *RemoteStatus) loop(ctx context.Context, log logger.Logger, config libkbfs.Config) { for { tctx, cancel := context.WithTimeout(ctx, 1*time.Second) st, ch, err := config.KBFSOps().Status(tctx) // No deferring inside loops, and no panics either here. cancel() if err != nil { log.Warning("KBFS Status failed: %v", err) } r.update(st) // Block on the channel or shutdown. select { case <-ctx.Done(): return case <-ch: } } }
func readHelper(ctx context.Context, config libkbfs.Config, args []string) error { flags := flag.NewFlagSet("kbfs read", flag.ContinueOnError) verbose := flags.Bool("v", false, "Print extra status output.") flags.Parse(args) if flags.NArg() != 1 { return errExactlyOnePath } filePathStr := flags.Arg(0) p, err := makeKbfsPath(filePathStr) if err != nil { return err } if p.pathType != tlfPath { return fmt.Errorf("Cannot read %s", p) } if *verbose { fmt.Fprintf(os.Stderr, "Looking up %s\n", p) } fileNode, err := p.getFileNode(ctx, config) if err != nil { return err } nr := nodeReader{ ctx: ctx, kbfsOps: config.KBFSOps(), node: fileNode, off: 0, verbose: *verbose, } _, err = io.Copy(os.Stdout, &nr) if err != nil { return err } return nil }
// GetEncodedErrors gets the list of encoded errors in a format suitable // for error file. func GetEncodedErrors(config libkbfs.Config) func(context.Context) ([]byte, time.Time, error) { return func(_ context.Context) ([]byte, time.Time, error) { errors := config.Reporter().AllKnownErrors() jsonErrors := make([]JSONReportedError, len(errors)) for i, e := range errors { jsonErrors[i].Time = e.Time jsonErrors[i].Error = e.Error.Error() jsonErrors[i].Stack = convertStack(e.Stack) } data, err := json.MarshalIndent(jsonErrors, "", " ") if err != nil { return nil, time.Time{}, err } data = append(data, '\n') var t time.Time if len(errors) > 0 { t = errors[len(errors)-1].Time } return data, t, err } }
// Returns a nil node if p doesn't have type tlfPath. func (p kbfsPath) getNode(ctx context.Context, config libkbfs.Config) (n libkbfs.Node, ei libkbfs.EntryInfo, err error) { if p.pathType != tlfPath { ei := libkbfs.EntryInfo{ Type: libkbfs.Dir, } return nil, ei, nil } name := p.tlfName outer: for { n, ei, err = config.KBFSOps().GetOrCreateRootNode( ctx, name, p.public, libkbfs.MasterBranch) switch err := err.(type) { case nil: // No error. break outer case libkbfs.TlfNameNotCanonical: // Non-canonical name, so try again. name = err.NameToTry default: // Some other error. return nil, libkbfs.EntryInfo{}, err } } for _, component := range p.tlfComponents { cn, cei, err := config.KBFSOps().Lookup(ctx, n, component) if err != nil { return nil, libkbfs.EntryInfo{}, err } n = cn ei = cei } return n, ei, nil }
func writeHelper(ctx context.Context, config libkbfs.Config, args []string) (err error) { flags := flag.NewFlagSet("kbfs write", flag.ContinueOnError) append := flags.Bool("a", false, "Append to an existing file instead of truncating it.") verbose := flags.Bool("v", false, "Print extra status output.") flags.Parse(args) if flags.NArg() != 1 { return errExactlyOnePath } filePathStr := flags.Arg(0) defer func() { if err != nil { if _, ok := err.(cannotWriteErr); !ok { err = cannotWriteErr{filePathStr, err} } } }() p, err := makeKbfsPath(filePathStr) if err != nil { return } if p.pathType != tlfPath { err = cannotWriteErr{filePathStr, nil} return } dir, filename, err := p.dirAndBasename() if err != nil { return } if dir.pathType != tlfPath { err = cannotWriteErr{filePathStr, nil} return } parentNode, err := dir.getDirNode(ctx, config) if err != nil { return err } kbfsOps := config.KBFSOps() noSuchFileErr := libkbfs.NoSuchNameError{Name: filename} // The operations below are racy, but that is inherent to a // distributed FS. fileNode, de, err := kbfsOps.Lookup(ctx, parentNode, filename) if err != nil && err != noSuchFileErr { return err } needSync := false var off int64 if err == noSuchFileErr { if *verbose { fmt.Fprintf(os.Stderr, "Creating %s\n", p) } fileNode, _, err = kbfsOps.CreateFile(ctx, parentNode, filename, false) if err != nil { return err } } else { if *append { if *verbose { fmt.Fprintf(os.Stderr, "Appending to %s\n", p) } off = int64(de.Size) } else { if *verbose { fmt.Fprintf(os.Stderr, "Truncating %s\n", p) } err = kbfsOps.Truncate(ctx, fileNode, 0) if err != nil { return err } needSync = true } } nw := nodeWriter{ ctx: ctx, kbfsOps: kbfsOps, node: fileNode, off: off, verbose: *verbose, } written, err := io.Copy(&nw, os.Stdin) if err != nil { return err } if written > 0 { needSync = true } if needSync { if *verbose { fmt.Fprintf(os.Stderr, "Syncing %s\n", p) } err := kbfsOps.Sync(ctx, fileNode) if err != nil { return err } } return nil }
func mkdirOne(ctx context.Context, config libkbfs.Config, dirPathStr string, createIntermediate, verbose bool) error { p, err := makeKbfsPath(dirPathStr) if err != nil { return err } kbfsOps := config.KBFSOps() if createIntermediate { if p.pathType != tlfPath || len(p.tlfComponents) == 0 { // Nothing to do. return nil } tlfRoot := kbfsPath{ pathType: tlfPath, public: p.public, tlfName: p.tlfName, } tlfNode, err := tlfRoot.getDirNode(ctx, config) if err != nil { return err } currP := tlfRoot currNode := tlfNode for i := 0; i < len(p.tlfComponents); i++ { dirname := p.tlfComponents[i] currP, err = currP.join(dirname) if err != nil { return err } nextNode, err := createDir(ctx, kbfsOps, currNode, dirname, currP.String(), verbose) if err == (libkbfs.NameExistsError{Name: dirname}) { nextNode, _, err = kbfsOps.Lookup(ctx, currNode, dirname) } if err != nil { return err } currNode = nextNode } } else { if p.pathType != tlfPath { return libkbfs.NameExistsError{Name: p.String()} } parentDir, dirname, err := p.dirAndBasename() if err != nil { return err } if parentDir.pathType != tlfPath { // TODO: Ideally, this would error out if // p already existed. _, err := p.getDirNode(ctx, config) maybePrintPath(p.String(), err, verbose) return err } parentNode, err := parentDir.getDirNode(ctx, config) if err != nil { return err } _, err = createDir(ctx, kbfsOps, parentNode, dirname, p.String(), verbose) if err != nil { return err } } return nil }
func lsHelper(ctx context.Context, config libkbfs.Config, p kbfsPath, hasMultiple bool, handleEntry func(string, libkbfs.EntryType)) error { kbfsOps := config.KBFSOps() switch p.pathType { case rootPath: if hasMultiple { printHeader(p) } handleEntry(topName, libkbfs.Dir) return nil case keybasePath: if hasMultiple { printHeader(p) } handleEntry(publicName, libkbfs.Dir) handleEntry(privateName, libkbfs.Dir) return nil case keybaseChildPath: favs, err := kbfsOps.GetFavorites(ctx) if err != nil { return err } if hasMultiple { printHeader(p) } for _, fav := range favs { if p.public == fav.Public { handleEntry(fav.Name, libkbfs.Dir) } } return nil case tlfPath: n, de, err := p.getNode(ctx, config) if err != nil { return err } if de.Type == libkbfs.Dir { // GetDirChildren doesn't verify the dir-ness // of the node correctly (since it ends up // creating a new DirBlock if the node isn't // in the cache already). // // TODO: Fix the above. children, err := kbfsOps.GetDirChildren(ctx, n) if err != nil { return err } if hasMultiple { printHeader(p) } for name, entryInfo := range children { handleEntry(name, entryInfo.Type) } } else { _, name, err := p.dirAndBasename() if err != nil { return err } handleEntry(name, de.Type) } return nil default: break } return fmt.Errorf("invalid KBFS path %s", p) }