Beispiel #1
0
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
}
Beispiel #2
0
// 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
	}
}
Beispiel #3
0
// 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
}
Beispiel #4
0
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:
		}
	}
}
Beispiel #5
0
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
}
Beispiel #6
0
// 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
	}
}
Beispiel #7
0
// 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
}
Beispiel #8
0
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
}
Beispiel #9
0
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
}
Beispiel #10
0
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)
}