mirror of
https://github.com/kopia/kopia.git
synced 2026-01-28 00:08:04 -05:00
* cli: simplified mount command See https://youtu.be/1Nt_HIl-NWQ It will always use WebDAV on Windows and FUSE on Unix. Removed confusing options. New usage: $ kopia mount [--browse] Mounts all snapshots in a temporary filesystem directory (both Unix and Windows). $ kopia mount <object> [--browse] Mounts given object in a temporary filesystem directory (both Unix and Windows). $ kopia mount <object> z: [--browse] Mounts given object as a given drive letter in Windows (using temporary WebDAV mount). $ kopia mount <object> * [--browse] Mounts given object as a random drive letter in Windows. $ kopia mount <object> /mount/path [--browse] Mounts given object in given path in Unix. <object> can be the ID of a directory 'k<hash>' or 'all' Optional --browse automatically opens OS-native file browser. * htmlui: added UI for mounting directories See https://youtu.be/T-9SshVa1d8 for a quick demo. Also replaced some UI text with icons. * lint: windows-specific fix
124 lines
2.8 KiB
Go
124 lines
2.8 KiB
Go
package server
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"net/http"
|
|
|
|
"github.com/gorilla/mux"
|
|
|
|
"github.com/kopia/kopia/internal/mount"
|
|
"github.com/kopia/kopia/internal/serverapi"
|
|
"github.com/kopia/kopia/repo/object"
|
|
"github.com/kopia/kopia/snapshot/snapshotfs"
|
|
)
|
|
|
|
func (s *Server) handleMountCreate(ctx context.Context, r *http.Request, body []byte) (interface{}, *apiError) {
|
|
req := &serverapi.MountSnapshotRequest{}
|
|
if err := json.Unmarshal(body, req); err != nil {
|
|
return nil, requestError(serverapi.ErrorMalformedRequest, "malformed request body")
|
|
}
|
|
|
|
oid, err := object.ParseID(req.Root)
|
|
if err != nil {
|
|
return nil, requestError(serverapi.ErrorMalformedRequest, "unable to parse OID")
|
|
}
|
|
|
|
var c mount.Controller
|
|
|
|
v, ok := s.mounts.Load(oid)
|
|
if !ok {
|
|
log(ctx).Debugf("mount controller for %v not found, starting", oid)
|
|
|
|
var err error
|
|
c, err = mount.Directory(ctx, snapshotfs.DirectoryEntry(s.rep, oid, nil), "*")
|
|
|
|
if err != nil {
|
|
return nil, internalServerError(err)
|
|
}
|
|
|
|
if actual, loaded := s.mounts.LoadOrStore(oid, c); loaded {
|
|
c.Unmount(ctx) // nolint:errcheck
|
|
c = actual.(mount.Controller)
|
|
}
|
|
} else {
|
|
c = v.(mount.Controller)
|
|
}
|
|
|
|
log(ctx).Debugf("mount for %v => %v", oid, c.MountPath())
|
|
|
|
return &serverapi.MountedSnapshot{
|
|
Path: c.MountPath(),
|
|
Root: oid,
|
|
}, nil
|
|
}
|
|
|
|
func (s *Server) handleMountGet(ctx context.Context, r *http.Request, body []byte) (interface{}, *apiError) {
|
|
oid := object.ID(mux.Vars(r)["rootObjectID"])
|
|
|
|
v, ok := s.mounts.Load(oid)
|
|
if !ok {
|
|
return nil, notFoundError("mount point not found")
|
|
}
|
|
|
|
c := v.(mount.Controller)
|
|
|
|
return &serverapi.MountedSnapshot{
|
|
Path: c.MountPath(),
|
|
Root: oid,
|
|
}, nil
|
|
}
|
|
|
|
func (s *Server) handleMountDelete(ctx context.Context, r *http.Request, body []byte) (interface{}, *apiError) {
|
|
oid := object.ID(mux.Vars(r)["rootObjectID"])
|
|
|
|
v, ok := s.mounts.Load(oid)
|
|
if !ok {
|
|
return nil, notFoundError("mount point not found")
|
|
}
|
|
|
|
c := v.(mount.Controller)
|
|
|
|
if err := c.Unmount(ctx); err != nil {
|
|
return nil, internalServerError(err)
|
|
}
|
|
|
|
s.mounts.Delete(oid)
|
|
|
|
return &serverapi.Empty{}, nil
|
|
}
|
|
|
|
func (s *Server) handleMountList(ctx context.Context, r *http.Request, body []byte) (interface{}, *apiError) {
|
|
res := &serverapi.MountedSnapshots{
|
|
Items: []*serverapi.MountedSnapshot{},
|
|
}
|
|
|
|
s.mounts.Range(func(key, val interface{}) bool {
|
|
oid := key.(object.ID)
|
|
c := val.(mount.Controller)
|
|
|
|
res.Items = append(res.Items, &serverapi.MountedSnapshot{
|
|
Path: c.MountPath(),
|
|
Root: oid,
|
|
})
|
|
return true
|
|
})
|
|
|
|
return res, nil
|
|
}
|
|
|
|
func (s *Server) unmountAll(ctx context.Context) {
|
|
s.mounts.Range(func(key, val interface{}) bool {
|
|
c := val.(mount.Controller)
|
|
|
|
log(ctx).Debugf("unmounting %v from %v", key, c.MountPath())
|
|
|
|
if err := c.Unmount(ctx); err != nil {
|
|
log(ctx).Warningf("unable to unmount %v", key)
|
|
}
|
|
|
|
s.mounts.Delete(key)
|
|
return true
|
|
})
|
|
}
|