82ab4b0983
This also adds some generic handling of stale umounts. Fuse returns immediately and does not indicate that the mounter has finished writing to the backend. The process finding is sort of hacky as I could not find a better way to get to the PID from a fuse mount.
112 lines
2.3 KiB
Go
112 lines
2.3 KiB
Go
package s3
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"net/url"
|
|
"os"
|
|
"os/exec"
|
|
"path"
|
|
"strings"
|
|
|
|
"gopkg.in/ini.v1"
|
|
)
|
|
|
|
// Implements Mounter
|
|
type s3qlMounter struct {
|
|
bucket string
|
|
url string
|
|
bucketURL string
|
|
login string
|
|
password string
|
|
passphrase string
|
|
options []string
|
|
ssl bool
|
|
targetPath string
|
|
}
|
|
|
|
const (
|
|
s3qlCmdMkfs = "mkfs.s3ql"
|
|
s3qlCmdMount = "mount.s3ql"
|
|
s3qlCmdUnmount = "umount.s3ql"
|
|
)
|
|
|
|
func newS3qlMounter(bucket string, cfg *Config) (Mounter, error) {
|
|
url, err := url.Parse(cfg.Endpoint)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
ssl := url.Scheme != "http"
|
|
if strings.Contains(url.Scheme, "http") {
|
|
url.Scheme = "s3c"
|
|
}
|
|
s3ql := &s3qlMounter{
|
|
bucket: bucket,
|
|
url: url.String(),
|
|
login: cfg.AccessKeyID,
|
|
password: cfg.SecretAccessKey,
|
|
passphrase: cfg.EncryptionKey,
|
|
ssl: ssl,
|
|
}
|
|
|
|
url.Path = path.Join(url.Path, bucket)
|
|
s3ql.bucketURL = url.String()
|
|
|
|
if !ssl {
|
|
s3ql.options = []string{"--backend-options", "no-ssl"}
|
|
}
|
|
|
|
return s3ql, s3ql.writeConfig()
|
|
}
|
|
|
|
func (s3ql *s3qlMounter) Format() error {
|
|
// force creation to ignore existing data
|
|
args := []string{
|
|
s3ql.bucketURL,
|
|
"--force",
|
|
}
|
|
|
|
p := fmt.Sprintf("%s\n%s\n", s3ql.passphrase, s3ql.passphrase)
|
|
reader := bytes.NewReader([]byte(p))
|
|
cmd := exec.Command(s3qlCmdMkfs, append(args, s3ql.options...)...)
|
|
cmd.Stdin = reader
|
|
|
|
out, err := cmd.CombinedOutput()
|
|
if err != nil {
|
|
return fmt.Errorf("Error running s3ql command: %s", out)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (s3ql *s3qlMounter) Mount(targetPath string) error {
|
|
args := []string{
|
|
s3ql.bucketURL,
|
|
targetPath,
|
|
"--allow-other",
|
|
}
|
|
return fuseMount(targetPath, s3qlCmdMount, append(args, s3ql.options...))
|
|
}
|
|
|
|
func (s3ql *s3qlMounter) Unmount(targetPath string) error {
|
|
return fuseUnmount(targetPath, s3qlCmdMount)
|
|
}
|
|
|
|
func (s3ql *s3qlMounter) writeConfig() error {
|
|
s3qlIni := ini.Empty()
|
|
section, err := s3qlIni.NewSection("s3ql")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
section.NewKey("storage-url", s3ql.url)
|
|
section.NewKey("backend-login", s3ql.login)
|
|
section.NewKey("backend-password", s3ql.password)
|
|
section.NewKey("fs-passphrase", s3ql.passphrase)
|
|
|
|
authDir := os.Getenv("HOME") + "/.s3ql"
|
|
authFile := authDir + "/authinfo2"
|
|
os.Mkdir(authDir, 0700)
|
|
s3qlIni.SaveTo(authFile)
|
|
os.Chmod(authFile, 0600)
|
|
return nil
|
|
}
|