mirror of
https://github.com/kopia/kopia.git
synced 2026-04-27 09:27:54 -04:00
added support for mounting snapshots as drive letters and opening them in explorer on Windows.
This commit is contained in:
@@ -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()
|
||||
)
|
||||
|
||||
70
cli/command_mount_browse.go
Normal file
70
cli/command_mount_browse.go
Normal 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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user