Example #1
0
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
	}

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

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

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

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

	return fuse.ENOSYS
}
Example #2
0
func (vfs FuseVfs) openTaggedEntryDir(path []string) ([]fuse.DirEntry, fuse.Status) {
	log.Infof(2, "BEGIN openTaggedEntryDir(%v)", path)
	defer log.Infof(2, "END openTaggedEntryDir(%v)", path)

	expression := query.HasAll(path)
	files, err := vfs.store.QueryFiles(expression)
	if err != nil {
		log.Fatalf("could not query files: %v", err)
	}

	tagNames := make(map[string]interface{}, len(path))
	for _, tagName := range path {
		tagNames[tagName] = nil
	}

	furtherTagNames := make([]string, 0, 10)
	for _, file := range files {
		fileTags, err := vfs.store.FileTagsByFileId(file.Id)
		if err != nil {
			log.Fatalf("could not retrieve file-tags for file '%v': %v", file.Id, err)
		}

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

		tags, err := vfs.store.TagsByIds(tagIds)
		if err != nil {
			log.Fatalf("could not retrieve tags: %v", err)
		}

		for _, tag := range tags {
			_, has := tagNames[tag.Name]
			if !has {
				if !containsName(furtherTagNames, tag.Name) {
					furtherTagNames = append(furtherTagNames, tag.Name)
				}
			}
		}
	}

	entries := make([]fuse.DirEntry, 0, len(files)+len(furtherTagNames))
	for _, tagName := range furtherTagNames {
		entries = append(entries, fuse.DirEntry{Name: tagName, 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
}
Example #3
0
func (vfs FuseVfs) Unlink(name string, context *fuse.Context) fuse.Status {
	log.Infof(2, "BEGIN Unlink(%v)", name)
	defer log.Infof(2, "END Unlink(%v)", name)

	fileId := vfs.parseFileId(name)
	if fileId == 0 {
		// can only unlink file symbolic links
		return fuse.EPERM
	}

	file, err := vfs.store.File(fileId)
	if err != nil {
		log.Fatal("could not retrieve file '%v': %v", fileId, err)
	}
	if file == nil {
		// reply ok if file doesn't exist otherwise recursive deletes fail
		return fuse.OK
	}
	path := vfs.splitPath(name)

	switch path[0] {
	case tagsDir:
		tagName := path[len(path)-2]
		//TODO value name

		tag, err := vfs.store.TagByName(tagName)
		if err != nil {
			log.Fatal(err)
		}
		if tag == nil {
			log.Fatalf("could not retrieve tag '%v'.", tagName)
		}

		if err = vfs.store.DeleteFileTag(fileId, tag.Id, 0); err != nil {
			log.Fatal(err)
		}

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

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

	return fuse.ENOSYS
}
Example #4
0
func (vfs FuseVfs) openQueryEntryDir(path []string) ([]fuse.DirEntry, fuse.Status) {
	log.Infof(2, "BEGIN openQueryEntryDir(%v)", path)
	defer log.Infof(2, "END openQueryEntryDir(%v)", path)

	queryText := path[0]

	expression, err := query.Parse(queryText)
	if err != nil {
		return nil, fuse.ENOENT
	}

	tagNames := query.TagNames(expression)
	tags, err := vfs.store.TagsByNames(tagNames)
	for _, tagName := range tagNames {
		if !containsTag(tags, tagName) {
			return nil, fuse.ENOENT
		}
	}

	files, err := vfs.store.QueryFiles(expression)
	if err != nil {
		log.Fatalf("could not query files: %v", err)
	}

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

	return entries, fuse.OK
}
Example #5
0
func (vfs FuseVfs) getTagsAttr() (*fuse.Attr, fuse.Status) {
	log.Infof(2, "BEGIN getTagsAttr")
	defer log.Infof(2, "END getTagsAttr")

	tagCount, err := vfs.store.TagCount()
	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
}
Example #6
0
func (vfs FuseVfs) Rmdir(name string, context *fuse.Context) fuse.Status {
	log.Infof(2, "BEGIN Rmdir(%v)", name)
	defer log.Infof(2, "END Rmdir(%v)", name)

	path := vfs.splitPath(name)

	switch path[0] {
	case tagsDir:
		if len(path) != 2 {
			// can only remove top-level tag directories
			return fuse.EPERM
		}

		tagName := path[1]
		tag, err := vfs.store.TagByName(tagName)
		if err != nil {
			log.Fatalf("could not retrieve tag '%v': %v", tagName, err)
		}
		if tag == nil {
			return fuse.ENOENT
		}

		count, err := vfs.store.FileTagCountByTagId(tag.Id)
		if err != nil {
			log.Fatalf("could not retrieve file-tag count for tag '%v': %v", tagName, err)
		}
		if count > 0 {
			return fuse.Status(syscall.ENOTEMPTY)
		}

		if err := vfs.store.DeleteTag(tag.Id); err != nil {
			log.Fatalf("could not delete tag '%v': %v", tagName, err)
		}

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

		return fuse.OK
	case queriesDir:
		if len(path) != 2 {
			// can only remove top-level queries directories
			return fuse.EPERM
		}

		text := path[1]

		if err := vfs.store.DeleteQuery(text); err != nil {
			log.Fatalf("could not remove tag '%v': %v", name, err)
		}

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

		return fuse.OK
	}

	return fuse.ENOSYS
}
Example #7
0
func init() {
	if path := os.Getenv("TMSU_DB"); path != "" {
		log.Info(3, "TMSU_DB=", path)
		Path = path
	} else {
		u, err := user.Current()
		if err != nil {
			log.Fatalf("could not identify current user: %v", err)
		}

		Path = filepath.Join(u.HomeDir, ".tmsu", "default.db")
	}
}
Example #8
0
func (vfs FuseVfs) getQueryEntryAttr(path []string) (*fuse.Attr, fuse.Status) {
	log.Infof(2, "BEGIN getQueryEntryAttr(%v)", path)
	defer log.Infof(2, "END getQueryEntryAttr(%v)", path)

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

	if len(path) == 1 && path[0] == queryHelpFilename {
		now := time.Now()
		return &fuse.Attr{Mode: fuse.S_IFREG | 0444, Nlink: 1, Size: uint64(len(queryDirHelp)), Mtime: uint64(now.Unix()), Mtimensec: uint32(now.Nanosecond())}, fuse.OK
	}

	if len(path) > 1 {
		fileId := vfs.parseFileId(name)
		if fileId != 0 {
			return vfs.getFileEntryAttr(fileId)
		}

		return nil, fuse.ENOENT
	}

	queryText := path[0]

	if queryText[len(queryText)-1] == ' ' {
		// prevent multiple entries for same query when typing path in a GUI
		return nil, fuse.ENOENT
	}

	expression, err := query.Parse(queryText)
	if err != nil {
		return nil, fuse.ENOENT
	}

	tagNames := query.TagNames(expression)
	tags, err := vfs.store.TagsByNames(tagNames)
	for _, tagName := range tagNames {
		if !containsTag(tags, tagName) {
			return nil, fuse.ENOENT
		}
	}

	_, _ = vfs.store.AddQuery(queryText)

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

	now := time.Now()
	return &fuse.Attr{Mode: fuse.S_IFDIR | 0755, Nlink: 2, Size: uint64(0), Mtime: uint64(now.Unix()), Mtimensec: uint32(now.Nanosecond())}, fuse.OK
}
Example #9
0
func (vfs FuseVfs) Rename(oldName string, newName string, context *fuse.Context) fuse.Status {
	log.Infof(2, "BEGIN Rename(%v, %v)", oldName, newName)
	defer log.Infof(2, "END Rename(%v, %v)", oldName, newName)

	oldPath := vfs.splitPath(oldName)
	newPath := vfs.splitPath(newName)

	if len(oldPath) != 2 || len(newPath) != 2 {
		return fuse.EPERM
	}

	if oldPath[0] != tagsDir || newPath[0] != tagsDir {
		return fuse.EPERM
	}

	oldTagName := oldPath[1]
	newTagName := newPath[1]

	tag, err := vfs.store.TagByName(oldTagName)
	if err != nil {
		log.Fatalf("could not retrieve tag '%v': %v", oldTagName, err)
	}
	if tag == nil {
		return fuse.ENOENT
	}

	if _, err := vfs.store.RenameTag(tag.Id, newTagName); err != nil {
		log.Fatalf("could not rename tag '%v' to '%v': %v", oldTagName, newTagName, err)
	}

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

	return fuse.OK
}
Example #10
0
func (vfs FuseVfs) tagDirectories() ([]fuse.DirEntry, fuse.Status) {
	log.Infof(2, "BEGIN tagDirectories")
	defer log.Infof(2, "END tagDirectories")

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

	entries := make([]fuse.DirEntry, len(tags))
	for index, tag := range tags {
		entries[index] = fuse.DirEntry{Name: tag.Name, Mode: fuse.S_IFDIR}
	}

	return entries, fuse.OK
}
Example #11
0
func (vfs FuseVfs) readTaggedEntryLink(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(fileId)
	if err != nil {
		log.Fatalf("could not find file %v in database.", fileId)
	}

	return file.Path(), fuse.OK
}
Example #12
0
func (vfs FuseVfs) queriesDirectories() ([]fuse.DirEntry, fuse.Status) {
	log.Infof(2, "BEGIN queriesDirectories")
	defer log.Infof(2, "END queriesDirectories")

	queries, err := vfs.store.Queries()
	if err != nil {
		log.Fatalf("could not retrieve queries: %v", err)
	}

	if len(queries) == 0 {
		return []fuse.DirEntry{fuse.DirEntry{Name: queryHelpFilename, Mode: fuse.S_IFREG}}, fuse.OK
	}

	entries := make([]fuse.DirEntry, len(queries))
	for index, query := range queries {
		entries[index] = fuse.DirEntry{Name: query.Text, Mode: fuse.S_IFDIR}
	}

	return entries, fuse.OK
}
Example #13
0
func (vfs FuseVfs) getFileEntryAttr(fileId uint) (*fuse.Attr, fuse.Status) {
	file, err := vfs.store.File(fileId)
	if err != nil {
		log.Fatalf("could not retrieve file #%v: %v", fileId, err)
	}
	if file == nil {
		return &fuse.Attr{Mode: fuse.S_IFREG}, fuse.ENOENT
	}

	fileInfo, err := os.Stat(file.Path())
	var size int64
	var modTime time.Time
	if err == nil {
		size = fileInfo.Size()
		modTime = fileInfo.ModTime()
	} else {
		size = 0
		modTime = time.Time{}
	}

	return &fuse.Attr{Mode: fuse.S_IFLNK | 0755, Size: uint64(size), Mtime: uint64(modTime.Unix()), Mtimensec: uint32(modTime.Nanosecond())}, fuse.OK
}
Example #14
0
func Run() {
	helpCommands = commands

	parser := NewOptionParser(globalOptions, commands)
	commandName, options, arguments, err := parser.Parse(os.Args[1:])
	if err != nil {
		log.Fatal(err)
	}

	switch {
	case options.HasOption("--version"):
		commandName = "version"
	case options.HasOption("--help"), commandName == "":
		commandName = "help"
	}

	log.Verbosity = options.Count("--verbose") + 1

	if dbOption := options.Get("--database"); dbOption != nil && dbOption.Argument != "" {
		database.Path = dbOption.Argument
	}

	command := commands[commandName]
	if command == nil {
		log.Fatalf("Invalid command '%v'.", commandName)
	}

	err = command.Exec(options, arguments)
	if err != nil {
		if err != blankError {
			log.Warn(err.Error())
		}

		os.Exit(1)
	}
}
Example #15
0
func (vfs FuseVfs) getTaggedEntryAttr(path []string) (*fuse.Attr, fuse.Status) {
	log.Infof(2, "BEGIN getTaggedEntryAttr(%v)", path)
	defer log.Infof(2, "END getTaggedEntryAttr(%v)", path)

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

	fileId := vfs.parseFileId(name)
	if fileId != 0 {
		return vfs.getFileEntryAttr(fileId)
	}

	// tag directory
	tagIds, err := vfs.tagNamesToIds(path)
	if err != nil {
		log.Fatalf("could not lookup tag IDs: %v.", err)
	}
	if tagIds == nil {
		return nil, fuse.ENOENT
	}

	now := time.Now()
	return &fuse.Attr{Mode: fuse.S_IFDIR | 0755, Nlink: 2, Size: uint64(0), Mtime: uint64(now.Unix()), Mtimensec: uint32(now.Nanosecond())}, fuse.OK
}