diff --git a/docs/content/en/docs/config/grpc/services/storageprovider/_index.md b/docs/content/en/docs/config/grpc/services/storageprovider/_index.md index 6c1b9fbb75a..ab43e8abdd9 100644 --- a/docs/content/en/docs/config/grpc/services/storageprovider/_index.md +++ b/docs/content/en/docs/config/grpc/services/storageprovider/_index.md @@ -32,13 +32,11 @@ driver = "localhome" {{< /highlight >}} {{% /dir %}} -{{% dir name="drivers" type="map[string]map[string]interface{}" default="localhome" %}} +{{% dir name="drivers" type="map[string]map[string]interface{}" default="local" %}} [[Ref]](https://github.com/cs3org/reva/tree/master/internal/grpc/services/storageprovider/storageprovider.go#L64) {{< highlight toml >}} -[grpc.services.storageprovider.drivers.localhome] +[grpc.services.storageprovider.drivers.local] root = "/var/tmp/reva/" -share_folder = "/MyShares" -user_layout = "{{.Username}}" {{< /highlight >}} {{% /dir %}} diff --git a/docs/content/en/docs/config/http/services/dataprovider/_index.md b/docs/content/en/docs/config/http/services/dataprovider/_index.md index 8baa240f16b..842926e53fc 100644 --- a/docs/content/en/docs/config/http/services/dataprovider/_index.md +++ b/docs/content/en/docs/config/http/services/dataprovider/_index.md @@ -16,21 +16,19 @@ prefix = "data" {{< /highlight >}} {{% /dir %}} -{{% dir name="driver" type="string" default="localhome" %}} +{{% dir name="driver" type="string" default="local" %}} The storage driver to be used. [[Ref]](https://github.com/cs3org/reva/tree/master/internal/http/services/dataprovider/dataprovider.go#L41) {{< highlight toml >}} [http.services.dataprovider] -driver = "localhome" +driver = "local" {{< /highlight >}} {{% /dir %}} -{{% dir name="drivers" type="map[string]map[string]interface{}" default="localhome" %}} +{{% dir name="drivers" type="map[string]map[string]interface{}" default="local" %}} The configuration for the storage driver [[Ref]](https://github.com/cs3org/reva/tree/master/internal/http/services/dataprovider/dataprovider.go#L42) {{< highlight toml >}} -[http.services.dataprovider.drivers.localhome] +[http.services.dataprovider.drivers.local] root = "/var/tmp/reva/" -share_folder = "/MyShares" -user_layout = "{{.Username}}" {{< /highlight >}} {{% /dir %}} diff --git a/docs/content/en/docs/config/http/services/owncloud/ocdav/_index.md b/docs/content/en/docs/config/http/services/owncloud/ocdav/_index.md index 09f3385228f..7e7e885478e 100644 --- a/docs/content/en/docs/config/http/services/owncloud/ocdav/_index.md +++ b/docs/content/en/docs/config/http/services/owncloud/ocdav/_index.md @@ -17,7 +17,7 @@ insecure = false {{% /dir %}} {{% dir name="notifications" type="map[string]interface{}" default=Settingsg for the Notification Helper %}} - [[Ref]](https://github.com/cs3org/reva/tree/master/internal/http/services/owncloud/ocdav/ocdav.go#L122) + [[Ref]](https://github.com/cs3org/reva/tree/master/internal/http/services/owncloud/ocdav/ocdav.go#L123) {{< highlight toml >}} [http.services.owncloud.ocdav] notifications = Settingsg for the Notification Helper diff --git a/docs/content/en/docs/config/packages/storage/fs/local/_index.md b/docs/content/en/docs/config/packages/storage/fs/local/_index.md index 550016e895c..da60a9dce73 100644 --- a/docs/content/en/docs/config/packages/storage/fs/local/_index.md +++ b/docs/content/en/docs/config/packages/storage/fs/local/_index.md @@ -16,11 +16,3 @@ root = "/var/tmp/reva/" {{< /highlight >}} {{% /dir %}} -{{% dir name="share_folder" type="string" default="/MyShares" %}} -Path for storing share references. [[Ref]](https://github.com/cs3org/reva/tree/master/pkg/storage/fs/local/local.go#L36) -{{< highlight toml >}} -[storage.fs.local] -share_folder = "/MyShares" -{{< /highlight >}} -{{% /dir %}} - diff --git a/docs/content/en/docs/config/packages/storage/registry/dynamic/_index.md b/docs/content/en/docs/config/packages/storage/registry/dynamic/_index.md index f7fda188ccf..6f93495a2f5 100644 --- a/docs/content/en/docs/config/packages/storage/registry/dynamic/_index.md +++ b/docs/content/en/docs/config/packages/storage/registry/dynamic/_index.md @@ -9,7 +9,7 @@ description: > # _struct: config_ {{% dir name="rules" type="map[string]string" default=nil %}} -A map from mountID to provider address [[Ref]](https://github.com/cs3org/reva/tree/master/pkg/storage/registry/dynamic/dynamic.go#L53) +A map from mountID to provider address [[Ref]](https://github.com/cs3org/reva/tree/master/pkg/storage/registry/dynamic/dynamic.go#L56) {{< highlight toml >}} [storage.registry.dynamic] rules = nil @@ -17,10 +17,18 @@ rules = nil {{% /dir %}} {{% dir name="rewrites" type="map[string]string" default=nil %}} -A map from a path to an template alias to use when resolving [[Ref]](https://github.com/cs3org/reva/tree/master/pkg/storage/registry/dynamic/dynamic.go#L54) +A map from a path to an template alias to use when resolving [[Ref]](https://github.com/cs3org/reva/tree/master/pkg/storage/registry/dynamic/dynamic.go#L57) {{< highlight toml >}} [storage.registry.dynamic] rewrites = nil {{< /highlight >}} {{% /dir %}} +{{% dir name="aliases" type="map[string]string" default=nil %}} +A map containing storageID aliases, can contain simple brackets [[Ref]](https://github.com/cs3org/reva/tree/master/pkg/storage/registry/dynamic/dynamic.go#L58) +{{< highlight toml >}} +[storage.registry.dynamic] +aliases = nil +{{< /highlight >}} +{{% /dir %}} + diff --git a/internal/grpc/services/storageprovider/storageprovider.go b/internal/grpc/services/storageprovider/storageprovider.go index b8efbdc83cb..470df433f83 100644 --- a/internal/grpc/services/storageprovider/storageprovider.go +++ b/internal/grpc/services/storageprovider/storageprovider.go @@ -61,7 +61,7 @@ type config struct { MountPath string `docs:"/;The path where the file system would be mounted." mapstructure:"mount_path"` MountID string `docs:"-;The ID of the mounted file system." mapstructure:"mount_id"` Driver string `docs:"localhome;The storage driver to be used." mapstructure:"driver"` - Drivers map[string]map[string]interface{} `docs:"url:pkg/storage/fs/localhome/localhome.go" mapstructure:"drivers"` + Drivers map[string]map[string]interface{} `docs:"url:pkg/storage/fs/local/local.go" mapstructure:"drivers"` TmpFolder string `docs:"/var/tmp;Path to temporary folder." mapstructure:"tmp_folder"` DataServerURL string `docs:"http://localhost/data;The URL for the data server." mapstructure:"data_server_url"` ExposeDataServer bool `docs:"false;Whether to expose data server." mapstructure:"expose_data_server"` // if true the client will be able to upload/download directly to it diff --git a/internal/http/services/dataprovider/dataprovider.go b/internal/http/services/dataprovider/dataprovider.go index bb4718ffcf5..6083601d492 100644 --- a/internal/http/services/dataprovider/dataprovider.go +++ b/internal/http/services/dataprovider/dataprovider.go @@ -38,8 +38,8 @@ func init() { type config struct { Prefix string `docs:"data;The prefix to be used for this HTTP service" mapstructure:"prefix"` - Driver string `docs:"localhome;The storage driver to be used." mapstructure:"driver"` - Drivers map[string]map[string]interface{} `docs:"url:pkg/storage/fs/localhome/localhome.go;The configuration for the storage driver" mapstructure:"drivers"` + Driver string `docs:"local;The storage driver to be used." mapstructure:"driver"` + Drivers map[string]map[string]interface{} `docs:"url:pkg/storage/fs/local/local.go;The configuration for the storage driver" mapstructure:"drivers"` DataTXs map[string]map[string]interface{} `docs:"url:pkg/rhttp/datatx/manager/simple/simple.go;The configuration for the data tx protocols" mapstructure:"data_txs"` Timeout int64 `mapstructure:"timeout"` Insecure bool `docs:"false;Whether to skip certificate checks when sending requests." mapstructure:"insecure"` @@ -50,7 +50,7 @@ func (c *config) ApplyDefaults() { c.Prefix = "data" } if c.Driver == "" { - c.Driver = "localhome" + c.Driver = "local" } } diff --git a/pkg/storage/fs/loader/loader.go b/pkg/storage/fs/loader/loader.go index 488d5a8fe80..5c2db352827 100644 --- a/pkg/storage/fs/loader/loader.go +++ b/pkg/storage/fs/loader/loader.go @@ -29,7 +29,6 @@ import ( _ "github.com/cs3org/reva/pkg/storage/fs/eosgrpchome" _ "github.com/cs3org/reva/pkg/storage/fs/eoshome" _ "github.com/cs3org/reva/pkg/storage/fs/local" - _ "github.com/cs3org/reva/pkg/storage/fs/localhome" _ "github.com/cs3org/reva/pkg/storage/fs/nextcloud" // Add your own here. ) diff --git a/pkg/storage/fs/local/local.go b/pkg/storage/fs/local/local.go index 504cb835a93..e1b1c2ac8fe 100644 --- a/pkg/storage/fs/local/local.go +++ b/pkg/storage/fs/local/local.go @@ -32,21 +32,17 @@ func init() { } type config struct { - Root string `docs:"/var/tmp/reva/;Path of root directory for user storage." mapstructure:"root"` - ShareFolder string `docs:"/MyShares;Path for storing share references." mapstructure:"share_folder"` + Root string `docs:"/var/tmp/reva/;Path of root directory for user storage." mapstructure:"root"` } func (c *config) ApplyDefaults() { if c.Root == "" { c.Root = "/var/tmp/reva" } - if c.ShareFolder == "" { - c.ShareFolder = "/MyShares" - } } // New returns an implementation to of the storage.FS interface that talks to -// a local filesystem with user homes disabled. +// a local filesystem. func New(ctx context.Context, m map[string]interface{}) (storage.FS, error) { var c config if err := cfg.Decode(m, &c); err != nil { @@ -54,9 +50,7 @@ func New(ctx context.Context, m map[string]interface{}) (storage.FS, error) { } conf := localfs.Config{ - Root: c.Root, - ShareFolder: c.ShareFolder, - DisableHome: true, + Root: c.Root, } return localfs.NewLocalFS(&conf) } diff --git a/pkg/storage/fs/localhome/localhome.go b/pkg/storage/fs/localhome/localhome.go deleted file mode 100644 index fae49c711e6..00000000000 --- a/pkg/storage/fs/localhome/localhome.go +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright 2018-2023 CERN -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// In applying this license, CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -package localhome - -import ( - "context" - - "github.com/cs3org/reva/pkg/storage" - "github.com/cs3org/reva/pkg/storage/fs/registry" - "github.com/cs3org/reva/pkg/storage/utils/localfs" - "github.com/mitchellh/mapstructure" - "github.com/pkg/errors" -) - -func init() { - registry.Register("localhome", New) -} - -type config struct { - Root string `docs:"/var/tmp/reva/;Path of root directory for user storage." mapstructure:"root"` - ShareFolder string `docs:"/MyShares;Path for storing share references." mapstructure:"share_folder"` - UserLayout string `docs:"{{.Username}};Template for user home directories" mapstructure:"user_layout"` -} - -func (c *config) ApplyDefaults() { - if c.Root == "" { - c.Root = "/var/tmp/reva" - } - if c.ShareFolder == "" { - c.ShareFolder = "/MyShares" - } - if c.UserLayout == "" { - c.UserLayout = "{{.Username}}" - } -} - -func parseConfig(m map[string]interface{}) (*config, error) { - c := &config{} - if err := mapstructure.Decode(m, c); err != nil { - err = errors.Wrap(err, "error decoding conf") - return nil, err - } - return c, nil -} - -// New returns an implementation to of the storage.FS interface that talks to -// a local filesystem with user homes. -func New(ctx context.Context, m map[string]interface{}) (storage.FS, error) { - c, err := parseConfig(m) - if err != nil { - return nil, err - } - - conf := localfs.Config{ - Root: c.Root, - ShareFolder: c.ShareFolder, - UserLayout: c.UserLayout, - } - return localfs.NewLocalFS(&conf) -} diff --git a/pkg/storage/utils/localfs/db.go b/pkg/storage/utils/localfs/db.go deleted file mode 100644 index fd9f989a225..00000000000 --- a/pkg/storage/utils/localfs/db.go +++ /dev/null @@ -1,247 +0,0 @@ -// Copyright 2018-2023 CERN -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// In applying this license, CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -package localfs - -import ( - "context" - "database/sql" - "path" - - // Provides sqlite drivers. - _ "github.com/mattn/go-sqlite3" - "github.com/pkg/errors" -) - -func initializeDB(root, dbName string) (*sql.DB, error) { - dbPath := path.Join(root, dbName) - db, err := sql.Open("sqlite3", dbPath) - if err != nil { - return nil, errors.Wrap(err, "localfs: error opening DB connection") - } - - stmt, err := db.Prepare("CREATE TABLE IF NOT EXISTS recycled_entries (key TEXT PRIMARY KEY, path TEXT)") - if err != nil { - return nil, errors.Wrap(err, "localfs: error preparing statement") - } - _, err = stmt.Exec() - if err != nil { - return nil, errors.Wrap(err, "localfs: error executing create statement") - } - - stmt, err = db.Prepare("CREATE TABLE IF NOT EXISTS user_interaction (resource TEXT, grantee TEXT, role TEXT DEFAULT '', favorite INTEGER DEFAULT 0, PRIMARY KEY (resource, grantee))") - if err != nil { - return nil, errors.Wrap(err, "localfs: error preparing statement") - } - _, err = stmt.Exec() - if err != nil { - return nil, errors.Wrap(err, "localfs: error executing create statement") - } - - stmt, err = db.Prepare("CREATE TABLE IF NOT EXISTS metadata (resource TEXT, key TEXT, value TEXT, PRIMARY KEY (resource, key))") - if err != nil { - return nil, errors.Wrap(err, "localfs: error preparing statement") - } - _, err = stmt.Exec() - if err != nil { - return nil, errors.Wrap(err, "localfs: error executing create statement") - } - - stmt, err = db.Prepare("CREATE TABLE IF NOT EXISTS share_references (resource TEXT PRIMARY KEY, target TEXT)") - if err != nil { - return nil, errors.Wrap(err, "localfs: error preparing statement") - } - _, err = stmt.Exec() - if err != nil { - return nil, errors.Wrap(err, "localfs: error executing create statement") - } - - return db, nil -} - -func (fs *localfs) addToRecycledDB(ctx context.Context, key, fileName string) error { - stmt, err := fs.db.Prepare("INSERT INTO recycled_entries VALUES (?, ?)") - if err != nil { - return errors.Wrap(err, "localfs: error preparing statement") - } - _, err = stmt.Exec(key, fileName) - if err != nil { - return errors.Wrap(err, "localfs: error executing insert statement") - } - return nil -} - -func (fs *localfs) getRecycledEntry(ctx context.Context, key string) (string, error) { - var filePath string - err := fs.db.QueryRow("SELECT path FROM recycled_entries WHERE key=?", key).Scan(&filePath) - if err != nil { - return "", err - } - return filePath, nil -} - -func (fs *localfs) removeFromRecycledDB(ctx context.Context, key string) error { - stmt, err := fs.db.Prepare("DELETE FROM recycled_entries WHERE key=?") - if err != nil { - return errors.Wrap(err, "localfs: error preparing statement") - } - _, err = stmt.Exec(key) - if err != nil { - return errors.Wrap(err, "localfs: error executing delete statement") - } - return nil -} - -func (fs *localfs) addToACLDB(ctx context.Context, resource, grantee, role string) error { - stmt, err := fs.db.Prepare("INSERT INTO user_interaction (resource, grantee, role) VALUES (?, ?, ?) ON CONFLICT(resource, grantee) DO UPDATE SET role=?") - if err != nil { - return errors.Wrap(err, "localfs: error preparing statement") - } - _, err = stmt.Exec(resource, grantee, role, role) - if err != nil { - return errors.Wrap(err, "localfs: error executing insert statement") - } - return nil -} - -func (fs *localfs) getACLs(ctx context.Context, resource string) (*sql.Rows, error) { - grants, err := fs.db.Query("SELECT grantee, role FROM user_interaction WHERE resource=?", resource) - if err != nil { - return nil, err - } - return grants, nil -} - -func (fs *localfs) removeFromACLDB(ctx context.Context, resource, grantee string) error { - stmt, err := fs.db.Prepare("UPDATE user_interaction SET role='' WHERE resource=? AND grantee=?") - if err != nil { - return errors.Wrap(err, "localfs: error preparing statement") - } - _, err = stmt.Exec(resource, grantee) - if err != nil { - return errors.Wrap(err, "localfs: error executing delete statement") - } - return nil -} - -func (fs *localfs) addToFavoritesDB(ctx context.Context, resource, grantee string) error { - stmt, err := fs.db.Prepare("INSERT INTO user_interaction (resource, grantee, favorite) VALUES (?, ?, 1) ON CONFLICT(resource, grantee) DO UPDATE SET favorite=1") - if err != nil { - return errors.Wrap(err, "localfs: error preparing statement") - } - _, err = stmt.Exec(resource, grantee) - if err != nil { - return errors.Wrap(err, "localfs: error executing insert statement") - } - return nil -} - -func (fs *localfs) removeFromFavoritesDB(ctx context.Context, resource, grantee string) error { - stmt, err := fs.db.Prepare("UPDATE user_interaction SET favorite=0 WHERE resource=? AND grantee=?") - if err != nil { - return errors.Wrap(err, "localfs: error preparing statement") - } - _, err = stmt.Exec(resource, grantee) - if err != nil { - return errors.Wrap(err, "localfs: error executing delete statement") - } - return nil -} - -func (fs *localfs) addToMetadataDB(ctx context.Context, resource, key, value string) error { - stmt, err := fs.db.Prepare("INSERT INTO metadata (resource, key, value) VALUES (?, ?, ?) ON CONFLICT(resource, key) DO UPDATE SET value=?") - if err != nil { - return errors.Wrap(err, "localfs: error preparing statement") - } - _, err = stmt.Exec(resource, key, value, value) - if err != nil { - return errors.Wrap(err, "localfs: error executing insert statement") - } - return nil -} - -func (fs *localfs) removeFromMetadataDB(ctx context.Context, resource, key string) error { - stmt, err := fs.db.Prepare("DELETE FROM metadata WHERE resource=? AND key=?") - if err != nil { - return errors.Wrap(err, "localfs: error preparing statement") - } - _, err = stmt.Exec(resource, key) - if err != nil { - return errors.Wrap(err, "localfs: error executing delete statement") - } - return nil -} - -func (fs *localfs) getMetadata(ctx context.Context, resource string) (*sql.Rows, error) { - grants, err := fs.db.Query("SELECT key, value FROM metadata WHERE resource=?", resource) - if err != nil { - return nil, err - } - return grants, nil -} - -func (fs *localfs) addToReferencesDB(ctx context.Context, resource, target string) error { - stmt, err := fs.db.Prepare("INSERT INTO share_references (resource, target) VALUES (?, ?) ON CONFLICT(resource) DO UPDATE SET target=?") - if err != nil { - return errors.Wrap(err, "localfs: error preparing statement") - } - _, err = stmt.Exec(resource, target, target) - if err != nil { - return errors.Wrap(err, "localfs: error executing insert statement") - } - return nil -} - -func (fs *localfs) getReferenceEntry(ctx context.Context, resource string) (string, error) { - var target string - err := fs.db.QueryRow("SELECT target FROM share_references WHERE resource=?", resource).Scan(&target) - if err != nil { - return "", err - } - return target, nil -} - -func (fs *localfs) copyMD(s string, t string) (err error) { - stmt, err := fs.db.Prepare("UPDATE user_interaction SET resource=? WHERE resource=?") - if err != nil { - return errors.Wrap(err, "localfs: error preparing statement") - } - _, err = stmt.Exec(t, s) - if err != nil { - return errors.Wrap(err, "localfs: error executing delete statement") - } - - stmt, err = fs.db.Prepare("UPDATE metadata SET resource=? WHERE resource=?") - if err != nil { - return errors.Wrap(err, "localfs: error preparing statement") - } - _, err = stmt.Exec(t, s) - if err != nil { - return errors.Wrap(err, "localfs: error executing delete statement") - } - - stmt, err = fs.db.Prepare("UPDATE share_references SET resource=? WHERE resource=?") - if err != nil { - return errors.Wrap(err, "localfs: error preparing statement") - } - _, err = stmt.Exec(t, s) - if err != nil { - return errors.Wrap(err, "localfs: error executing delete statement") - } - return nil -} diff --git a/pkg/storage/utils/localfs/localfs.go b/pkg/storage/utils/localfs/localfs.go index fedc2353af8..3ea9048fb62 100644 --- a/pkg/storage/utils/localfs/localfs.go +++ b/pkg/storage/utils/localfs/localfs.go @@ -20,18 +20,14 @@ package localfs import ( "context" - "database/sql" "fmt" "io" iofs "io/fs" "net/url" "os" "path" - "strconv" "strings" - "time" - grouppb "github.com/cs3org/go-cs3apis/cs3/identity/group/v1beta1" userpb "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1" provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1" types "github.com/cs3org/go-cs3apis/cs3/types/v1beta1" @@ -40,27 +36,16 @@ import ( "github.com/cs3org/reva/pkg/errtypes" "github.com/cs3org/reva/pkg/mime" "github.com/cs3org/reva/pkg/storage" - "github.com/cs3org/reva/pkg/storage/utils/acl" "github.com/cs3org/reva/pkg/storage/utils/chunking" - "github.com/cs3org/reva/pkg/storage/utils/grants" - "github.com/cs3org/reva/pkg/storage/utils/templates" - "github.com/cs3org/reva/pkg/utils" "github.com/pkg/errors" ) // Config holds the configuration details for the local fs. type Config struct { Root string `mapstructure:"root"` - DisableHome bool `mapstructure:"disable_home"` - UserLayout string `mapstructure:"user_layout"` - ShareFolder string `mapstructure:"share_folder"` DataTransfersFolder string `mapstructure:"data_transfers_folder"` Uploads string `mapstructure:"uploads"` DataDirectory string `mapstructure:"data_directory"` - RecycleBin string `mapstructure:"recycle_bin"` - Versions string `mapstructure:"versions"` - Shadow string `mapstructure:"shadow"` - References string `mapstructure:"references"` } func (c *Config) ApplyDefaults() { @@ -68,33 +53,16 @@ func (c *Config) ApplyDefaults() { c.Root = "/var/tmp/reva" } - if c.UserLayout == "" { - c.UserLayout = "{{.Username}}" - } - - if c.ShareFolder == "" { - c.ShareFolder = "/MyShares" - } - if c.DataTransfersFolder == "" { c.DataTransfersFolder = "/DataTransfers" } - // ensure share folder always starts with slash - c.ShareFolder = path.Join("/", c.ShareFolder) - c.DataDirectory = path.Join(c.Root, "data") c.Uploads = path.Join(c.Root, ".uploads") - c.Shadow = path.Join(c.Root, ".shadow") - - c.References = path.Join(c.Shadow, "references") - c.RecycleBin = path.Join(c.Shadow, "recycle_bin") - c.Versions = path.Join(c.Shadow, "versions") } type localfs struct { conf *Config - db *sql.DB chunkHandler *chunking.ChunkHandler } @@ -104,35 +72,20 @@ func NewLocalFS(c *Config) (storage.FS, error) { c.ApplyDefaults() // create namespaces if they do not exist - namespaces := []string{c.DataDirectory, c.Uploads, c.Shadow, c.References, c.RecycleBin, c.Versions} + namespaces := []string{c.DataDirectory, c.Uploads} for _, v := range namespaces { if err := os.MkdirAll(v, 0755); err != nil { return nil, errors.Wrap(err, "could not create home dir "+v) } } - dbName := "localfs.db" - if !c.DisableHome { - dbName = "localhomefs.db" - } - - db, err := initializeDB(c.Root, dbName) - if err != nil { - return nil, errors.Wrap(err, "localfs: error initializing db") - } - return &localfs{ conf: c, - db: db, chunkHandler: chunking.NewChunkHandler(c.Uploads), }, nil } func (fs *localfs) Shutdown(ctx context.Context) error { - err := fs.db.Close() - if err != nil { - return errors.Wrap(err, "localfs: error closing db connection") - } return nil } @@ -165,73 +118,13 @@ func (fs *localfs) wrap(ctx context.Context, p string) string { // This is to prevent path traversal. // With this p can't break out of its parent folder p = path.Join("/", p) - var internal string - if !fs.conf.DisableHome { - layout, err := fs.GetHome(ctx) - if err != nil { - panic(err) - } - internal = path.Join(fs.conf.DataDirectory, layout, p) - } else { - internal = path.Join(fs.conf.DataDirectory, p) - } - return internal -} - -func (fs *localfs) wrapReferences(ctx context.Context, p string) string { - var internal string - if !fs.conf.DisableHome { - layout, err := fs.GetHome(ctx) - if err != nil { - panic(err) - } - internal = path.Join(fs.conf.References, layout, p) - } else { - internal = path.Join(fs.conf.References, p) - } - return internal -} - -func (fs *localfs) wrapRecycleBin(ctx context.Context, p string) string { - var internal string - if !fs.conf.DisableHome { - layout, err := fs.GetHome(ctx) - if err != nil { - panic(err) - } - internal = path.Join(fs.conf.RecycleBin, layout, p) - } else { - internal = path.Join(fs.conf.RecycleBin, p) - } - return internal -} - -func (fs *localfs) wrapVersions(ctx context.Context, p string) string { - p = path.Join("/", p) - var internal string - if !fs.conf.DisableHome { - layout, err := fs.GetHome(ctx) - if err != nil { - panic(err) - } - internal = path.Join(fs.conf.Versions, layout, p) - } else { - internal = path.Join(fs.conf.Versions, p) - } + internal := path.Join(fs.conf.DataDirectory, p) return internal } func (fs *localfs) unwrap(ctx context.Context, np string) string { - ns := fs.getNsMatch(np, []string{fs.conf.DataDirectory, fs.conf.References, fs.conf.RecycleBin, fs.conf.Versions}) + ns := fs.getNsMatch(np, []string{fs.conf.DataDirectory}) var external string - if !fs.conf.DisableHome { - layout, err := fs.GetHome(ctx) - if err != nil { - panic(err) - } - ns = path.Join(ns, layout) - } - external = strings.TrimPrefix(np, ns) if external == "" { external = "/" @@ -253,24 +146,6 @@ func (fs *localfs) getNsMatch(internal string, nss []string) string { return match } -func (fs *localfs) isShareFolder(ctx context.Context, p string) bool { - return strings.HasPrefix(p, fs.conf.ShareFolder) -} - -func (fs *localfs) isDataTransfersFolder(ctx context.Context, p string) bool { - return strings.HasPrefix(p, fs.conf.DataTransfersFolder) -} - -func (fs *localfs) isShareFolderRoot(ctx context.Context, p string) bool { - return path.Clean(p) == fs.conf.ShareFolder -} - -func (fs *localfs) isShareFolderChild(ctx context.Context, p string) bool { - p = path.Clean(p) - vals := strings.Split(p, fs.conf.ShareFolder+"/") - return len(vals) > 1 && vals[1] != "" -} - // permissionSet returns the permission set for the current user. func (fs *localfs) permissionSet(ctx context.Context, owner *userpb.UserId) *provider.ResourcePermissions { u, ok := appctx.ContextGetUser(ctx) @@ -342,12 +217,6 @@ func (fs *localfs) normalize(ctx context.Context, fi os.FileInfo, fn string, mdK } var layout string - if !fs.conf.DisableHome { - layout, err = fs.GetHome(ctx) - if err != nil { - return nil, err - } - } // A fileid is constructed like `fileid-url_encoded_path`. See GetPathByID for the inverse conversion md := &provider.ResourceInfo{ @@ -368,20 +237,6 @@ func (fs *localfs) normalize(ctx context.Context, fi os.FileInfo, fn string, mdK return md, nil } -func (fs *localfs) convertToFileReference(ctx context.Context, fi os.FileInfo, fn string, mdKeys []string) (*provider.ResourceInfo, error) { - info, err := fs.normalize(ctx, fi, fn, mdKeys) - if err != nil { - return nil, err - } - info.Type = provider.ResourceType_RESOURCE_TYPE_REFERENCE - target, err := fs.getReferenceEntry(ctx, fn) - if err != nil { - return nil, err - } - info.Target = target - return info, nil -} - func getResourceType(isDir bool) provider.ResourceType { if isDir { return provider.ResourceType_RESOURCE_TYPE_CONTAINER @@ -390,48 +245,13 @@ func getResourceType(isDir bool) provider.ResourceType { } func (fs *localfs) retrieveArbitraryMetadata(ctx context.Context, fn string, mdKeys []string) (*provider.ArbitraryMetadata, error) { - md, err := fs.getMetadata(ctx, fn) - if err != nil { - return nil, errors.Wrap(err, "localfs: error listing metadata") - } - var mdKey, mdVal string - metadata := map[string]string{} - - mdKeysMap := make(map[string]struct{}) - for _, k := range mdKeys { - mdKeysMap[k] = struct{}{} - } - - var returnAllKeys bool - if _, ok := mdKeysMap["*"]; len(mdKeys) == 0 || ok { - returnAllKeys = true - } - - for md.Next() { - err = md.Scan(&mdKey, &mdVal) - if err != nil { - return nil, errors.Wrap(err, "localfs: error scanning db rows") - } - if _, ok := mdKeysMap[mdKey]; returnAllKeys || ok { - metadata[mdKey] = mdVal - } - } - return &provider.ArbitraryMetadata{ - Metadata: metadata, - }, nil + return nil, errtypes.NotSupported("localfs: not supported") } // GetPathByID returns the path pointed by the file id // In this implementation the file id is in the form `fileid-url_encoded_path`. func (fs *localfs) GetPathByID(ctx context.Context, ref *provider.ResourceId) (string, error) { var layout string - if !fs.conf.DisableHome { - var err error - layout, err = fs.GetHome(ctx) - if err != nil { - return "", err - } - } return url.QueryUnescape(strings.TrimPrefix(ref.OpaqueId, "fileid-"+layout)) } @@ -440,127 +260,23 @@ func (fs *localfs) DenyGrant(ctx context.Context, ref *provider.Reference, g *pr } func (fs *localfs) AddGrant(ctx context.Context, ref *provider.Reference, g *provider.Grant) error { - fn, err := fs.resolve(ctx, ref) - if err != nil { - return errors.Wrap(err, "localfs: error resolving ref") - } - fn = fs.wrap(ctx, fn) - - role, err := grants.GetACLPerm(g.Permissions) - if err != nil { - return errors.Wrap(err, "localfs: unknown set permissions") - } - - granteeType, err := grants.GetACLType(g.Grantee.Type) - if err != nil { - return errors.Wrap(err, "localfs: error getting grantee type") - } - var grantee string - if granteeType == acl.TypeUser { - grantee = fmt.Sprintf("%s:%s:%s@%s", granteeType, g.Grantee.GetUserId().OpaqueId, utils.UserTypeToString(g.Grantee.GetUserId().Type), g.Grantee.GetUserId().Idp) - } else if granteeType == acl.TypeGroup { - grantee = fmt.Sprintf("%s::%s@%s", granteeType, g.Grantee.GetGroupId().OpaqueId, g.Grantee.GetGroupId().Idp) - } - - err = fs.addToACLDB(ctx, fn, grantee, role) - if err != nil { - return errors.Wrap(err, "localfs: error adding entry to DB") - } - - return fs.propagate(ctx, fn) + return errtypes.NotSupported("localfs: deny grant not supported") } func (fs *localfs) ListGrants(ctx context.Context, ref *provider.Reference) ([]*provider.Grant, error) { - fn, err := fs.resolve(ctx, ref) - if err != nil { - return nil, errors.Wrap(err, "localfs: error resolving ref") - } - fn = fs.wrap(ctx, fn) - - g, err := fs.getACLs(ctx, fn) - if err != nil { - return nil, errors.Wrap(err, "localfs: error listing grants") - } - var granteeID, role string - var grantList []*provider.Grant - - for g.Next() { - err = g.Scan(&granteeID, &role) - if err != nil { - return nil, errors.Wrap(err, "localfs: error scanning db rows") - } - grantSplit := strings.Split(granteeID, ":") - grantee := &provider.Grantee{Type: grants.GetGranteeType(grantSplit[0])} - parts := strings.Split(grantSplit[2], "@") - if grantSplit[0] == acl.TypeUser { - grantee.Id = &provider.Grantee_UserId{UserId: &userpb.UserId{OpaqueId: parts[0], Idp: parts[1], Type: utils.UserTypeMap(grantSplit[1])}} - } else if grantSplit[0] == acl.TypeGroup { - grantee.Id = &provider.Grantee_GroupId{GroupId: &grouppb.GroupId{OpaqueId: parts[0], Idp: parts[1]}} - } - permissions := grants.GetGrantPermissionSet(role) - - grantList = append(grantList, &provider.Grant{ - Grantee: grantee, - Permissions: permissions, - }) - } - return grantList, nil + return nil, errtypes.NotSupported("localfs: deny grant not supported") } func (fs *localfs) RemoveGrant(ctx context.Context, ref *provider.Reference, g *provider.Grant) error { - fn, err := fs.resolve(ctx, ref) - if err != nil { - return errors.Wrap(err, "localfs: error resolving ref") - } - fn = fs.wrap(ctx, fn) - - granteeType, err := grants.GetACLType(g.Grantee.Type) - if err != nil { - return errors.Wrap(err, "localfs: error getting grantee type") - } - var grantee string - if granteeType == acl.TypeUser { - grantee = fmt.Sprintf("%s:%s@%s", granteeType, g.Grantee.GetUserId().OpaqueId, g.Grantee.GetUserId().Idp) - } else if granteeType == acl.TypeGroup { - grantee = fmt.Sprintf("%s:%s@%s", granteeType, g.Grantee.GetGroupId().OpaqueId, g.Grantee.GetGroupId().Idp) - } - - err = fs.removeFromACLDB(ctx, fn, grantee) - if err != nil { - return errors.Wrap(err, "localfs: error removing from DB") - } - - return fs.propagate(ctx, fn) + return errtypes.NotSupported("localfs: deny grant not supported") } func (fs *localfs) UpdateGrant(ctx context.Context, ref *provider.Reference, g *provider.Grant) error { - return fs.AddGrant(ctx, ref, g) + return errtypes.NotSupported("localfs: deny grant not supported") } func (fs *localfs) CreateReference(ctx context.Context, path string, targetURI *url.URL) error { - var fn string - switch { - case fs.isShareFolder(ctx, path): - fn = fs.wrapReferences(ctx, path) - case fs.isDataTransfersFolder(ctx, path): - fn = fs.wrap(ctx, path) - default: - return errtypes.PermissionDenied("localfs: cannot create references outside the share folder and data transfers folder") - } - - err := os.MkdirAll(fn, 0700) - if err != nil { - if os.IsNotExist(err) { - return errtypes.NotFound(fn) - } - return errors.Wrap(err, "localfs: error creating dir "+fn) - } - - if err = fs.addToReferencesDB(ctx, fn, targetURI.String()); err != nil { - return errors.Wrap(err, "localfs: error adding entry to DB") - } - - return fs.propagate(ctx, fn) + return errtypes.NotSupported("localfs: not supported") } // CreateStorageSpace creates a storage space. @@ -569,143 +285,11 @@ func (fs *localfs) CreateStorageSpace(ctx context.Context, req *provider.CreateS } func (fs *localfs) SetArbitraryMetadata(ctx context.Context, ref *provider.Reference, md *provider.ArbitraryMetadata) error { - np, err := fs.resolve(ctx, ref) - if err != nil { - return errors.Wrap(err, "localfs: error resolving ref") - } - - if fs.isShareFolderRoot(ctx, np) { - return errtypes.PermissionDenied("localfs: cannot set metadata for the virtual share folder") - } - - if fs.isShareFolderChild(ctx, np) { - np = fs.wrapReferences(ctx, np) - } else { - np = fs.wrap(ctx, np) - } - - fi, err := os.Stat(np) - if err != nil { - if os.IsNotExist(err) { - return errtypes.NotFound(fs.unwrap(ctx, np)) - } - return errors.Wrap(err, "localfs: error stating "+np) - } - - if md.Metadata != nil { - if val, ok := md.Metadata["mtime"]; ok { - if mtime, err := parseMTime(val); err == nil { - // updating mtime also updates atime - if err := os.Chtimes(np, mtime, mtime); err != nil { - return errors.Wrap(err, "could not set mtime") - } - } else { - return errors.Wrap(err, "could not parse mtime") - } - delete(md.Metadata, "mtime") - } - - if _, ok := md.Metadata["etag"]; ok { - etag := calcEtag(ctx, fi) - if etag != md.Metadata["etag"] { - err = fs.addToMetadataDB(ctx, np, "etag", etag) - if err != nil { - return errors.Wrap(err, "localfs: error adding entry to DB") - } - } - delete(md.Metadata, "etag") - } - - if _, ok := md.Metadata["favorite"]; ok { - u, err := getUser(ctx) - if err != nil { - return err - } - if uid := u.GetId(); uid != nil { - usr := fmt.Sprintf("u:%s@%s", uid.GetOpaqueId(), uid.GetIdp()) - if err = fs.addToFavoritesDB(ctx, np, usr); err != nil { - return errors.Wrap(err, "localfs: error adding entry to DB") - } - } else { - return errors.Wrap(errtypes.UserRequired("userrequired"), "user has no id") - } - delete(md.Metadata, "favorite") - } - } - - for k, v := range md.Metadata { - err = fs.addToMetadataDB(ctx, np, k, v) - if err != nil { - return errors.Wrap(err, "localfs: error adding entry to DB") - } - } - - return fs.propagate(ctx, np) -} - -func parseMTime(v string) (t time.Time, err error) { - p := strings.SplitN(v, ".", 2) - var sec, nsec int64 - if sec, err = strconv.ParseInt(p[0], 10, 64); err == nil { - if len(p) > 1 { - nsec, err = strconv.ParseInt(p[1], 10, 64) - } - } - return time.Unix(sec, nsec), err + return errtypes.NotSupported("localfs: not supported") } func (fs *localfs) UnsetArbitraryMetadata(ctx context.Context, ref *provider.Reference, keys []string) error { - np, err := fs.resolve(ctx, ref) - if err != nil { - return errors.Wrap(err, "localfs: error resolving ref") - } - - if fs.isShareFolderRoot(ctx, np) { - return errtypes.PermissionDenied("localfs: cannot set metadata for the virtual share folder") - } - - if fs.isShareFolderChild(ctx, np) { - np = fs.wrapReferences(ctx, np) - } else { - np = fs.wrap(ctx, np) - } - - _, err = os.Stat(np) - if err != nil { - if os.IsNotExist(err) { - return errtypes.NotFound(fs.unwrap(ctx, np)) - } - return errors.Wrap(err, "localfs: error stating "+np) - } - - for _, k := range keys { - switch k { - case "favorite": - u, err := getUser(ctx) - if err != nil { - return err - } - if uid := u.GetId(); uid != nil { - usr := fmt.Sprintf("u:%s@%s", uid.GetOpaqueId(), uid.GetIdp()) - if err = fs.removeFromFavoritesDB(ctx, np, usr); err != nil { - return errors.Wrap(err, "localfs: error removing entry from DB") - } - } else { - return errors.Wrap(errtypes.UserRequired("userrequired"), "user has no id") - } - case "etag": - return errors.Wrap(errtypes.NotSupported("unsetting etag not supported"), "could not unset metadata") - case "mtime": - return errors.Wrap(errtypes.NotSupported("unsetting mtime not supported"), "could not unset metadata") - default: - err = fs.removeFromMetadataDB(ctx, np, k) - if err != nil { - return errors.Wrap(err, "localfs: error adding entry to DB") - } - } - } - - return fs.propagate(ctx, np) + return errtypes.NotSupported("localfs: not supported") } // GetLock returns an existing lock on the given reference. @@ -729,48 +313,11 @@ func (fs *localfs) Unlock(ctx context.Context, ref *provider.Reference, lock *pr } func (fs *localfs) GetHome(ctx context.Context) (string, error) { - if fs.conf.DisableHome { - return "", errtypes.NotSupported("local: get home not supported") - } - - u, err := getUser(ctx) - if err != nil { - err = errors.Wrap(err, "local: wrap: no user in ctx and home is enabled") - return "", err - } - relativeHome := templates.WithUser(u, fs.conf.UserLayout) - - return relativeHome, nil + return "", errtypes.NotSupported("local: get home not supported") } func (fs *localfs) CreateHome(ctx context.Context) error { - if fs.conf.DisableHome { - return errtypes.NotSupported("localfs: create home not supported") - } - - homePaths := []string{fs.wrap(ctx, "/"), fs.wrapRecycleBin(ctx, "/"), fs.wrapVersions(ctx, "/"), fs.wrapReferences(ctx, fs.conf.ShareFolder)} - - for _, v := range homePaths { - if err := fs.createHomeInternal(ctx, v); err != nil { - return errors.Wrap(err, "local: error creating home dir "+v) - } - } - - return nil -} - -func (fs *localfs) createHomeInternal(ctx context.Context, fn string) error { - _, err := os.Stat(fn) - if err != nil { - if !os.IsNotExist(err) { - return errors.Wrap(err, "local: error stating:"+fn) - } - } - err = os.MkdirAll(fn, 0700) - if err != nil { - return errors.Wrap(err, "local: error creating dir:"+fn) - } - return nil + return errtypes.NotSupported("localfs: create home not supported") } func (fs *localfs) CreateDir(ctx context.Context, ref *provider.Reference) error { @@ -779,10 +326,6 @@ func (fs *localfs) CreateDir(ctx context.Context, ref *provider.Reference) error return nil } - if fs.isShareFolder(ctx, fn) { - return errtypes.PermissionDenied("localfs: cannot create folder under the share folder") - } - fn = fs.wrap(ctx, fn) if _, err := os.Stat(fn); err == nil { return errtypes.AlreadyExists(fn) @@ -795,7 +338,7 @@ func (fs *localfs) CreateDir(ctx context.Context, ref *provider.Reference) error return errors.Wrap(err, "localfs: error creating dir "+fn) } - return fs.propagate(ctx, path.Dir(fn)) + return nil } // TouchFile as defined in the storage.FS interface. @@ -809,17 +352,7 @@ func (fs *localfs) Delete(ctx context.Context, ref *provider.Reference) error { return errors.Wrap(err, "localfs: error resolving ref") } - if fs.isShareFolderRoot(ctx, fn) { - return errtypes.PermissionDenied("localfs: cannot delete the virtual share folder") - } - var fp string - if fs.isShareFolderChild(ctx, fn) { - fp = fs.wrapReferences(ctx, fn) - } else { - fp = fs.wrap(ctx, fn) - } - _, err = os.Stat(fp) if err != nil { if os.IsNotExist(err) { @@ -828,17 +361,11 @@ func (fs *localfs) Delete(ctx context.Context, ref *provider.Reference) error { return errors.Wrap(err, "localfs: error stating "+fp) } - key := fmt.Sprintf("%s.d%d", path.Base(fn), time.Now().UnixNano()/int64(time.Millisecond)) - if err := os.Rename(fp, fs.wrapRecycleBin(ctx, key)); err != nil { + if err := os.RemoveAll(fp); err != nil { return errors.Wrap(err, "localfs: could not delete item") } - err = fs.addToRecycledDB(ctx, key, fn) - if err != nil { - return errors.Wrap(err, "localfs: error adding entry to DB") - } - - return fs.propagate(ctx, path.Dir(fp)) + return nil } func (fs *localfs) Move(ctx context.Context, oldRef, newRef *provider.Reference) error { @@ -852,10 +379,6 @@ func (fs *localfs) Move(ctx context.Context, oldRef, newRef *provider.Reference) return errors.Wrap(err, "localfs: error resolving ref") } - if fs.isShareFolder(ctx, oldName) || fs.isShareFolder(ctx, newName) { - return fs.moveReferences(ctx, oldName, newName) - } - oldName = fs.wrap(ctx, oldName) newName = fs.wrap(ctx, newName) @@ -863,51 +386,6 @@ func (fs *localfs) Move(ctx context.Context, oldRef, newRef *provider.Reference) return errors.Wrap(err, "localfs: error moving "+oldName+" to "+newName) } - if err := fs.copyMD(oldName, newName); err != nil { - return errors.Wrap(err, "localfs: error copying metadata") - } - - if err := fs.propagate(ctx, newName); err != nil { - return err - } - if err := fs.propagate(ctx, path.Dir(oldName)); err != nil { - return err - } - - return nil -} - -func (fs *localfs) moveReferences(ctx context.Context, oldName, newName string) error { - if fs.isShareFolderRoot(ctx, oldName) || fs.isShareFolderRoot(ctx, newName) { - return errtypes.PermissionDenied("localfs: cannot move/rename the virtual share folder") - } - - // only rename of the reference is allowed, hence having the same basedir - bold, _ := path.Split(oldName) - bnew, _ := path.Split(newName) - - if bold != bnew { - return errtypes.PermissionDenied("localfs: cannot move references under the virtual share folder") - } - - oldName = fs.wrapReferences(ctx, oldName) - newName = fs.wrapReferences(ctx, newName) - - if err := os.Rename(oldName, newName); err != nil { - return errors.Wrap(err, "localfs: error moving "+oldName+" to "+newName) - } - - if err := fs.copyMD(oldName, newName); err != nil { - return errors.Wrap(err, "localfs: error copying metadata") - } - - if err := fs.propagate(ctx, newName); err != nil { - return err - } - if err := fs.propagate(ctx, path.Dir(oldName)); err != nil { - return err - } - return nil } @@ -917,12 +395,6 @@ func (fs *localfs) GetMD(ctx context.Context, ref *provider.Reference, mdKeys [] return nil, errors.Wrap(err, "localfs: error resolving ref") } - if !fs.conf.DisableHome { - if fs.isShareFolder(ctx, fn) { - return fs.getMDShareFolder(ctx, fn, mdKeys) - } - } - fn = fs.wrap(ctx, fn) md, err := os.Stat(fn) if err != nil { @@ -935,22 +407,6 @@ func (fs *localfs) GetMD(ctx context.Context, ref *provider.Reference, mdKeys [] return fs.normalize(ctx, md, fn, mdKeys) } -func (fs *localfs) getMDShareFolder(ctx context.Context, p string, mdKeys []string) (*provider.ResourceInfo, error) { - fn := fs.wrapReferences(ctx, p) - md, err := os.Stat(fn) - if err != nil { - if os.IsNotExist(err) { - return nil, errtypes.NotFound(fn) - } - return nil, errors.Wrap(err, "localfs: error stating "+fn) - } - - if fs.isShareFolderRoot(ctx, p) { - return fs.normalize(ctx, md, fn, mdKeys) - } - return fs.convertToFileReference(ctx, md, fn, mdKeys) -} - func (fs *localfs) ListFolder(ctx context.Context, ref *provider.Reference, mdKeys []string) ([]*provider.ResourceInfo, error) { fn, err := fs.resolve(ctx, ref) if err != nil { @@ -962,24 +418,9 @@ func (fs *localfs) ListFolder(ctx context.Context, ref *provider.Reference, mdKe if err != nil { return nil, err } - if !fs.conf.DisableHome { - sharedReferences, err := fs.listShareFolderRoot(ctx, fn, mdKeys) - if err != nil { - return nil, err - } - homeFiles = append(homeFiles, sharedReferences...) - } return homeFiles, nil } - if fs.isShareFolderRoot(ctx, fn) { - return fs.listShareFolderRoot(ctx, fn, mdKeys) - } - - if fs.isShareFolderChild(ctx, fn) { - return nil, errtypes.PermissionDenied("localfs: error listing folders inside the shared folder, only file references are stored inside") - } - return fs.listFolder(ctx, fn, mdKeys) } @@ -1013,51 +454,12 @@ func (fs *localfs) listFolder(ctx context.Context, fn string, mdKeys []string) ( return finfos, nil } -func (fs *localfs) listShareFolderRoot(ctx context.Context, home string, mdKeys []string) ([]*provider.ResourceInfo, error) { - fn := fs.wrapReferences(ctx, home) - - entries, err := os.ReadDir(fn) - if err != nil { - if os.IsNotExist(err) { - return nil, errtypes.NotFound(fn) - } - return nil, errors.Wrap(err, "localfs: error listing "+fn) - } - mds := make([]iofs.FileInfo, 0, len(entries)) - for _, entry := range entries { - info, err := entry.Info() - if err != nil { - return nil, err - } - mds = append(mds, info) - } - - finfos := []*provider.ResourceInfo{} - for _, md := range mds { - var info *provider.ResourceInfo - var err error - if fs.isShareFolderRoot(ctx, path.Join("/", md.Name())) { - info, err = fs.normalize(ctx, md, path.Join(fn, md.Name()), mdKeys) - } else { - info, err = fs.convertToFileReference(ctx, md, path.Join(fn, md.Name()), mdKeys) - } - if err == nil { - finfos = append(finfos, info) - } - } - return finfos, nil -} - func (fs *localfs) Download(ctx context.Context, ref *provider.Reference) (io.ReadCloser, error) { fn, err := fs.resolve(ctx, ref) if err != nil { return nil, errors.Wrap(err, "localfs: error resolving ref") } - if fs.isShareFolder(ctx, fn) { - return nil, errtypes.PermissionDenied("localfs: cannot download under the virtual share folder") - } - fn = fs.wrap(ctx, fn) r, err := os.Open(fn) if err != nil { @@ -1069,279 +471,39 @@ func (fs *localfs) Download(ctx context.Context, ref *provider.Reference) (io.Re return r, nil } -func (fs *localfs) archiveRevision(ctx context.Context, np string) error { - versionsDir := fs.wrapVersions(ctx, fs.unwrap(ctx, np)) - if err := os.MkdirAll(versionsDir, 0700); err != nil { - return errors.Wrap(err, "localfs: error creating file versions dir "+versionsDir) - } - - vp := path.Join(versionsDir, fmt.Sprintf("v%d", time.Now().UnixNano()/int64(time.Millisecond))) - if err := os.Rename(np, vp); err != nil { - return errors.Wrap(err, "localfs: error renaming from "+np+" to "+vp) - } - - return nil -} - func (fs *localfs) ListRevisions(ctx context.Context, ref *provider.Reference) ([]*provider.FileVersion, error) { - np, err := fs.resolve(ctx, ref) - if err != nil { - return nil, errors.Wrap(err, "localfs: error resolving ref") - } - - if fs.isShareFolder(ctx, np) { - return nil, errtypes.PermissionDenied("localfs: cannot list revisions under the virtual share folder") - } - - versionsDir := fs.wrapVersions(ctx, np) - revisions := []*provider.FileVersion{} - entries, err := os.ReadDir(versionsDir) - if err != nil { - return nil, errors.Wrap(err, "localfs: error reading"+versionsDir) - } - mds := make([]iofs.FileInfo, 0, len(entries)) - for _, entry := range entries { - info, err := entry.Info() - if err != nil { - return nil, err - } - mds = append(mds, info) - } - - for i := range mds { - // versions resemble v12345678 - version := mds[i].Name()[1:] - - mtime, err := strconv.Atoi(version) - if err != nil { - continue - } - revisions = append(revisions, &provider.FileVersion{ - Key: version, - Size: uint64(mds[i].Size()), - Mtime: uint64(mtime), - Etag: calcEtag(ctx, mds[i]), - }) - } - return revisions, nil + return nil, errtypes.NotSupported("localfs: not supported") } func (fs *localfs) DownloadRevision(ctx context.Context, ref *provider.Reference, revisionKey string) (io.ReadCloser, error) { - np, err := fs.resolve(ctx, ref) - if err != nil { - return nil, errors.Wrap(err, "localfs: error resolving ref") - } - - if fs.isShareFolder(ctx, np) { - return nil, errtypes.PermissionDenied("localfs: cannot download revisions under the virtual share folder") - } - - versionsDir := fs.wrapVersions(ctx, np) - vp := path.Join(versionsDir, revisionKey) - - r, err := os.Open(vp) - if err != nil { - if os.IsNotExist(err) { - return nil, errtypes.NotFound(vp) - } - return nil, errors.Wrap(err, "localfs: error reading "+vp) - } - - return r, nil + return nil, errtypes.NotSupported("localfs: not supported") } func (fs *localfs) RestoreRevision(ctx context.Context, ref *provider.Reference, revisionKey string) error { - np, err := fs.resolve(ctx, ref) - if err != nil { - return errors.Wrap(err, "localfs: error resolving ref") - } - - if fs.isShareFolder(ctx, np) { - return errtypes.PermissionDenied("localfs: cannot restore revisions under the virtual share folder") - } - - versionsDir := fs.wrapVersions(ctx, np) - vp := path.Join(versionsDir, revisionKey) - np = fs.wrap(ctx, np) - - // check revision exists - vs, err := os.Stat(vp) - if err != nil { - if os.IsNotExist(err) { - return errtypes.NotFound(revisionKey) - } - return errors.Wrap(err, "localfs: error stating "+vp) - } - - if !vs.Mode().IsRegular() { - return fmt.Errorf("%s is not a regular file", vp) - } - - if err := fs.archiveRevision(ctx, np); err != nil { - return err - } - - if err := os.Rename(vp, np); err != nil { - return errors.Wrap(err, "localfs: error renaming from "+vp+" to "+np) - } - - return fs.propagate(ctx, np) + return errtypes.NotSupported("localfs: not supported") } func (fs *localfs) PurgeRecycleItem(ctx context.Context, basePath, key, relativePath string) error { - rp := fs.wrapRecycleBin(ctx, key) - - if err := os.Remove(rp); err != nil { - return errors.Wrap(err, "localfs: error deleting recycle item") - } - return nil + return errtypes.NotSupported("localfs: not supported") } func (fs *localfs) EmptyRecycle(ctx context.Context) error { - rp := fs.wrapRecycleBin(ctx, "/") - - if err := os.RemoveAll(rp); err != nil { - return errors.Wrap(err, "localfs: error deleting recycle files") - } - if err := fs.createHomeInternal(ctx, rp); err != nil { - return errors.Wrap(err, "localfs: error deleting recycle files") - } - return nil -} - -func (fs *localfs) convertToRecycleItem(ctx context.Context, rp string, md os.FileInfo) *provider.RecycleItem { - // trashbin items have filename.txt.d12345678 - suffix := path.Ext(md.Name()) - if len(suffix) == 0 || !strings.HasPrefix(suffix, ".d") { - return nil - } - - trashtime := suffix[2:] - ttime, err := strconv.Atoi(trashtime) - if err != nil { - return nil - } - - filePath, err := fs.getRecycledEntry(ctx, md.Name()) - if err != nil { - return nil - } - - return &provider.RecycleItem{ - Type: getResourceType(md.IsDir()), - Key: md.Name(), - Ref: &provider.Reference{Path: filePath}, - Size: uint64(md.Size()), - DeletionTime: &types.Timestamp{ - Seconds: uint64(ttime), - }, - } + return errtypes.NotSupported("localfs: not supported") } func (fs *localfs) ListRecycle(ctx context.Context, basePath, key, relativePath string) ([]*provider.RecycleItem, error) { - rp := fs.wrapRecycleBin(ctx, "/") - - entries, err := os.ReadDir(rp) - if err != nil { - return nil, errors.Wrap(err, "localfs: error listing deleted files") - } - mds := make([]iofs.FileInfo, 0, len(entries)) - for _, entry := range entries { - info, err := entry.Info() - if err != nil { - return nil, err - } - mds = append(mds, info) - } - items := []*provider.RecycleItem{} - for i := range mds { - ri := fs.convertToRecycleItem(ctx, rp, mds[i]) - if ri != nil { - items = append(items, ri) - } - } - return items, nil + return nil, errtypes.NotSupported("localfs: not supported") } func (fs *localfs) RestoreRecycleItem(ctx context.Context, basePath, key, relativePath string, restoreRef *provider.Reference) error { - suffix := path.Ext(key) - if len(suffix) == 0 || !strings.HasPrefix(suffix, ".d") { - return errors.New("localfs: invalid trash item suffix") - } - - filePath, err := fs.getRecycledEntry(ctx, key) - if err != nil { - return errors.Wrap(err, "localfs: invalid key") - } - - var localRestorePath string - switch { - case restoreRef != nil && restoreRef.Path != "": - localRestorePath = fs.wrap(ctx, restoreRef.Path) - case fs.isShareFolder(ctx, filePath): - localRestorePath = fs.wrapReferences(ctx, filePath) - default: - localRestorePath = fs.wrap(ctx, filePath) - } - - if _, err = os.Stat(localRestorePath); err == nil { - return errors.New("localfs: can't restore - file already exists at original path") - } - - rp := fs.wrapRecycleBin(ctx, key) - if _, err = os.Stat(rp); err != nil { - if os.IsNotExist(err) { - return errtypes.NotFound(key) - } - return errors.Wrap(err, "localfs: error stating "+rp) - } - - if err := os.Rename(rp, localRestorePath); err != nil { - return errors.Wrap(err, "ocfs: could not restore item") - } - - err = fs.removeFromRecycledDB(ctx, key) - if err != nil { - return errors.Wrap(err, "localfs: error adding entry to DB") - } - - return fs.propagate(ctx, localRestorePath) + return errtypes.NotSupported("localfs: not supported") } func (fs *localfs) ListStorageSpaces(ctx context.Context, filter []*provider.ListStorageSpacesRequest_Filter) ([]*provider.StorageSpace, error) { - return nil, errtypes.NotSupported("list storage spaces") + return nil, errtypes.NotSupported("localfs: not supported") } // UpdateStorageSpace updates a storage space. func (fs *localfs) UpdateStorageSpace(ctx context.Context, req *provider.UpdateStorageSpaceRequest) (*provider.UpdateStorageSpaceResponse, error) { return nil, errtypes.NotSupported("update storage space") } - -func (fs *localfs) propagate(ctx context.Context, leafPath string) error { - var root string - if fs.isShareFolderChild(ctx, leafPath) || strings.HasSuffix(path.Clean(leafPath), fs.conf.ShareFolder) { - root = fs.wrapReferences(ctx, "/") - } else { - root = fs.wrap(ctx, "/") - } - - if !strings.HasPrefix(leafPath, root) { - return errors.New("internal path: " + leafPath + " outside root: " + root) - } - - fi, err := os.Stat(leafPath) - if err != nil { - return err - } - - parts := strings.Split(strings.TrimPrefix(leafPath, root), "/") - // root never ends in / so the split returns an empty first element, which we can skip - // we do not need to chmod the last element because it is the leaf path (< and not <= comparison) - for i := 1; i < len(parts); i++ { - if err := os.Chtimes(root, fi.ModTime(), fi.ModTime()); err != nil { - return err - } - root = path.Join(root, parts[i]) - } - return nil -} diff --git a/pkg/storage/utils/localfs/upload.go b/pkg/storage/utils/localfs/upload.go index f4ba06e5e35..9462567672b 100644 --- a/pkg/storage/utils/localfs/upload.go +++ b/pkg/storage/utils/localfs/upload.go @@ -317,14 +317,6 @@ func (upload *fileUpload) FinishUpload(ctx context.Context) error { // the local storage does not track revisions //} - // if destination exists - if _, err := os.Stat(np); err == nil { - // create revision - if err := upload.fs.archiveRevision(upload.ctx, np); err != nil { - return err - } - } - err := os.Rename(upload.binPath, np) if err != nil { return err