diff --git a/cli/command_mount.go b/cli/command_mount.go index 8fb46afef..3269e499a 100644 --- a/cli/command_mount.go +++ b/cli/command_mount.go @@ -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() ) diff --git a/cli/command_mount_browse.go b/cli/command_mount_browse.go new file mode 100644 index 000000000..515dfcce5 --- /dev/null +++ b/cli/command_mount_browse.go @@ -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 +} diff --git a/cli/command_mount_webdav.go b/cli/command_mount_webdav.go index ed7d3424b..dd24ed7b8 100644 --- a/cli/command_mount_webdav.go +++ b/cli/command_mount_webdav.go @@ -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 }