Use hidden directory based on mount path

This commit is contained in:
Ben Johnson
2020-11-03 12:21:13 -07:00
parent 42f9ba9d1c
commit bcc6963db6
3 changed files with 53 additions and 16 deletions

View File

@@ -8,6 +8,7 @@ import (
"io/ioutil" "io/ioutil"
"log" "log"
"os" "os"
"path/filepath"
"bazil.org/fuse" "bazil.org/fuse"
"bazil.org/fuse/fs" "bazil.org/fuse/fs"
@@ -27,8 +28,8 @@ func main() {
type Main struct { type Main struct {
logger *log.Logger logger *log.Logger
SourcePath string TargetPath string
MountPath string Path string
} }
func NewMain() *Main { func NewMain() *Main {
@@ -39,19 +40,36 @@ func NewMain() *Main {
func (m *Main) Run(args []string) (err error) { func (m *Main) Run(args []string) (err error) {
flagSet := flag.NewFlagSet("litestream", flag.ContinueOnError) flagSet := flag.NewFlagSet("litestream", flag.ContinueOnError)
flagSet.StringVar(&m.TargetPath, "target", "", "target directory")
verbose := flagSet.Bool("v", false, "verbose") verbose := flagSet.Bool("v", false, "verbose")
flagSet.Usage = m.usage flagSet.Usage = m.usage
if err := flagSet.Parse(args); err != nil { if err := flagSet.Parse(args); err != nil {
return err return err
} }
// Ensure src & mount paths are specified. // Ensure mount path is specified.
if m.SourcePath = flagSet.Arg(0); m.SourcePath == "" { if flagSet.NArg() > 1 {
return errors.New("source path required") return errors.New("too many arguments, only specify mount path")
} else if m.MountPath = flagSet.Arg(1); m.MountPath == "" { } else if m.Path = flagSet.Arg(0); m.Path == "" {
return errors.New("mount path required") return errors.New("mount path required")
} }
// Ensure mount path exists & is a directory.
if fi, err := os.Stat(m.Path); err != nil {
return err
} else if !fi.IsDir() {
return fmt.Errorf("mount path must be a directory")
}
// If no target is specified, default to a hidden directory based on the mount path.
if m.TargetPath == "" {
m.TargetPath = filepath.Join(filepath.Dir(m.Path), "."+filepath.Base(m.Path))
if err := m.ensureTargetPath(); err != nil {
return err
}
}
// Setup logging, if verbose specified. // Setup logging, if verbose specified.
var config fs.Config var config fs.Config
if *verbose { if *verbose {
@@ -60,29 +78,48 @@ func (m *Main) Run(args []string) (err error) {
} }
// Mount FUSE filesystem. // Mount FUSE filesystem.
conn, err := fuse.Mount(m.MountPath, fuse.FSName("litestream"), fuse.Subtype("litestreamfs")) conn, err := fuse.Mount(m.Path, fuse.FSName("litestream"), fuse.Subtype("litestreamfs"))
if err != nil { if err != nil {
return err return err
} }
defer fuse.Unmount(m.MountPath) defer fuse.Unmount(m.Path)
defer conn.Close() defer conn.Close()
m.logger.Printf("mounted") m.logger.Printf("mounted %s; target=%s", m.Path, m.TargetPath)
s := fs.New(conn, &config) s := fs.New(conn, &config)
return s.Serve(&litestream.FileSystem{SourcePath: m.SourcePath}) return s.Serve(&litestream.FileSystem{TargetPath: m.TargetPath})
}
func (m *Main) ensureTargetPath() error {
// Check if target path exists, exit if it does.
if _, err := os.Stat(m.TargetPath); err == nil {
return nil
} else if err != nil && !os.IsNotExist(err) {
return err
}
// Create target path with the same permissions as the mount path.
fi, err := os.Stat(m.Path)
if err != nil {
return err
}
return os.Mkdir(m.TargetPath, fi.Mode())
} }
func (m *Main) usage() { func (m *Main) usage() {
fmt.Println(` fmt.Println(`
Litestream is a FUSE file system that automatically replicates SQLite databases. Litestream is a FUSE file system that replicates SQLite databases.
Usage: Usage:
litestream [arguments] source_dir mount_dir litestream [arguments] PATH
Arguments: Arguments:
-target PATH
Specifies the directory to store data.
Defaults to a hidden directory next to PATH.
-v -v
Enable verbose logging. Enable verbose logging.

View File

@@ -24,7 +24,7 @@ type FileSystem struct {
config Config // configuration file config Config // configuration file
// Filepath to the root of the source directory. // Filepath to the root of the source directory.
SourcePath string TargetPath string
} }
func NewFileSystem() *FileSystem { func NewFileSystem() *FileSystem {
@@ -35,7 +35,7 @@ func NewFileSystem() *FileSystem {
// ConfigPath returns the path to the file system config file. // ConfigPath returns the path to the file system config file.
func (f *FileSystem) ConfigPath() string { func (f *FileSystem) ConfigPath() string {
return filepath.Join(f.SourcePath, ConfigName) return filepath.Join(f.TargetPath, ConfigName)
} }
// Open initializes the file system and finds all managed database files. // Open initializes the file system and finds all managed database files.

View File

@@ -42,7 +42,7 @@ func NewNode(fs *FileSystem, path string) *Node {
} }
func (n *Node) srcpath() string { func (n *Node) srcpath() string {
return filepath.Join(n.fs.SourcePath, n.path) return filepath.Join(n.fs.TargetPath, n.path)
} }
func (n *Node) Attr(ctx context.Context, a *fuse.Attr) (err error) { func (n *Node) Attr(ctx context.Context, a *fuse.Attr) (err error) {
@@ -82,7 +82,7 @@ func (n *Node) Attr(ctx context.Context, a *fuse.Attr) (err error) {
// Lookup need not to handle the names "." and "..". // Lookup need not to handle the names "." and "..".
func (n *Node) Lookup(ctx context.Context, name string) (_ fs.Node, err error) { func (n *Node) Lookup(ctx context.Context, name string) (_ fs.Node, err error) {
path := filepath.Join(n.path, name) path := filepath.Join(n.path, name)
srcpath := filepath.Join(n.fs.SourcePath, path) srcpath := filepath.Join(n.fs.TargetPath, path)
if _, err := os.Stat(srcpath); os.IsNotExist(err) { if _, err := os.Stat(srcpath); os.IsNotExist(err) {
return nil, syscall.ENOENT return nil, syscall.ENOENT
} }