func (vfs FuseVfs) openQueryEntryDir(tx *storage.Tx, 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 { log.Fatalf("could not parse query: %v", err) } tagNames, err := query.TagNames(expression) if err != nil { log.Fatalf("could not identify tag names: %v", err) } tags, err := vfs.store.TagsByNames(tx, tagNames) for _, tagName := range tagNames { if !containsTag(tags, tagName) { return nil, fuse.ENOENT } } files, err := vfs.store.FilesForQuery(tx, expression, "", false, false, "name") 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 }
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) if len(path) == 1 && path[0] == helpFilename { 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 } name := path[len(path)-1] 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 } tx, err := vfs.store.Begin() if err != nil { log.Fatalf("could not begin transaction: %v", err) } defer tx.Commit() tagNames, err := query.TagNames(expression) if err != nil { log.Fatalf("could not identify tag names: %v", err) } tags, err := vfs.store.TagsByNames(tx, tagNames) for _, tagName := range tagNames { if !containsTag(tags, tagName) { return nil, fuse.ENOENT } } q, err := vfs.store.Query(tx, queryText) if err != nil { log.Fatalf("could not retrieve query '%v': %v", queryText, err) } if q == nil { _, err = vfs.store.AddQuery(tx, queryText) if err != nil { log.Fatalf("could not add query '%v': %v", queryText, 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 }
func listFilesForQuery(store *storage.Storage, tx *storage.Tx, queryText, path string, dirOnly, fileOnly, print0, showCount, explicitOnly, ignoreCase bool, sort string) (error, warnings) { log.Info(2, "parsing query") expression, err := query.Parse(queryText) if err != nil { return fmt.Errorf("could not parse query: %v", err), nil } log.Info(2, "checking tag names") warnings := make(warnings, 0, 10) tagNames, err := query.TagNames(expression) if err != nil { return fmt.Errorf("could not identify tag names: %v", err), nil } tags, err := store.TagsByCasedNames(tx, tagNames, ignoreCase) for _, tagName := range tagNames { if err := entities.ValidateTagName(tagName); err != nil { warnings = append(warnings, err.Error()) continue } if !tags.ContainsCasedName(tagName, ignoreCase) { warnings = append(warnings, fmt.Sprintf("no such tag '%v'", tagName)) continue } } valueNames, err := query.ExactValueNames(expression) if err != nil { return fmt.Errorf("could not identify value names: %v", err), nil } values, err := store.ValuesByCasedNames(tx, valueNames, ignoreCase) for _, valueName := range valueNames { if err := entities.ValidateValueName(valueName); err != nil { warnings = append(warnings, err.Error()) continue } if !values.ContainsCasedName(valueName, ignoreCase) { warnings = append(warnings, fmt.Sprintf("no such value '%v'", valueName)) continue } } log.Info(2, "querying database") files, err := store.FilesForQuery(tx, expression, path, explicitOnly, ignoreCase, sort) if err != nil { if strings.Index(err.Error(), "parser stack overflow") > -1 { return fmt.Errorf("the query is too complex (see the troubleshooting wiki for how to increase the stack size)"), warnings } else { return fmt.Errorf("could not query files: %v", err), warnings } } if err = listFiles(tx, files, dirOnly, fileOnly, print0, showCount); err != nil { return err, warnings } return nil, warnings }