func repairModified(store *storage.Storage, tx *storage.Tx, modified entities.Files, pretend bool, settings entities.Settings) error { log.Infof(2, "repairing modified files") for _, dbFile := range modified { stat, err := os.Stat(dbFile.Path()) if err != nil { return err } fingerprint, err := fingerprint.Create(dbFile.Path(), settings.FileFingerprintAlgorithm(), settings.DirectoryFingerprintAlgorithm(), settings.SymlinkFingerprintAlgorithm()) if err != nil { log.Warnf("%v: could not create fingerprint: %v", dbFile.Path(), err) continue } if !pretend { _, err := store.UpdateFile(tx, dbFile.Id, dbFile.Path(), fingerprint, stat.ModTime(), stat.Size(), stat.IsDir()) if err != nil { return fmt.Errorf("%v: could not update file in database: %v", dbFile.Path(), err) } } fmt.Printf("%v: updated fingerprint\n", dbFile.Path()) } return nil }
func repairMoved(store *storage.Storage, tx *storage.Tx, missing entities.Files, searchPaths []string, pretend bool, settings entities.Settings) error { log.Infof(2, "repairing moved files") if len(missing) == 0 || len(searchPaths) == 0 { // don't bother enumerating filesystem if nothing to do return nil } pathsBySize, err := buildPathBySizeMap(searchPaths) if err != nil { return err } for index, dbFile := range missing { log.Infof(2, "%v: searching for new location", dbFile.Path()) pathsOfSize := pathsBySize[dbFile.Size] log.Infof(2, "%v: file is of size %v, identified %v files of this size", dbFile.Path(), dbFile.Size, len(pathsOfSize)) for _, candidatePath := range pathsOfSize { candidateFile, err := store.FileByPath(tx, candidatePath) if err != nil { return err } if candidateFile != nil { // file is already tagged continue } stat, err := os.Stat(candidatePath) if err != nil { return fmt.Errorf("%v: could not stat file: %v", candidatePath, err) } fingerprint, err := fingerprint.Create(candidatePath, settings.FileFingerprintAlgorithm(), settings.DirectoryFingerprintAlgorithm(), settings.SymlinkFingerprintAlgorithm()) if err != nil { return fmt.Errorf("%v: could not create fingerprint: %v", candidatePath, err) } if fingerprint == dbFile.Fingerprint { if !pretend { _, err := store.UpdateFile(tx, 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", dbFile.Path(), err) } } fmt.Printf("%v: updated path to %v\n", dbFile.Path(), candidatePath) missing[index] = nil break } } } return nil }
func findDuplicatesOf(store *storage.Storage, tx *storage.Tx, paths []string, recursive bool) (error, warnings) { settings, err := store.Settings(tx) if err != nil { return err, nil } warnings := make(warnings, 0, 10) for _, path := range paths { _, err := os.Stat(path) if err != nil { switch { case os.IsNotExist(err): warnings = append(warnings, fmt.Sprintf("%v: no such file", path)) continue case os.IsPermission(err): warnings = append(warnings, fmt.Sprintf("%v: permission denied", path)) continue default: return err, warnings } } } if recursive { p, err := filesystem.Enumerate(paths...) if err != nil { return fmt.Errorf("could not enumerate paths: %v", err), warnings } paths = make([]string, len(p)) for index, path := range p { paths[index] = path.Path } } first := true for _, path := range paths { log.Infof(2, "%v: identifying duplicate files.", path) fp, err := fingerprint.Create(path, settings.FileFingerprintAlgorithm(), settings.DirectoryFingerprintAlgorithm(), settings.SymlinkFingerprintAlgorithm()) if err != nil { return fmt.Errorf("%v: could not create fingerprint: %v", path, err), warnings } if fp == fingerprint.Fingerprint("") { continue } files, err := store.FilesByFingerprint(tx, fp) if err != nil { return fmt.Errorf("%v: could not retrieve files matching fingerprint '%v': %v", path, fp, err), warnings } absPath, err := filepath.Abs(path) if err != nil { return fmt.Errorf("%v: could not determine absolute path: %v", path, err), warnings } // filter out the file we're searching on dupes := files.Where(func(file *entities.File) bool { return file.Path() != absPath }) if len(paths) > 1 && len(dupes) > 0 { if first { first = false } else { fmt.Println() } fmt.Printf("%v:\n", path) for _, dupe := range dupes { relPath := _path.Rel(dupe.Path()) fmt.Printf(" %v\n", relPath) } } else { for _, dupe := range dupes { relPath := _path.Rel(dupe.Path()) fmt.Println(relPath) } } } return nil, warnings }
func tagPath(store *storage.Storage, tx *storage.Tx, path string, pairs []entities.TagIdValueIdPair, explicit, recursive, force bool, fileFingerprintAlg, dirFingerprintAlg, symlinkFingerprintAlg string, reportDuplicates bool) error { absPath, err := filepath.Abs(path) if err != nil { return fmt.Errorf("%v: could not get absolute path: %v", path, err) } stat, err := os.Stat(path) if err != nil { switch { case os.IsNotExist(err), os.IsPermission(err): if !force { return err } else { stat = emptyStat{} } default: return err } } log.Infof(2, "%v: checking if file exists in database", path) file, err := store.FileByPath(tx, absPath) if err != nil { return fmt.Errorf("%v: could not retrieve file: %v", path, err) } if file == nil { log.Infof(2, "%v: creating fingerprint", path) fp, err := fingerprint.Create(path, fileFingerprintAlg, dirFingerprintAlg, symlinkFingerprintAlg) if err != nil { if !force || !(os.IsNotExist(err) || os.IsPermission(err)) { return fmt.Errorf("%v: could not create fingerprint: %v", path, err) } } if fp != fingerprint.Empty && reportDuplicates { log.Infof(2, "%v: checking for duplicates", path) count, err := store.FileCountByFingerprint(tx, fp) if err != nil { return fmt.Errorf("%v: could not identify duplicates: %v", path, err) } if count != 0 { log.Warnf("'%v' is a duplicate", path) } } log.Infof(2, "%v: adding file", path) file, err = store.AddFile(tx, path, fp, stat.ModTime(), int64(stat.Size()), stat.IsDir()) if err != nil { return fmt.Errorf("%v: could not add file to database: %v", path, err) } } if !explicit { pairs, err = removeAlreadyAppliedTagValuePairs(store, tx, pairs, file) if err != nil { return fmt.Errorf("%v: could not remove applied tags: %v", path, err) } } log.Infof(2, "%v: applying tags.", path) for _, pair := range pairs { if _, err = store.AddFileTag(tx, file.Id, pair.TagId, pair.ValueId); err != nil { return fmt.Errorf("%v: could not apply tags: %v", file.Path(), err) } } if recursive && stat.IsDir() { if err = tagRecursively(store, tx, path, pairs, explicit, force, fileFingerprintAlg, dirFingerprintAlg, symlinkFingerprintAlg, reportDuplicates); err != nil { return err } } return nil }