added support for mounting snapshots as drive letters and opening them in explorer on Windows.

This commit is contained in:
Jarek
2017-09-05 19:01:51 -07:00
parent 82657f957d
commit fa80f40185
3 changed files with 107 additions and 23 deletions

View File

@@ -16,7 +16,7 @@
mountCommand = app.Command("mount", "Mount repository object as a local filesystem.")
mountObjectID = mountCommand.Arg("path", "Identifier of the directory to mount.").Required().String()
mountPoint = mountCommand.Arg("mountPoint", "Mount point").Required().ExistingDir()
mountPoint = mountCommand.Arg("mountPoint", "Mount point").Required().String()
mountTraceFS = mountCommand.Flag("trace-fs", "Trace filesystem operations").Bool()
mountCacheRefreshInterval = mountCommand.Flag("cache-refresh", "Cache refresh interval").Default("600s").Duration()
)

View File

@@ -0,0 +1,70 @@
package cli
import (
"os"
"os/exec"
"runtime"
"github.com/skratchdot/open-golang/open"
)
var (
mountBrowser = mountCommand.Flag("browse", "Browse mounted filesystem using the provided method").Default("OS").Enum("NONE", "WEB", "OS")
)
var mountBrowsers = map[string]func(mountPoint string, addr string) error{
"NONE": nil,
"WEB": openInWebBrowser,
"OS": openInOSBrowser,
}
func browseMount(mountPoint string, addr string) error {
b := mountBrowsers[*mountBrowser]
if b == nil {
return nil
}
return b(mountPoint, addr)
}
func openInWebBrowser(mountPoint string, addr string) error {
open.Start(addr)
return nil
}
func openInOSBrowser(mountPoint string, addr string) error {
if runtime.GOOS == "windows" {
return netUSE(mountPoint, addr)
}
open.Start(addr)
return nil
}
func netUSE(mountPoint string, addr string) error {
c := exec.Command("net", "use", mountPoint, addr)
c.Stdout = os.Stdout
c.Stderr = os.Stderr
c.Stdin = os.Stdin
c.Run()
open.Start("x:\\")
// Wait until ctrl-c pressed
done := make(chan bool)
onCtrlC(func() {
if done != nil {
close(done)
done = nil
}
})
<-done
c = exec.Command("net", "use", mountPoint, "/d")
c.Stdout = os.Stdout
c.Stderr = os.Stderr
c.Stdin = os.Stdin
c.Run()
return nil
}

View File

@@ -6,6 +6,7 @@
"log"
"net/http"
"os"
"sync"
"golang.org/x/net/webdav"
@@ -13,22 +14,35 @@
"github.com/kopia/kopia/internal/webdavmount"
)
var (
traceWebDAVServer = mountCommand.Flag("trace-webdav", "Enable tracing on WebDAV server").Hidden().Bool()
)
func webdavServerLogger(r *http.Request, err error) {
var maybeRange string
if r := r.Header.Get("Range"); r != "" {
maybeRange = " " + r
}
if err != nil {
log.Printf("%v %v%v err: %v", r.Method, r.URL.RequestURI(), maybeRange, err)
} else {
log.Printf("%v %v%v OK", r.Method, r.URL.RequestURI(), maybeRange)
}
}
func mountDirectoryWebDAV(entry fs.Directory, mountPoint string) error {
mux := http.NewServeMux()
var logger func(r *http.Request, err error)
if *traceWebDAVServer {
logger = webdavServerLogger
}
mux.Handle("/", &webdav.Handler{
FileSystem: webdavmount.WebDAVFS(entry),
LockSystem: webdav.NewMemLS(),
Logger: func(r *http.Request, err error) {
var maybeRange string
if r := r.Header.Get("Range"); r != "" {
maybeRange = " " + r
}
if err != nil {
log.Printf("%v %v%v err: %v", r.Method, r.URL.RequestURI(), maybeRange, err)
} else {
log.Printf("%v %v%v OK", r.Method, r.URL.RequestURI(), maybeRange)
}
},
Logger: logger,
})
s := http.Server{
@@ -36,20 +50,20 @@ func mountDirectoryWebDAV(entry fs.Directory, mountPoint string) error {
Handler: mux,
}
onCtrlC(func() {
s.Shutdown(context.Background())
})
var wg sync.WaitGroup
fmt.Fprintf(os.Stderr, "Server listening at http://%v/ Press Ctrl-C to shut down.\n", s.Addr)
err := s.ListenAndServe()
if err == http.ErrServerClosed {
wg.Add(1)
go func() {
defer wg.Done()
fmt.Fprintf(os.Stderr, "Server listening at http://%v/ Press Ctrl-C to shut down.\n", s.Addr)
s.ListenAndServe()
fmt.Println("Server shut down.")
}()
}
if err != http.ErrServerClosed {
return err
}
browseMount(mountPoint, fmt.Sprintf("http://%v", s.Addr))
// Shut down the server and wait for it.
s.Shutdown(context.Background())
wg.Wait()
return nil
}