mountlib: rc: fix mounts created with mountPoint "*" overwriting each other
On Windows, passing "*" as mountPoint to the mount/mount RC command auto-assigns a drive letter (e.g. "Z:"), but the resolved letter was never propagated back to mountlib. This caused liveMounts to be keyed on the literal "*", breaking tracking of multiple mounts and making unmount unreliable. Change MountFn to return the actual mount point as an additional return value. Update MountPoint.Mount() to store the resolved value, and mountRc() to use it as the liveMounts key. The mount/mount RC response now returns the actual mountPoint so callers can discover which drive letter was assigned.
This commit is contained in:
+10
-2
@@ -195,7 +195,11 @@ type (
|
||||
// UnmountFn is called to unmount the file system
|
||||
UnmountFn func() error
|
||||
// MountFn is called to mount the file system
|
||||
MountFn func(VFS *vfs.VFS, mountpoint string, opt *Options) (<-chan error, func() error, error)
|
||||
//
|
||||
// It returns the errChan, unmount function, the actual mountpoint
|
||||
// (which may differ from the input, e.g. on Windows when "*" is
|
||||
// used to auto-assign a drive letter) and an error.
|
||||
MountFn func(VFS *vfs.VFS, mountpoint string, opt *Options) (<-chan error, func() error, string, error)
|
||||
)
|
||||
|
||||
// MountPoint represents a mount with options and runtime state
|
||||
@@ -371,13 +375,17 @@ func (m *MountPoint) Mount() (mountDaemon *os.Process, err error) {
|
||||
|
||||
m.VFS = vfs.New(context.Background(), m.Fs, &m.VFSOpt)
|
||||
|
||||
m.ErrChan, m.UnmountFn, err = m.MountFn(m.VFS, m.MountPoint, &m.MountOpt)
|
||||
var actualMountpoint string
|
||||
m.ErrChan, m.UnmountFn, actualMountpoint, err = m.MountFn(m.VFS, m.MountPoint, &m.MountOpt)
|
||||
if err != nil {
|
||||
if len(os.Args) > 0 && strings.HasPrefix(os.Args[0], "/snap/") {
|
||||
return nil, fmt.Errorf("mounting is not supported when running from snap")
|
||||
}
|
||||
return nil, fmt.Errorf("failed to mount FUSE fs: %w", err)
|
||||
}
|
||||
if actualMountpoint != "" {
|
||||
m.MountPoint = actualMountpoint
|
||||
}
|
||||
m.MountedOn = time.Now()
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
+21
-4
@@ -62,12 +62,24 @@ This takes the following parameters:
|
||||
- mountOpt: a JSON object with Mount options in.
|
||||
- vfsOpt: a JSON object with VFS options in.
|
||||
|
||||
On Windows mountPoint may be set to "*" to assign the next available
|
||||
drive letter automatically, or a network share UNC path (e.g.
|
||||
"\\server\share") to mount as a network drive. In these cases the
|
||||
actual drive letter is chosen at mount time.
|
||||
|
||||
This returns the following values:
|
||||
|
||||
- mountPoint: the actual mount point that was used (this may differ
|
||||
from the input, e.g. on Windows when "*" is passed the allocated
|
||||
drive letter is returned)
|
||||
|
||||
Example:
|
||||
|
||||
` + "```console" + `
|
||||
rclone rc mount/mount fs=mydrive: mountPoint=/home/<user>/mountPoint
|
||||
rclone rc mount/mount fs=mydrive: mountPoint=/home/<user>/mountPoint mountType=mount
|
||||
rclone rc mount/mount fs=TestDrive: mountPoint=/mnt/tmp vfsOpt='{"CacheMode": 2}' mountOpt='{"AllowOther": true}'
|
||||
rclone rc mount/mount fs=mydrive: mountPoint=* mountType=cmount
|
||||
` + "```" + `
|
||||
|
||||
The vfsOpt are as described in options/get and can be seen in the
|
||||
@@ -128,6 +140,9 @@ func mountRc(ctx context.Context, in rc.Params) (out rc.Params, err error) {
|
||||
fs.Logf(nil, "mount FAILED: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
// mnt.MountPoint may have been updated by MountFn (e.g. on
|
||||
// Windows when "*" is resolved to an actual drive letter)
|
||||
actualMountPoint := mnt.MountPoint
|
||||
go func() {
|
||||
if err = mnt.Wait(); err != nil {
|
||||
fs.Logf(nil, "unmount FAILED: %v", err)
|
||||
@@ -135,13 +150,15 @@ func mountRc(ctx context.Context, in rc.Params) (out rc.Params, err error) {
|
||||
}
|
||||
mountMu.Lock()
|
||||
defer mountMu.Unlock()
|
||||
delete(liveMounts, mountPoint)
|
||||
delete(liveMounts, actualMountPoint)
|
||||
}()
|
||||
// Add mount to list if mount point was successfully created
|
||||
liveMounts[mountPoint] = mnt
|
||||
liveMounts[actualMountPoint] = mnt
|
||||
|
||||
fs.Debugf(nil, "Mount for %s created at %s using %s", fdst.String(), mountPoint, mountType)
|
||||
return nil, nil
|
||||
fs.Debugf(nil, "Mount for %s created at %s using %s", fdst.String(), actualMountPoint, mountType)
|
||||
return rc.Params{
|
||||
"mountPoint": actualMountPoint,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func init() {
|
||||
|
||||
@@ -82,11 +82,16 @@ func TestRc(t *testing.T) {
|
||||
require.True(t, os.IsNotExist(err))
|
||||
|
||||
// mount
|
||||
_, err = mount.Fn(ctx, in)
|
||||
out, err := mount.Fn(ctx, in)
|
||||
if err != nil {
|
||||
t.Skipf("Mount failed - skipping test: %v", err)
|
||||
}
|
||||
|
||||
// check the returned mount point matches what we asked for
|
||||
returnedMountPoint, err := out.GetString("mountPoint")
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, mountPoint, returnedMountPoint)
|
||||
|
||||
// check file.txt is there now
|
||||
fi, err := os.Stat(filePath)
|
||||
require.NoError(t, err)
|
||||
|
||||
Reference in New Issue
Block a user