github.com/cs3org/reva/v2@v2.27.7/pkg/storage/fs/cephfs/utils.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  //go:build ceph
    20  // +build ceph
    21  
    22  package cephfs
    23  
    24  import (
    25  	"crypto/md5"
    26  	"encoding/hex"
    27  	"fmt"
    28  	"io"
    29  	"os"
    30  	"path/filepath"
    31  	"strconv"
    32  	"strings"
    33  
    34  	cephfs2 "github.com/ceph/go-ceph/cephfs"
    35  	provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
    36  )
    37  
    38  // Mount type
    39  type Mount = *cephfs2.MountInfo
    40  
    41  // Statx type
    42  type Statx = *cephfs2.CephStatx
    43  
    44  var dirPermFull = uint32(0777)
    45  var dirPermDefault = uint32(0775)
    46  var filePermDefault = uint32(0660)
    47  
    48  func closeDir(directory *cephfs2.Directory) {
    49  	if directory != nil {
    50  		_ = directory.Close()
    51  	}
    52  }
    53  
    54  func closeFile(file *cephfs2.File) {
    55  	if file != nil {
    56  		_ = file.Close()
    57  	}
    58  }
    59  
    60  func destroyCephConn(mt Mount, perm *cephfs2.UserPerm) *cacheVal {
    61  	if perm != nil {
    62  		perm.Destroy()
    63  	}
    64  	if mt != nil {
    65  		_ = mt.Release()
    66  	}
    67  	return nil
    68  }
    69  
    70  func deleteFile(mount *cephfs2.MountInfo, path string) {
    71  	_ = mount.Unlink(path)
    72  }
    73  
    74  func isDir(t provider.ResourceType) bool {
    75  	return t == provider.ResourceType_RESOURCE_TYPE_CONTAINER
    76  }
    77  
    78  func (fs *cephfs) makeFIDPath(fid string) string {
    79  	return "" //filepath.Join(fs.conf.EIDFolder, fid)
    80  }
    81  
    82  func (fs *cephfs) makeFID(absolutePath string, inode string) (rid *provider.ResourceId, err error) {
    83  	sum := md5.New()
    84  	sum.Write([]byte(absolutePath))
    85  	fid := fmt.Sprintf("%s-%s", hex.EncodeToString(sum.Sum(nil)), inode)
    86  	rid = &provider.ResourceId{OpaqueId: fid}
    87  
    88  	_ = fs.adminConn.adminMount.Link(absolutePath, fs.makeFIDPath(fid))
    89  	_ = fs.adminConn.adminMount.SetXattr(absolutePath, xattrEID, []byte(fid), 0)
    90  
    91  	return
    92  }
    93  
    94  func (fs *cephfs) getFIDPath(cv *cacheVal, path string) (fid string, err error) {
    95  	var buffer []byte
    96  	if buffer, err = cv.mount.GetXattr(path, xattrEID); err != nil {
    97  		return
    98  	}
    99  
   100  	return fs.makeFIDPath(string(buffer)), err
   101  }
   102  
   103  func calcChecksum(filepath string, mt Mount, stat Statx) (checksum string, err error) {
   104  	file, err := mt.Open(filepath, os.O_RDONLY, 0)
   105  	defer closeFile(file)
   106  	if err != nil {
   107  		return
   108  	}
   109  	hash := md5.New()
   110  	if _, err = io.Copy(hash, file); err != nil {
   111  		return
   112  	}
   113  	checksum = hex.EncodeToString(hash.Sum(nil))
   114  	// we don't care if they fail, the checksum will just be recalculated if an error happens
   115  	_ = mt.SetXattr(filepath, xattrMd5ts, []byte(strconv.FormatInt(stat.Mtime.Sec, 10)), 0)
   116  	_ = mt.SetXattr(filepath, xattrMd5, []byte(checksum), 0)
   117  
   118  	return
   119  }
   120  
   121  func resolveRevRef(mt Mount, ref *provider.Reference, revKey string) (str string, err error) {
   122  	var buf []byte
   123  	if ref.GetResourceId() != nil {
   124  		str, err = mt.Readlink(filepath.Join(snap, revKey, ref.ResourceId.OpaqueId))
   125  		if err != nil {
   126  			return "", fmt.Errorf("cephfs: invalid reference %+v", ref)
   127  		}
   128  	} else if str = ref.GetPath(); str != "" {
   129  		buf, err = mt.GetXattr(str, xattrEID)
   130  		if err != nil {
   131  			return
   132  		}
   133  		str, err = mt.Readlink(filepath.Join(snap, revKey, string(buf)))
   134  		if err != nil {
   135  			return
   136  		}
   137  	} else {
   138  		return "", fmt.Errorf("cephfs: empty reference %+v", ref)
   139  	}
   140  
   141  	return filepath.Join(snap, revKey, str), err
   142  }
   143  
   144  func removeLeadingSlash(path string) string {
   145  	return filepath.Join(".", path)
   146  }
   147  
   148  func addLeadingSlash(path string) string {
   149  	return filepath.Join("/", path)
   150  }
   151  
   152  func in(lookup string, list []string) bool {
   153  	for _, item := range list {
   154  		if item == lookup {
   155  			return true
   156  		}
   157  	}
   158  	return false
   159  }
   160  
   161  func pathGenerator(path string, reverse bool, str chan string) {
   162  	if reverse {
   163  		str <- path
   164  		for i := range path {
   165  			if path[len(path)-i-1] == filepath.Separator {
   166  				str <- path[:len(path)-i-1]
   167  			}
   168  		}
   169  	} else {
   170  		for i := range path {
   171  			if path[i] == filepath.Separator {
   172  				str <- path[:i]
   173  			}
   174  		}
   175  		str <- path
   176  	}
   177  
   178  	close(str)
   179  }
   180  
   181  func walkPath(path string, f func(string) error, reverse bool) (err error) {
   182  	paths := make(chan string)
   183  	go pathGenerator(path, reverse, paths)
   184  	for path := range paths {
   185  		if path == "" {
   186  			continue
   187  		}
   188  		if err = f(path); err != nil && err.Error() != errFileExists && err.Error() != errNotFound {
   189  			break
   190  		} else {
   191  			err = nil
   192  		}
   193  	}
   194  
   195  	return
   196  }
   197  
   198  func (fs *cephfs) writeIndex(oid string, value string) (err error) {
   199  	return fs.adminConn.radosIO.WriteFull(oid, []byte(value))
   200  }
   201  
   202  func (fs *cephfs) removeIndex(oid string) error {
   203  	return fs.adminConn.radosIO.Delete(oid)
   204  }
   205  
   206  func (fs *cephfs) resolveIndex(oid string) (fullPath string, err error) {
   207  	var i int
   208  	var currPath strings.Builder
   209  	root := string(filepath.Separator)
   210  	offset := uint64(0)
   211  	io := fs.adminConn.radosIO
   212  	bsize := 4096
   213  	buffer := make([]byte, bsize)
   214  	for {
   215  		for { //read object
   216  			i, err = io.Read(oid, buffer, offset)
   217  			offset += uint64(bsize)
   218  			currPath.Write(buffer)
   219  			if err == nil && i >= bsize {
   220  				buffer = buffer[:0]
   221  				continue
   222  			} else {
   223  				offset = 0
   224  				break
   225  			}
   226  		}
   227  		if err != nil {
   228  			return
   229  		}
   230  
   231  		ss := strings.SplitN(currPath.String(), string(filepath.Separator), 2)
   232  		if len(ss) != 2 {
   233  			if currPath.String() == root {
   234  				return
   235  			}
   236  
   237  			return "", fmt.Errorf("cephfs: entry id is not in the form of \"parentID/entryname\"")
   238  		}
   239  		parentOID := ss[0]
   240  		entryName := ss[1]
   241  		fullPath = filepath.Join(entryName, fullPath)
   242  		oid = parentOID
   243  		currPath.Reset()
   244  	}
   245  }