func (command UnmountCommand) unmount(path string) error { if command.verbose { log.Info("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) } if command.verbose { log.Infof("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) } if command.verbose { log.Info("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 (command DupesCommand) findDuplicatesInDb() error { store, err := storage.Open() if err != nil { return fmt.Errorf("could not open storage: %v", err) } defer store.Close() if command.verbose { log.Info("identifying duplicate files.") } fileSets, err := store.DuplicateFiles() if err != nil { return fmt.Errorf("could not identify duplicate files: %v", err) } if command.verbose { log.Infof("found %v sets of duplicate files.", len(fileSets)) } for index, fileSet := range fileSets { if index > 0 { log.Print() } log.Printf("Set of %v duplicates:", len(fileSet)) for _, file := range fileSet { relPath := _path.Rel(file.Path()) log.Printf(" %v", relPath) } } return nil }
func (command TagsCommand) listAllTags() error { store, err := storage.Open() if err != nil { return fmt.Errorf("could not open storage: %v", err) } defer store.Close() if command.verbose { log.Info("retrieving all tags.") } if command.count { count, err := store.TagCount() if err != nil { return fmt.Errorf("could not retrieve tag count: %v", err) } log.Print(count) } else { tags, err := store.Tags() if err != nil { return fmt.Errorf("could not retrieve tags: %v", err) } for _, tag := range tags { log.Print(tag.Name) } } return nil }
func (command RepairCommand) repairModified(store *storage.Storage, modified fileIdAndInfoMap) error { if command.verbose { log.Info("repairing modified files") } for path, fileIdAndStat := range modified { fileId := fileIdAndStat.fileId stat := fileIdAndStat.stat log.Infof("%v: modified", path) fingerprint, err := fingerprint.Create(path) if err != nil { return fmt.Errorf("%v: could not create fingerprint: %v", path, err) } if !command.pretend { _, err := store.UpdateFile(fileId, path, fingerprint, stat.ModTime(), stat.Size(), stat.IsDir()) if err != nil { return fmt.Errorf("%v: could not update file in database: %v", path, err) } } } return nil }
func (command RepairCommand) determineStatuses(fsPaths fileInfoMap, dbPaths databaseFileMap) (tagged databaseFileMap, untagged fileInfoMap, modified fileIdAndInfoMap, missing databaseFileMap) { if command.verbose { log.Info("determining file statuses") } tagged = make(databaseFileMap, 100) untagged = make(fileInfoMap, 100) modified = make(fileIdAndInfoMap, 100) missing = make(databaseFileMap, 100) for path, stat := range fsPaths { if dbFile, isTagged := dbPaths[path]; isTagged { if dbFile.ModTime == stat.ModTime().UTC() && dbFile.Size == stat.Size() { tagged[path] = dbFile } else { modified[path] = struct { fileId uint stat os.FileInfo }{dbFile.Id, stat} } } else { untagged[path] = stat } } for path, dbFile := range dbPaths { if _, found := fsPaths[path]; !found { missing[path] = dbFile } } return tagged, untagged, modified, missing }
func (command FilesCommand) listFilesForTags(args []string) error { if len(args) == 0 { return fmt.Errorf("at least one tag must be specified. Use --all to show all files.") } store, err := storage.Open() if err != nil { return fmt.Errorf("could not open storage: %v", err) } defer store.Close() includeTagIds := make([]uint, 0) excludeTagIds := make([]uint, 0) for _, arg := range args { var tagName string var include bool if arg[0] == '-' { tagName = arg[1:] include = false } else { tagName = arg include = true } tag, err := store.TagByName(tagName) if err != nil { return fmt.Errorf("could not retrieve tag '%v': %v", tagName, err) } if tag == nil { log.Fatalf("no such tag '%v'.", tagName) } if include { includeTagIds = append(includeTagIds, tag.Id) } else { excludeTagIds = append(excludeTagIds, tag.Id) } } if command.verbose { log.Info("retrieving set of tagged files from the database.") } files, err := store.FilesWithTags(includeTagIds, excludeTagIds) if err != nil { return fmt.Errorf("could not retrieve files with tags %v and without tags %v: %v", includeTagIds, excludeTagIds, err) } return command.listFiles(files) }
func (command UnmountCommand) unmountAll() error { if command.verbose { log.Info("retrieving mount table.") } mt, err := vfs.GetMountTable() if err != nil { return fmt.Errorf("could not get mount table: %v", err) } if command.verbose && len(mt) == 0 { log.Info("mount table is empty.") } for _, mount := range mt { err = command.unmount(mount.MountPath) if err != nil { return err } } return nil }
func (command RepairCommand) repairMoved(store *storage.Storage, missing databaseFileMap, untagged fileInfoMap) error { if command.verbose { log.Info("repairing moved files") } moved := make([]string, 0, 10) for path, dbFile := range missing { if command.verbose { log.Infof("%v: searching for new location", path) } for candidatePath, stat := range untagged { if stat.Size() == dbFile.Size { fingerprint, err := fingerprint.Create(candidatePath) if err != nil { return fmt.Errorf("%v: could not create fingerprint: %v", path, err) } if fingerprint == dbFile.Fingerprint { log.Infof("%v: moved to %v", path, candidatePath) moved = append(moved, path) if !command.pretend { _, err := store.UpdateFile(dbFile.Id, candidatePath, dbFile.Fingerprint, stat.ModTime(), dbFile.Size, dbFile.IsDir) if err != nil { return fmt.Errorf("%v: could not update file in database: %v", path, err) } } delete(untagged, candidatePath) break } } } } for _, path := range moved { delete(missing, path) } return nil }
func (command FilesCommand) listAllFiles() error { store, err := storage.Open() if err != nil { return fmt.Errorf("could not open storage: %v", err) } defer store.Close() if command.verbose { log.Info("retrieving all files from database.") } files, err := store.Files() if err != nil { return fmt.Errorf("could not retrieve files: %v", err) } return command.listFiles(files) }
func (command StatusCommand) statusDatabase() (*StatusReport, error) { report := NewReport() store, err := storage.Open() if err != nil { return nil, fmt.Errorf("could not open storage: %v", err) } defer store.Close() if command.verbose { log.Info("retrieving all files from database.") } files, err := store.Files() if err != nil { return nil, fmt.Errorf("could not retrieve files: %v", err) } err = command.checkFiles(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 = command.findNewFiles(path, report); err != nil { return nil, err } } return report, nil }
func (command RepairCommand) repairDatabase(store *storage.Storage) error { if command.verbose { log.Info("retrieving all files from the database.") } files, err := store.Files() if err != nil { return fmt.Errorf("could not retrieve paths from storage: %v", err) } paths := make([]string, len(files)) for index := 0; index < len(files); index++ { paths[index] = files[index].Path() } err = command.checkFiles(store, paths) if err != nil { return err } return nil }