func untagPathsAll(store *storage.Storage, tx *storage.Tx, paths []string, recursive, followSymlinks bool) (error, warnings) { warnings := make(warnings, 0, 10) for _, path := range paths { absPath, err := filepath.Abs(path) if err != nil { return fmt.Errorf("%v: could not get absolute path: %v", path, err), warnings } log.Infof(2, "%v: resolving path", path) stat, err := os.Lstat(absPath) if err != nil { switch { case os.IsNotExist(err), os.IsPermission(err): // ignore default: return err, nil } } else if stat.Mode()&os.ModeSymlink != 0 && followSymlinks { absPath, err = _path.Dereference(absPath) if err != nil { return err, nil } } file, err := store.FileByPath(tx, absPath) if err != nil { return fmt.Errorf("%v: could not retrieve file: %v", path, err), warnings } if file == nil { warnings = append(warnings, fmt.Sprintf("%v: file is not tagged.", path)) continue } log.Infof(2, "%v: removing all tags.", path) if err := store.DeleteFileTagsByFileId(tx, file.Id); err != nil { return fmt.Errorf("%v: could not remove file's tags: %v", path, err), warnings } if recursive { childFiles, err := store.FilesByDirectory(tx, file.Path()) if err != nil { return fmt.Errorf("%v: could not retrieve files for directory: %v", path, err), warnings } for _, childFile := range childFiles { if err := store.DeleteFileTagsByFileId(tx, childFile.Id); err != nil { return fmt.Errorf("%v: could not remove file's tags: %v", childFile.Path(), err), warnings } } } } return nil, warnings }
func tagFrom(store *storage.Storage, tx *storage.Tx, fromPath string, paths []string, explicit, recursive, force, followSymlinks bool) (error, warnings) { log.Infof(2, "loading settings") settings, err := store.Settings(tx) if err != nil { return fmt.Errorf("could not retrieve settings: %v", err), nil } stat, err := os.Lstat(fromPath) if err != nil { return err, nil } if stat.Mode()&os.ModeSymlink != 0 && followSymlinks { fromPath, err = _path.Dereference(fromPath) if err != nil { return err, nil } } file, err := store.FileByPath(tx, fromPath) if err != nil { return fmt.Errorf("%v: could not retrieve file: %v", fromPath, err), nil } if file == nil { return fmt.Errorf("%v: path is not tagged", fromPath), nil } fileTags, err := store.FileTagsByFileId(tx, file.Id, true) if err != nil { return fmt.Errorf("%v: could not retrieve filetags: %v", fromPath, err), nil } pairs := make([]entities.TagIdValueIdPair, len(fileTags)) for index, fileTag := range fileTags { pairs[index] = entities.TagIdValueIdPair{fileTag.TagId, fileTag.ValueId} } warnings := make(warnings, 0, 10) for _, path := range paths { if err := tagPath(store, tx, path, pairs, explicit, recursive, force, followSymlinks, settings.FileFingerprintAlgorithm(), settings.DirectoryFingerprintAlgorithm(), settings.SymlinkFingerprintAlgorithm(), settings.ReportDuplicates()); err != nil { switch { case os.IsPermission(err): warnings = append(warnings, fmt.Sprintf("%v: permisison denied", path)) case os.IsNotExist(err): warnings = append(warnings, fmt.Sprintf("%v: no such file", path)) default: return fmt.Errorf("%v: could not stat file: %v", path, err), warnings } } } return nil, warnings }
func findUntaggedFunc(store *storage.Storage, tx *storage.Tx, paths []string, recursive, followSymlinks bool, action func(absPath string)) error { for _, path := range paths { absPath, err := filepath.Abs(path) if err != nil { return fmt.Errorf("%v: could not get absolute path: %v", path, err) } if followSymlinks { log.Infof(2, "%v: resolving path", path) absPath, err = _path.Dereference(absPath) if err != nil { return fmt.Errorf("%v: could not dereference path: %v", path, err) } } //TODO PERF no need to retrieve file: we merely need to know it exists file, err := store.FileByPath(tx, absPath) if err != nil { return fmt.Errorf("%v: could not retrieve file: %v", path, err) } if file == nil { action(absPath) } if recursive { entries, err := directoryEntries(path) if err != nil { return err } findUntaggedFunc(store, tx, entries, true, followSymlinks, action) } } return nil }
func statusPaths(store *storage.Storage, tx *storage.Tx, paths []string, dirOnly, followSymlinks bool) (*StatusReport, error) { report := NewReport() for _, path := range paths { absPath, err := filepath.Abs(path) if err != nil { return nil, fmt.Errorf("%v: could not get absolute path: %v", path, err) } log.Infof(2, "%v: resolving file", path) resolvedPath := absPath stat, err := os.Lstat(absPath) if err != nil { switch { case os.IsNotExist(err), os.IsPermission(err): stat = emptyStat{} default: return nil, fmt.Errorf("%v: could not stat path: %v", path, err) } } else if stat.Mode()&os.ModeSymlink != 0 { resolvedPath, err = _path.Dereference(absPath) if err != nil { return nil, fmt.Errorf("%v: could not dereference symbolic link: %v", path, err) } } log.Infof(2, "%v: checking file in database", path) file, err := store.FileByPath(tx, resolvedPath) if err != nil { return nil, fmt.Errorf("%v: could not retrieve file: %v", path, err) } if file != nil { err = statusCheckFile(absPath, file, report) if err != nil { return nil, err } } if !dirOnly && (stat.Mode()&os.ModeSymlink == 0 || followSymlinks) { log.Infof(2, "%v: retrieving files from database.", path) files, err := store.FilesByDirectory(tx, resolvedPath) if err != nil { return nil, fmt.Errorf("%v: could not retrieve files for directory: %v", path, err) } err = statusCheckFiles(files, report) if err != nil { return nil, err } } err = findNewFiles(absPath, report, dirOnly, followSymlinks) if err != nil { return nil, err } } return report, nil }
func untagPaths(store *storage.Storage, tx *storage.Tx, paths, tagArgs []string, recursive, followSymlinks bool) (error, warnings) { warnings := make(warnings, 0, 10) files := make(entities.Files, 0, len(paths)) for _, path := range paths { absPath, err := filepath.Abs(path) if err != nil { return fmt.Errorf("%v: could not get absolute path: %v", path, err), warnings } log.Infof(2, "%v: resolving path", path) stat, err := os.Lstat(absPath) if err != nil { switch { case os.IsNotExist(err), os.IsPermission(err): // ignore default: return err, nil } } else if stat.Mode()&os.ModeSymlink != 0 && followSymlinks { absPath, err = _path.Dereference(absPath) if err != nil { return err, nil } } file, err := store.FileByPath(tx, absPath) if err != nil { return fmt.Errorf("%v: could not retrieve file: %v", path, err), warnings } if file == nil { warnings = append(warnings, fmt.Sprintf("%v: file is not tagged", path)) continue } files = append(files, file) if recursive { childFiles, err := store.FilesByDirectory(tx, file.Path()) if err != nil { return fmt.Errorf("%v: could not retrieve files for directory: %v", file.Path()), warnings } files = append(files, childFiles...) } } for _, tagArg := range tagArgs { tagName, valueName := parseTagEqValueName(tagArg) tag, err := store.TagByName(tx, tagName) if err != nil { return fmt.Errorf("could not retrieve tag '%v': %v", tagName, err), warnings } if tag == nil { warnings = append(warnings, fmt.Sprintf("no such tag '%v'", tagName)) continue } value, err := store.ValueByName(tx, valueName) if err != nil { return fmt.Errorf("could not retrieve value '%v': %v", valueName, err), warnings } if value == nil { warnings = append(warnings, fmt.Sprintf("no such value '%v'", valueName)) continue } for _, file := range files { if err := store.DeleteFileTag(tx, file.Id, tag.Id, value.Id); err != nil { switch err.(type) { case storage.FileTagDoesNotExist: exists, err := store.FileTagExists(tx, file.Id, tag.Id, value.Id, false) if err != nil { return fmt.Errorf("could not check if tag exists: %v", err), warnings } if exists { if value.Id != 0 { warnings = append(warnings, fmt.Sprintf("%v: cannot remove '%v=%v': delete implication to remove this tag.", file.Path(), tag.Name, value.Name)) } else { warnings = append(warnings, fmt.Sprintf("%v: cannot remove '%v': delete implication to remove this tag.", file.Path(), tag.Name)) } } else { if value.Id != 0 { warnings = append(warnings, fmt.Sprintf("%v: file is not tagged '%v=%v'.", file.Path(), tag.Name, value.Name)) } else { warnings = append(warnings, fmt.Sprintf("%v: file is not tagged '%v'.", file.Path(), tag.Name)) } } default: return fmt.Errorf("%v: could not remove tag '%v', value '%v': %v", file.Path(), tag.Name, value.Name, err), warnings } } } } return nil, warnings }
func tagPath(store *storage.Storage, tx *storage.Tx, path string, pairs []entities.TagIdValueIdPair, explicit, recursive, force, followSymlinks 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) } log.Infof(2, "%v: resolving path", path) stat, err := os.Lstat(absPath) if err != nil { switch { case os.IsNotExist(err), os.IsPermission(err): if force { // force tag even though can't access file stat = emptyStat{} } else { return err } default: return err } } else if stat.Mode()&os.ModeSymlink != 0 && followSymlinks { absPath, err = _path.Dereference(absPath) if err != nil { // can't honour 'force' as we don't know the target path return err } stat, err = os.Lstat(absPath) if err != nil { 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(absPath, 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, absPath, 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", path, err) } } if recursive && stat.IsDir() { if err = tagRecursively(store, tx, absPath, pairs, explicit, force, followSymlinks, fileFingerprintAlg, dirFingerprintAlg, symlinkFingerprintAlg, reportDuplicates); err != nil { return err } } return nil }
func listTagsForPaths(store *storage.Storage, tx *storage.Tx, paths []string, showCount, onePerLine, explicitOnly, printPath, colour, followSymlinks bool) (error, warnings) { warnings := make(warnings, 0, 10) printPath = printPath || len(paths) > 1 || !stdoutIsCharDevice() for index, path := range paths { absPath, err := filepath.Abs(path) if err != nil { return err, warnings } log.Infof(2, "%v: resolving path", absPath) stat, err := os.Lstat(absPath) if err != nil { switch { case os.IsNotExist(err), os.IsPermission(err): stat = emptyStat{} default: warnings = append(warnings, err.Error()) continue } } else if stat.Mode()&os.ModeSymlink != 0 && followSymlinks { absPath, err = _path.Dereference(absPath) if err != nil { warnings = append(warnings, err.Error()) continue } } log.Infof(2, "%v: retrieving tags", absPath) file, err := store.FileByPath(tx, absPath) if err != nil { warnings = append(warnings, err.Error()) continue } var tagNames []string if file != nil { tagNames, err = tagNamesForFile(store, tx, file.Id, explicitOnly, colour) if err != nil { return err, warnings } } else { _, err := os.Stat(absPath) if err != nil { switch { case os.IsPermission(err): warnings = append(warnings, fmt.Sprintf("%v: permission denied", absPath)) continue case os.IsNotExist(err): warnings = append(warnings, fmt.Sprintf("%v: no such file", absPath)) continue default: return fmt.Errorf("%v: could not stat file: %v", absPath, err), warnings } } } escapedPath := escape(path, '\\', ':') switch { case showCount: if printPath { fmt.Print(escapedPath + ": ") } fmt.Println(strconv.Itoa(len(tagNames))) case onePerLine: if index > 0 { fmt.Println() } if printPath { fmt.Println(escapedPath + ":") } for _, tagName := range tagNames { fmt.Println(tagName) } default: if printPath { fmt.Print(escapedPath + ":") for _, tagName := range tagNames { fmt.Print(" " + tagName) } fmt.Println() } else { terminal.PrintColumns(tagNames) } } } return nil, warnings }