github.com/cs3org/reva/v2@v2.27.7/internal/grpc/services/storageprovider/storageprovider.go (about) 1 // Copyright 2018-2021 CERN 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 // 15 // In applying this license, CERN does not waive the privileges and immunities 16 // granted to it by virtue of its status as an Intergovernmental Organization 17 // or submit itself to any jurisdiction. 18 19 package storageprovider 20 21 import ( 22 "context" 23 "encoding/json" 24 "fmt" 25 "net/url" 26 "os" 27 "path" 28 "sort" 29 "strconv" 30 "strings" 31 "time" 32 33 rpc "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1" 34 provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1" 35 typesv1beta1 "github.com/cs3org/go-cs3apis/cs3/types/v1beta1" 36 "github.com/cs3org/reva/v2/pkg/appctx" 37 "github.com/cs3org/reva/v2/pkg/conversions" 38 ctxpkg "github.com/cs3org/reva/v2/pkg/ctx" 39 "github.com/cs3org/reva/v2/pkg/errtypes" 40 "github.com/cs3org/reva/v2/pkg/events" 41 "github.com/cs3org/reva/v2/pkg/events/stream" 42 "github.com/cs3org/reva/v2/pkg/mime" 43 "github.com/cs3org/reva/v2/pkg/rgrpc" 44 "github.com/cs3org/reva/v2/pkg/rgrpc/status" 45 "github.com/cs3org/reva/v2/pkg/rhttp/router" 46 "github.com/cs3org/reva/v2/pkg/storage" 47 "github.com/cs3org/reva/v2/pkg/storage/fs/registry" 48 "github.com/cs3org/reva/v2/pkg/storagespace" 49 "github.com/cs3org/reva/v2/pkg/utils" 50 "github.com/mitchellh/mapstructure" 51 "github.com/pkg/errors" 52 "github.com/rs/zerolog" 53 "go.opentelemetry.io/otel/attribute" 54 "google.golang.org/grpc" 55 ) 56 57 // name is the Tracer name used to identify this instrumentation library. 58 const tracerName = "storageprovider" 59 60 func init() { 61 rgrpc.Register("storageprovider", New) 62 } 63 64 type config struct { 65 Driver string `mapstructure:"driver" docs:"localhome;The storage driver to be used."` 66 Drivers map[string]map[string]interface{} `mapstructure:"drivers" docs:"url:pkg/storage/fs/localhome/localhome.go"` 67 DataServerURL string `mapstructure:"data_server_url" docs:"http://localhost/data;The URL for the data server."` 68 ExposeDataServer bool `mapstructure:"expose_data_server" docs:"false;Whether to expose data server."` // if true the client will be able to upload/download directly to it 69 AvailableXS map[string]uint32 `mapstructure:"available_checksums" docs:"nil;List of available checksums."` 70 CustomMimeTypesJSON string `mapstructure:"custom_mimetypes_json" docs:"nil;An optional mapping file with the list of supported custom file extensions and corresponding mime types."` 71 MountID string `mapstructure:"mount_id"` 72 UploadExpiration int64 `mapstructure:"upload_expiration" docs:"0;Duration for how long uploads will be valid."` 73 Events eventconfig `mapstructure:"events" docs:"0;Event stream configuration"` 74 } 75 76 type eventconfig struct { 77 Endpoint string `mapstructure:"nats_address" docs:"address of the nats server"` 78 Cluster string `mapstructure:"nats_clusterid" docs:"clusterid of the nats server"` 79 TLSInsecure bool `mapstructure:"tls_insecure" docs:"Whether to verify the server TLS certificates."` 80 TLSRootCACertificate string `mapstructure:"tls_root_ca_cert" docs:"The root CA certificate used to validate the server's TLS certificate."` 81 EnableTLS bool `mapstructure:"nats_enable_tls" docs:"events tls switch"` 82 AuthUsername string `mapstructure:"nats_username" docs:"event stream username"` 83 AuthPassword string `mapstructure:"nats_password" docs:"event stream password"` 84 } 85 86 func (c *config) init() { 87 if c.Driver == "" { 88 c.Driver = "localhome" 89 } 90 91 if c.DataServerURL == "" { 92 host, err := os.Hostname() 93 if err != nil || host == "" { 94 c.DataServerURL = "http://0.0.0.0:19001/data" 95 } else { 96 c.DataServerURL = fmt.Sprintf("http://%s:19001/data", host) 97 } 98 } 99 100 // set sane defaults 101 if len(c.AvailableXS) == 0 { 102 c.AvailableXS = map[string]uint32{"md5": 100, "unset": 1000} 103 } 104 } 105 106 type Service struct { 107 conf *config 108 Storage storage.FS 109 dataServerURL *url.URL 110 availableXS []*provider.ResourceChecksumPriority 111 } 112 113 func (s *Service) Close() error { 114 return s.Storage.Shutdown(context.Background()) 115 } 116 117 func (s *Service) UnprotectedEndpoints() []string { return []string{} } 118 119 func (s *Service) Register(ss *grpc.Server) { 120 provider.RegisterProviderAPIServer(ss, s) 121 provider.RegisterSpacesAPIServer(ss, s) 122 } 123 124 func parseXSTypes(xsTypes map[string]uint32) ([]*provider.ResourceChecksumPriority, error) { 125 var types = make([]*provider.ResourceChecksumPriority, 0, len(xsTypes)) 126 for xs, prio := range xsTypes { 127 t := PKG2GRPCXS(xs) 128 if t == provider.ResourceChecksumType_RESOURCE_CHECKSUM_TYPE_INVALID { 129 return nil, errtypes.BadRequest("checksum type is invalid: " + xs) 130 } 131 xsPrio := &provider.ResourceChecksumPriority{ 132 Priority: prio, 133 Type: t, 134 } 135 types = append(types, xsPrio) 136 } 137 return types, nil 138 } 139 140 func parseConfig(m map[string]interface{}) (*config, error) { 141 c := &config{} 142 if err := mapstructure.Decode(m, c); err != nil { 143 err = errors.Wrap(err, "error decoding conf") 144 return nil, err 145 } 146 return c, nil 147 } 148 149 func registerMimeTypes(mappingFile string) error { 150 if mappingFile != "" { 151 f, err := os.ReadFile(mappingFile) 152 if err != nil { 153 return fmt.Errorf("storageprovider: error reading the custom mime types file: +%v", err) 154 } 155 mimeTypes := map[string]string{} 156 err = json.Unmarshal(f, &mimeTypes) 157 if err != nil { 158 return fmt.Errorf("storageprovider: error unmarshalling the custom mime types file: +%v", err) 159 } 160 // register all mime types that were read 161 for e, m := range mimeTypes { 162 mime.RegisterMime(e, m) 163 } 164 } 165 return nil 166 } 167 168 // New creates a new storage provider svc 169 func New(m map[string]interface{}, ss *grpc.Server, log *zerolog.Logger) (rgrpc.Service, error) { 170 171 c, err := parseConfig(m) 172 if err != nil { 173 return nil, err 174 } 175 176 c.init() 177 178 fs, err := getFS(c, log) 179 if err != nil { 180 return nil, err 181 } 182 183 // parse data server url 184 u, err := url.Parse(c.DataServerURL) 185 if err != nil { 186 return nil, err 187 } 188 189 // validate available checksums 190 xsTypes, err := parseXSTypes(c.AvailableXS) 191 if err != nil { 192 return nil, err 193 } 194 195 if len(xsTypes) == 0 { 196 return nil, errtypes.NotFound("no available checksum, please set in config") 197 } 198 199 // read and register custom mime types if configured 200 err = registerMimeTypes(c.CustomMimeTypesJSON) 201 if err != nil { 202 return nil, err 203 } 204 205 service := &Service{ 206 conf: c, 207 Storage: fs, 208 dataServerURL: u, 209 availableXS: xsTypes, 210 } 211 212 return service, nil 213 } 214 215 func (s *Service) SetArbitraryMetadata(ctx context.Context, req *provider.SetArbitraryMetadataRequest) (*provider.SetArbitraryMetadataResponse, error) { 216 ctx = ctxpkg.ContextSetLockID(ctx, req.LockId) 217 218 err := s.Storage.SetArbitraryMetadata(ctx, req.Ref, req.ArbitraryMetadata) 219 220 return &provider.SetArbitraryMetadataResponse{ 221 Status: status.NewStatusFromErrType(ctx, "set arbitrary metadata", err), 222 }, nil 223 } 224 225 func (s *Service) UnsetArbitraryMetadata(ctx context.Context, req *provider.UnsetArbitraryMetadataRequest) (*provider.UnsetArbitraryMetadataResponse, error) { 226 ctx = ctxpkg.ContextSetLockID(ctx, req.LockId) 227 228 err := s.Storage.UnsetArbitraryMetadata(ctx, req.Ref, req.ArbitraryMetadataKeys) 229 230 return &provider.UnsetArbitraryMetadataResponse{ 231 Status: status.NewStatusFromErrType(ctx, "unset arbitrary metadata", err), 232 }, nil 233 } 234 235 // SetLock puts a lock on the given reference 236 func (s *Service) SetLock(ctx context.Context, req *provider.SetLockRequest) (*provider.SetLockResponse, error) { 237 if !canLockPublicShare(ctx) { 238 return &provider.SetLockResponse{ 239 Status: status.NewPermissionDenied(ctx, nil, "no permission to lock the share"), 240 }, nil 241 } 242 err := s.Storage.SetLock(ctx, req.Ref, req.Lock) 243 244 return &provider.SetLockResponse{ 245 Status: status.NewStatusFromErrType(ctx, "set lock", err), 246 }, nil 247 } 248 249 // GetLock returns an existing lock on the given reference 250 func (s *Service) GetLock(ctx context.Context, req *provider.GetLockRequest) (*provider.GetLockResponse, error) { 251 lock, err := s.Storage.GetLock(ctx, req.Ref) 252 253 return &provider.GetLockResponse{ 254 Status: status.NewStatusFromErrType(ctx, "get lock", err), 255 Lock: lock, 256 }, nil 257 } 258 259 // RefreshLock refreshes an existing lock on the given reference 260 func (s *Service) RefreshLock(ctx context.Context, req *provider.RefreshLockRequest) (*provider.RefreshLockResponse, error) { 261 if !canLockPublicShare(ctx) { 262 return &provider.RefreshLockResponse{ 263 Status: status.NewPermissionDenied(ctx, nil, "no permission to refresh the share lock"), 264 }, nil 265 } 266 267 err := s.Storage.RefreshLock(ctx, req.Ref, req.Lock, req.ExistingLockId) 268 269 return &provider.RefreshLockResponse{ 270 Status: status.NewStatusFromErrType(ctx, "refresh lock", err), 271 }, nil 272 } 273 274 // Unlock removes an existing lock from the given reference 275 func (s *Service) Unlock(ctx context.Context, req *provider.UnlockRequest) (*provider.UnlockResponse, error) { 276 if !canLockPublicShare(ctx) { 277 return &provider.UnlockResponse{ 278 Status: status.NewPermissionDenied(ctx, nil, "no permission to unlock the share"), 279 }, nil 280 } 281 282 err := s.Storage.Unlock(ctx, req.Ref, req.Lock) 283 284 return &provider.UnlockResponse{ 285 Status: status.NewStatusFromErrType(ctx, "unlock", err), 286 }, nil 287 } 288 289 func (s *Service) InitiateFileDownload(ctx context.Context, req *provider.InitiateFileDownloadRequest) (*provider.InitiateFileDownloadResponse, error) { 290 // TODO(labkode): maybe add some checks before download starts? eg. check permissions? 291 // TODO(labkode): maybe add short-lived token? 292 // We now simply point the client to the data server. 293 // For example, https://data-server.example.org/home/docs/myfile.txt 294 // or ownclouds://data-server.example.org/home/docs/myfile.txt 295 log := appctx.GetLogger(ctx) 296 u := *s.dataServerURL 297 log.Info().Str("data-server", u.String()).Interface("ref", req.Ref).Msg("file download") 298 299 protocol := &provider.FileDownloadProtocol{Expose: s.conf.ExposeDataServer} 300 301 if utils.IsRelativeReference(req.Ref) { 302 s.addMissingStorageProviderID(req.GetRef().GetResourceId(), nil) 303 protocol.Protocol = "spaces" 304 u.Path = path.Join(u.Path, "spaces", storagespace.FormatResourceID(req.Ref.ResourceId), req.Ref.Path) 305 } else { 306 // Currently, we only support the simple protocol for GET requests 307 // Once we have multiple protocols, this would be moved to the fs layer 308 protocol.Protocol = "simple" 309 u.Path = path.Join(u.Path, "simple", req.Ref.GetPath()) 310 } 311 312 protocol.DownloadEndpoint = u.String() 313 314 return &provider.InitiateFileDownloadResponse{ 315 Protocols: []*provider.FileDownloadProtocol{protocol}, 316 Status: status.NewOK(ctx), 317 }, nil 318 } 319 320 func validateIfMatch(ifMatch string, info *provider.ResourceInfo) bool { 321 return ifMatch == info.GetEtag() 322 } 323 324 func validateIfUnmodifiedSince(ifUnmodifiedSince *typesv1beta1.Timestamp, info *provider.ResourceInfo) bool { 325 switch { 326 case ifUnmodifiedSince == nil || info.GetMtime() == nil: 327 return true 328 case utils.LaterTS(info.GetMtime(), ifUnmodifiedSince) == info.GetMtime(): 329 return false 330 default: 331 return true 332 } 333 } 334 335 func (s *Service) InitiateFileUpload(ctx context.Context, req *provider.InitiateFileUploadRequest) (*provider.InitiateFileUploadResponse, error) { 336 // TODO(labkode): same considerations as download 337 log := appctx.GetLogger(ctx) 338 if req.Ref.GetPath() == "/" { 339 return &provider.InitiateFileUploadResponse{ 340 Status: status.NewInternal(ctx, "can't upload to mount path"), 341 }, nil 342 } 343 344 // FIXME move the etag check into the InitiateUpload call instead of making a Stat call here 345 sRes, err := s.Stat(ctx, &provider.StatRequest{Ref: req.Ref}) 346 if err != nil { 347 return nil, err 348 } 349 switch sRes.Status.Code { 350 case rpc.Code_CODE_OK: 351 if req.GetIfNotExist() { 352 return &provider.InitiateFileUploadResponse{ 353 Status: status.NewAlreadyExists(ctx, errors.New("already exists"), "already exists"), 354 }, nil 355 } 356 case rpc.Code_CODE_NOT_FOUND: 357 // Just continue with a normal upload 358 default: 359 return &provider.InitiateFileUploadResponse{ 360 Status: sRes.Status, 361 }, nil 362 } 363 364 metadata := map[string]string{} 365 ifMatch := req.GetIfMatch() 366 if ifMatch != "" { 367 if !validateIfMatch(ifMatch, sRes.GetInfo()) { 368 return &provider.InitiateFileUploadResponse{ 369 Status: status.NewFailedPrecondition(ctx, errors.New("etag mismatch"), "etag mismatch"), 370 }, nil 371 } 372 metadata["if-match"] = ifMatch 373 } 374 ifUnmodifiedSince := req.GetIfUnmodifiedSince() 375 if ifUnmodifiedSince != nil { 376 metadata["if-unmodified-since"] = utils.TSToTime(ifUnmodifiedSince).Format(time.RFC3339Nano) 377 if !validateIfUnmodifiedSince(ifUnmodifiedSince, sRes.GetInfo()) { 378 return &provider.InitiateFileUploadResponse{ 379 Status: status.NewFailedPrecondition(ctx, errors.New("resource has been modified"), "resource has been modified"), 380 }, nil 381 } 382 } 383 384 ctx = ctxpkg.ContextSetLockID(ctx, req.LockId) 385 386 var uploadLength int64 387 if req.Opaque != nil && req.Opaque.Map != nil { 388 if req.Opaque.Map["Upload-Length"] != nil { 389 var err error 390 uploadLength, err = strconv.ParseInt(string(req.Opaque.Map["Upload-Length"].Value), 10, 64) 391 if err != nil { 392 log.Error().Err(err).Msg("error parsing upload length") 393 return &provider.InitiateFileUploadResponse{ 394 Status: status.NewInternal(ctx, "error parsing upload length"), 395 }, nil 396 } 397 } 398 // TUS forward Upload-Checksum header as checksum, uses '[type] [hash]' format 399 if req.Opaque.Map["Upload-Checksum"] != nil { 400 metadata["checksum"] = string(req.Opaque.Map["Upload-Checksum"].Value) 401 } 402 // ownCloud mtime to set for the uploaded file 403 if req.Opaque.Map["X-OC-Mtime"] != nil { 404 metadata["mtime"] = string(req.Opaque.Map["X-OC-Mtime"].Value) 405 } 406 } 407 408 // pass on the provider it to be persisted with the upload info. that is required to correlate the upload with the proper provider later on 409 metadata["providerID"] = s.conf.MountID 410 var expirationTimestamp *typesv1beta1.Timestamp 411 if s.conf.UploadExpiration > 0 { 412 expirationTimestamp = &typesv1beta1.Timestamp{ 413 Seconds: uint64(time.Now().UTC().Add(time.Duration(s.conf.UploadExpiration) * time.Second).Unix()), 414 } 415 metadata["expires"] = strconv.Itoa(int(expirationTimestamp.Seconds)) 416 } 417 418 uploadIDs, err := s.Storage.InitiateUpload(ctx, req.Ref, uploadLength, metadata) 419 if err != nil { 420 var st *rpc.Status 421 switch err.(type) { 422 case errtypes.IsNotFound: 423 st = status.NewNotFound(ctx, "path not found when initiating upload") 424 case errtypes.IsBadRequest, errtypes.IsChecksumMismatch: 425 st = status.NewInvalid(ctx, err.Error()) 426 // TODO TUS uses a custom ChecksumMismatch 460 http status which is in an unassigned range in 427 // https://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml 428 // maybe 409 conflict is good enough 429 // someone is proposing `419 Checksum Error`, see https://stackoverflow.com/a/35665694 430 // - it is also unassigned 431 // - ends in 9 as the 409 conflict 432 // - is near the 4xx errors about conditions: 415 Unsupported Media Type, 416 Range Not Satisfiable or 417 Expectation Failed 433 // owncloud only expects a 400 Bad request so InvalidArg is good enough for now 434 // seealso errtypes.StatusChecksumMismatch 435 case errtypes.PermissionDenied: 436 st = status.NewPermissionDenied(ctx, err, "permission denied") 437 case errtypes.InsufficientStorage: 438 st = status.NewInsufficientStorage(ctx, err, "insufficient storage") 439 case errtypes.PreconditionFailed: 440 st = status.NewFailedPrecondition(ctx, err, "failed precondition") 441 case errtypes.Locked: 442 st = status.NewLocked(ctx, "locked") 443 default: 444 st = status.NewInternal(ctx, "error getting upload id: "+err.Error()) 445 } 446 log.Error(). 447 Err(err). 448 Interface("status", st). 449 Msg("failed to initiate upload") 450 return &provider.InitiateFileUploadResponse{ 451 Status: st, 452 }, nil 453 } 454 455 protocols := make([]*provider.FileUploadProtocol, len(uploadIDs)) 456 var i int 457 for protocol, ID := range uploadIDs { 458 u := *s.dataServerURL 459 u.Path = path.Join(u.Path, protocol, ID) 460 protocols[i] = &provider.FileUploadProtocol{ 461 Protocol: protocol, 462 UploadEndpoint: u.String(), 463 AvailableChecksums: s.availableXS, 464 Expose: s.conf.ExposeDataServer, 465 Expiration: expirationTimestamp, 466 } 467 i++ 468 log.Info().Str("data-server", u.String()). 469 Str("fn", req.Ref.GetPath()). 470 Str("xs", fmt.Sprintf("%+v", s.conf.AvailableXS)). 471 Msg("file upload") 472 } 473 474 res := &provider.InitiateFileUploadResponse{ 475 Protocols: protocols, 476 Status: status.NewOK(ctx), 477 } 478 // FIXME make created flag a property on the InitiateFileUploadResponse 479 if sRes.Status.Code == rpc.Code_CODE_NOT_FOUND { 480 res.Opaque = utils.AppendPlainToOpaque(res.Opaque, "created", "true") 481 } 482 return res, nil 483 } 484 485 func (s *Service) GetPath(ctx context.Context, req *provider.GetPathRequest) (*provider.GetPathResponse, error) { 486 // TODO(labkode): check that the storage ID is the same as the storage provider id. 487 fn, err := s.Storage.GetPathByID(ctx, req.ResourceId) 488 if err != nil { 489 return &provider.GetPathResponse{ 490 Status: status.NewStatusFromErrType(ctx, "get path", err), 491 }, nil 492 } 493 res := &provider.GetPathResponse{ 494 Path: fn, 495 Status: status.NewOK(ctx), 496 } 497 return res, nil 498 } 499 500 func (s *Service) GetHome(ctx context.Context, req *provider.GetHomeRequest) (*provider.GetHomeResponse, error) { 501 return nil, errtypes.NotSupported("unused, use the gateway to look up the user home") 502 } 503 504 func (s *Service) CreateHome(ctx context.Context, req *provider.CreateHomeRequest) (*provider.CreateHomeResponse, error) { 505 return nil, errtypes.NotSupported("use CreateStorageSpace with type personal") 506 } 507 508 // CreateStorageSpace creates a storage space 509 func (s *Service) CreateStorageSpace(ctx context.Context, req *provider.CreateStorageSpaceRequest) (*provider.CreateStorageSpaceResponse, error) { 510 resp, err := s.Storage.CreateStorageSpace(ctx, req) 511 if err != nil { 512 var st *rpc.Status 513 switch err.(type) { 514 case errtypes.IsNotFound: 515 st = status.NewNotFound(ctx, "not found when creating space") 516 case errtypes.PermissionDenied: 517 st = status.NewPermissionDenied(ctx, err, "permission denied") 518 case errtypes.NotSupported: 519 // if trying to create a user home fall back to CreateHome 520 if u, ok := ctxpkg.ContextGetUser(ctx); ok && req.Type == "personal" && utils.UserEqual(req.GetOwner().Id, u.Id) { 521 if err := s.Storage.CreateHome(ctx); err != nil { 522 st = status.NewInternal(ctx, "error creating home") 523 } else { 524 st = status.NewOK(ctx) 525 // TODO we cannot return a space, but the gateway currently does not expect one... 526 } 527 } else { 528 st = status.NewUnimplemented(ctx, err, "not implemented") 529 } 530 case errtypes.AlreadyExists: 531 st = status.NewAlreadyExists(ctx, err, "already exists") 532 case errtypes.BadRequest: 533 st = status.NewInvalid(ctx, err.Error()) 534 default: 535 st = status.NewInternal(ctx, "error creating space") 536 appctx.GetLogger(ctx). 537 Error(). 538 Err(err). 539 Interface("status", st). 540 Interface("request", req). 541 Msg("failed to create storage space") 542 } 543 return &provider.CreateStorageSpaceResponse{ 544 Status: st, 545 }, nil 546 } 547 548 s.addMissingStorageProviderID(resp.GetStorageSpace().GetRoot(), resp.GetStorageSpace().GetId()) 549 return resp, nil 550 } 551 552 func (s *Service) ListStorageSpaces(ctx context.Context, req *provider.ListStorageSpacesRequest) (*provider.ListStorageSpacesResponse, error) { 553 log := appctx.GetLogger(ctx) 554 555 // TODO this is just temporary. Update the API to include this flag. 556 unrestricted := false 557 if req.Opaque != nil { 558 if entry, ok := req.Opaque.Map["unrestricted"]; ok { 559 unrestricted, _ = strconv.ParseBool(string(entry.Value)) 560 } 561 } 562 563 spaces, err := s.Storage.ListStorageSpaces(ctx, req.Filters, unrestricted) 564 if err != nil { 565 var st *rpc.Status 566 switch err.(type) { 567 case errtypes.IsNotFound: 568 st = status.NewNotFound(ctx, "not found when listing spaces") 569 case errtypes.PermissionDenied: 570 st = status.NewPermissionDenied(ctx, err, "permission denied") 571 case errtypes.NotSupported: 572 st = status.NewUnimplemented(ctx, err, "not implemented") 573 default: 574 st = status.NewInternal(ctx, "error listing spaces") 575 } 576 log.Error(). 577 Err(err). 578 Interface("status", st). 579 Interface("filters", req.Filters). 580 Msg("failed to list storage spaces") 581 return &provider.ListStorageSpacesResponse{ 582 Status: st, 583 }, nil 584 } 585 586 for _, sp := range spaces { 587 if sp.Id == nil || sp.Id.OpaqueId == "" { 588 log.Error().Str("service", "storageprovider").Str("driver", s.conf.Driver).Interface("space", sp).Msg("space is missing space id and root id") 589 continue 590 } 591 592 s.addMissingStorageProviderID(sp.GetRoot(), sp.GetId()) 593 } 594 595 return &provider.ListStorageSpacesResponse{ 596 Status: status.NewOK(ctx), 597 StorageSpaces: spaces, 598 }, nil 599 } 600 601 func (s *Service) UpdateStorageSpace(ctx context.Context, req *provider.UpdateStorageSpaceRequest) (*provider.UpdateStorageSpaceResponse, error) { 602 res, err := s.Storage.UpdateStorageSpace(ctx, req) 603 if err != nil { 604 appctx.GetLogger(ctx). 605 Error(). 606 Err(err). 607 Interface("req", req). 608 Msg("failed to update storage space") 609 return nil, err 610 } 611 s.addMissingStorageProviderID(res.GetStorageSpace().GetRoot(), res.GetStorageSpace().GetId()) 612 return res, nil 613 } 614 615 func (s *Service) DeleteStorageSpace(ctx context.Context, req *provider.DeleteStorageSpaceRequest) (*provider.DeleteStorageSpaceResponse, error) { 616 // we need to get the space before so we can return critical information 617 // FIXME: why is this string parsing necessary? 618 idraw, _ := storagespace.ParseID(req.Id.GetOpaqueId()) 619 idraw.OpaqueId = idraw.GetSpaceId() 620 id := &provider.StorageSpaceId{OpaqueId: storagespace.FormatResourceID(&idraw)} 621 622 spaces, err := s.Storage.ListStorageSpaces(ctx, []*provider.ListStorageSpacesRequest_Filter{{Type: provider.ListStorageSpacesRequest_Filter_TYPE_ID, Term: &provider.ListStorageSpacesRequest_Filter_Id{Id: id}}}, true) 623 if err != nil { 624 var st *rpc.Status 625 switch err.(type) { 626 case errtypes.IsNotFound: 627 st = status.NewNotFound(ctx, "space not found") 628 case errtypes.PermissionDenied: 629 st = status.NewPermissionDenied(ctx, err, "permission denied") 630 case errtypes.BadRequest: 631 st = status.NewInvalid(ctx, err.Error()) 632 default: 633 st = status.NewInternal(ctx, "error deleting space: "+req.Id.String()) 634 } 635 return &provider.DeleteStorageSpaceResponse{ 636 Status: st, 637 }, nil 638 } else if len(spaces) != 1 { 639 return &provider.DeleteStorageSpaceResponse{ 640 Status: status.NewNotFound(ctx, "space not found"), 641 }, nil 642 } 643 644 if err := s.Storage.DeleteStorageSpace(ctx, req); err != nil { 645 var st *rpc.Status 646 switch err.(type) { 647 case errtypes.IsNotFound: 648 st = status.NewNotFound(ctx, "space not found") 649 case errtypes.PermissionDenied: 650 st = status.NewPermissionDenied(ctx, err, "permission denied") 651 case errtypes.BadRequest: 652 st = status.NewInvalid(ctx, err.Error()) 653 default: 654 st = status.NewInternal(ctx, "error deleting space: "+req.Id.String()) 655 } 656 appctx.GetLogger(ctx). 657 Error(). 658 Err(err). 659 Interface("status", st). 660 Interface("storage_space_id", req.Id). 661 Msg("failed to delete storage space") 662 return &provider.DeleteStorageSpaceResponse{ 663 Status: st, 664 }, nil 665 } 666 667 // TODO: update cs3api 668 o := utils.AppendPlainToOpaque(nil, "spacename", spaces[0].GetName()) 669 o.Map["grants"] = spaces[0].GetOpaque().GetMap()["grants"] 670 671 res := &provider.DeleteStorageSpaceResponse{ 672 Opaque: o, 673 Status: status.NewOK(ctx), 674 } 675 return res, nil 676 } 677 678 func (s *Service) CreateContainer(ctx context.Context, req *provider.CreateContainerRequest) (*provider.CreateContainerResponse, error) { 679 // FIXME these should be part of the CreateContainerRequest object 680 if req.Opaque != nil { 681 if e, ok := req.Opaque.Map["lockid"]; ok && e.Decoder == "plain" { 682 ctx = ctxpkg.ContextSetLockID(ctx, string(e.Value)) 683 } 684 } 685 686 err := s.Storage.CreateDir(ctx, req.Ref) 687 688 return &provider.CreateContainerResponse{ 689 Status: status.NewStatusFromErrType(ctx, "create container", err), 690 }, nil 691 } 692 693 func (s *Service) TouchFile(ctx context.Context, req *provider.TouchFileRequest) (*provider.TouchFileResponse, error) { 694 // FIXME these should be part of the TouchFileRequest object 695 var mtime string 696 if req.Opaque != nil { 697 if e, ok := req.Opaque.Map["lockid"]; ok && e.Decoder == "plain" { 698 ctx = ctxpkg.ContextSetLockID(ctx, string(e.Value)) 699 } 700 mtime = utils.ReadPlainFromOpaque(req.Opaque, "X-OC-Mtime") 701 } 702 703 err := s.Storage.TouchFile(ctx, req.Ref, utils.ExistsInOpaque(req.Opaque, "markprocessing"), mtime) 704 705 return &provider.TouchFileResponse{ 706 Status: status.NewStatusFromErrType(ctx, "touch file", err), 707 }, nil 708 } 709 710 func (s *Service) Delete(ctx context.Context, req *provider.DeleteRequest) (*provider.DeleteResponse, error) { 711 if req.Ref.GetPath() == "/" { 712 return &provider.DeleteResponse{ 713 Status: status.NewInternal(ctx, "can't delete mount path"), 714 }, nil 715 } 716 717 ctx = ctxpkg.ContextSetLockID(ctx, req.LockId) 718 719 // check DeleteRequest for any known opaque properties. 720 // FIXME these should be part of the DeleteRequest object 721 if req.Opaque != nil { 722 if _, ok := req.Opaque.Map["deleting_shared_resource"]; ok { 723 // it is a binary key; its existence signals true. Although, do not assume. 724 ctx = appctx.WithDeletingSharedResource(ctx) 725 } 726 } 727 728 md, err := s.Storage.GetMD(ctx, req.Ref, []string{}, []string{"id", "status"}) 729 if err != nil { 730 return &provider.DeleteResponse{ 731 Status: status.NewStatusFromErrType(ctx, "can't stat resource to delete", err), 732 }, nil 733 } 734 735 if utils.ReadPlainFromOpaque(md.GetOpaque(), "status") == "processing" { 736 return &provider.DeleteResponse{ 737 Status: &rpc.Status{ 738 Code: rpc.Code_CODE_TOO_EARLY, 739 Message: "file is processing", 740 }, 741 Opaque: &typesv1beta1.Opaque{ 742 Map: map[string]*typesv1beta1.OpaqueEntry{ 743 "status": {Decoder: "plain", Value: []byte("processing")}, 744 }, 745 }, 746 }, nil 747 } 748 749 err = s.Storage.Delete(ctx, req.Ref) 750 751 return &provider.DeleteResponse{ 752 Status: status.NewStatusFromErrType(ctx, "delete", err), 753 Opaque: &typesv1beta1.Opaque{ 754 Map: map[string]*typesv1beta1.OpaqueEntry{ 755 "opaque_id": {Decoder: "plain", Value: []byte(md.Id.OpaqueId)}, 756 }, 757 }, 758 }, nil 759 } 760 761 func (s *Service) Move(ctx context.Context, req *provider.MoveRequest) (*provider.MoveResponse, error) { 762 ctx = ctxpkg.ContextSetLockID(ctx, req.LockId) 763 764 err := s.Storage.Move(ctx, req.Source, req.Destination) 765 766 return &provider.MoveResponse{ 767 Status: status.NewStatusFromErrType(ctx, "move", err), 768 }, nil 769 } 770 771 func (s *Service) Stat(ctx context.Context, req *provider.StatRequest) (*provider.StatResponse, error) { 772 ctx, span := appctx.GetTracerProvider(ctx).Tracer(tracerName).Start(ctx, "stat") 773 defer span.End() 774 775 span.SetAttributes(attribute.KeyValue{ 776 Key: "reference", 777 Value: attribute.StringValue(req.GetRef().String()), 778 }) 779 780 md, err := s.Storage.GetMD(ctx, req.GetRef(), req.GetArbitraryMetadataKeys(), req.GetFieldMask().GetPaths()) 781 if err != nil { 782 return &provider.StatResponse{ 783 Status: status.NewStatusFromErrType(ctx, "stat", err), 784 }, nil 785 } 786 787 s.addMissingStorageProviderID(md.GetId(), nil) 788 s.addMissingStorageProviderID(md.GetParentId(), nil) 789 s.addMissingStorageProviderID(md.GetSpace().GetRoot(), nil) 790 791 return &provider.StatResponse{ 792 Status: status.NewOK(ctx), 793 Info: md, 794 }, nil 795 } 796 797 func (s *Service) ListContainerStream(req *provider.ListContainerStreamRequest, ss provider.ProviderAPI_ListContainerStreamServer) error { 798 ctx := ss.Context() 799 log := appctx.GetLogger(ctx) 800 801 mds, err := s.Storage.ListFolder(ctx, req.GetRef(), req.GetArbitraryMetadataKeys(), req.GetFieldMask().GetPaths()) 802 if err != nil { 803 var st *rpc.Status 804 switch err.(type) { 805 case errtypes.IsNotFound: 806 st = status.NewNotFound(ctx, "path not found when listing container") 807 case errtypes.PermissionDenied: 808 st = status.NewPermissionDenied(ctx, err, "permission denied") 809 default: 810 st = status.NewInternal(ctx, "error listing container: "+req.Ref.String()) 811 } 812 log.Error(). 813 Err(err). 814 Interface("status", st). 815 Interface("reference", req.Ref). 816 Msg("failed to list folder (stream)") 817 res := &provider.ListContainerStreamResponse{ 818 Status: st, 819 } 820 if err := ss.Send(res); err != nil { 821 log.Error().Err(err).Msg("ListContainerStream: error sending response") 822 return err 823 } 824 return nil 825 } 826 827 for _, md := range mds { 828 s.addMissingStorageProviderID(md.GetId(), nil) 829 s.addMissingStorageProviderID(md.GetParentId(), nil) 830 s.addMissingStorageProviderID(md.GetSpace().GetRoot(), nil) 831 res := &provider.ListContainerStreamResponse{ 832 Info: md, 833 Status: status.NewOK(ctx), 834 } 835 836 if err := ss.Send(res); err != nil { 837 log.Error().Err(err).Msg("ListContainerStream: error sending response") 838 return err 839 } 840 } 841 return nil 842 } 843 844 func (s *Service) ListContainer(ctx context.Context, req *provider.ListContainerRequest) (*provider.ListContainerResponse, error) { 845 mds, err := s.Storage.ListFolder(ctx, req.GetRef(), req.GetArbitraryMetadataKeys(), req.GetFieldMask().GetPaths()) 846 res := &provider.ListContainerResponse{ 847 Status: status.NewStatusFromErrType(ctx, "list container", err), 848 Infos: mds, 849 } 850 if err != nil { 851 return res, nil 852 } 853 854 for _, i := range res.Infos { 855 s.addMissingStorageProviderID(i.GetId(), nil) 856 s.addMissingStorageProviderID(i.GetParentId(), nil) 857 s.addMissingStorageProviderID(i.GetSpace().GetRoot(), nil) 858 } 859 return res, nil 860 } 861 862 func (s *Service) ListFileVersions(ctx context.Context, req *provider.ListFileVersionsRequest) (*provider.ListFileVersionsResponse, error) { 863 revs, err := s.Storage.ListRevisions(ctx, req.Ref) 864 865 sort.Sort(descendingMtime(revs)) 866 867 return &provider.ListFileVersionsResponse{ 868 Status: status.NewStatusFromErrType(ctx, "list file versions", err), 869 Versions: revs, 870 }, nil 871 } 872 873 func (s *Service) RestoreFileVersion(ctx context.Context, req *provider.RestoreFileVersionRequest) (*provider.RestoreFileVersionResponse, error) { 874 ctx = ctxpkg.ContextSetLockID(ctx, req.LockId) 875 876 err := s.Storage.RestoreRevision(ctx, req.Ref, req.Key) 877 878 return &provider.RestoreFileVersionResponse{ 879 Status: status.NewStatusFromErrType(ctx, "restore file version", err), 880 }, nil 881 } 882 883 func (s *Service) ListRecycleStream(req *provider.ListRecycleStreamRequest, ss provider.ProviderAPI_ListRecycleStreamServer) error { 884 ctx := ss.Context() 885 log := appctx.GetLogger(ctx) 886 887 // if no slash is present in the key, do not pass a relative path to the storage 888 // when a path is passed to the storage, it will list the contents of the directory 889 key, relativePath := splitKeyAndPath(req.GetKey()) 890 items, err := s.Storage.ListRecycle(ctx, req.Ref, key, relativePath) 891 892 if err != nil { 893 var st *rpc.Status 894 switch err.(type) { 895 case errtypes.IsNotFound: 896 st = status.NewNotFound(ctx, "resource not found when listing recycle stream") 897 case errtypes.PermissionDenied: 898 st = status.NewPermissionDenied(ctx, err, "permission denied") 899 default: 900 st = status.NewInternal(ctx, "error listing recycle stream") 901 } 902 log.Error(). 903 Err(err). 904 Interface("status", st). 905 Interface("reference", req.Ref). 906 Str("key", req.Key). 907 Msg("failed to list recycle (stream)") 908 res := &provider.ListRecycleStreamResponse{ 909 Status: st, 910 } 911 if err := ss.Send(res); err != nil { 912 log.Error().Err(err).Msg("ListRecycleStream: error sending response") 913 return err 914 } 915 return nil 916 } 917 918 // TODO(labkode): CRITICAL: fill recycle info with storage provider. 919 for _, item := range items { 920 s.addMissingStorageProviderID(item.GetRef().GetResourceId(), nil) 921 res := &provider.ListRecycleStreamResponse{ 922 RecycleItem: item, 923 Status: status.NewOK(ctx), 924 } 925 if err := ss.Send(res); err != nil { 926 log.Error().Err(err).Msg("ListRecycleStream: error sending response") 927 return err 928 } 929 } 930 return nil 931 } 932 933 func (s *Service) ListRecycle(ctx context.Context, req *provider.ListRecycleRequest) (*provider.ListRecycleResponse, error) { 934 // if no slash is present in the key, do not pass a relative path to the storage 935 // when a path is passed to the storage, it will list the contents of the directory 936 key, relativePath := splitKeyAndPath(req.GetKey()) 937 items, err := s.Storage.ListRecycle(ctx, req.Ref, key, relativePath) 938 if err != nil { 939 var st *rpc.Status 940 switch err.(type) { 941 case errtypes.IsNotFound: 942 st = status.NewNotFound(ctx, "resource not found when listing recycle") 943 case errtypes.PermissionDenied: 944 st = status.NewPermissionDenied(ctx, err, "permission denied") 945 default: 946 st = status.NewInternal(ctx, "error listing recycle") 947 } 948 appctx.GetLogger(ctx). 949 Error(). 950 Err(err). 951 Interface("status", st). 952 Interface("reference", req.Ref). 953 Str("key", req.Key). 954 Msg("failed to list recycle") 955 return &provider.ListRecycleResponse{ 956 Status: st, 957 }, nil 958 } 959 960 for _, i := range items { 961 s.addMissingStorageProviderID(i.GetRef().GetResourceId(), nil) 962 } 963 res := &provider.ListRecycleResponse{ 964 Status: status.NewOK(ctx), 965 RecycleItems: items, 966 } 967 return res, nil 968 } 969 970 func (s *Service) RestoreRecycleItem(ctx context.Context, req *provider.RestoreRecycleItemRequest) (*provider.RestoreRecycleItemResponse, error) { 971 ctx = ctxpkg.ContextSetLockID(ctx, req.LockId) 972 973 // TODO(labkode): CRITICAL: fill recycle info with storage provider. 974 key, relativePath := splitKeyAndPath(req.GetKey()) 975 err := s.Storage.RestoreRecycleItem(ctx, req.Ref, key, relativePath, req.RestoreRef) 976 977 res := &provider.RestoreRecycleItemResponse{ 978 Status: status.NewStatusFromErrType(ctx, "restore recycle item", err), 979 } 980 return res, nil 981 } 982 983 func (s *Service) PurgeRecycle(ctx context.Context, req *provider.PurgeRecycleRequest) (*provider.PurgeRecycleResponse, error) { 984 // FIXME these should be part of the PurgeRecycleRequest object 985 if req.Opaque != nil { 986 if e, ok := req.Opaque.Map["lockid"]; ok && e.Decoder == "plain" { 987 ctx = ctxpkg.ContextSetLockID(ctx, string(e.Value)) 988 } 989 } 990 991 // if a key was sent as opaque id purge only that item 992 key, relativePath := splitKeyAndPath(req.GetKey()) 993 if key != "" { 994 if err := s.Storage.PurgeRecycleItem(ctx, req.Ref, key, relativePath); err != nil { 995 st := status.NewStatusFromErrType(ctx, "error purging recycle item", err) 996 appctx.GetLogger(ctx). 997 Error(). 998 Err(err). 999 Interface("status", st). 1000 Interface("reference", req.Ref). 1001 Str("key", req.Key). 1002 Msg("failed to purge recycle item") 1003 return &provider.PurgeRecycleResponse{ 1004 Status: st, 1005 }, nil 1006 } 1007 } else if err := s.Storage.EmptyRecycle(ctx, req.Ref); err != nil { 1008 // otherwise try emptying the whole recycle bin 1009 st := status.NewStatusFromErrType(ctx, "error emptying recycle", err) 1010 appctx.GetLogger(ctx). 1011 Error(). 1012 Err(err). 1013 Interface("status", st). 1014 Interface("reference", req.Ref). 1015 Str("key", req.Key). 1016 Msg("failed to empty recycle") 1017 return &provider.PurgeRecycleResponse{ 1018 Status: st, 1019 }, nil 1020 } 1021 1022 res := &provider.PurgeRecycleResponse{ 1023 Status: status.NewOK(ctx), 1024 } 1025 return res, nil 1026 } 1027 1028 func (s *Service) ListGrants(ctx context.Context, req *provider.ListGrantsRequest) (*provider.ListGrantsResponse, error) { 1029 grants, err := s.Storage.ListGrants(ctx, req.Ref) 1030 if err != nil { 1031 var st *rpc.Status 1032 switch err.(type) { 1033 case errtypes.IsNotFound: 1034 st = status.NewNotFound(ctx, "path not found when listing grants") 1035 case errtypes.PermissionDenied: 1036 st = status.NewPermissionDenied(ctx, err, "permission denied") 1037 default: 1038 st = status.NewInternal(ctx, "error listing grants") 1039 } 1040 appctx.GetLogger(ctx). 1041 Error(). 1042 Err(err). 1043 Interface("status", st). 1044 Interface("reference", req.Ref). 1045 Msg("failed to list grants") 1046 return &provider.ListGrantsResponse{ 1047 Status: st, 1048 }, nil 1049 } 1050 1051 res := &provider.ListGrantsResponse{ 1052 Status: status.NewOK(ctx), 1053 Grants: grants, 1054 } 1055 return res, nil 1056 } 1057 1058 func (s *Service) DenyGrant(ctx context.Context, req *provider.DenyGrantRequest) (*provider.DenyGrantResponse, error) { 1059 // check grantee type is valid 1060 if req.Grantee.Type == provider.GranteeType_GRANTEE_TYPE_INVALID { 1061 return &provider.DenyGrantResponse{ 1062 Status: status.NewInvalid(ctx, "grantee type is invalid"), 1063 }, nil 1064 } 1065 1066 err := s.Storage.DenyGrant(ctx, req.Ref, req.Grantee) 1067 if err != nil { 1068 var st *rpc.Status 1069 switch err.(type) { 1070 case errtypes.NotSupported: 1071 // ignore - setting storage grants is optional 1072 return &provider.DenyGrantResponse{ 1073 Status: status.NewOK(ctx), 1074 }, nil 1075 case errtypes.IsNotFound: 1076 st = status.NewNotFound(ctx, "path not found when setting grants") 1077 case errtypes.PermissionDenied: 1078 st = status.NewPermissionDenied(ctx, err, "permission denied") 1079 default: 1080 st = status.NewInternal(ctx, "error setting grants") 1081 } 1082 appctx.GetLogger(ctx). 1083 Error(). 1084 Err(err). 1085 Interface("status", st). 1086 Interface("reference", req.Ref). 1087 Msg("failed to deny grant") 1088 return &provider.DenyGrantResponse{ 1089 Status: st, 1090 }, nil 1091 } 1092 1093 res := &provider.DenyGrantResponse{ 1094 Status: status.NewOK(ctx), 1095 } 1096 return res, nil 1097 } 1098 1099 type spaceTypeKey struct{} 1100 1101 func WithSpaceType(ctx context.Context, spaceType string) context.Context { 1102 return context.WithValue(ctx, spaceTypeKey{}, spaceType) 1103 } 1104 func SpaceTypeFromContext(ctx context.Context) (string, bool) { 1105 spaceType, ok := ctx.Value(spaceTypeKey{}).(string) 1106 return spaceType, ok 1107 } 1108 1109 func (s *Service) AddGrant(ctx context.Context, req *provider.AddGrantRequest) (*provider.AddGrantResponse, error) { 1110 ctx = ctxpkg.ContextSetLockID(ctx, req.LockId) 1111 1112 // TODO: update CS3 APIs 1113 // FIXME these should be part of the AddGrantRequest object 1114 // https://github.com/owncloud/ocis/issues/4312 1115 if utils.ExistsInOpaque(req.Opaque, "spacegrant") { 1116 ctx = WithSpaceType(ctx, utils.ReadPlainFromOpaque(req.Opaque, "spacetype")) 1117 } 1118 1119 // check grantee type is valid 1120 if req.Grant.Grantee.Type == provider.GranteeType_GRANTEE_TYPE_INVALID { 1121 return &provider.AddGrantResponse{ 1122 Status: status.NewInvalid(ctx, "grantee type is invalid"), 1123 }, nil 1124 } 1125 1126 err := s.Storage.AddGrant(ctx, req.Ref, req.Grant) 1127 1128 return &provider.AddGrantResponse{ 1129 Status: status.NewStatusFromErrType(ctx, "add grant", err), 1130 }, nil 1131 } 1132 1133 func (s *Service) UpdateGrant(ctx context.Context, req *provider.UpdateGrantRequest) (*provider.UpdateGrantResponse, error) { 1134 // FIXME these should be part of the UpdateGrantRequest object 1135 if req.Opaque != nil { 1136 if e, ok := req.Opaque.Map["lockid"]; ok && e.Decoder == "plain" { 1137 ctx = ctxpkg.ContextSetLockID(ctx, string(e.Value)) 1138 } 1139 } 1140 1141 // TODO: update CS3 APIs 1142 // FIXME these should be part of the AddGrantRequest object 1143 // https://github.com/owncloud/ocis/issues/4312 1144 if utils.ExistsInOpaque(req.Opaque, "spacegrant") { 1145 ctx = WithSpaceType(ctx, utils.ReadPlainFromOpaque(req.Opaque, "spacetype")) 1146 } 1147 1148 // check grantee type is valid 1149 if req.Grant.Grantee.Type == provider.GranteeType_GRANTEE_TYPE_INVALID { 1150 return &provider.UpdateGrantResponse{ 1151 Status: status.NewInvalid(ctx, "grantee type is invalid"), 1152 }, nil 1153 } 1154 1155 err := s.Storage.UpdateGrant(ctx, req.Ref, req.Grant) 1156 1157 return &provider.UpdateGrantResponse{ 1158 Status: status.NewStatusFromErrType(ctx, "update grant", err), 1159 }, nil 1160 } 1161 1162 func (s *Service) RemoveGrant(ctx context.Context, req *provider.RemoveGrantRequest) (*provider.RemoveGrantResponse, error) { 1163 ctx = ctxpkg.ContextSetLockID(ctx, req.LockId) 1164 1165 // check targetType is valid 1166 if req.Grant.Grantee.Type == provider.GranteeType_GRANTEE_TYPE_INVALID { 1167 return &provider.RemoveGrantResponse{ 1168 Status: status.NewInvalid(ctx, "grantee type is invalid"), 1169 }, nil 1170 } 1171 1172 // TODO: update CS3 APIs 1173 // FIXME these should be part of the RemoveGrantRequest object 1174 // https://github.com/owncloud/ocis/issues/4312 1175 if utils.ExistsInOpaque(req.Opaque, "spacegrant") { 1176 ctx = WithSpaceType(ctx, "") 1177 } 1178 1179 err := s.Storage.RemoveGrant(ctx, req.Ref, req.Grant) 1180 1181 return &provider.RemoveGrantResponse{ 1182 Status: status.NewStatusFromErrType(ctx, "remove grant", err), 1183 }, nil 1184 } 1185 1186 func (s *Service) CreateReference(ctx context.Context, req *provider.CreateReferenceRequest) (*provider.CreateReferenceResponse, error) { 1187 log := appctx.GetLogger(ctx) 1188 1189 // parse uri is valid 1190 u, err := url.Parse(req.TargetUri) 1191 if err != nil { 1192 log.Error().Err(err).Msg("invalid target uri") 1193 return &provider.CreateReferenceResponse{ 1194 Status: status.NewInvalid(ctx, "target uri is invalid: "+err.Error()), 1195 }, nil 1196 } 1197 1198 if err := s.Storage.CreateReference(ctx, req.Ref.GetPath(), u); err != nil { 1199 var st *rpc.Status 1200 switch err.(type) { 1201 case errtypes.IsNotFound: 1202 st = status.NewNotFound(ctx, "path not found when creating reference") 1203 case errtypes.PermissionDenied: 1204 st = status.NewPermissionDenied(ctx, err, "permission denied") 1205 default: 1206 st = status.NewInternal(ctx, "error creating reference") 1207 } 1208 log.Error(). 1209 Err(err). 1210 Interface("status", st). 1211 Interface("reference", req.Ref). 1212 Msg("failed to create reference") 1213 return &provider.CreateReferenceResponse{ 1214 Status: st, 1215 }, nil 1216 } 1217 1218 return &provider.CreateReferenceResponse{ 1219 Status: status.NewOK(ctx), 1220 }, nil 1221 } 1222 1223 func (s *Service) CreateSymlink(ctx context.Context, req *provider.CreateSymlinkRequest) (*provider.CreateSymlinkResponse, error) { 1224 return &provider.CreateSymlinkResponse{ 1225 Status: status.NewUnimplemented(ctx, errtypes.NotSupported("CreateSymlink not implemented"), "CreateSymlink not implemented"), 1226 }, nil 1227 } 1228 1229 func (s *Service) GetQuota(ctx context.Context, req *provider.GetQuotaRequest) (*provider.GetQuotaResponse, error) { 1230 total, used, remaining, err := s.Storage.GetQuota(ctx, req.Ref) 1231 if err != nil { 1232 var st *rpc.Status 1233 switch err.(type) { 1234 case errtypes.IsNotFound: 1235 st = status.NewNotFound(ctx, "path not found when getting quota") 1236 case errtypes.PermissionDenied: 1237 st = status.NewPermissionDenied(ctx, err, "permission denied") 1238 default: 1239 st = status.NewInternal(ctx, "error getting quota") 1240 } 1241 appctx.GetLogger(ctx). 1242 Error(). 1243 Err(err). 1244 Interface("status", st). 1245 Interface("reference", req.Ref). 1246 Msg("failed to get quota") 1247 return &provider.GetQuotaResponse{ 1248 Status: st, 1249 }, nil 1250 } 1251 1252 res := &provider.GetQuotaResponse{ 1253 Opaque: &typesv1beta1.Opaque{ 1254 Map: map[string]*typesv1beta1.OpaqueEntry{ 1255 "remaining": { 1256 Decoder: "plain", 1257 Value: []byte(strconv.FormatUint(remaining, 10)), 1258 }, 1259 }, 1260 }, 1261 Status: status.NewOK(ctx), 1262 TotalBytes: total, 1263 UsedBytes: used, 1264 } 1265 return res, nil 1266 } 1267 1268 func (s *Service) addMissingStorageProviderID(resourceID *provider.ResourceId, spaceID *provider.StorageSpaceId) { 1269 // The storage driver might set the mount ID by itself, in which case skip this step 1270 if resourceID != nil && resourceID.GetStorageId() == "" { 1271 resourceID.StorageId = s.conf.MountID 1272 if spaceID != nil { 1273 rid, _ := storagespace.ParseID(spaceID.GetOpaqueId()) 1274 rid.StorageId = s.conf.MountID 1275 spaceID.OpaqueId, _ = storagespace.FormatReference(&provider.Reference{ResourceId: &rid}) 1276 } 1277 } 1278 } 1279 1280 func getFS(c *config, log *zerolog.Logger) (storage.FS, error) { 1281 evstream, err := estreamFromConfig(c.Events) 1282 if err != nil { 1283 return nil, err 1284 } 1285 1286 if f, ok := registry.NewFuncs[c.Driver]; ok { 1287 driverConf := c.Drivers[c.Driver] 1288 driverConf["mount_id"] = c.MountID // pass the mount id to the driver 1289 1290 return f(driverConf, evstream, log) 1291 } 1292 1293 return nil, errtypes.NotFound("driver not found: " + c.Driver) 1294 } 1295 1296 type descendingMtime []*provider.FileVersion 1297 1298 func (v descendingMtime) Len() int { 1299 return len(v) 1300 } 1301 1302 func (v descendingMtime) Less(i, j int) bool { 1303 return v[i].Mtime >= v[j].Mtime 1304 } 1305 1306 func (v descendingMtime) Swap(i, j int) { 1307 v[i], v[j] = v[j], v[i] 1308 } 1309 1310 func estreamFromConfig(c eventconfig) (events.Stream, error) { 1311 if c.Endpoint == "" { 1312 return nil, nil 1313 } 1314 1315 return stream.NatsFromConfig("storageprovider", false, stream.NatsConfig(c)) 1316 } 1317 1318 func canLockPublicShare(ctx context.Context) bool { 1319 u := ctxpkg.ContextMustGetUser(ctx) 1320 psr := utils.ReadPlainFromOpaque(u.Opaque, "public-share-role") 1321 return psr == "" || psr == conversions.RoleEditor 1322 } 1323 1324 // splitKeyAndPath splits a key into a root and a relative path 1325 func splitKeyAndPath(key string) (string, string) { 1326 root, relativePath := router.ShiftPath(key) 1327 if relativePath == "/" && !strings.HasSuffix(key, "/") { 1328 relativePath = "" 1329 } 1330 return root, relativePath 1331 }