From 3937c6d6a0bcfb18a09be0d3243e81a05b66d3be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rn=20Friedrich=20Dreyer?= Date: Fri, 3 Jul 2026 13:36:57 +0200 Subject: [PATCH] add posixfs index command MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jörn Friedrich Dreyer --- opencloud/pkg/command/posixfs.go | 144 +++++++++++++++++++++++++++++++ 1 file changed, 144 insertions(+) diff --git a/opencloud/pkg/command/posixfs.go b/opencloud/pkg/command/posixfs.go index de40a093cc..e32b41bfdb 100644 --- a/opencloud/pkg/command/posixfs.go +++ b/opencloud/pkg/command/posixfs.go @@ -19,6 +19,7 @@ import ( "github.com/opencloud-eu/reva/v2/pkg/storage/fs/posix/ignore" "github.com/opencloud-eu/reva/v2/pkg/storage/fs/posix/options" "github.com/opencloud-eu/reva/v2/pkg/storage/fs/registry" + "github.com/opencloud-eu/reva/v2/pkg/storage/utils/decomposedfs/spaceidindex" "github.com/pkg/xattr" "github.com/rs/zerolog" @@ -62,6 +63,7 @@ func PosixfsCommand(cfg *config.Config) *cobra.Command { } posixCmd.AddCommand(consistencyCmd(cfg)) + posixCmd.AddCommand(indexCmd(cfg)) posixCmd.AddCommand(scanCmd(cfg)) return posixCmd @@ -138,6 +140,148 @@ func scanCmd(ocCfg *config.Config) *cobra.Command { return cmd } +func indexCmd(ocCfg *config.Config) *cobra.Command { + cmd := &cobra.Command{ + Use: "index", + Short: "Add spaces from the filesystem to the index", + RunE: func(cmd *cobra.Command, args []string) error { + return rebuildIndexes(cmd) + }, + } + cmd.Flags().StringP("root", "r", "", "Path to the root directory of the posixfs storage") + cmd.Flags().StringSliceP("dirs", "d", []string{"users", "projects"}, "Subdirectories to scan for spaces") + cmd.Flags().StringP("space", "s", "", "Only index a specific space by ID") + _ = cmd.MarkFlagRequired("root") + return cmd +} + +func rebuildIndexes(cmd *cobra.Command) error { + rootPath, _ := cmd.Flags().GetString("root") + spaceFilter, _ := cmd.Flags().GetString("space") + indexesDir := filepath.Join(rootPath, "indexes") + + if _, err := os.Stat(indexesDir); err != nil { + return fmt.Errorf("'%s' is not a posixfs root: %w", rootPath, err) + } + + userIndex := spaceidindex.New(indexesDir, "by-user-id") + if err := userIndex.Init(); err != nil { + return fmt.Errorf("failed to init by-user-id index: %w", err) + } + groupIndex := spaceidindex.New(indexesDir, "by-group-id") + if err := groupIndex.Init(); err != nil { + return fmt.Errorf("failed to init by-group-id index: %w", err) + } + typeIndex := spaceidindex.New(indexesDir, "by-type") + if err := typeIndex.Init(); err != nil { + return fmt.Errorf("failed to init by-type index: %w", err) + } + + userEntries := map[string]map[string]string{} + groupEntries := map[string]map[string]string{} + typeEntries := map[string]map[string]string{} + + dirs, _ := cmd.Flags().GetStringSlice("dirs") + for _, dir := range dirs { + basePath := filepath.Join(rootPath, dir) + entries, err := os.ReadDir(basePath) + if err != nil { + if os.IsNotExist(err) { + continue + } + return fmt.Errorf("failed to read '%s': %w", basePath, err) + } + + for _, entry := range entries { + if !entry.IsDir() { + continue + } + + spacePath := filepath.Join(basePath, entry.Name()) + + spaceID, err := xattr.Get(spacePath, idAttrName) + if err != nil || len(spaceID) == 0 { + fmt.Fprintf(os.Stderr, " - Skipping '%s': missing space ID\n", spacePath) + continue + } + + sid := string(spaceID) + if spaceFilter != "" && sid != spaceFilter { + continue + } + + spaceType, err := xattr.Get(spacePath, "user.oc.space.type") + if err != nil || len(spaceType) == 0 { + fmt.Fprintf(os.Stderr, " - Skipping '%s': missing space type\n", spacePath) + continue + } + + stype := string(spaceType) + fmt.Printf("Collecting space '%s' (%s)\n", sid, stype) + + if typeEntries[stype] == nil { + typeEntries[stype] = map[string]string{} + } + typeEntries[stype][sid] = sid + + ownerType, _ := xattr.Get(spacePath, "user.oc.owner.type") + if string(ownerType) != "spaceowner" { + ownerID, err := xattr.Get(spacePath, ownerIDAttrName) + if err == nil && len(ownerID) > 0 { + oid := string(ownerID) + if userEntries[oid] == nil { + userEntries[oid] = map[string]string{} + } + userEntries[oid][sid] = sid + } + } + + attrs, err := xattr.List(spacePath) + if err != nil { + fmt.Fprintf(os.Stderr, " - Failed to list xattrs for '%s': %v\n", spacePath, err) + continue + } + for _, attr := range attrs { + switch { + case strings.HasPrefix(attr, "user.oc.grant.u:"): + grantee := strings.TrimPrefix(attr, "user.oc.grant.u:") + if userEntries[grantee] == nil { + userEntries[grantee] = map[string]string{} + } + userEntries[grantee][sid] = sid + case strings.HasPrefix(attr, "user.oc.grant.g:"): + grantee := strings.TrimPrefix(attr, "user.oc.grant.g:") + if groupEntries[grantee] == nil { + groupEntries[grantee] = map[string]string{} + } + groupEntries[grantee][sid] = sid + } + } + } + } + + fmt.Println("Writing indexes...") + + for spaceType, entries := range typeEntries { + if err := typeIndex.AddAll(spaceType, entries); err != nil { + fmt.Fprintf(os.Stderr, " - Failed to write type index '%s': %v\n", spaceType, err) + } + } + for userID, entries := range userEntries { + if err := userIndex.AddAll(userID, entries); err != nil { + fmt.Fprintf(os.Stderr, " - Failed to write user index '%s': %v\n", userID, err) + } + } + for groupID, entries := range groupEntries { + if err := groupIndex.AddAll(groupID, entries); err != nil { + fmt.Fprintf(os.Stderr, " - Failed to write group index '%s': %v\n", groupID, err) + } + } + + fmt.Println("Done.") + return nil +} + // consistencyCmd returns a command to check the consistency of the posixfs storage. func consistencyCmd(cfg *config.Config) *cobra.Command { consCmd := &cobra.Command{