示例#1
0
文件: fusevfs.go 项目: logtcn/TMSU
func (vfs FuseVfs) OpenDir(name string, context *fuse.Context) ([]fuse.DirEntry, fuse.Status) {
	log.Infof(2, "BEGIN OpenDir(%v)", name)
	defer log.Infof(2, "END OpenDir(%v)", name)

	tx, err := vfs.store.Begin()
	if err != nil {
		log.Fatalf("could not begin transaction: %v", err)
	}
	defer tx.Commit()

	switch name {
	case "":
		return vfs.topFiles()
	case tagsDir:
		return vfs.tagDirectories(tx)
	case queriesDir:
		return vfs.queriesDirectories(tx)
	}

	path := vfs.splitPath(name)
	switch path[0] {
	case tagsDir:
		return vfs.openTaggedEntryDir(tx, path[1:])
	case queriesDir:
		return vfs.openQueryEntryDir(tx, path[1:])
	}

	return nil, fuse.ENOENT
}
示例#2
0
文件: fusevfs.go 项目: logtcn/TMSU
func (vfs FuseVfs) tagDirectories(tx *storage.Tx) ([]fuse.DirEntry, fuse.Status) {
	log.Infof(2, "BEGIN tagDirectories")
	defer log.Infof(2, "END tagDirectories")

	tags, err := vfs.store.Tags(tx)
	if err != nil {
		log.Fatalf("Could not retrieve tags: %v", err)
	}

	entries := make([]fuse.DirEntry, 0, len(tags))
	for _, tag := range tags {
		if strings.ContainsAny(tag.Name, "/\\") {
			log.Infof(2, "Tag '%v' contains slashes so is omitted from the VFS")
			continue
		}

		entries = append(entries, fuse.DirEntry{Name: tag.Name, Mode: fuse.S_IFDIR})
	}

	// show help file until there are three tags
	if len(tags) < 3 {
		entries = append(entries, fuse.DirEntry{Name: helpFilename, Mode: fuse.S_IFREG})
	}

	return entries, fuse.OK
}
示例#3
0
文件: fusevfs.go 项目: logtcn/TMSU
func (vfs FuseVfs) getQueryAttr() (*fuse.Attr, fuse.Status) {
	log.Infof(2, "BEGIN getQueryAttr")
	defer log.Infof(2, "END getQueryAttr")

	now := time.Now()
	return &fuse.Attr{Mode: fuse.S_IFDIR | 0755, Nlink: 2, Size: 0, Mtime: uint64(now.Unix()), Mtimensec: uint32(now.Nanosecond())}, fuse.OK
}
示例#4
0
文件: status.go 项目: peer23peer/TMSU
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
}
示例#5
0
文件: repair.go 项目: logtcn/TMSU
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
}
示例#6
0
文件: fusevfs.go 项目: logtcn/TMSU
func (vfs FuseVfs) Mkdir(name string, mode uint32, context *fuse.Context) fuse.Status {
	log.Infof(2, "BEGIN Mkdir(%v)", name)
	defer log.Infof(2, "END Mkdir(%v)", name)

	path := vfs.splitPath(name)

	if len(path) != 2 {
		return fuse.EPERM
	}

	tx, err := vfs.store.Begin()
	if err != nil {
		log.Fatalf("could not begin transaction: %v", err)
	}
	defer tx.Commit()

	switch path[0] {
	case tagsDir:
		name := path[1]

		if _, err := vfs.store.AddTag(tx, name); err != nil {
			log.Fatalf("could not create tag '%v': %v", name, err)
		}

		if err := tx.Commit(); err != nil {
			log.Fatalf("could not commit transaction: %v", err)
		}

		return fuse.OK
	case queriesDir:
		return fuse.EINVAL
	}

	return fuse.ENOSYS
}
示例#7
0
文件: fusevfs.go 项目: logtcn/TMSU
func (vfs FuseVfs) GetAttr(name string, context *fuse.Context) (*fuse.Attr, fuse.Status) {
	log.Infof(2, "BEGIN GetAttr(%v)", name)
	defer log.Infof(2, "END GetAttr(%v)", name)

	switch name {
	case databaseFilename:
		return vfs.getDatabaseFileAttr()
	case "":
		fallthrough
	case tagsDir:
		return vfs.getTagsAttr()
	case queriesDir:
		return vfs.getQueryAttr()
	}

	path := vfs.splitPath(name)

	switch path[0] {
	case tagsDir:
		return vfs.getTaggedEntryAttr(path[1:])
	case queriesDir:
		return vfs.getQueryEntryAttr(path[1:])
	}

	return nil, fuse.ENOENT
}
示例#8
0
文件: repair.go 项目: logtcn/TMSU
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
}
示例#9
0
文件: untag.go 项目: peer23peer/TMSU
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
}
示例#10
0
文件: fusevfs.go 项目: logtcn/TMSU
func (vfs FuseVfs) topFiles() ([]fuse.DirEntry, fuse.Status) {
	log.Infof(2, "BEGIN topFiles")
	defer log.Infof(2, "END topFiles")

	entries := []fuse.DirEntry{
		fuse.DirEntry{Name: databaseFilename, Mode: fuse.S_IFLNK},
		fuse.DirEntry{Name: tagsDir, Mode: fuse.S_IFDIR},
		fuse.DirEntry{Name: queriesDir, Mode: fuse.S_IFDIR}}
	return entries, fuse.OK
}
示例#11
0
func upgrade(tx *sql.Tx) error {
	version := currentSchemaVersion(tx)

	log.Infof(2, "database schema has version %v, latest schema version is %v", version, latestSchemaVersion)

	if version == latestSchemaVersion {
		log.Infof(2, "schema is up to date")
		return nil
	}

	noVersion := schemaVersion{}
	if version == noVersion {
		log.Infof(2, "creating schema")

		if err := createSchema(tx); err != nil {
			return err
		}

		// still need to run upgrade as per 0.5.0 database did not store a version
	}

	log.Infof(2, "upgrading database")

	if version.LessThan(schemaVersion{common.Version{0, 5, 0}, 0}) {
		log.Infof(2, "renaming fingerprint algorithm setting")

		if err := renameFingerprintAlgorithmSetting(tx); err != nil {
			return err
		}
	}
	if version.LessThan(schemaVersion{common.Version{0, 6, 0}, 0}) {
		log.Infof(2, "recreating implication table")

		if err := recreateImplicationTable(tx); err != nil {
			return err
		}
	}
	if version.LessThan(schemaVersion{common.Version{0, 7, 0}, 0}) {
		log.Infof(2, "updating fingerprint algorithms")

		if err := updateFingerprintAlgorithms(tx); err != nil {
			return err
		}
	}
	if version.LessThan(schemaVersion{common.Version{0, 7, 0}, 1}) {
		log.Infof(2, "recreating version table")

		if err := recreateVersionTable(tx); err != nil {
			return err
		}
	}

	log.Infof(2, "updating schema version")
	if err := updateSchemaVersion(tx, latestSchemaVersion); err != nil {
		return err
	}

	return nil
}
示例#12
0
文件: imply.go 项目: logtcn/TMSU
func deleteImplications(store *storage.Storage, tx *storage.Tx, tagArgs []string) (error, warnings) {
	log.Infof(2, "loading settings")

	implyingTagArg := tagArgs[0]
	impliedTagArgs := tagArgs[1:]

	implyingTagName, implyingValueName := parseTagEqValueName(implyingTagArg)

	implyingTag, err := store.TagByName(tx, implyingTagName)
	if err != nil {
		return err, nil
	}
	if implyingTag == nil {
		return NoSuchTagError{implyingTagName}, nil
	}

	implyingValue, err := store.ValueByName(tx, implyingValueName)
	if err != nil {
		return err, nil
	}
	if implyingValue == nil {
		return NoSuchValueError{implyingValueName}, nil
	}

	warnings := make(warnings, 0, 10)
	for _, impliedTagArg := range impliedTagArgs {
		log.Infof(2, "removing tag implication %v -> %v.", implyingTagArg, impliedTagArg)

		impliedTagName, impliedValueName := parseTagEqValueName(impliedTagArg)

		impliedTag, err := store.TagByName(tx, impliedTagName)
		if err != nil {
			return err, warnings
		}
		if impliedTag == nil {
			warnings = append(warnings, fmt.Sprintf("no such tag '%v'", impliedTagName))
		}

		impliedValue, err := store.ValueByName(tx, impliedValueName)
		if err != nil {
			return err, warnings
		}
		if impliedValue == nil {
			warnings = append(warnings, fmt.Sprintf("no such value '%v'", impliedValueName))
		}

		if err := store.DeleteImplication(tx, entities.TagIdValueIdPair{implyingTag.Id, implyingValue.Id}, entities.TagIdValueIdPair{impliedTag.Id, impliedValue.Id}); err != nil {
			return fmt.Errorf("could not delete tag implication of %v to %v: %v", implyingTagArg, impliedTagArg, err), warnings
		}
	}

	return nil, warnings
}
示例#13
0
文件: fusevfs.go 项目: logtcn/TMSU
func (vfs FuseVfs) Open(name string, flags uint32, context *fuse.Context) (nodefs.File, fuse.Status) {
	log.Infof(2, "BEGIN Open(%v)", name)
	defer log.Infof(2, "END Open(%v)", name)

	switch name {
	case filepath.Join(queriesDir, helpFilename):
		return nodefs.NewDataFile([]byte(queryDirHelp)), fuse.OK
	case filepath.Join(tagsDir, helpFilename):
		return nodefs.NewDataFile([]byte(tagsDirHelp)), fuse.OK
	}

	return nil, fuse.ENOSYS
}
示例#14
0
文件: merge.go 项目: logtcn/TMSU
func mergeValues(store *storage.Storage, tx *storage.Tx, sourceValueNames []string, destValueName string) (error, warnings) {
	destValue, err := store.ValueByName(tx, destValueName)
	if err != nil {
		return fmt.Errorf("could not retrieve value '%v': %v", destValueName, err), nil
	}
	if destValue == nil {
		return fmt.Errorf("no such value '%v'", destValueName), nil
	}

	warnings := make(warnings, 0, 10)

	for _, sourceValueName := range sourceValueNames {
		if sourceValueName == destValueName {
			warnings = append(warnings, fmt.Sprintf("cannot merge value '%v' into itself", sourceValueName))
			continue
		}

		sourceValue, err := store.ValueByName(tx, sourceValueName)
		if err != nil {
			return fmt.Errorf("could not retrieve value '%v': %v", sourceValueName, err), warnings
		}
		if sourceValue == nil {
			warnings = append(warnings, fmt.Sprintf("no such value '%v'", sourceValueName))
			continue
		}

		log.Infof(2, "finding files tagged with value '%v'.", sourceValueName)

		fileTags, err := store.FileTagsByValueId(tx, sourceValue.Id)
		if err != nil {
			return fmt.Errorf("could not retrieve files for value '%v': %v", sourceValueName, err), warnings
		}

		log.Infof(2, "applying value '%v' to these files.", destValueName)

		for _, fileTag := range fileTags {
			if _, err = store.AddFileTag(tx, fileTag.FileId, fileTag.TagId, destValue.Id); err != nil {
				return fmt.Errorf("could not apply value '%v' to file #%v: %v", destValueName, fileTag.FileId, err), warnings
			}
		}

		log.Infof(2, "deleting value '%v'.", sourceValueName)

		if err = store.DeleteValue(tx, sourceValue.Id); err != nil {
			return fmt.Errorf("could not delete value '%v': %v", sourceValueName, err), warnings
		}
	}

	return nil, warnings
}
示例#15
0
func (vfs FuseVfs) openTaggedEntryDir(tx *storage.Tx, path []string) ([]fuse.DirEntry, fuse.Status) {
	log.Infof(2, "BEGIN openTaggedEntryDir(%v)", path)
	defer log.Infof(2, "END openTaggedEntryDir(%v)", path)

	expression := pathToExpression(path)
	files, err := vfs.store.FilesForQuery(tx, expression, "", false, false, "name")
	if err != nil {
		log.Fatalf("could not query files: %v", err)
	}

	lastPathElement := path[len(path)-1]

	var valueNames []string
	if lastPathElement[0] != '=' {
		tagName := unescape(lastPathElement)

		valueNames, err = vfs.tagValueNamesForFiles(tx, tagName, files)
		if err != nil {
			log.Fatalf("could not retrieve values for '%v': %v", err)
		}
	} else {
		valueNames = []string{}
	}

	furtherTagNames, err := vfs.tagNamesForFiles(tx, files)
	if err != nil {
		log.Fatalf("could not retrieve further tags: %v", err)
	}

	entries := make([]fuse.DirEntry, 0, len(files)+len(furtherTagNames))
	for _, tagName := range furtherTagNames {
		tagName = escape(tagName)
		if !containsString(path, tagName) {
			entries = append(entries, fuse.DirEntry{Name: tagName, Mode: fuse.S_IFDIR | 0755})
		}
	}

	for _, valueName := range valueNames {
		valueName = escape(valueName)
		entries = append(entries, fuse.DirEntry{Name: "=" + valueName, Mode: fuse.S_IFDIR | 0755})
	}

	for _, file := range files {
		linkName := vfs.getLinkName(file)
		entries = append(entries, fuse.DirEntry{Name: linkName, Mode: fuse.S_IFLNK})
	}

	return entries, fuse.OK
}
示例#16
0
文件: repair.go 项目: logtcn/TMSU
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
}
示例#17
0
文件: repair.go 项目: logtcn/TMSU
func manualRepair(store *storage.Storage, tx *storage.Tx, fromPath, toPath string, pretend bool) error {
	absFromPath, err := filepath.Abs(fromPath)
	if err != nil {
		return fmt.Errorf("%v: could not determine absolute path", err)
	}

	absToPath, err := filepath.Abs(toPath)
	if err != nil {
		return fmt.Errorf("%v: could not determine absolute path", err)
	}

	log.Infof(2, "retrieving files under '%v' from the database", fromPath)

	dbFile, err := store.FileByPath(tx, absFromPath)
	if err != nil {
		return fmt.Errorf("%v: could not retrieve file: %v", fromPath, err)
	}

	if dbFile != nil {
		log.Infof(2, "%v: updating to %v", fromPath, toPath)

		if !pretend {
			if err := manualRepairFile(store, tx, dbFile, absToPath); err != nil {
				return err
			}
		}
	}

	dbFiles, err := store.FilesByDirectory(tx, absFromPath)
	if err != nil {
		return fmt.Errorf("could not retrieve files from storage: %v", err)
	}

	for _, dbFile = range dbFiles {
		relFileFromPath := _path.Rel(dbFile.Path())
		absFileToPath := strings.Replace(dbFile.Path(), absFromPath, absToPath, 1)
		relFileToPath := _path.Rel(absFileToPath)

		log.Infof(2, "%v: updating to %v", relFileFromPath, relFileToPath)

		if !pretend {
			if err := manualRepairFile(store, tx, dbFile, absFileToPath); err != nil {
				return err
			}
		}
	}

	return nil
}
示例#18
0
文件: repair.go 项目: logtcn/TMSU
func buildPathBySizeMap(paths []string) (map[int64][]string, error) {
	log.Infof(2, "building map of paths by size")

	pathsBySize := make(map[int64][]string, 10)

	for _, path := range paths {
		if err := buildPathBySizeMapRecursive(path, pathsBySize); err != nil {
			return nil, err
		}
	}

	log.Infof(2, "path by size map has %v sizes", len(pathsBySize))

	return pathsBySize, nil
}
示例#19
0
文件: values.go 项目: peer23peer/TMSU
func listValuesForTag(store *storage.Storage, tx *storage.Tx, tagName string, showCount, onePerLine bool) error {
	tag, err := store.TagByName(tx, tagName)
	if err != nil {
		return fmt.Errorf("could not retrieve tag '%v': %v", tagName, err)
	}
	if tag == nil {
		return fmt.Errorf("no such tag, '%v'", tagName)
	}

	log.Infof(2, "retrieving values for tag '%v'.", tagName)

	values, err := store.ValuesByTag(tx, tag.Id)
	if err != nil {
		return fmt.Errorf("could not retrieve values for tag '%v': %v", tagName, err)
	}

	if showCount {
		fmt.Println(len(values))
	} else {
		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
}
示例#20
0
文件: dupes.go 项目: peer23peer/TMSU
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
}
示例#21
0
func OpenAt(path string) (*Database, error) {
	log.Infof(2, "opening database at '%v'.", path)

	_, err := os.Stat(path)
	if err != nil {
		switch {
		case os.IsNotExist(err):
			return nil, DatabaseNotFoundError{path}
		default:
			return nil, DatabaseAccessError{path, err}
		}
	}

	db, err := sql.Open("sqlite3", path)
	if err != nil {
		return nil, DatabaseAccessError{path, err}
	}

	tx, err := db.Begin()
	if err != nil {
		return nil, DatabaseTransactionError{path, err}
	}

	if err := upgrade(tx); err != nil {
		return nil, err
	}

	if err := tx.Commit(); err != nil {
		return nil, DatabaseTransactionError{path, err}
	}

	return &Database{db}, nil
}
示例#22
0
文件: repair.go 项目: logtcn/TMSU
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
}
示例#23
0
文件: fusevfs.go 项目: logtcn/TMSU
func (vfs FuseVfs) tagNamesForFiles(tx *storage.Tx, files entities.Files) ([]string, error) {
	tagNames := make([]string, 0, 10)

	for _, file := range files {
		fileTags, err := vfs.store.FileTagsByFileId(tx, file.Id, false)
		if err != nil {
			return nil, fmt.Errorf("could not retrieve file-tags for file '%v': %v", file.Id, err)
		}

		tagIds := make(entities.TagIds, len(fileTags))
		for index, fileTag := range fileTags {
			tagIds[index] = fileTag.TagId
		}

		tags, err := vfs.store.TagsByIds(tx, tagIds)
		if err != nil {
			return nil, fmt.Errorf("could not retrieve tags: %v", err)
		}

		for _, tag := range tags {
			if strings.ContainsAny(tag.Name, "/\\") {
				log.Infof(2, "tag '%v' omitted as it contains slashes")
				continue
			}

			if !containsString(tagNames, tag.Name) {
				tagNames = append(tagNames, tag.Name)
			}
		}
	}

	return tagNames, nil
}
示例#24
0
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
}
示例#25
0
文件: imply.go 项目: logtcn/TMSU
func listImplications(store *storage.Storage, tx *storage.Tx, colour bool) error {
	log.Infof(2, "retrieving tag implications.")

	implications, err := store.Implications(tx)
	if err != nil {
		return fmt.Errorf("could not retrieve implications: %v", err)
	}

	width := 0
	for _, implication := range implications {
		length := len(implication.ImplyingTag.Name)
		if implication.ImplyingValue.Id != 0 {
			length += 1 + len(implication.ImplyingValue.Name)
		}

		if length > width {
			width = length
		}
	}

	if len(implications) > 0 {
		for _, implication := range implications {
			implying := formatTagValueName(implication.ImplyingTag.Name, implication.ImplyingValue.Name, colour, false, true)
			implied := formatTagValueName(implication.ImpliedTag.Name, implication.ImpliedValue.Name, colour, true, false)

			fmt.Printf("%*v -> %v\n", width, implying, implied)
		}
	}

	return nil
}
示例#26
0
文件: rename.go 项目: peer23peer/TMSU
func renameTag(store *storage.Storage, tx *storage.Tx, currentName, newName string) error {
	sourceTag, err := store.TagByName(tx, currentName)
	if err != nil {
		return fmt.Errorf("could not retrieve tag '%v': %v", currentName, err)
	}
	if sourceTag == nil {
		return fmt.Errorf("no such tag '%v'", currentName)
	}

	destTag, err := store.TagByName(tx, newName)
	if err != nil {
		return fmt.Errorf("could not retrieve tag '%v': %v", newName, err)
	}
	if destTag != nil {
		return fmt.Errorf("tag '%v' already exists", newName)
	}

	log.Infof(2, "renaming tag '%v' to '%v'.", currentName, newName)

	_, err = store.RenameTag(tx, sourceTag.Id, newName)
	if err != nil {
		return fmt.Errorf("could not rename tag '%v' to '%v': %v", currentName, newName, err)
	}

	return nil
}
示例#27
0
文件: rename.go 项目: peer23peer/TMSU
func renameValue(store *storage.Storage, tx *storage.Tx, currentName, newName string) error {
	sourceValue, err := store.ValueByName(tx, currentName)
	if err != nil {
		return fmt.Errorf("could not retrieve value '%v': %v", currentName, err)
	}
	if sourceValue == nil {
		return fmt.Errorf("no such value '%v'", currentName)
	}

	destValue, err := store.ValueByName(tx, newName)
	if err != nil {
		return fmt.Errorf("could not retrieve value '%v': %v", newName, err)
	}
	if destValue != nil {
		return fmt.Errorf("value '%v' already exists", newName)
	}

	log.Infof(2, "renaming value '%v' to '%v'.", currentName, newName)

	_, err = store.RenameValue(tx, sourceValue.Id, newName)
	if err != nil {
		return fmt.Errorf("could not rename value '%v' to '%v': %v", currentName, newName, err)
	}

	return nil
}
示例#28
0
文件: fusevfs.go 项目: logtcn/TMSU
func (vfs FuseVfs) readTaggedEntryLink(tx *storage.Tx, path []string) (string, fuse.Status) {
	log.Infof(2, "BEGIN readTaggedEntryLink(%v)", path)
	defer log.Infof(2, "END readTaggedEntryLink(%v)", path)

	name := path[len(path)-1]

	fileId := vfs.parseFileId(name)
	if fileId == 0 {
		return "", fuse.ENOENT
	}

	file, err := vfs.store.File(tx, fileId)
	if err != nil {
		log.Fatalf("could not find file %v in database.", fileId)
	}

	return file.Path(), fuse.OK
}
示例#29
0
文件: fusevfs.go 项目: logtcn/TMSU
func (vfs FuseVfs) getTagsAttr() (*fuse.Attr, fuse.Status) {
	log.Infof(2, "BEGIN getTagsAttr")
	defer log.Infof(2, "END getTagsAttr")

	tx, err := vfs.store.Begin()
	if err != nil {
		log.Fatalf("could not begin transaction: %v", err)
	}
	defer tx.Commit()

	tagCount, err := vfs.store.TagCount(tx)
	if err != nil {
		log.Fatalf("could not get tag count: %v", err)
	}

	now := time.Now()
	return &fuse.Attr{Mode: fuse.S_IFDIR | 0755, Nlink: 2, Size: uint64(tagCount), Mtime: uint64(now.Unix()), Mtimensec: uint32(now.Nanosecond())}, fuse.OK
}
示例#30
0
文件: repair.go 项目: logtcn/TMSU
func deleteUntaggedFiles(store *storage.Storage, tx *storage.Tx, files entities.Files) error {
	log.Infof(2, "purging untagged files")

	fileIds := make([]entities.FileId, len(files))
	for index, file := range files {
		fileIds[index] = file.Id
	}

	return store.DeleteUntaggedFiles(tx, fileIds)
}