github.com/cs3org/reva/v2@v2.27.7/pkg/storagespace/storagespace.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 storagespace
    20  
    21  import (
    22  	"path"
    23  	"strings"
    24  
    25  	provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
    26  	"github.com/cs3org/reva/v2/pkg/utils"
    27  	"github.com/pkg/errors"
    28  )
    29  
    30  const (
    31  	_idDelimiter        string = "!"
    32  	_storageIDDelimiter string = "$"
    33  )
    34  
    35  var (
    36  	// ErrInvalidSpaceReference signals that the space reference is invalid.
    37  	ErrInvalidSpaceReference = errors.New("invalid storage space reference")
    38  	// ErrInvalidSpaceID signals that the space ID is invalid.
    39  	ErrInvalidSpaceID = errors.New("invalid storage space id")
    40  )
    41  
    42  // SplitID splits a storage space ID into a provider ID and a node ID.
    43  // The accepted formats results of the storage space ID and respective results
    44  // are:
    45  // <storageid>$<spaceid>!<nodeid> 	-> <storageid>, <spaceid>, <nodeid>
    46  // <storageid>$<spaceid>			-> <storageid>, <spaceid>, ""
    47  // <spaceid>						-> "", <spaceid>, ""
    48  func SplitID(ssid string) (storageid, spaceid, nodeid string, err error) {
    49  	if ssid == "" {
    50  		return "", "", "", errors.Wrap(ErrInvalidSpaceID, "can't split empty storage space ID")
    51  	}
    52  
    53  	storageid, snid := SplitStorageID(ssid)
    54  	parts := strings.SplitN(snid, _idDelimiter, 2)
    55  	if len(parts) == 1 || parts[1] == "" {
    56  		return storageid, parts[0], "", nil
    57  	}
    58  
    59  	return storageid, parts[0], parts[1], nil
    60  }
    61  
    62  // SplitStorageID splits a storage ID into the storage ID and the spaceID.
    63  // The accepted formats are:
    64  // <storageid>$<spaceid>			-> <storageid>, <spaceid>
    65  // <spaceid>						-> "", <spaceid>
    66  func SplitStorageID(sid string) (storageID, spaceID string) {
    67  	parts := strings.SplitN(sid, _storageIDDelimiter, 2)
    68  	if len(parts) == 2 {
    69  		return parts[0], parts[1]
    70  	}
    71  	return "", parts[0]
    72  }
    73  
    74  // FormatResourceID converts a ResourceId into the string format.
    75  // The result format will look like:
    76  // <storageid>$<spaceid>!<opaqueid>
    77  func FormatResourceID(sid *provider.ResourceId) string {
    78  	if sid.GetOpaqueId() == "" {
    79  		return FormatStorageID(sid.GetStorageId(), sid.GetSpaceId())
    80  	}
    81  	return strings.Join([]string{FormatStorageID(sid.StorageId, sid.SpaceId), sid.OpaqueId}, _idDelimiter)
    82  }
    83  
    84  // FormatStorageID converts the provider ID and space ID into the string format.
    85  // The result format will look like:
    86  // <storageid>$<spaceid> or
    87  // <spaceid> in case the provider ID is empty.
    88  func FormatStorageID(storageID, spaceID string) string {
    89  	if storageID == "" {
    90  		return spaceID
    91  	}
    92  	return strings.Join([]string{storageID, spaceID}, _storageIDDelimiter)
    93  }
    94  
    95  // ParseID parses a storage space ID and returns a storageprovider ResourceId.
    96  // The accepted formats are:
    97  // <providerid>$<spaceid>!<nodeid> 	-> <providerid>$<spaceid>, <nodeid>
    98  // <providerid>$<spaceid>			-> <providerid>$<spaceid>, <spaceid>
    99  // <spaceid>						-> <spaceid>, <spaceid>
   100  func ParseID(ssid string) (provider.ResourceId, error) {
   101  	sid, spid, oid, err := SplitID(ssid)
   102  	return provider.ResourceId{
   103  		StorageId: sid,
   104  		SpaceId:   spid,
   105  		OpaqueId:  oid,
   106  	}, err
   107  }
   108  
   109  // ParseReference parses a string into a spaces reference.
   110  // The expected format is `<providerid>$<spaceid>!<nodeid>/<path>`.
   111  func ParseReference(sRef string) (provider.Reference, error) {
   112  	parts := strings.SplitN(sRef, "/", 2)
   113  
   114  	rid, err := ParseID(parts[0])
   115  	if err != nil {
   116  		return provider.Reference{}, err
   117  	}
   118  
   119  	var path string
   120  	if len(parts) == 2 {
   121  		path = parts[1]
   122  	}
   123  
   124  	return provider.Reference{
   125  		ResourceId: &rid,
   126  		Path:       utils.MakeRelativePath(path),
   127  	}, nil
   128  }
   129  
   130  // FormatReference will format a storage space reference into a string representation.
   131  // If ref or ref.ResourceId are nil an error will be returned.
   132  // The function doesn't check if all values are set.
   133  // The resulting format can be:
   134  //
   135  // "storage_id!opaque_id"
   136  // "storage_id!opaque_id/path"
   137  // "storage_id/path"
   138  // "storage_id"
   139  func FormatReference(ref *provider.Reference) (string, error) {
   140  	if ref == nil || ref.ResourceId == nil || ref.ResourceId.SpaceId == "" {
   141  		return "", ErrInvalidSpaceReference
   142  	}
   143  	ssid := FormatResourceID(ref.ResourceId)
   144  	return path.Join(ssid, ref.Path), nil
   145  }
   146  
   147  // UpdateLegacyResourceID checks if the given resource id contains a correct triple and will convert legacy ids without a spaceid
   148  // by splitting the storageid.
   149  func UpdateLegacyResourceID(id *provider.ResourceId) *provider.ResourceId {
   150  	if storageid, spaceid := SplitStorageID(id.StorageId); storageid != "" && id.SpaceId == "" {
   151  		return &provider.ResourceId{
   152  			StorageId: storageid,
   153  			SpaceId:   spaceid,
   154  			OpaqueId:  id.OpaqueId,
   155  		}
   156  	}
   157  	return id
   158  }