From b8835fe7b417e0cfeefe05bbefa4783b6f734d53 Mon Sep 17 00:00:00 2001 From: Nick Craig-Wood Date: Fri, 22 Nov 2024 11:42:31 +0000 Subject: [PATCH] fs: make --links flag global and add new --local-links and --vfs-links flag Before this change the --links flag when using the VFS override the --links flag for the local backend which meant the local backend needed explicit config to use links. This fixes the problem by making the --links flag global and adding a new --local-links flag and --vfs-links flags to control the features individually if required. --- backend/local/local.go | 9 ++++++--- docs/content/docs.md | 16 ++++++++++++++++ docs/content/local.md | 16 ++++++++++------ fs/config.go | 7 +++++++ vfs/vfs.md | 15 ++++++++++----- vfs/vfscommon/options.go | 19 +++++++++++++------ 6 files changed, 62 insertions(+), 20 deletions(-) diff --git a/backend/local/local.go b/backend/local/local.go index 242656c92..b955688d1 100644 --- a/backend/local/local.go +++ b/backend/local/local.go @@ -100,10 +100,8 @@ Metadata is supported on files and directories. }, { Name: "links", - Help: "Translate symlinks to/from regular files with a '" + fs.LinkSuffix + "' extension.", + Help: "Translate symlinks to/from regular files with a '" + fs.LinkSuffix + "' extension for the local backend.", Default: false, - NoPrefix: true, - ShortOpt: "l", Advanced: true, }, { @@ -383,12 +381,17 @@ var ( // NewFs constructs an Fs from the path func NewFs(ctx context.Context, name, root string, m configmap.Mapper) (fs.Fs, error) { + ci := fs.GetConfig(ctx) // Parse config into Options struct opt := new(Options) err := configstruct.Set(m, opt) if err != nil { return nil, err } + // Override --local-links with --links if set + if ci.Links { + opt.TranslateSymlinks = true + } if opt.TranslateSymlinks && opt.FollowSymlinks { return nil, errLinksAndCopyLinks } diff --git a/docs/content/docs.md b/docs/content/docs.md index cb05455b6..cb65ed746 100644 --- a/docs/content/docs.md +++ b/docs/content/docs.md @@ -1426,6 +1426,22 @@ The options mean During rmdirs it will not remove root directory, even if it's empty. +### --links / -l + +Normally rclone will ignore symlinks or junction points (which behave +like symlinks under Windows). + +If you supply this flag then rclone will copy symbolic links from any +supported backend backend, and store them as text files, with a +`.rclonelink` suffix in the destination. + +The text file will contain the target of the symbolic link. + +The `--links` / `-l` flag enables this feature for all supported +backends and the VFS. There are individual flags for just enabling it +for the VFS `--vfs-links` and the local backend `--local-links` if +required. + ### --log-file=FILE ### Log all of rclone's output to FILE. This is not active by default. diff --git a/docs/content/local.md b/docs/content/local.md index 9d5c8363c..89c4f2e4c 100644 --- a/docs/content/local.md +++ b/docs/content/local.md @@ -209,13 +209,13 @@ $ rclone -L ls /tmp/a 6 b/one ``` -#### --links, -l +#### --local-links, --links, -l Normally rclone will ignore symlinks or junction points (which behave like symlinks under Windows). If you supply this flag then rclone will copy symbolic links from the local storage, -and store them as text files, with a '.rclonelink' suffix in the remote storage. +and store them as text files, with a `.rclonelink` suffix in the remote storage. The text file will contain the target of the symbolic link (see example). @@ -236,7 +236,7 @@ Copying the entire directory with '-l' $ rclone copy -l /tmp/a/ remote:/tmp/a/ ``` -The remote files are created with a '.rclonelink' suffix +The remote files are created with a `.rclonelink` suffix ``` $ rclone ls remote:/tmp/a @@ -274,7 +274,7 @@ $ tree /tmp/b /tmp/b ├── file1.rclonelink └── file2.rclonelink -```` +``` If you want to copy a single file with `-l` then you must use the `.rclonelink` suffix. @@ -286,6 +286,10 @@ $ tree /tmp/c └── file1 -> ./file4 ``` +Note that `--local-links` just enables this feature for the local +backend. `--links` and `-l` enable the feature for all supported +backends and the VFS. + Note that this flag is incompatible with `-copy-links` / `-L`. ### Restricting filesystems with --one-file-system @@ -361,9 +365,9 @@ Properties: - Type: bool - Default: false -#### --links / -l +#### --local-links -Translate symlinks to/from regular files with a '.rclonelink' extension. +Translate symlinks to/from regular files with a '.rclonelink' extension for the local backend. Properties: diff --git a/fs/config.go b/fs/config.go index 1b11da821..e83d2cac1 100644 --- a/fs/config.go +++ b/fs/config.go @@ -105,6 +105,12 @@ var ConfigOptionsInfo = Options{{ Default: false, Help: "Enable interactive mode", Groups: "Config,Important", +}, { + Name: "links", + Help: "Translate symlinks to/from regular files with a '" + LinkSuffix + "' extension.", + Default: false, + ShortOpt: "l", + Groups: "Copy", }, { Name: "contimeout", Default: 60 * time.Second, @@ -537,6 +543,7 @@ type ConfigInfo struct { UseJSONLog bool `config:"use_json_log"` DryRun bool `config:"dry_run"` Interactive bool `config:"interactive"` + Links bool `config:"links"` CheckSum bool `config:"checksum"` SizeOnly bool `config:"size_only"` IgnoreTimes bool `config:"ignore_times"` diff --git a/vfs/vfs.md b/vfs/vfs.md index d1d394eed..4ffe1c313 100644 --- a/vfs/vfs.md +++ b/vfs/vfs.md @@ -305,10 +305,11 @@ modified files from the cache (the related global flag `--checkers` has no effec ### Symlinks -Be default the VFS does not support symlinks. However this may be -enabled with the following flag: +By default the VFS does not support symlinks. However this may be +enabled with either of the following flags: - --links Translate symlinks to/from regular files with a '.rclonelink' extension. + --links Translate symlinks to/from regular files with a '.rclonelink' extension. + --vfs-links Translate symlinks to/from regular files with a '.rclonelink' extension for the VFS As most cloud storage systems do not support symlinks directly, rclone stores the symlink as a normal file with a special extension. So a @@ -316,9 +317,13 @@ file which appears as a symlink `link-to-file.txt` would be stored on cloud storage as `link-to-file.txt.rclonelink` and the contents would be the path to the symlink destination. -This scheme is compatible with that used by the [local backend with the --links flag](/local/#symlinks-junction-points). +Note that `--links` enables symlink translation globally in rclone - +this includes any backend which supports the concept (for example the +local backend). `--vfs-links` just enables it for the VFS layer. -The `--links` flag has been designed for `rclone mount`, `rclone +This scheme is compatible with that used by the [local backend with the --local-links flag](/local/#symlinks-junction-points). + +The `--vfs-links` flag has been designed for `rclone mount`, `rclone nfsmount` and `rclone serve nfs`. It hasn't been tested with the other `rclone serve` commands yet. diff --git a/vfs/vfscommon/options.go b/vfs/vfscommon/options.go index adaaeb7c9..650aedd97 100644 --- a/vfs/vfscommon/options.go +++ b/vfs/vfscommon/options.go @@ -1,6 +1,7 @@ package vfscommon import ( + "context" "os" "runtime" "time" @@ -45,11 +46,10 @@ var OptionsInfo = fs.Options{{ Help: "Only allow read-only access", Groups: "VFS", }, { - Name: "links", - Default: false, - Help: "Translate symlinks to/from regular files with a '" + fs.LinkSuffix + "' extension", - Groups: "VFS", - ShortOpt: "l", + Name: "vfs_links", + Default: false, + Help: "Translate symlinks to/from regular files with a '" + fs.LinkSuffix + "' extension for the VFS", + Groups: "VFS", }, { Name: "vfs_cache_mode", Default: CacheModeOff, @@ -176,7 +176,7 @@ type Options struct { NoSeek bool `config:"no_seek"` // don't allow seeking if set NoChecksum bool `config:"no_checksum"` // don't check checksums if set ReadOnly bool `config:"read_only"` // if set VFS is read only - Links bool `config:"links"` // if set interpret link files + Links bool `config:"vfs_links"` // if set interpret link files NoModTime bool `config:"no_modtime"` // don't read mod times for files DirCacheTime fs.Duration `config:"dir_cache_time"` // how long to consider directory listing cache valid Refresh bool `config:"vfs_refresh"` // refreshes the directory listing recursively on start @@ -211,6 +211,13 @@ var Opt Options // Init the options, making sure everything is within range func (opt *Options) Init() { + ci := fs.GetConfig(context.Background()) + + // Override --vfs-links with --links if set + if ci.Links { + opt.Links = true + } + // Mask the permissions with the umask opt.DirPerms &= ^opt.Umask opt.FilePerms &= ^opt.Umask