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  }