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 }