github.com/rclone/rclone@v1.66.1-0.20240517100346-7b89735ae726/cmd/serve/s3/utils.go (about) 1 package s3 2 3 import ( 4 "context" 5 "encoding/hex" 6 "fmt" 7 "io" 8 "os" 9 "path" 10 "strings" 11 12 "github.com/rclone/gofakes3" 13 "github.com/rclone/rclone/fs" 14 "github.com/rclone/rclone/fs/hash" 15 "github.com/rclone/rclone/vfs" 16 ) 17 18 func getDirEntries(prefix string, VFS *vfs.VFS) (vfs.Nodes, error) { 19 node, err := VFS.Stat(prefix) 20 21 if err == vfs.ENOENT { 22 return nil, gofakes3.ErrNoSuchKey 23 } else if err != nil { 24 return nil, err 25 } 26 27 if !node.IsDir() { 28 return nil, gofakes3.ErrNoSuchKey 29 } 30 31 dir := node.(*vfs.Dir) 32 dirEntries, err := dir.ReadDirAll() 33 if err != nil { 34 return nil, err 35 } 36 37 return dirEntries, nil 38 } 39 40 func getFileHashByte(node interface{}) []byte { 41 b, err := hex.DecodeString(getFileHash(node)) 42 if err != nil { 43 return nil 44 } 45 return b 46 } 47 48 func getFileHash(node interface{}) string { 49 var o fs.Object 50 51 switch b := node.(type) { 52 case vfs.Node: 53 fsObj, ok := b.DirEntry().(fs.Object) 54 if !ok { 55 fs.Debugf("serve s3", "File uploading - reading hash from VFS cache") 56 in, err := b.Open(os.O_RDONLY) 57 if err != nil { 58 return "" 59 } 60 defer func() { 61 _ = in.Close() 62 }() 63 h, err := hash.NewMultiHasherTypes(hash.NewHashSet(Opt.hashType)) 64 if err != nil { 65 return "" 66 } 67 _, err = io.Copy(h, in) 68 if err != nil { 69 return "" 70 } 71 return h.Sums()[Opt.hashType] 72 } 73 o = fsObj 74 case fs.Object: 75 o = b 76 } 77 78 hash, err := o.Hash(context.Background(), Opt.hashType) 79 if err != nil { 80 return "" 81 } 82 return hash 83 } 84 85 func prefixParser(p *gofakes3.Prefix) (path, remaining string) { 86 idx := strings.LastIndexByte(p.Prefix, '/') 87 if idx < 0 { 88 return "", p.Prefix 89 } 90 return p.Prefix[:idx], p.Prefix[idx+1:] 91 } 92 93 // FIXME this could be implemented by VFS.MkdirAll() 94 func mkdirRecursive(path string, VFS *vfs.VFS) error { 95 path = strings.Trim(path, "/") 96 dirs := strings.Split(path, "/") 97 dir := "" 98 for _, d := range dirs { 99 dir += "/" + d 100 if _, err := VFS.Stat(dir); err != nil { 101 err := VFS.Mkdir(dir, 0777) 102 if err != nil { 103 return err 104 } 105 } 106 } 107 return nil 108 } 109 110 func rmdirRecursive(p string, VFS *vfs.VFS) { 111 dir := path.Dir(p) 112 if !strings.ContainsAny(dir, "/\\") { 113 // might be bucket(root) 114 return 115 } 116 if _, err := VFS.Stat(dir); err == nil { 117 err := VFS.Remove(dir) 118 if err != nil { 119 return 120 } 121 rmdirRecursive(dir, VFS) 122 } 123 } 124 125 func authlistResolver(list []string) map[string]string { 126 authList := make(map[string]string) 127 for _, v := range list { 128 parts := strings.Split(v, ",") 129 if len(parts) != 2 { 130 fs.Infof(nil, fmt.Sprintf("Ignored: invalid auth pair %s", v)) 131 continue 132 } 133 authList[parts[0]] = parts[1] 134 } 135 return authList 136 }