func listMounts() error { log.Info(2, "retrieving mount table.") mt, err := vfs.GetMountTable() if err != nil { return fmt.Errorf("could not get mount table: %v", err) } if len(mt) == 0 { log.Info(2, "mount table is empty.") } dbPathWidth := 0 for _, mount := range mt { if len(mount.DatabasePath) > dbPathWidth { dbPathWidth = len(mount.DatabasePath) } } for _, mount := range mt { fmt.Printf("%-*v\tat\t%v\n", dbPathWidth, mount.DatabasePath, mount.MountPath) } return nil }
func unmount(path string) error { log.Info(2, "searching path for fusermount.") fusermountPath, err := exec.LookPath("fusermount") if err != nil { return fmt.Errorf("could not find 'fusermount': ensure fuse is installed: %v", err) } log.Infof(2, "running: %v -u %v.", fusermountPath, path) process, err := os.StartProcess(fusermountPath, []string{fusermountPath, "-u", path}, &os.ProcAttr{}) if err != nil { return fmt.Errorf("could not start 'fusermount': %v", err) } log.Info(2, "waiting for process to exit.") processState, err := process.Wait() if err != nil { return fmt.Errorf("error waiting for process to exit: %v", err) } if !processState.Success() { return fmt.Errorf("could not unmount virtual filesystem") } return nil }
func listAllTags(store *storage.Storage, tx *storage.Tx, showCount, onePerLine bool) error { log.Info(2, "retrieving all tags.") if showCount { count, err := store.TagCount(tx) if err != nil { return fmt.Errorf("could not retrieve tag count: %v", err) } fmt.Println(count) } else { tags, err := store.Tags(tx) if err != nil { return fmt.Errorf("could not retrieve tags: %v", err) } if onePerLine { for _, tag := range tags { fmt.Println(escape(tag.Name, '=', ' ')) } } else { tagNames := make([]string, len(tags)) for index, tag := range tags { tagNames[index] = escape(tag.Name, '=', ' ') } terminal.PrintColumns(tagNames) } } return nil }
func listAllValues(store *storage.Storage, tx *storage.Tx, showCount, onePerLine bool) error { log.Info(2, "retrieving all values.") if showCount { count, err := store.ValueCount(tx) if err != nil { return fmt.Errorf("could not retrieve value count: %v", err) } fmt.Println(count) } else { values, err := store.Values(tx) if err != nil { return fmt.Errorf("could not retrieve values: %v", err) } if onePerLine { for _, value := range values { fmt.Println(escape(value.Name)) } } else { valueNames := make([]string, len(values)) for index, value := range values { valueNames[index] = escape(value.Name) } terminal.PrintColumns(valueNames) } } return nil }
func findDuplicatesInDb(store *storage.Storage, tx *storage.Tx) error { log.Info(2, "identifying duplicate files.") fileSets, err := store.DuplicateFiles(tx) if err != nil { return fmt.Errorf("could not identify duplicate files: %v", err) } log.Infof(2, "found %v sets of duplicate files.", len(fileSets)) for index, fileSet := range fileSets { if index > 0 { fmt.Println() } fmt.Printf("Set of %v duplicates:\n", len(fileSet)) for _, file := range fileSet { relPath := _path.Rel(file.Path()) fmt.Printf(" %v\n", relPath) } } return nil }
func statusDatabase(store *storage.Storage, tx *storage.Tx, dirOnly, followSymlinks bool) (*StatusReport, error) { report := NewReport() log.Info(2, "retrieving all files from database.") files, err := store.Files(tx, "name") if err != nil { return nil, fmt.Errorf("could not retrieve files: %v", err) } err = statusCheckFiles(files, report) if err != nil { return nil, err } tree := _path.NewTree() for _, file := range files { tree.Add(file.Path(), file.IsDir) } topLevelPaths := tree.TopLevel().Paths() if err != nil { return nil, err } for _, path := range topLevelPaths { if err = findNewFiles(path, report, dirOnly, followSymlinks); err != nil { return nil, err } } return report, nil }
func unmountAll() error { log.Info(2, "retrieving mount table.") mt, err := vfs.GetMountTable() if err != nil { return fmt.Errorf("could not get mount table: %v", err) } if len(mt) == 0 { log.Info(2, "mount table is empty.") } for _, mount := range mt { err = unmount(mount.MountPath) if err != nil { return err } } return nil }
func mountExplicit(databasePath string, mountPath string, mountOptions string) error { if alreadyMounted(mountPath) { return fmt.Errorf("%v: mount path already in use", mountPath) } stat, err := os.Stat(mountPath) if err != nil { return fmt.Errorf("%v: could not stat: %v", mountPath, err) } if stat == nil { return fmt.Errorf("%v: mount point does not exist", mountPath) } if !stat.IsDir() { return fmt.Errorf("%v: mount point is not a directory", mountPath) } stat, err = os.Stat(databasePath) if err != nil { return fmt.Errorf("%v: could not stat: %v", databasePath, err) } if stat == nil { return fmt.Errorf("%v: database does not exist") } log.Infof(2, "spawning daemon to mount VFS for database '%v' at '%v'", databasePath, mountPath) args := []string{"vfs", "--database=" + databasePath, mountPath, "--options=" + mountOptions} daemon := exec.Command(os.Args[0], args...) errorPipe, err := daemon.StderrPipe() if err != nil { return fmt.Errorf("could not open standard error pipe: %v", err) } err = daemon.Start() if err != nil { return fmt.Errorf("could not start daemon: %v", err) } log.Info(2, "sleeping.") const halfSecond = 500000000 time.Sleep(halfSecond) log.Info(2, "checking whether daemon started successfully.") var waitStatus syscall.WaitStatus var rusage syscall.Rusage _, err = syscall.Wait4(daemon.Process.Pid, &waitStatus, syscall.WNOHANG, &rusage) if err != nil { return fmt.Errorf("could not check daemon status: %v", err) } if waitStatus.Exited() { if waitStatus.ExitStatus() != 0 { buffer := make([]byte, 1024) count, err := errorPipe.Read(buffer) if err != nil { return fmt.Errorf("could not read from error pipe: %v", err) } return fmt.Errorf("virtual filesystem mount failed: %v", string(buffer[0:count])) } } return nil }
func listFilesForQuery(store *storage.Storage, tx *storage.Tx, queryText, path string, dirOnly, fileOnly, print0, showCount, explicitOnly, ignoreCase bool, sort string) (error, warnings) { log.Info(2, "parsing query") expression, err := query.Parse(queryText) if err != nil { return fmt.Errorf("could not parse query: %v", err), nil } log.Info(2, "checking tag names") warnings := make(warnings, 0, 10) tagNames, err := query.TagNames(expression) if err != nil { return fmt.Errorf("could not identify tag names: %v", err), nil } tags, err := store.TagsByCasedNames(tx, tagNames, ignoreCase) for _, tagName := range tagNames { if err := entities.ValidateTagName(tagName); err != nil { warnings = append(warnings, err.Error()) continue } if !tags.ContainsCasedName(tagName, ignoreCase) { warnings = append(warnings, fmt.Sprintf("no such tag '%v'", tagName)) continue } } valueNames, err := query.ExactValueNames(expression) if err != nil { return fmt.Errorf("could not identify value names: %v", err), nil } values, err := store.ValuesByCasedNames(tx, valueNames, ignoreCase) for _, valueName := range valueNames { if err := entities.ValidateValueName(valueName); err != nil { warnings = append(warnings, err.Error()) continue } if !values.ContainsCasedName(valueName, ignoreCase) { warnings = append(warnings, fmt.Sprintf("no such value '%v'", valueName)) continue } } log.Info(2, "querying database") files, err := store.FilesForQuery(tx, expression, path, explicitOnly, ignoreCase, sort) if err != nil { if strings.Index(err.Error(), "parser stack overflow") > -1 { return fmt.Errorf("the query is too complex (see the troubleshooting wiki for how to increase the stack size)"), warnings } else { return fmt.Errorf("could not query files: %v", err), warnings } } if err = listFiles(tx, files, dirOnly, fileOnly, print0, showCount); err != nil { return err, warnings } return nil, warnings }