func statusCheckFile(absPath string, file *entities.File, report *StatusReport) error { log.Infof(2, "%v: checking file status.", absPath) stat, err := os.Stat(file.Path()) if err != nil { switch { case os.IsNotExist(err): log.Infof(2, "%v: file is missing.", absPath) report.AddRow(Row{absPath, MISSING}) return nil case os.IsPermission(err): log.Warnf("%v: permission denied.", absPath) case strings.Contains(err.Error(), "not a directory"): //TODO improve report.AddRow(Row{file.Path(), MISSING}) return nil default: return fmt.Errorf("%v: could not stat: %v", file.Path(), err) } } else { if stat.Size() != file.Size || !stat.ModTime().UTC().Equal(file.ModTime) { log.Infof(2, "%v: file is modified.", absPath) report.AddRow(Row{absPath, MODIFIED}) } else { log.Infof(2, "%v: file is unchanged.", absPath) report.AddRow(Row{absPath, TAGGED}) } } return nil }
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 determineStatuses(dbFiles entities.Files) (unmodified, modified, missing entities.Files) { log.Infof(2, "determining file statuses") unmodified = make(entities.Files, 0, 10) modified = make(entities.Files, 0, 10) missing = make(entities.Files, 0, 10) for _, dbFile := range dbFiles { stat, err := os.Stat(dbFile.Path()) if err != nil { switch { case os.IsPermission(err): //TODO return as warning log.Warnf("%v: permission denied", dbFile.Path()) continue case os.IsNotExist(err): //TODO return as warning log.Infof(2, "%v: missing", dbFile.Path()) missing = append(missing, dbFile) continue } } if dbFile.ModTime.Equal(stat.ModTime().UTC()) && dbFile.Size == stat.Size() { log.Infof(2, "%v: unmodified", dbFile.Path()) unmodified = append(unmodified, dbFile) } else { log.Infof(2, "%v: modified", dbFile.Path()) modified = append(modified, dbFile) } } return }
func createValue(store *storage.Storage, tx *storage.Tx, valueName string) (*entities.Value, error) { value, err := store.AddValue(tx, valueName) if err != nil { return nil, err } log.Warnf("new value '%v'", valueName) return value, nil }
func createTag(store *storage.Storage, tx *storage.Tx, tagName string) (*entities.Tag, error) { tag, err := store.AddTag(tx, tagName) if err != nil { return nil, err } log.Warnf("new tag '%v'", tagName) return tag, nil }
func initializeDatabase(path string) error { log.Warnf("%v: creating database", path) tmsuPath := filepath.Join(path, ".tmsu") os.Mkdir(tmsuPath, 0755) dbPath := filepath.Join(tmsuPath, "db") return storage.CreateAt(dbPath) }
func directoryEntries(path string) ([]string, error) { stat, err := os.Stat(path) if err != nil { switch { case os.IsNotExist(err): //TODO return as warning log.Warnf("%v: does not exist", path) return []string{}, nil case os.IsPermission(err): //TODO return as warning log.Warnf("%v: permission denied", path) return []string{}, nil default: return nil, fmt.Errorf("%v: could not stat", path, err) } } if !stat.IsDir() { return []string{}, nil } dir, err := os.Open(path) if err != nil { return nil, fmt.Errorf("%v could not open directory", path, err) } names, err := dir.Readdirnames(0) dir.Close() if err != nil { return nil, fmt.Errorf("%v: could not read directory entries", path, err) } entries := make([]string, len(names)) for index, name := range names { entries[index] = filepath.Join(path, name) } return entries, nil }
func findNewFiles(searchPath string, report *StatusReport, dirOnly bool) error { log.Infof(2, "%v: finding new files.", searchPath) relPath := path.Rel(searchPath) if !report.ContainsRow(relPath) { report.AddRow(Row{relPath, UNTAGGED}) } absPath, err := filepath.Abs(searchPath) if err != nil { return fmt.Errorf("%v: could not get absolute path: %v", searchPath, err) } stat, err := os.Stat(absPath) if err != nil { switch { case os.IsNotExist(err): return nil case os.IsPermission(err): log.Warnf("%v: permission denied.", searchPath) return nil default: return fmt.Errorf("%v: could not stat: %v", searchPath, err) } } if !dirOnly && stat.IsDir() { dir, err := os.Open(absPath) if err != nil { return fmt.Errorf("%v: could not open file: %v", searchPath, err) } dirNames, err := dir.Readdirnames(0) if err != nil { return fmt.Errorf("%v: could not read directory listing: %v", searchPath, err) } sort.Strings(dirNames) for _, dirName := range dirNames { dirPath := filepath.Join(searchPath, dirName) err = findNewFiles(dirPath, report, dirOnly) if err != nil { return err } } } return nil }
func buildPathBySizeMapRecursive(path string, pathBySizeMap map[int64][]string) error { absPath, err := filepath.Abs(path) if err != nil { return fmt.Errorf("%v: could not get absolute path", path) } stat, err := os.Stat(absPath) if err != nil { switch { case os.IsPermission(err): log.Warnf("%v: permission denied", path) default: return err } } if stat.IsDir() { log.Infof(3, "%v: examining directory contents", absPath) dir, err := os.Open(absPath) if err != nil { return fmt.Errorf("%v: could not open directory: %v", path, err) } names, err := dir.Readdirnames(0) dir.Close() if err != nil { return fmt.Errorf("%v: could not read directory entries: %v", path, err) } for _, name := range names { childPath := filepath.Join(path, name) if err := buildPathBySizeMapRecursive(childPath, pathBySizeMap); err != nil { return err } } } else { log.Infof(3, "%v: file is of size %v", absPath, stat.Size()) filesOfSize, ok := pathBySizeMap[stat.Size()] if ok { pathBySizeMap[stat.Size()] = append(filesOfSize, absPath) } else { pathBySizeMap[stat.Size()] = []string{absPath} } } return nil }
func enumerate(path string, files []FileSystemFile) ([]FileSystemFile, error) { stat, err := os.Stat(path) if err != nil { switch { case os.IsNotExist(err): return files, nil case os.IsPermission(err): log.Warnf("%v: permission denied", path) return files, nil default: return nil, fmt.Errorf("%v: could not stat: %v", path, err) } } files = append(files, FileSystemFile{path, stat.IsDir()}) if stat.IsDir() { dir, err := os.Open(path) if err != nil { return nil, fmt.Errorf("%v: could not open directory: %v", path, err) } names, err := dir.Readdirnames(0) dir.Close() if err != nil { return nil, fmt.Errorf("%v: could not read directory entries: %v", path, err) } for _, name := range names { childPath := filepath.Join(path, name) files, err = enumerate(childPath, files) if err != nil { return nil, err } } } return files, nil }
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 }