Compare commits
72
Commits
master
...
v1.73-stable
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2c12ca64d4 | ||
|
|
2a9e952b38 | ||
|
|
c097c36064 | ||
|
|
cfa9072d9f | ||
|
|
03eed87045 | ||
|
|
e4e4c5efe0 | ||
|
|
08eecf4cc8 | ||
|
|
5cd87e2d75 | ||
|
|
f86f0518c3 | ||
|
|
d6c937f908 | ||
|
|
b5465afd1c | ||
|
|
984d07c9c3 | ||
|
|
06c054bbc8 | ||
|
|
6987bc1318 | ||
|
|
c9ea98e752 | ||
|
|
4c5deb435c | ||
|
|
d757bd6645 | ||
|
|
6b44b65fba | ||
|
|
28805943b0 | ||
|
|
2ed57c301b | ||
|
|
3e8d4f2118 | ||
|
|
0f6401e57e | ||
|
|
543ac7c50c | ||
|
|
61b4897c33 | ||
|
|
504042f6aa | ||
|
|
68996b4429 | ||
|
|
83025eaef2 | ||
|
|
634e93e339 | ||
|
|
f9bf6d823e | ||
|
|
14defb23dc | ||
|
|
00b47c99a5 | ||
|
|
c7f4adb970 | ||
|
|
9468ac3129 | ||
|
|
9fce660b4b | ||
|
|
c0f03f8ac0 | ||
|
|
5f149a91c4 | ||
|
|
41fb73c669 | ||
|
|
4b63e78358 | ||
|
|
690587ebbf | ||
|
|
3821c64711 | ||
|
|
dc73dba9b5 | ||
|
|
9267568fe3 | ||
|
|
a285c9eeee | ||
|
|
cf4d78e3c9 | ||
|
|
ea29edb35d | ||
|
|
de93ad8744 | ||
|
|
9bfc1a7a8a | ||
|
|
d9e455d1d3 | ||
|
|
7502ec934b | ||
|
|
bffc49742c | ||
|
|
c7dab94e94 | ||
|
|
615a6f57bb | ||
|
|
b52fab6868 | ||
|
|
b740e9c299 | ||
|
|
3b63bd280c | ||
|
|
3a902dd1a0 | ||
|
|
1e24958861 | ||
|
|
77e0a760d8 | ||
|
|
e16ac436f7 | ||
|
|
1f34163857 | ||
|
|
132184a47f | ||
|
|
6e78bb1c40 | ||
|
|
d720452656 | ||
|
|
a8d374f068 | ||
|
|
53fbeb21c8 | ||
|
|
350a9bc389 | ||
|
|
6ba40cc97e | ||
|
|
1d2a159c6a | ||
|
|
1adc3e241d | ||
|
|
d5483e3e93 | ||
|
|
d6bc7a69a1 | ||
|
|
3311b72407 |
No files matched your search
@@ -29,12 +29,12 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
job_name: ['linux', 'linux_386', 'mac_amd64', 'mac_arm64', 'windows', 'other_os', 'go1.24']
|
||||
job_name: ['linux', 'linux_386', 'mac_amd64', 'mac_arm64', 'windows', 'other_os']
|
||||
|
||||
include:
|
||||
- job_name: linux
|
||||
os: ubuntu-latest
|
||||
go: '>=1.25.0-rc.1'
|
||||
go: '~1.25.9'
|
||||
gotags: cmount
|
||||
build_flags: '-include "^linux/"'
|
||||
check: true
|
||||
@@ -45,14 +45,14 @@ jobs:
|
||||
|
||||
- job_name: linux_386
|
||||
os: ubuntu-latest
|
||||
go: '>=1.25.0-rc.1'
|
||||
go: '~1.25.9'
|
||||
goarch: 386
|
||||
gotags: cmount
|
||||
quicktest: true
|
||||
|
||||
- job_name: mac_amd64
|
||||
os: macos-latest
|
||||
go: '>=1.25.0-rc.1'
|
||||
go: '~1.25.9'
|
||||
gotags: 'cmount'
|
||||
build_flags: '-include "^darwin/amd64" -cgo'
|
||||
quicktest: true
|
||||
@@ -61,14 +61,14 @@ jobs:
|
||||
|
||||
- job_name: mac_arm64
|
||||
os: macos-latest
|
||||
go: '>=1.25.0-rc.1'
|
||||
go: '~1.25.9'
|
||||
gotags: 'cmount'
|
||||
build_flags: '-include "^darwin/arm64" -cgo -macos-arch arm64 -cgo-cflags=-I/usr/local/include -cgo-ldflags=-L/usr/local/lib'
|
||||
deploy: true
|
||||
|
||||
- job_name: windows
|
||||
os: windows-latest
|
||||
go: '>=1.25.0-rc.1'
|
||||
go: '~1.25.9'
|
||||
gotags: cmount
|
||||
cgo: '0'
|
||||
build_flags: '-include "^windows/"'
|
||||
@@ -78,17 +78,11 @@ jobs:
|
||||
|
||||
- job_name: other_os
|
||||
os: ubuntu-latest
|
||||
go: '>=1.25.0-rc.1'
|
||||
go: '~1.25.9'
|
||||
build_flags: '-exclude "^(windows/|darwin/|linux/)"'
|
||||
compile_all: true
|
||||
deploy: true
|
||||
|
||||
- job_name: go1.24
|
||||
os: ubuntu-latest
|
||||
go: '1.24'
|
||||
quicktest: true
|
||||
racequicktest: true
|
||||
|
||||
name: ${{ matrix.job_name }}
|
||||
|
||||
runs-on: ${{ matrix.os }}
|
||||
@@ -224,7 +218,7 @@ jobs:
|
||||
id: setup-go
|
||||
uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version: '>=1.24.0-rc.1'
|
||||
go-version: '~1.25.9'
|
||||
check-latest: true
|
||||
cache: false
|
||||
|
||||
@@ -315,7 +309,7 @@ jobs:
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version: '>=1.25.0-rc.1'
|
||||
go-version: '~1.25.9'
|
||||
|
||||
- name: Set global environment variables
|
||||
run: |
|
||||
|
||||
Generated
+1714
-1408
File diff suppressed because it is too large.
Load diff
@@ -1,6 +1,6 @@
|
||||
% rclone(1) User Manual
|
||||
% Nick Craig-Wood
|
||||
% Jan 30, 2026
|
||||
% Apr 19, 2026
|
||||
|
||||
# NAME
|
||||
|
||||
@@ -3768,6 +3768,26 @@ Flags for anything which can copy a file
|
||||
-u, --update Skip files that are newer on the destination
|
||||
```
|
||||
|
||||
### Sync Options
|
||||
|
||||
Flags used for sync commands
|
||||
|
||||
```text
|
||||
--backup-dir string Make backups into hierarchy based in DIR
|
||||
--delete-after When synchronizing, delete files on destination after transferring (default)
|
||||
--delete-before When synchronizing, delete files on destination before transferring
|
||||
--delete-during When synchronizing, delete files during transfer
|
||||
--fix-case Force rename of case insensitive dest to match source
|
||||
--ignore-errors Delete even if there are I/O errors
|
||||
--list-cutoff int To save memory, sort directory listings on disk above this threshold (default 1000000)
|
||||
--max-delete int When synchronizing, limit the number of deletes (default -1)
|
||||
--max-delete-size SizeSuffix When synchronizing, limit the total size of deletes (default off)
|
||||
--suffix string Suffix to add to changed files
|
||||
--suffix-keep-extension Preserve the extension when using --suffix
|
||||
--track-renames When synchronizing, track file renames and do a server-side move if possible
|
||||
--track-renames-strategy string Strategies to use when synchronizing using track-renames hash|modtime|leaf (default "hash")
|
||||
```
|
||||
|
||||
### Important Options
|
||||
|
||||
Important flags useful for most commands
|
||||
@@ -5388,12 +5408,12 @@ rclone convmv "stories/The Quick Brown Fox!.txt" --name-transform "all,command=e
|
||||
|
||||
```console
|
||||
rclone convmv "stories/The Quick Brown Fox!" --name-transform "date=-{YYYYMMDD}"
|
||||
// Output: stories/The Quick Brown Fox!-20260130
|
||||
// Output: stories/The Quick Brown Fox!-20260419
|
||||
```
|
||||
|
||||
```console
|
||||
rclone convmv "stories/The Quick Brown Fox!" --name-transform "date=-{macfriendlytime}"
|
||||
// Output: stories/The Quick Brown Fox!-2026-01-30 0825PM
|
||||
// Output: stories/The Quick Brown Fox!-2026-04-19 1137AM
|
||||
```
|
||||
|
||||
```console
|
||||
@@ -5841,6 +5861,15 @@ Note that `--stdout` and `--print-filename` are incompatible with `--urls`.
|
||||
This will do `--transfers` copies in parallel. Note that if `--auto-filename`
|
||||
is desired for all URLs then a file with only URLs and no filename can be used.
|
||||
|
||||
Each FILENAME in the CSV file can start with a relative path which will be appended
|
||||
to the destination path provided at the command line. For example, running the command
|
||||
shown above with the following CSV file will write two files to the destination:
|
||||
`remote:dir/local/path/bar.json` and `remote:dir/another/local/directory/qux.json`
|
||||
```csv
|
||||
https://example.org/foo/bar.json,local/path/bar.json
|
||||
https://example.org/qux/baz.json,another/local/directory/qux.json
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
If you can't get `rclone copyurl` to work then here are some things you can try:
|
||||
@@ -6892,7 +6921,8 @@ Mount the remote as file system on a mountpoint.
|
||||
Rclone mount allows Linux, FreeBSD, macOS and Windows to
|
||||
mount any of Rclone's cloud storage systems as a file system with FUSE.
|
||||
|
||||
First set up your remote using `rclone config`. Check it works with `rclone ls` etc.
|
||||
First set up your remote using `rclone config`. Check it works with `rclone ls`
|
||||
etc.
|
||||
|
||||
On Linux and macOS, you can run mount in either foreground or background (aka
|
||||
daemon) mode. Mount runs in foreground mode by default. Use the `--daemon` flag
|
||||
@@ -6920,8 +6950,8 @@ The following examples will mount to an automatically assigned drive,
|
||||
to specific drive letter `X:`, to path `C:\path\parent\mount`
|
||||
(where parent directory or drive must exist, and mount must **not** exist,
|
||||
and is not supported when [mounting as a network drive](#mounting-modes-on-windows)),
|
||||
and the last example will mount as network share `\\cloud\remote` and map it to an
|
||||
automatically assigned drive:
|
||||
and the last example will mount as network share `\\cloud\remote` and map it to
|
||||
an automatically assigned drive:
|
||||
|
||||
```console
|
||||
rclone mount remote:path/to/files *
|
||||
@@ -7027,8 +7057,8 @@ rclone mount remote:path/to/files X: --volname \\server\share
|
||||
|
||||
You may also specify the network share UNC path as the mountpoint itself. Then rclone
|
||||
will automatically assign a drive letter, same as with `*` and use that as
|
||||
mountpoint, and instead use the UNC path specified as the volume name, as if it were
|
||||
specified with the `--volname` option. This will also implicitly set
|
||||
mountpoint, and instead use the UNC path specified as the volume name, as if it
|
||||
were specified with the `--volname` option. This will also implicitly set
|
||||
the `--network-mode` option. This means the following two examples have same result:
|
||||
|
||||
```console
|
||||
@@ -7159,7 +7189,7 @@ does not suffer from the same limitations.
|
||||
|
||||
Mounting on macOS can be done either via [built-in NFS server](https://rclone.org/commands/rclone_serve_nfs/),
|
||||
[macFUSE](https://osxfuse.github.io/) (also known as osxfuse) or
|
||||
[FUSE-T](https://www.fuse-t.org/).macFUSE is a traditional FUSE driver utilizing
|
||||
[FUSE-T](https://www.fuse-t.org/). macFUSE is a traditional FUSE driver utilizing
|
||||
a macOS kernel extension (kext). FUSE-T is an alternative FUSE system which
|
||||
"mounts" via an NFSv4 local server.
|
||||
|
||||
@@ -7202,29 +7232,30 @@ current as of FUSE-T version 1.0.14.
|
||||
|
||||
As per the [FUSE-T wiki](https://github.com/macos-fuse-t/fuse-t/wiki#caveats):
|
||||
|
||||
> File access and modification times cannot be set separately as it seems to be an
|
||||
> issue with the NFS client which always modifies both. Can be reproduced with
|
||||
> 'touch -m' and 'touch -a' commands
|
||||
> File access and modification times cannot be set separately as it seems to be
|
||||
> an issue with the NFS client which always modifies both. Can be reproduced
|
||||
> with `touch -m` and `touch -a` commands
|
||||
|
||||
This means that viewing files with various tools, notably macOS Finder, will cause
|
||||
rlcone to update the modification time of the file. This may make rclone upload a
|
||||
full new copy of the file.
|
||||
This means that viewing files with various tools, notably macOS Finder, will
|
||||
cause rlcone to update the modification time of the file. This may make rclone
|
||||
upload a full new copy of the file.
|
||||
|
||||
#### Read Only mounts
|
||||
|
||||
When mounting with `--read-only`, attempts to write to files will fail *silently*
|
||||
as opposed to with a clear warning as in macFUSE.
|
||||
|
||||
# Mounting on Linux
|
||||
## Mounting on Linux
|
||||
|
||||
On newer versions of Ubuntu, you may encounter the following error when running
|
||||
`rclone mount`:
|
||||
|
||||
> NOTICE: mount helper error: fusermount3: mount failed: Permission denied
|
||||
> CRITICAL: Fatal error: failed to mount FUSE fs: fusermount: exit status 1
|
||||
|
||||
This may be due to newer [Apparmor](https://wiki.ubuntu.com/AppArmor) restrictions,
|
||||
which can be disabled with `sudo aa-disable /usr/bin/fusermount3` (you may need to
|
||||
`sudo apt install apparmor-utils` beforehand).
|
||||
which can be disabled with `sudo aa-disable /usr/bin/fusermount3` (you may need
|
||||
to `sudo apt install apparmor-utils` beforehand).
|
||||
|
||||
## Limitations
|
||||
|
||||
@@ -8334,7 +8365,8 @@ Mount the remote as file system on a mountpoint.
|
||||
Rclone nfsmount allows Linux, FreeBSD, macOS and Windows to
|
||||
mount any of Rclone's cloud storage systems as a file system with FUSE.
|
||||
|
||||
First set up your remote using `rclone config`. Check it works with `rclone ls` etc.
|
||||
First set up your remote using `rclone config`. Check it works with `rclone ls`
|
||||
etc.
|
||||
|
||||
On Linux and macOS, you can run mount in either foreground or background (aka
|
||||
daemon) mode. Mount runs in foreground mode by default. Use the `--daemon` flag
|
||||
@@ -8362,8 +8394,8 @@ The following examples will mount to an automatically assigned drive,
|
||||
to specific drive letter `X:`, to path `C:\path\parent\mount`
|
||||
(where parent directory or drive must exist, and mount must **not** exist,
|
||||
and is not supported when [mounting as a network drive](#mounting-modes-on-windows)),
|
||||
and the last example will mount as network share `\\cloud\remote` and map it to an
|
||||
automatically assigned drive:
|
||||
and the last example will mount as network share `\\cloud\remote` and map it to
|
||||
an automatically assigned drive:
|
||||
|
||||
```console
|
||||
rclone nfsmount remote:path/to/files *
|
||||
@@ -8469,8 +8501,8 @@ rclone nfsmount remote:path/to/files X: --volname \\server\share
|
||||
|
||||
You may also specify the network share UNC path as the mountpoint itself. Then rclone
|
||||
will automatically assign a drive letter, same as with `*` and use that as
|
||||
mountpoint, and instead use the UNC path specified as the volume name, as if it were
|
||||
specified with the `--volname` option. This will also implicitly set
|
||||
mountpoint, and instead use the UNC path specified as the volume name, as if it
|
||||
were specified with the `--volname` option. This will also implicitly set
|
||||
the `--network-mode` option. This means the following two examples have same result:
|
||||
|
||||
```console
|
||||
@@ -8601,7 +8633,7 @@ does not suffer from the same limitations.
|
||||
|
||||
Mounting on macOS can be done either via [built-in NFS server](https://rclone.org/commands/rclone_serve_nfs/),
|
||||
[macFUSE](https://osxfuse.github.io/) (also known as osxfuse) or
|
||||
[FUSE-T](https://www.fuse-t.org/).macFUSE is a traditional FUSE driver utilizing
|
||||
[FUSE-T](https://www.fuse-t.org/). macFUSE is a traditional FUSE driver utilizing
|
||||
a macOS kernel extension (kext). FUSE-T is an alternative FUSE system which
|
||||
"mounts" via an NFSv4 local server.
|
||||
|
||||
@@ -8644,29 +8676,30 @@ current as of FUSE-T version 1.0.14.
|
||||
|
||||
As per the [FUSE-T wiki](https://github.com/macos-fuse-t/fuse-t/wiki#caveats):
|
||||
|
||||
> File access and modification times cannot be set separately as it seems to be an
|
||||
> issue with the NFS client which always modifies both. Can be reproduced with
|
||||
> 'touch -m' and 'touch -a' commands
|
||||
> File access and modification times cannot be set separately as it seems to be
|
||||
> an issue with the NFS client which always modifies both. Can be reproduced
|
||||
> with `touch -m` and `touch -a` commands
|
||||
|
||||
This means that viewing files with various tools, notably macOS Finder, will cause
|
||||
rlcone to update the modification time of the file. This may make rclone upload a
|
||||
full new copy of the file.
|
||||
This means that viewing files with various tools, notably macOS Finder, will
|
||||
cause rlcone to update the modification time of the file. This may make rclone
|
||||
upload a full new copy of the file.
|
||||
|
||||
#### Read Only mounts
|
||||
|
||||
When mounting with `--read-only`, attempts to write to files will fail *silently*
|
||||
as opposed to with a clear warning as in macFUSE.
|
||||
|
||||
# Mounting on Linux
|
||||
## Mounting on Linux
|
||||
|
||||
On newer versions of Ubuntu, you may encounter the following error when running
|
||||
`rclone mount`:
|
||||
|
||||
> NOTICE: mount helper error: fusermount3: mount failed: Permission denied
|
||||
> CRITICAL: Fatal error: failed to mount FUSE fs: fusermount: exit status 1
|
||||
|
||||
This may be due to newer [Apparmor](https://wiki.ubuntu.com/AppArmor) restrictions,
|
||||
which can be disabled with `sudo aa-disable /usr/bin/fusermount3` (you may need to
|
||||
`sudo apt install apparmor-utils` beforehand).
|
||||
which can be disabled with `sudo aa-disable /usr/bin/fusermount3` (you may need
|
||||
to `sudo apt install apparmor-utils` beforehand).
|
||||
|
||||
## Limitations
|
||||
|
||||
@@ -18685,7 +18718,7 @@ This is the default.
|
||||
`CAUTIOUS` will try to prevent rclone from reaching the limit. Only applicable
|
||||
for `--max-transfer`.
|
||||
|
||||
## -M, --metadata
|
||||
### -M, --metadata
|
||||
|
||||
Setting this flag enables rclone to copy the metadata from the source
|
||||
to the destination. For local backends this is ownership, permissions,
|
||||
@@ -19587,6 +19620,10 @@ knowing the local file is newer than the time it was last uploaded to the
|
||||
remote is sufficient. In those cases, this flag can speed up the process and
|
||||
reduce the number of API calls necessary.
|
||||
|
||||
This flag is only supported on certain backends and will be silently
|
||||
ignored on unsupported backends. Supported backends include
|
||||
`azureblob`, `oracleobjectstorage`, `s3`, `swift`.
|
||||
|
||||
Using this flag on a sync operation without also using `--update` would cause
|
||||
all files modified at any time other than the last upload time to be uploaded
|
||||
again, which is probably not what you want.
|
||||
@@ -23049,6 +23086,8 @@ This command does not have a command line equivalent so use this instead:
|
||||
|
||||
rclone rc --loopback operations/fsinfo fs=remote:
|
||||
|
||||
**Authentication is required for this call.**
|
||||
|
||||
### operations/hashsum: Produces a hashsum file for all the objects in the path. {#operations-hashsum}
|
||||
|
||||
Produces a hash file for all the objects in the path using the hash
|
||||
@@ -23370,6 +23409,8 @@ And this sets NOTICE level logs (normal without -v)
|
||||
|
||||
rclone rc options/set --json '{"main": {"LogLevel": "NOTICE"}}'
|
||||
|
||||
**Authentication is required for this call.**
|
||||
|
||||
### pluginsctl/addPlugin: Add a plugin using url {#pluginsctl-addPlugin}
|
||||
|
||||
Used for adding a plugin to the webgui.
|
||||
@@ -24776,7 +24817,7 @@ Flags for general networking and HTTP stuff.
|
||||
--tpslimit float Limit HTTP transactions per second to this
|
||||
--tpslimit-burst int Max burst of transactions for --tpslimit (default 1)
|
||||
--use-cookies Enable session cookiejar
|
||||
--user-agent string Set the user-agent to a specified string (default "rclone/v1.73.0")
|
||||
--user-agent string Set the user-agent to a specified string (default "rclone/v1.73.5")
|
||||
```
|
||||
|
||||
|
||||
@@ -25260,9 +25301,11 @@ Backend-only flags (these can be set in the config file also).
|
||||
--filefabric-token-expiry string Token expiry time
|
||||
--filefabric-url string URL of the Enterprise File Fabric to connect to
|
||||
--filefabric-version string Version read from the file fabric
|
||||
--filelu-chunk-size SizeSuffix Chunk size to use for uploading. Used for multipart uploads (default 64Mi)
|
||||
--filelu-description string Description of the remote
|
||||
--filelu-encoding Encoding The encoding for the backend (default Slash,LtGt,DoubleQuote,SingleQuote,BackQuote,Dollar,Colon,Question,Asterisk,Pipe,Hash,Percent,BackSlash,CrLf,Del,Ctl,LeftSpace,LeftPeriod,LeftTilde,LeftCrLfHtVt,RightSpace,RightPeriod,RightCrLfHtVt,InvalidUtf8,Dot,SquareBracket,Semicolon,Exclamation)
|
||||
--filelu-key string Your FileLu Rclone key from My Account
|
||||
--filelu-upload-cutoff SizeSuffix Cutoff for switching to chunked upload. Any files larger than this will be uploaded in chunks of chunk_size (default 500Mi)
|
||||
--filen-api-key string API Key for your Filen account (obscured)
|
||||
--filen-auth-version string Authentication Version (internal use only)
|
||||
--filen-base-folder-uuid string UUID of Account Root Directory (internal use only)
|
||||
@@ -27528,11 +27571,9 @@ The following backends have known issues that need more investigation:
|
||||
<!--- start list_failures - DO NOT EDIT THIS SECTION - use make commanddocs --->
|
||||
- `TestDropbox` (`dropbox`)
|
||||
- [`TestBisyncRemoteRemote/normalization`](https://pub.rclone.org/integration-tests/current/dropbox-cmd.bisync-TestDropbox-1.txt)
|
||||
- `TestSeafile` (`seafile`)
|
||||
- [`TestBisyncLocalRemote/volatile`](https://pub.rclone.org/integration-tests/current/seafile-cmd.bisync-TestSeafile-1.txt)
|
||||
- `TestSeafileV6` (`seafile`)
|
||||
- [`TestBisyncLocalRemote/volatile`](https://pub.rclone.org/integration-tests/current/seafile-cmd.bisync-TestSeafileV6-1.txt)
|
||||
- Updated: 2026-01-30-010015
|
||||
- [`TestBisyncLocalRemote/rmdirs`](https://pub.rclone.org/integration-tests/current/seafile-cmd.bisync-TestSeafileV6-1.txt)
|
||||
- Updated: 2026-04-19-010011
|
||||
<!--- end list_failures - DO NOT EDIT THIS SECTION - use make commanddocs --->
|
||||
|
||||
The following backends either have not been tested recently or have known issues
|
||||
@@ -29649,6 +29690,20 @@ work with the SDK properly:
|
||||
| . | . |
|
||||
| .. | .. |
|
||||
|
||||
#### Important note about double slashes (`//`)
|
||||
|
||||
Object keys containing consecutive forward slashes (`//`) are **not supported** by rclone.
|
||||
|
||||
When rclone encounters an object key with `//` (e.g., `a//b`), it will normalize the path to use a single slash (e.g., `a/b`). This normalization can cause "object not found" errors when trying to access the original object, as rclone will look for the normalized path instead of the actual object key.
|
||||
|
||||
**Example:**
|
||||
- Original S3 object key: `folder//file.txt`
|
||||
- rclone interprets it as: `folder/file.txt`
|
||||
- Result: "object not found" error when trying to access `folder//file.txt`
|
||||
|
||||
**Workaround:**
|
||||
Avoid using consecutive forward slashes (`//`) in S3 object keys when using rclone. If you have existing objects with `//` in their keys, you will need to rename them to use single slashes or access them through other means.
|
||||
|
||||
### Multipart uploads
|
||||
|
||||
rclone supports multipart uploads with S3 which means that it can
|
||||
@@ -30669,6 +30724,9 @@ Properties:
|
||||
- "s3.cubbit.eu"
|
||||
- Cubbit DS3 Object Storage endpoint
|
||||
- Provider: Cubbit
|
||||
- "s3.{tenant_name}.cubbit.eu"
|
||||
- Multi-tenant endpoint - replace {tenant_name} with your actual tenant name. Do not select this directly
|
||||
- Provider: Cubbit
|
||||
- "syd1.digitaloceanspaces.com"
|
||||
- DigitalOcean Spaces Sydney 1
|
||||
- Provider: DigitalOcean
|
||||
@@ -34065,7 +34123,9 @@ can follow this [guide](https://docs.cubbit.io/getting-started/quickstart#api-ke
|
||||
to retrieve these keys. They will be needed when prompted by `rclone config`.
|
||||
|
||||
Default region will correspond to `eu-west-1` and the endpoint has to be specified
|
||||
as `s3.cubbit.eu`.
|
||||
as `s3.cubbit.eu`. If you set a custom tenant endpoint, you must use
|
||||
`s3.{tenant_name}.cubbit.eu`, because the generic `s3.cubbit.eu` endpoint will not
|
||||
work in this case.
|
||||
|
||||
Going through the whole process of creating a new remote by running `rclone config`,
|
||||
each prompt should be answered as shown below:
|
||||
@@ -34078,7 +34138,7 @@ env_auth> false
|
||||
access_key_id> YOUR_ACCESS_KEY
|
||||
secret_access_key> YOUR_SECRET_KEY
|
||||
region> eu-west-1 (or leave empty)
|
||||
endpoint> s3.cubbit.eu
|
||||
endpoint> s3.cubbit.eu (or s3.{tenant_name}.cubbit.eu)
|
||||
acl>
|
||||
```
|
||||
|
||||
@@ -37965,6 +38025,15 @@ To configure access to Tencent COS, follow the steps below:
|
||||
cos s3
|
||||
```
|
||||
|
||||
#### Tencent COS Global Acceleration Endpoint
|
||||
|
||||
When using the Global Acceleration Endpoint (`cos.accelerate.myqcloud.com`),
|
||||
rclone automatically sets `no_check_bucket = true` because this acceleration
|
||||
endpoint does not support the `CreateBucket` call which is used for ensuring
|
||||
a bucket's existence by rclone. Global Acceleration is a per-bucket feature,
|
||||
so you should first create the bucket in one physical region, then enable it
|
||||
in the Tencent Cloud console.
|
||||
|
||||
### Wasabi
|
||||
|
||||
[Wasabi](https://wasabi.com) is a cloud-based object storage service for a
|
||||
@@ -44693,6 +44762,28 @@ Properties:
|
||||
|
||||
Here are the Advanced options specific to filelu (FileLu Cloud Storage).
|
||||
|
||||
#### --filelu-upload-cutoff
|
||||
|
||||
Cutoff for switching to chunked upload. Any files larger than this will be uploaded in chunks of chunk_size.
|
||||
|
||||
Properties:
|
||||
|
||||
- Config: upload_cutoff
|
||||
- Env Var: RCLONE_FILELU_UPLOAD_CUTOFF
|
||||
- Type: SizeSuffix
|
||||
- Default: 500Mi
|
||||
|
||||
#### --filelu-chunk-size
|
||||
|
||||
Chunk size to use for uploading. Used for multipart uploads.
|
||||
|
||||
Properties:
|
||||
|
||||
- Config: chunk_size
|
||||
- Env Var: RCLONE_FILELU_CHUNK_SIZE
|
||||
- Type: SizeSuffix
|
||||
- Default: 64Mi
|
||||
|
||||
#### --filelu-encoding
|
||||
|
||||
The encoding for the backend.
|
||||
@@ -44734,6 +44825,8 @@ The initial setup for Filen requires that you get an API key for your account,
|
||||
currently this is only possible using the [Filen CLI](https://github.com/FilenCloudDienste/filen-cli).
|
||||
This means you must first download the CLI, login, and then run the `export-api-key` command.
|
||||
|
||||
**Note:** If you change your Filen account password, you will need to update your rclone configuration with the new password and a re-exported API key (via `export-api-key`).
|
||||
|
||||
Here is an example of how to make a remote called `FilenRemote`. First run:
|
||||
|
||||
rclone config
|
||||
@@ -51980,7 +52073,7 @@ its own datacenters in Norway.
|
||||
In addition to the official service at [jottacloud.com](https://www.jottacloud.com/),
|
||||
it also provides white-label solutions to different companies. The following
|
||||
are currently supported by this backend, using a different authentication setup
|
||||
as described [below](#whitelabel-authentication):
|
||||
as described [below](#traditional):
|
||||
|
||||
- Elkjøp (with subsidiaries):
|
||||
- Elkjøp Cloud (cloud.elkjop.no)
|
||||
@@ -67369,7 +67462,7 @@ handling file names.
|
||||
| / | 0x2F | / |
|
||||
|
||||
When running on Windows the following characters are replaced. This
|
||||
list is based on the [Windows file naming conventions](https://docs.microsoft.com/de-de/windows/desktop/FileIO/naming-a-file#naming-conventions).
|
||||
list is based on the [Windows file naming conventions](https://docs.microsoft.com/windows/desktop/FileIO/naming-a-file#naming-conventions).
|
||||
|
||||
| Character | Value | Replacement |
|
||||
| --------- |:-----:|:-----------:|
|
||||
@@ -68058,6 +68151,121 @@ Options:
|
||||
|
||||
# Changelog
|
||||
|
||||
## v1.73.5 - 2026-04-19
|
||||
|
||||
[See commits](https://github.com/rclone/rclone/compare/v1.73.4...v1.73.5)
|
||||
|
||||
- Bug Fixes
|
||||
- operations: Add AuthRequired to operations/fsinfo to prevent backend creation CVE-2026-41179 (Nick Craig-Wood)
|
||||
- rc
|
||||
- Add AuthRequired to options/set to prevent auth bypass CVE-2026-41176 (Nick Craig-Wood)
|
||||
- Snapshot NoAuth at startup to prevent runtime auth bypass CVE-2026-41176 (Nick Craig-Wood)
|
||||
- filter: Fix debug logs that fire before logger is configured (Nick Craig-Wood)
|
||||
- Azureblob
|
||||
- Add Microsoft Partner Network User-Agent prefix (Nick Craig-Wood)
|
||||
- Drime
|
||||
- Fix User.EntryPermissions JSON unmarshalling (a1pcm)
|
||||
- Iclouddrive
|
||||
- Fix 'directory not found' error when the directory contains accent marks (Brais Couce)
|
||||
- S3
|
||||
- Fix TencentCOS CDN endpoint failing on bucket check (Mozi)
|
||||
- Fix empty delimiter parameter rejected by Archiware P5 server (Nick Craig-Wood)
|
||||
|
||||
## v1.73.4 - 2026-04-08
|
||||
|
||||
[See commits](https://github.com/rclone/rclone/compare/v1.73.3...v1.73.4)
|
||||
|
||||
- Bug Fixes
|
||||
- build
|
||||
- Update to go 1.25.9 to fix multiple CVEs (Nick Craig-Wood)
|
||||
- CVE-2026-32282: os: Root.Chmod can follow symlinks out of the root on Linux
|
||||
- CVE-2026-32289: html/template: JS template literal context incorrectly tracked
|
||||
- CVE-2026-33810: crypto/x509: excluded DNS constraints not properly applied to wildcard domains
|
||||
- CVE-2026-27144: cmd/compile: no-op interface conversion bypasses overlap checking
|
||||
- CVE-2026-27143: cmd/compile: possible memory corruption after bound check elimination
|
||||
- CVE-2026-32288: archive/tar: unbounded allocation when parsing old format GNU sparse map
|
||||
- CVE-2026-32283: crypto/tls: multiple key update handshake messages can cause connection to deadlock
|
||||
- CVE-2026-27140: cmd/go: trust layer bypass when using cgo and SWIG
|
||||
- CVE-2026-32280: crypto/x509: unexpected work during chain building
|
||||
- CVE-2026-32281: crypto/x509: inefficient policy validation
|
||||
- Fix Denial of Service due to Panic in AWS SDK for Go v2 SDK EventStream Decoder (dependabot[bot])
|
||||
- Update golang.org/x/image to 0.38.0 to fix CVE-2026-33809 (dependabot[bot])
|
||||
- docs
|
||||
- Fix header level for metadata option (Clément Notin)
|
||||
- Fix markdown issues in mount docs (albertony)
|
||||
- Fix link to not be language specific (Ross Smith II)
|
||||
- Note macOS 10.15 (Catalina) support with version v1.70.3 (kapitainsky)
|
||||
- Filen
|
||||
- Update SDK version (Enduriel)
|
||||
|
||||
## v1.73.3 - 2026-03-23
|
||||
|
||||
[See commits](https://github.com/rclone/rclone/compare/v1.73.2...v1.73.3)
|
||||
|
||||
- Bug Fixes
|
||||
- build
|
||||
- Update to google.golang.org/grpc 1.79.3 to fix CVE-2026-33186 (dependabot[bot])
|
||||
- Update to github.com/buger/jsonparser 1.1.2 to fix GHSA-6g7g-w4f8-9c9x (dependabot[bot])
|
||||
- doc fixes
|
||||
- Added text to the label showing version-introduced info (Jan-Philipp Reßler)
|
||||
- Clarify Filen password change requires updating both password and API key in rclone config (Jason)
|
||||
- s3: clarify multi tenant support for Cubbit (Marco Ferretti)
|
||||
- jottacloud: Fix broken link (albertony)
|
||||
- lib/rest: Fix URLPathEscapeAll breaking WebDAV servers (eg nzbdav) with strict path matching (Andrew Furman)
|
||||
- list: Fix nil pointer panic in Sorter when temp file creation fails (Nick Craig-Wood)
|
||||
|
||||
## v1.73.2 - 2026-03-06
|
||||
|
||||
[See commits](https://github.com/rclone/rclone/compare/v1.73.1...v1.73.2)
|
||||
|
||||
- Bug Fixes
|
||||
- build
|
||||
- Update to go 1.25.8 to fix CVE-2026-27137 CVE-2026-27138 CVE-2026-25679 CVE-2026-27142 (Nick Craig-Wood)
|
||||
- Update github.com/cloudflare/circl to v1.6.3 to fix CVE-2026-1229 (Nick Craig-Wood)
|
||||
- Update to golang.org/x/net v0.51.0 to fix CVE-2026-27141 (Nick Craig-Wood)
|
||||
- docs fixes:
|
||||
- bisync: Add group Sync to the bisync command (Jan-Philipp Reßler)
|
||||
- Note that --use-server-modtime only works on some backends (Nick Craig-Wood)
|
||||
- Document unsupported S3 object keys with double slashes (Adam Kasztenny)
|
||||
- Fix headers hierarchy for mount.md (Dark Dragon)
|
||||
- Fix new drive flag typo in changelog (razorloves)
|
||||
- Archive
|
||||
- Extract: fix extraction with "./" prefix from tar entry paths (Varun Chawla)
|
||||
- Drime
|
||||
- Fix chunk-uploaded files ignoring workspace ID (a1pcm)
|
||||
- Internxt
|
||||
- Fix Entry doesn't belong in directory errors on windows (jzunigax2)
|
||||
- WebDAV
|
||||
- Escape reserved characters in URL path segments (Varun Chawla)
|
||||
- Add missing headers for CORS (Romāns Potašovs)
|
||||
|
||||
## v1.73.1 - 2026-02-17
|
||||
|
||||
[See commits](https://github.com/rclone/rclone/compare/v1.73.0...v1.73.1)
|
||||
|
||||
- Bug Fixes
|
||||
- accounting: Fix missing server side stats from core/stats rc (Nick Craig-Wood)
|
||||
- build
|
||||
- Fix CVE-2025-68121 by updating go to 1.25.7 or later (Nick Craig-Wood)
|
||||
- Bump github.com/go-chi/chi/v5 from 5.2.3 to 5.2.5 to fix GO-2026-4316 (albertony)
|
||||
- docs: Extend copyurl docs with an example of CSV FILENAMEs starting with a path. (Jack Kelly)
|
||||
- march: Fix runtime: program exceeds 10000-thread limit (Nick Craig-Wood)
|
||||
- pacer
|
||||
- Fix deadlock between pacer token and --max-connections (Nick Craig-Wood)
|
||||
- Re-read the sleep time as it may be stale (Nick Craig-Wood)
|
||||
- Drime
|
||||
- Fix files and directories being created in the default workspace (Nick Craig-Wood)
|
||||
- Filelu
|
||||
- Avoid buffering entire file in memory (kingston125)
|
||||
- Add multipart upload support with configurable cutoff (kingston125)
|
||||
- Filen
|
||||
- Fix 32 bit targets not being able to list directories (Enduriel)
|
||||
- Fix potential panic in case of error during upload (Enduriel)
|
||||
- Internxt
|
||||
- Implement re-login under refresh logic, improve retry logic (José Zúniga)
|
||||
-S3
|
||||
- Set list_version to 2 for FileLu S3 configuration (kingston125)
|
||||
|
||||
## v1.73.0 - 2026-01-30
|
||||
|
||||
[See commits](https://github.com/rclone/rclone/compare/v1.72.0...v1.73.0)
|
||||
@@ -68088,7 +68296,7 @@ Options:
|
||||
- B2
|
||||
- Support authentication with new bucket restricted application keys (DianaNites)
|
||||
- Drive
|
||||
- Add `--drive-metadata-force-expansive-access` flag (Nick Craig-Wood)
|
||||
- Add `--drive-metadata-enforce-expansive-access` flag (Nick Craig-Wood)
|
||||
- Fix crash when trying to creating shortcut to a Google doc (Nick Craig-Wood)
|
||||
- FTP
|
||||
- Add http proxy authentication support (Nicolas Dessart)
|
||||
|
||||
Generated
+280
-21
@@ -1,6 +1,6 @@
|
||||
rclone(1) User Manual
|
||||
Nick Craig-Wood
|
||||
Jan 30, 2026
|
||||
Apr 19, 2026
|
||||
|
||||
NAME
|
||||
|
||||
@@ -3277,6 +3277,24 @@ Flags for anything which can copy a file
|
||||
--streaming-upload-cutoff SizeSuffix Cutoff for switching to chunked upload if file size is unknown, upload starts after reaching cutoff or when file ends (default 100Ki)
|
||||
-u, --update Skip files that are newer on the destination
|
||||
|
||||
Sync Options
|
||||
|
||||
Flags used for sync commands
|
||||
|
||||
--backup-dir string Make backups into hierarchy based in DIR
|
||||
--delete-after When synchronizing, delete files on destination after transferring (default)
|
||||
--delete-before When synchronizing, delete files on destination before transferring
|
||||
--delete-during When synchronizing, delete files during transfer
|
||||
--fix-case Force rename of case insensitive dest to match source
|
||||
--ignore-errors Delete even if there are I/O errors
|
||||
--list-cutoff int To save memory, sort directory listings on disk above this threshold (default 1000000)
|
||||
--max-delete int When synchronizing, limit the number of deletes (default -1)
|
||||
--max-delete-size SizeSuffix When synchronizing, limit the total size of deletes (default off)
|
||||
--suffix string Suffix to add to changed files
|
||||
--suffix-keep-extension Preserve the extension when using --suffix
|
||||
--track-renames When synchronizing, track file renames and do a server-side move if possible
|
||||
--track-renames-strategy string Strategies to use when synchronizing using track-renames hash|modtime|leaf (default "hash")
|
||||
|
||||
Important Options
|
||||
|
||||
Important flags useful for most commands
|
||||
@@ -4607,10 +4625,10 @@ Examples:
|
||||
// Output: stories/The Quick Brown Fox!.txt
|
||||
|
||||
rclone convmv "stories/The Quick Brown Fox!" --name-transform "date=-{YYYYMMDD}"
|
||||
// Output: stories/The Quick Brown Fox!-20260130
|
||||
// Output: stories/The Quick Brown Fox!-20260419
|
||||
|
||||
rclone convmv "stories/The Quick Brown Fox!" --name-transform "date=-{macfriendlytime}"
|
||||
// Output: stories/The Quick Brown Fox!-2026-01-30 0825PM
|
||||
// Output: stories/The Quick Brown Fox!-2026-04-19 1137AM
|
||||
|
||||
rclone convmv "stories/The Quick Brown Fox!.txt" --name-transform "all,regex=[\\.\\w]/ab"
|
||||
// Output: ababababababab/ababab ababababab ababababab ababab!abababab
|
||||
@@ -5032,6 +5050,15 @@ incompatible with --urls. This will do --transfers copies in parallel.
|
||||
Note that if --auto-filename is desired for all URLs then a file with
|
||||
only URLs and no filename can be used.
|
||||
|
||||
Each FILENAME in the CSV file can start with a relative path which will
|
||||
be appended to the destination path provided at the command line. For
|
||||
example, running the command shown above with the following CSV file
|
||||
will write two files to the destination: remote:dir/local/path/bar.json
|
||||
and remote:dir/another/local/directory/qux.json
|
||||
|
||||
https://example.org/foo/bar.json,local/path/bar.json
|
||||
https://example.org/qux/baz.json,another/local/directory/qux.json
|
||||
|
||||
Troubleshooting
|
||||
|
||||
If you can't get rclone copyurl to work then here are some things you
|
||||
@@ -6173,7 +6200,7 @@ not suffer from the same limitations.
|
||||
Mounting on macOS
|
||||
|
||||
Mounting on macOS can be done either via built-in NFS server, macFUSE
|
||||
(also known as osxfuse) or FUSE-T.macFUSE is a traditional FUSE driver
|
||||
(also known as osxfuse) or FUSE-T. macFUSE is a traditional FUSE driver
|
||||
utilizing a macOS kernel extension (kext). FUSE-T is an alternative FUSE
|
||||
system which "mounts" via an NFSv4 local server.
|
||||
|
||||
@@ -6218,7 +6245,7 @@ As per the FUSE-T wiki:
|
||||
|
||||
File access and modification times cannot be set separately as it
|
||||
seems to be an issue with the NFS client which always modifies both.
|
||||
Can be reproduced with 'touch -m' and 'touch -a' commands
|
||||
Can be reproduced with touch -m and touch -a commands
|
||||
|
||||
This means that viewing files with various tools, notably macOS Finder,
|
||||
will cause rlcone to update the modification time of the file. This may
|
||||
@@ -6236,9 +6263,11 @@ running rclone mount:
|
||||
|
||||
NOTICE: mount helper error: fusermount3: mount failed: Permission
|
||||
denied CRITICAL: Fatal error: failed to mount FUSE fs: fusermount:
|
||||
exit status 1 This may be due to newer Apparmor restrictions, which
|
||||
can be disabled with sudo aa-disable /usr/bin/fusermount3 (you may
|
||||
need to sudo apt install apparmor-utils beforehand).
|
||||
exit status 1
|
||||
|
||||
This may be due to newer Apparmor restrictions, which can be disabled
|
||||
with sudo aa-disable /usr/bin/fusermount3 (you may need to
|
||||
sudo apt install apparmor-utils beforehand).
|
||||
|
||||
Limitations
|
||||
|
||||
@@ -7522,7 +7551,7 @@ not suffer from the same limitations.
|
||||
Mounting on macOS
|
||||
|
||||
Mounting on macOS can be done either via built-in NFS server, macFUSE
|
||||
(also known as osxfuse) or FUSE-T.macFUSE is a traditional FUSE driver
|
||||
(also known as osxfuse) or FUSE-T. macFUSE is a traditional FUSE driver
|
||||
utilizing a macOS kernel extension (kext). FUSE-T is an alternative FUSE
|
||||
system which "mounts" via an NFSv4 local server.
|
||||
|
||||
@@ -7567,7 +7596,7 @@ As per the FUSE-T wiki:
|
||||
|
||||
File access and modification times cannot be set separately as it
|
||||
seems to be an issue with the NFS client which always modifies both.
|
||||
Can be reproduced with 'touch -m' and 'touch -a' commands
|
||||
Can be reproduced with touch -m and touch -a commands
|
||||
|
||||
This means that viewing files with various tools, notably macOS Finder,
|
||||
will cause rlcone to update the modification time of the file. This may
|
||||
@@ -7585,9 +7614,11 @@ running rclone mount:
|
||||
|
||||
NOTICE: mount helper error: fusermount3: mount failed: Permission
|
||||
denied CRITICAL: Fatal error: failed to mount FUSE fs: fusermount:
|
||||
exit status 1 This may be due to newer Apparmor restrictions, which
|
||||
can be disabled with sudo aa-disable /usr/bin/fusermount3 (you may
|
||||
need to sudo apt install apparmor-utils beforehand).
|
||||
exit status 1
|
||||
|
||||
This may be due to newer Apparmor restrictions, which can be disabled
|
||||
with sudo aa-disable /usr/bin/fusermount3 (you may need to
|
||||
sudo apt install apparmor-utils beforehand).
|
||||
|
||||
Limitations
|
||||
|
||||
@@ -17856,6 +17887,10 @@ server's modified time. In cases such as a local to remote sync using
|
||||
uploaded to the remote is sufficient. In those cases, this flag can
|
||||
speed up the process and reduce the number of API calls necessary.
|
||||
|
||||
This flag is only supported on certain backends and will be silently
|
||||
ignored on unsupported backends. Supported backends include azureblob,
|
||||
oracleobjectstorage, s3, swift.
|
||||
|
||||
Using this flag on a sync operation without also using --update would
|
||||
cause all files modified at any time other than the last upload time to
|
||||
be uploaded again, which is probably not what you want.
|
||||
@@ -21221,6 +21256,8 @@ instead:
|
||||
|
||||
rclone rc --loopback operations/fsinfo fs=remote:
|
||||
|
||||
Authentication is required for this call.
|
||||
|
||||
operations/hashsum: Produces a hashsum file for all the objects in the path.
|
||||
|
||||
Produces a hash file for all the objects in the path using the hash
|
||||
@@ -21549,6 +21586,8 @@ And this sets NOTICE level logs (normal without -v)
|
||||
|
||||
rclone rc options/set --json '{"main": {"LogLevel": "NOTICE"}}'
|
||||
|
||||
Authentication is required for this call.
|
||||
|
||||
pluginsctl/addPlugin: Add a plugin using url
|
||||
|
||||
Used for adding a plugin to the webgui.
|
||||
@@ -22962,7 +23001,7 @@ Flags for general networking and HTTP stuff.
|
||||
--tpslimit float Limit HTTP transactions per second to this
|
||||
--tpslimit-burst int Max burst of transactions for --tpslimit (default 1)
|
||||
--use-cookies Enable session cookiejar
|
||||
--user-agent string Set the user-agent to a specified string (default "rclone/v1.73.0")
|
||||
--user-agent string Set the user-agent to a specified string (default "rclone/v1.73.5")
|
||||
|
||||
Performance
|
||||
|
||||
@@ -23416,9 +23455,11 @@ Backend-only flags (these can be set in the config file also).
|
||||
--filefabric-token-expiry string Token expiry time
|
||||
--filefabric-url string URL of the Enterprise File Fabric to connect to
|
||||
--filefabric-version string Version read from the file fabric
|
||||
--filelu-chunk-size SizeSuffix Chunk size to use for uploading. Used for multipart uploads (default 64Mi)
|
||||
--filelu-description string Description of the remote
|
||||
--filelu-encoding Encoding The encoding for the backend (default Slash,LtGt,DoubleQuote,SingleQuote,BackQuote,Dollar,Colon,Question,Asterisk,Pipe,Hash,Percent,BackSlash,CrLf,Del,Ctl,LeftSpace,LeftPeriod,LeftTilde,LeftCrLfHtVt,RightSpace,RightPeriod,RightCrLfHtVt,InvalidUtf8,Dot,SquareBracket,Semicolon,Exclamation)
|
||||
--filelu-key string Your FileLu Rclone key from My Account
|
||||
--filelu-upload-cutoff SizeSuffix Cutoff for switching to chunked upload. Any files larger than this will be uploaded in chunks of chunk_size (default 500Mi)
|
||||
--filen-api-key string API Key for your Filen account (obscured)
|
||||
--filen-auth-version string Authentication Version (internal use only)
|
||||
--filen-base-folder-uuid string UUID of Account Root Directory (internal use only)
|
||||
@@ -25626,11 +25667,9 @@ The following backends have known issues that need more investigation:
|
||||
|
||||
- TestDropbox (dropbox)
|
||||
- TestBisyncRemoteRemote/normalization
|
||||
- TestSeafile (seafile)
|
||||
- TestBisyncLocalRemote/volatile
|
||||
- TestSeafileV6 (seafile)
|
||||
- TestBisyncLocalRemote/volatile
|
||||
- Updated: 2026-01-30-010015
|
||||
- TestBisyncLocalRemote/rmdirs
|
||||
- Updated: 2026-04-19-010011
|
||||
|
||||
The following backends either have not been tested recently or have
|
||||
known issues that are deemed unfixable for the time being:
|
||||
@@ -27690,6 +27729,26 @@ work with the SDK properly:
|
||||
. .
|
||||
.. ..
|
||||
|
||||
Important note about double slashes (//)
|
||||
|
||||
Object keys containing consecutive forward slashes (//) are not
|
||||
supported by rclone.
|
||||
|
||||
When rclone encounters an object key with // (e.g., a//b), it will
|
||||
normalize the path to use a single slash (e.g., a/b). This normalization
|
||||
can cause "object not found" errors when trying to access the original
|
||||
object, as rclone will look for the normalized path instead of the
|
||||
actual object key.
|
||||
|
||||
Example: - Original S3 object key: folder//file.txt - rclone interprets
|
||||
it as: folder/file.txt - Result: "object not found" error when trying to
|
||||
access folder//file.txt
|
||||
|
||||
Workaround: Avoid using consecutive forward slashes (//) in S3 object
|
||||
keys when using rclone. If you have existing objects with // in their
|
||||
keys, you will need to rename them to use single slashes or access them
|
||||
through other means.
|
||||
|
||||
Multipart uploads
|
||||
|
||||
rclone supports multipart uploads with S3 which means that it can upload
|
||||
@@ -28724,6 +28783,10 @@ Properties:
|
||||
- "s3.cubbit.eu"
|
||||
- Cubbit DS3 Object Storage endpoint
|
||||
- Provider: Cubbit
|
||||
- "s3.{tenant_name}.cubbit.eu"
|
||||
- Multi-tenant endpoint - replace {tenant_name} with your
|
||||
actual tenant name. Do not select this directly
|
||||
- Provider: Cubbit
|
||||
- "syd1.digitaloceanspaces.com"
|
||||
- DigitalOcean Spaces Sydney 1
|
||||
- Provider: DigitalOcean
|
||||
@@ -32076,7 +32139,9 @@ pair. You can follow this guide to retrieve these keys. They will be
|
||||
needed when prompted by rclone config.
|
||||
|
||||
Default region will correspond to eu-west-1 and the endpoint has to be
|
||||
specified as s3.cubbit.eu.
|
||||
specified as s3.cubbit.eu. If you set a custom tenant endpoint, you must
|
||||
use s3.{tenant_name}.cubbit.eu, because the generic s3.cubbit.eu
|
||||
endpoint will not work in this case.
|
||||
|
||||
Going through the whole process of creating a new remote by running
|
||||
rclone config, each prompt should be answered as shown below:
|
||||
@@ -32088,7 +32153,7 @@ rclone config, each prompt should be answered as shown below:
|
||||
access_key_id> YOUR_ACCESS_KEY
|
||||
secret_access_key> YOUR_SECRET_KEY
|
||||
region> eu-west-1 (or leave empty)
|
||||
endpoint> s3.cubbit.eu
|
||||
endpoint> s3.cubbit.eu (or s3.{tenant_name}.cubbit.eu)
|
||||
acl>
|
||||
|
||||
The resulting configuration file should look like:
|
||||
@@ -35699,6 +35764,16 @@ To configure access to Tencent COS, follow the steps below:
|
||||
==== ====
|
||||
cos s3
|
||||
|
||||
Tencent COS Global Acceleration Endpoint
|
||||
|
||||
When using the Global Acceleration Endpoint
|
||||
(cos.accelerate.myqcloud.com), rclone automatically sets
|
||||
no_check_bucket = true because this acceleration endpoint does not
|
||||
support the CreateBucket call which is used for ensuring a bucket's
|
||||
existence by rclone. Global Acceleration is a per-bucket feature, so you
|
||||
should first create the bucket in one physical region, then enable it in
|
||||
the Tencent Cloud console.
|
||||
|
||||
Wasabi
|
||||
|
||||
Wasabi is a cloud-based object storage service for a broad range of
|
||||
@@ -42261,6 +42336,29 @@ Advanced options
|
||||
|
||||
Here are the Advanced options specific to filelu (FileLu Cloud Storage).
|
||||
|
||||
--filelu-upload-cutoff
|
||||
|
||||
Cutoff for switching to chunked upload. Any files larger than this will
|
||||
be uploaded in chunks of chunk_size.
|
||||
|
||||
Properties:
|
||||
|
||||
- Config: upload_cutoff
|
||||
- Env Var: RCLONE_FILELU_UPLOAD_CUTOFF
|
||||
- Type: SizeSuffix
|
||||
- Default: 500Mi
|
||||
|
||||
--filelu-chunk-size
|
||||
|
||||
Chunk size to use for uploading. Used for multipart uploads.
|
||||
|
||||
Properties:
|
||||
|
||||
- Config: chunk_size
|
||||
- Env Var: RCLONE_FILELU_CHUNK_SIZE
|
||||
- Type: SizeSuffix
|
||||
- Default: 64Mi
|
||||
|
||||
--filelu-encoding
|
||||
|
||||
The encoding for the backend.
|
||||
@@ -42304,6 +42402,10 @@ account, currently this is only possible using the Filen CLI. This means
|
||||
you must first download the CLI, login, and then run the export-api-key
|
||||
command.
|
||||
|
||||
Note: If you change your Filen account password, you will need to update
|
||||
your rclone configuration with the new password and a re-exported API
|
||||
key (via export-api-key).
|
||||
|
||||
Here is an example of how to make a remote called FilenRemote. First
|
||||
run:
|
||||
|
||||
@@ -65100,6 +65202,163 @@ Options:
|
||||
|
||||
Changelog
|
||||
|
||||
v1.73.5 - 2026-04-19
|
||||
|
||||
See commits
|
||||
|
||||
- Bug Fixes
|
||||
- operations: Add AuthRequired to operations/fsinfo to prevent
|
||||
backend creation CVE-2026-41179 (Nick Craig-Wood)
|
||||
- rc
|
||||
- Add AuthRequired to options/set to prevent auth bypass
|
||||
CVE-2026-41176 (Nick Craig-Wood)
|
||||
- Snapshot NoAuth at startup to prevent runtime auth bypass
|
||||
CVE-2026-41176 (Nick Craig-Wood)
|
||||
- filter: Fix debug logs that fire before logger is configured
|
||||
(Nick Craig-Wood)
|
||||
- Azureblob
|
||||
- Add Microsoft Partner Network User-Agent prefix (Nick
|
||||
Craig-Wood)
|
||||
- Drime
|
||||
- Fix User.EntryPermissions JSON unmarshalling (a1pcm)
|
||||
- Iclouddrive
|
||||
- Fix 'directory not found' error when the directory contains
|
||||
accent marks (Brais Couce)
|
||||
- S3
|
||||
- Fix TencentCOS CDN endpoint failing on bucket check (Mozi)
|
||||
- Fix empty delimiter parameter rejected by Archiware P5 server
|
||||
(Nick Craig-Wood)
|
||||
|
||||
v1.73.4 - 2026-04-08
|
||||
|
||||
See commits
|
||||
|
||||
- Bug Fixes
|
||||
- build
|
||||
- Update to go 1.25.9 to fix multiple CVEs (Nick Craig-Wood)
|
||||
- CVE-2026-32282: os: Root.Chmod can follow symlinks out
|
||||
of the root on Linux
|
||||
- CVE-2026-32289: html/template: JS template literal
|
||||
context incorrectly tracked
|
||||
- CVE-2026-33810: crypto/x509: excluded DNS constraints
|
||||
not properly applied to wildcard domains
|
||||
- CVE-2026-27144: cmd/compile: no-op interface conversion
|
||||
bypasses overlap checking
|
||||
- CVE-2026-27143: cmd/compile: possible memory corruption
|
||||
after bound check elimination
|
||||
- CVE-2026-32288: archive/tar: unbounded allocation when
|
||||
parsing old format GNU sparse map
|
||||
- CVE-2026-32283: crypto/tls: multiple key update
|
||||
handshake messages can cause connection to deadlock
|
||||
- CVE-2026-27140: cmd/go: trust layer bypass when using
|
||||
cgo and SWIG
|
||||
- CVE-2026-32280: crypto/x509: unexpected work during
|
||||
chain building
|
||||
- CVE-2026-32281: crypto/x509: inefficient policy
|
||||
validation
|
||||
- Fix Denial of Service due to Panic in AWS SDK for Go v2 SDK
|
||||
EventStream Decoder (dependabot[bot])
|
||||
- Update golang.org/x/image to 0.38.0 to fix CVE-2026-33809
|
||||
(dependabot[bot])
|
||||
- docs
|
||||
- Fix header level for metadata option (Clément Notin)
|
||||
- Fix markdown issues in mount docs (albertony)
|
||||
- Fix link to not be language specific (Ross Smith II)
|
||||
- Note macOS 10.15 (Catalina) support with version v1.70.3
|
||||
(kapitainsky)
|
||||
- Filen
|
||||
- Update SDK version (Enduriel)
|
||||
|
||||
v1.73.3 - 2026-03-23
|
||||
|
||||
See commits
|
||||
|
||||
- Bug Fixes
|
||||
- build
|
||||
- Update to google.golang.org/grpc 1.79.3 to fix
|
||||
CVE-2026-33186 (dependabot[bot])
|
||||
- Update to github.com/buger/jsonparser 1.1.2 to fix
|
||||
GHSA-6g7g-w4f8-9c9x (dependabot[bot])
|
||||
- doc fixes
|
||||
- Added text to the label showing version-introduced info
|
||||
(Jan-Philipp Reßler)
|
||||
- Clarify Filen password change requires updating both
|
||||
password and API key in rclone config (Jason)
|
||||
- s3: clarify multi tenant support for Cubbit (Marco Ferretti)
|
||||
- jottacloud: Fix broken link (albertony)
|
||||
- lib/rest: Fix URLPathEscapeAll breaking WebDAV servers (eg
|
||||
nzbdav) with strict path matching (Andrew Furman)
|
||||
- list: Fix nil pointer panic in Sorter when temp file creation
|
||||
fails (Nick Craig-Wood)
|
||||
|
||||
v1.73.2 - 2026-03-06
|
||||
|
||||
See commits
|
||||
|
||||
- Bug Fixes
|
||||
- build
|
||||
- Update to go 1.25.8 to fix CVE-2026-27137 CVE-2026-27138
|
||||
CVE-2026-25679 CVE-2026-27142 (Nick Craig-Wood)
|
||||
- Update github.com/cloudflare/circl to v1.6.3 to fix
|
||||
CVE-2026-1229 (Nick Craig-Wood)
|
||||
- Update to golang.org/x/net v0.51.0 to fix CVE-2026-27141
|
||||
(Nick Craig-Wood)
|
||||
- docs fixes:
|
||||
- bisync: Add group Sync to the bisync command (Jan-Philipp
|
||||
Reßler)
|
||||
- Note that --use-server-modtime only works on some backends
|
||||
(Nick Craig-Wood)
|
||||
- Document unsupported S3 object keys with double slashes
|
||||
(Adam Kasztenny)
|
||||
- Fix headers hierarchy for mount.md (Dark Dragon)
|
||||
- Fix new drive flag typo in changelog (razorloves)
|
||||
- Archive
|
||||
- Extract: fix extraction with "./" prefix from tar entry paths
|
||||
(Varun Chawla)
|
||||
- Drime
|
||||
- Fix chunk-uploaded files ignoring workspace ID (a1pcm)
|
||||
- Internxt
|
||||
- Fix Entry doesn't belong in directory errors on windows
|
||||
(jzunigax2)
|
||||
- WebDAV
|
||||
- Escape reserved characters in URL path segments (Varun Chawla)
|
||||
- Add missing headers for CORS (Romāns Potašovs)
|
||||
|
||||
v1.73.1 - 2026-02-17
|
||||
|
||||
See commits
|
||||
|
||||
- Bug Fixes
|
||||
- accounting: Fix missing server side stats from core/stats rc
|
||||
(Nick Craig-Wood)
|
||||
- build
|
||||
- Fix CVE-2025-68121 by updating go to 1.25.7 or later (Nick
|
||||
Craig-Wood)
|
||||
- Bump github.com/go-chi/chi/v5 from 5.2.3 to 5.2.5 to fix
|
||||
GO-2026-4316 (albertony)
|
||||
- docs: Extend copyurl docs with an example of CSV FILENAMEs
|
||||
starting with a path. (Jack Kelly)
|
||||
- march: Fix runtime: program exceeds 10000-thread limit (Nick
|
||||
Craig-Wood)
|
||||
- pacer
|
||||
- Fix deadlock between pacer token and --max-connections (Nick
|
||||
Craig-Wood)
|
||||
- Re-read the sleep time as it may be stale (Nick Craig-Wood)
|
||||
- Drime
|
||||
- Fix files and directories being created in the default workspace
|
||||
(Nick Craig-Wood)
|
||||
- Filelu
|
||||
- Avoid buffering entire file in memory (kingston125)
|
||||
- Add multipart upload support with configurable cutoff
|
||||
(kingston125)
|
||||
- Filen
|
||||
- Fix 32 bit targets not being able to list directories (Enduriel)
|
||||
- Fix potential panic in case of error during upload (Enduriel)
|
||||
- Internxt
|
||||
- Implement re-login under refresh logic, improve retry logic
|
||||
(José Zúniga) -S3
|
||||
- Set list_version to 2 for FileLu S3 configuration (kingston125)
|
||||
|
||||
v1.73.0 - 2026-01-30
|
||||
|
||||
See commits
|
||||
@@ -65135,7 +65394,7 @@ See commits
|
||||
- Support authentication with new bucket restricted application
|
||||
keys (DianaNites)
|
||||
- Drive
|
||||
- Add --drive-metadata-force-expansive-access flag (Nick
|
||||
- Add --drive-metadata-enforce-expansive-access flag (Nick
|
||||
Craig-Wood)
|
||||
- Fix crash when trying to creating shortcut to a Google doc (Nick
|
||||
Craig-Wood)
|
||||
|
||||
+55
-1
@@ -32,10 +32,11 @@ This file describes how to make the various kinds of releases
|
||||
- make sign_upload
|
||||
- make check_sign
|
||||
- make upload
|
||||
- make upload_test_website # check sponsors are correct/unchanged
|
||||
- make upload_website
|
||||
- make upload_github
|
||||
- make startdev # make startstable for stable branch
|
||||
- \# announce with forum post, twitter post, patreon post
|
||||
- \# announce with forum post, twitter post, and post to annoucements list
|
||||
|
||||
## Update dependencies
|
||||
|
||||
@@ -109,6 +110,59 @@ go run github.com/icholy/gomajor@latest list -major
|
||||
|
||||
Expect API breakage when updating major versions.
|
||||
|
||||
## Updating Go
|
||||
|
||||
When a new Go stable is released update to it. We support the current
|
||||
stable Go and the previous release which is in line with the rest of
|
||||
the Go ecosystem.
|
||||
|
||||
These files will need editing:
|
||||
|
||||
- `.github/workflows/build.yml` - change current and previous Go versions
|
||||
- `docs/content/install.md` - change minimum Go version required
|
||||
- `fs/versioncheck.go` - update minimum Go version required
|
||||
- `go.mod` - update minimum Go version required
|
||||
|
||||
Check it builds
|
||||
|
||||
- `make GOTAGS=cmount`
|
||||
- `make compiletest`
|
||||
|
||||
Assuming `go1.XX` is current and `go1.YY` is previous version:
|
||||
|
||||
Use `git grep go1.YY` and `git grep go1.YY` to look for opportunities
|
||||
to remove build tags we no longer need.
|
||||
|
||||
Commit with message like this:
|
||||
|
||||
```text
|
||||
build: update to go1.YY and make go1.YY the minimum required version
|
||||
```
|
||||
|
||||
Send to CI and if it passes, merge.
|
||||
|
||||
### gofix
|
||||
|
||||
Updating the minimum required version of Go is a good opportunity to
|
||||
run the `go fix` command to modernize Go usage.
|
||||
|
||||
This needs to be run for all architectures.
|
||||
|
||||
```console
|
||||
GOOS=linux go fix -tags cmount ./...
|
||||
GOOS=freebsd go fix -tags cmount ./...
|
||||
GOOS=windows go fix -tags cmount ./...
|
||||
GOOS=darwin go fix -tags cmount ./...
|
||||
```
|
||||
|
||||
Examine the diff carefully.
|
||||
|
||||
Commit with message
|
||||
|
||||
```text
|
||||
build: modernize Go code with go fix for go1.YY
|
||||
```
|
||||
|
||||
## Tidy beta
|
||||
|
||||
At some point after the release run
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore/policy"
|
||||
@@ -283,6 +284,9 @@ type transporter struct {
|
||||
|
||||
// Make a new transporter
|
||||
func newTransporter(ctx context.Context) transporter {
|
||||
// Set the User-Agent to include the Microsoft Partner Network prefix
|
||||
ctx, ci := fs.AddConfig(ctx)
|
||||
ci.UserAgent = "APN/1.0 rclone/1.0 rclone/" + strings.TrimPrefix(fs.Version, "v")
|
||||
return transporter{
|
||||
RoundTripper: fshttp.NewTransport(ctx),
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ type User struct {
|
||||
Avatar string `json:"avatar"`
|
||||
ModelType string `json:"model_type"`
|
||||
OwnsEntry bool `json:"owns_entry"`
|
||||
EntryPermissions []any `json:"entry_permissions"`
|
||||
EntryPermissions any `json:"entry_permissions"`
|
||||
DisplayName string `json:"display_name"`
|
||||
}
|
||||
|
||||
@@ -173,6 +173,7 @@ type MultiPartCreateRequest struct {
|
||||
Extension string `json:"extension"`
|
||||
ParentID json.Number `json:"parent_id"`
|
||||
RelativePath string `json:"relativePath"`
|
||||
WorkspaceID string `json:"workspaceId,omitempty"`
|
||||
}
|
||||
|
||||
// MultiPartCreateResponse is returned by POST /s3/multipart/create
|
||||
@@ -223,6 +224,7 @@ type MultiPartEntriesRequest struct {
|
||||
ClientExtension string `json:"clientExtension"`
|
||||
ParentID json.Number `json:"parent_id"`
|
||||
RelativePath string `json:"relativePath"`
|
||||
WorkspaceID string `json:"workspaceId,omitempty"`
|
||||
}
|
||||
|
||||
// MultiPartEntriesResponse is the result of POST /s3/entries
|
||||
|
||||
+27
-8
@@ -476,8 +476,12 @@ func (f *Fs) createDir(ctx context.Context, pathID, leaf string, modTime time.Ti
|
||||
var resp *http.Response
|
||||
var result api.CreateFolderResponse
|
||||
opts := rest.Opts{
|
||||
Method: "POST",
|
||||
Path: "/folders",
|
||||
Method: "POST",
|
||||
Path: "/folders",
|
||||
Parameters: url.Values{},
|
||||
}
|
||||
if f.opt.WorkspaceID != "" {
|
||||
opts.Parameters.Set("workspaceId", f.opt.WorkspaceID)
|
||||
}
|
||||
mkdir := api.CreateFolderRequest{
|
||||
Name: f.opt.Enc.FromStandardName(leaf),
|
||||
@@ -779,8 +783,12 @@ func (f *Fs) patch(ctx context.Context, id, attribute string, value string) (ite
|
||||
}
|
||||
var result api.UpdateItemResponse
|
||||
opts := rest.Opts{
|
||||
Method: "PUT",
|
||||
Path: "/file-entries/" + id,
|
||||
Method: "PUT",
|
||||
Path: "/file-entries/" + id,
|
||||
Parameters: url.Values{},
|
||||
}
|
||||
if f.opt.WorkspaceID != "" {
|
||||
opts.Parameters.Set("workspaceId", f.opt.WorkspaceID)
|
||||
}
|
||||
err = f.pacer.Call(func() (bool, error) {
|
||||
resp, err = f.srv.CallJSON(ctx, &opts, &request, &result)
|
||||
@@ -807,8 +815,12 @@ func (f *Fs) move(ctx context.Context, id, newDirID string) (err error) {
|
||||
}
|
||||
var result api.MoveResponse
|
||||
opts := rest.Opts{
|
||||
Method: "POST",
|
||||
Path: "/file-entries/move",
|
||||
Method: "POST",
|
||||
Path: "/file-entries/move",
|
||||
Parameters: url.Values{},
|
||||
}
|
||||
if f.opt.WorkspaceID != "" {
|
||||
opts.Parameters.Set("workspaceId", f.opt.WorkspaceID)
|
||||
}
|
||||
err = f.pacer.Call(func() (bool, error) {
|
||||
resp, err = f.srv.CallJSON(ctx, &opts, &request, &result)
|
||||
@@ -945,8 +957,12 @@ func (f *Fs) copy(ctx context.Context, id, newDirID string) (item *api.Item, err
|
||||
}
|
||||
var result api.CopyResponse
|
||||
opts := rest.Opts{
|
||||
Method: "POST",
|
||||
Path: "/file-entries/duplicate",
|
||||
Method: "POST",
|
||||
Path: "/file-entries/duplicate",
|
||||
Parameters: url.Values{},
|
||||
}
|
||||
if f.opt.WorkspaceID != "" {
|
||||
opts.Parameters.Set("workspaceId", f.opt.WorkspaceID)
|
||||
}
|
||||
err = f.pacer.Call(func() (bool, error) {
|
||||
resp, err = f.srv.CallJSON(ctx, &opts, &request, &result)
|
||||
@@ -1114,6 +1130,7 @@ func (f *Fs) OpenChunkWriter(ctx context.Context, remote string, src fs.ObjectIn
|
||||
Extension: strings.TrimPrefix(path.Ext(leaf), `.`),
|
||||
ParentID: json.Number(directoryID),
|
||||
RelativePath: f.opt.Enc.FromStandardPath(path.Join(f.root, remote)),
|
||||
WorkspaceID: f.opt.WorkspaceID,
|
||||
}
|
||||
|
||||
var resp api.MultiPartCreateResponse
|
||||
@@ -1297,6 +1314,7 @@ func (s *drimeChunkWriter) Close(ctx context.Context) error {
|
||||
ClientExtension: s.extension,
|
||||
ParentID: s.parentID,
|
||||
RelativePath: s.relativePath,
|
||||
WorkspaceID: s.f.opt.WorkspaceID,
|
||||
}
|
||||
|
||||
entriesOpts := rest.Opts{
|
||||
@@ -1509,6 +1527,7 @@ func (o *Object) Update(ctx context.Context, in io.Reader, src fs.ObjectInfo, op
|
||||
MultipartParams: url.Values{
|
||||
"parentId": {directoryID},
|
||||
"relativePath": {encodedLeaf},
|
||||
"workspaceId": {o.fs.opt.WorkspaceID},
|
||||
},
|
||||
MultipartContentName: "file",
|
||||
MultipartFileName: encodedLeaf,
|
||||
|
||||
@@ -3,6 +3,19 @@ package api
|
||||
|
||||
import "encoding/json"
|
||||
|
||||
// MultipartInitResponse represents the response from multipart/init.
|
||||
type MultipartInitResponse struct {
|
||||
Status int `json:"status"`
|
||||
Msg string `json:"msg"`
|
||||
Result struct {
|
||||
UploadID string `json:"upload_id"`
|
||||
SessID string `json:"sess_id"`
|
||||
Server string `json:"server"`
|
||||
FolderID int64 `json:"folder_id"`
|
||||
ObjectPath string `json:"object_path"`
|
||||
} `json:"result"`
|
||||
}
|
||||
|
||||
// CreateFolderResponse represents the response for creating a folder.
|
||||
type CreateFolderResponse struct {
|
||||
Status int `json:"status"`
|
||||
|
||||
+24
-19
@@ -21,6 +21,11 @@ import (
|
||||
"github.com/rclone/rclone/lib/rest"
|
||||
)
|
||||
|
||||
const (
|
||||
defaultUploadCutoff = fs.SizeSuffix(500 * 1024 * 1024)
|
||||
defaultChunkSize = fs.SizeSuffix(64 * 1024 * 1024)
|
||||
)
|
||||
|
||||
// Register the backend with Rclone
|
||||
func init() {
|
||||
fs.Register(&fs.RegInfo{
|
||||
@@ -33,6 +38,17 @@ func init() {
|
||||
Required: true,
|
||||
Sensitive: true,
|
||||
},
|
||||
{
|
||||
Name: "upload_cutoff",
|
||||
Help: "Cutoff for switching to chunked upload. Any files larger than this will be uploaded in chunks of chunk_size.",
|
||||
Default: defaultUploadCutoff,
|
||||
Advanced: true,
|
||||
}, {
|
||||
Name: "chunk_size",
|
||||
Help: "Chunk size to use for uploading. Used for multipart uploads.",
|
||||
Default: defaultChunkSize,
|
||||
Advanced: true,
|
||||
},
|
||||
{
|
||||
Name: config.ConfigEncoding,
|
||||
Help: config.ConfigEncodingHelp,
|
||||
@@ -72,8 +88,10 @@ func init() {
|
||||
|
||||
// Options defines the configuration for the FileLu backend
|
||||
type Options struct {
|
||||
Key string `config:"key"`
|
||||
Enc encoder.MultiEncoder `config:"encoding"`
|
||||
Key string `config:"key"`
|
||||
Enc encoder.MultiEncoder `config:"encoding"`
|
||||
UploadCutoff fs.SizeSuffix `config:"upload_cutoff"`
|
||||
ChunkSize fs.SizeSuffix `config:"chunk_size"`
|
||||
}
|
||||
|
||||
// Fs represents the FileLu file system
|
||||
@@ -189,7 +207,6 @@ func (f *Fs) Purge(ctx context.Context, dir string) error {
|
||||
return f.deleteFolder(ctx, fullPath)
|
||||
}
|
||||
|
||||
// List returns a list of files and folders
|
||||
// List returns a list of files and folders for the given directory
|
||||
func (f *Fs) List(ctx context.Context, dir string) (fs.DirEntries, error) {
|
||||
// Compose full path for API call
|
||||
@@ -250,23 +267,11 @@ func (f *Fs) List(ctx context.Context, dir string) (fs.DirEntries, error) {
|
||||
|
||||
// Put uploads a file directly to the destination folder in the FileLu storage system.
|
||||
func (f *Fs) Put(ctx context.Context, in io.Reader, src fs.ObjectInfo, options ...fs.OpenOption) (fs.Object, error) {
|
||||
if src.Size() == 0 {
|
||||
return nil, fs.ErrorCantUploadEmptyFiles
|
||||
o := &Object{
|
||||
fs: f,
|
||||
remote: src.Remote(),
|
||||
}
|
||||
|
||||
err := f.uploadFile(ctx, in, src.Remote())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
newObject := &Object{
|
||||
fs: f,
|
||||
remote: src.Remote(),
|
||||
size: src.Size(),
|
||||
modTime: src.ModTime(ctx),
|
||||
}
|
||||
fs.Infof(f, "Put: Successfully uploaded new file %q", src.Remote())
|
||||
return newObject, nil
|
||||
return o, o.Update(ctx, in, src, options...)
|
||||
}
|
||||
|
||||
// Move moves the file to the specified location
|
||||
|
||||
@@ -16,6 +16,59 @@ import (
|
||||
"github.com/rclone/rclone/lib/rest"
|
||||
)
|
||||
|
||||
// multipartInit starts a new multipart upload and returns server details.
|
||||
func (f *Fs) multipartInit(ctx context.Context, folderPath, filename string) (*api.MultipartInitResponse, error) {
|
||||
opts := rest.Opts{
|
||||
Method: "GET",
|
||||
Path: "/multipart/init",
|
||||
Parameters: url.Values{
|
||||
"key": {f.opt.Key},
|
||||
"filename": {filename},
|
||||
"folder_path": {folderPath},
|
||||
},
|
||||
}
|
||||
|
||||
var result api.MultipartInitResponse
|
||||
|
||||
err := f.pacer.Call(func() (bool, error) {
|
||||
_, err := f.srv.CallJSON(ctx, &opts, nil, &result)
|
||||
return fserrors.ShouldRetry(err), err
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if result.Status != 200 {
|
||||
return nil, fmt.Errorf("multipart init error: %s", result.Msg)
|
||||
}
|
||||
|
||||
return &result, nil
|
||||
}
|
||||
|
||||
// completeMultipart finalizes the multipart upload on the file server.
|
||||
func (f *Fs) completeMultipart(ctx context.Context, server string, uploadID string, sessID string, objectPath string) error {
|
||||
req, err := http.NewRequestWithContext(ctx, "POST", server, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
req.Header.Set("X-RC-Upload-Id", uploadID)
|
||||
req.Header.Set("X-Sess-ID", sessID)
|
||||
req.Header.Set("X-Object-Path", objectPath)
|
||||
|
||||
resp, err := f.client.Do(req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer func() { _ = resp.Body.Close() }()
|
||||
|
||||
if resp.StatusCode != 202 {
|
||||
body, _ := io.ReadAll(resp.Body)
|
||||
return fmt.Errorf("completeMultipart failed %d: %s", resp.StatusCode, string(body))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// createFolder creates a folder at the specified path.
|
||||
func (f *Fs) createFolder(ctx context.Context, dirPath string) (*api.CreateFolderResponse, error) {
|
||||
encodedDir := f.fromStandardPath(dirPath)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package filelu
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
@@ -15,6 +16,105 @@ import (
|
||||
"github.com/rclone/rclone/fs"
|
||||
)
|
||||
|
||||
// multipartUpload uploads a file in fixed-size chunks using the multipart API.
|
||||
func (f *Fs) multipartUpload(ctx context.Context, in io.Reader, remote string) error {
|
||||
dir := path.Dir(remote)
|
||||
if dir == "." {
|
||||
dir = ""
|
||||
}
|
||||
|
||||
if dir != "" {
|
||||
_ = f.Mkdir(ctx, dir)
|
||||
}
|
||||
|
||||
folder := strings.Trim(dir, "/")
|
||||
if folder != "" {
|
||||
folder = "/" + folder
|
||||
}
|
||||
|
||||
file := path.Base(remote)
|
||||
|
||||
initResp, err := f.multipartInit(ctx, folder, file)
|
||||
if err != nil {
|
||||
return fmt.Errorf("multipart init failed: %w", err)
|
||||
}
|
||||
|
||||
uploadID := initResp.Result.UploadID
|
||||
sessID := initResp.Result.SessID
|
||||
server := initResp.Result.Server
|
||||
objectPath := initResp.Result.ObjectPath
|
||||
|
||||
chunkSize := int(f.opt.ChunkSize)
|
||||
buf := make([]byte, 0, chunkSize)
|
||||
tmp := make([]byte, 1024*1024)
|
||||
partNo := 1
|
||||
|
||||
for {
|
||||
n, errRead := in.Read(tmp)
|
||||
if n > 0 {
|
||||
buf = append(buf, tmp[:n]...)
|
||||
|
||||
// If buffer reached chunkSize, upload a full part
|
||||
if len(buf) >= chunkSize {
|
||||
err = f.uploadPart(ctx, server, uploadID, sessID, objectPath, partNo, bytes.NewReader(buf))
|
||||
if err != nil {
|
||||
return fmt.Errorf("upload part %d failed: %w", partNo, err)
|
||||
}
|
||||
partNo++
|
||||
buf = buf[:0]
|
||||
}
|
||||
}
|
||||
|
||||
if errRead == io.EOF {
|
||||
break
|
||||
}
|
||||
if errRead != nil {
|
||||
return fmt.Errorf("read failed: %w", errRead)
|
||||
}
|
||||
}
|
||||
|
||||
if len(buf) > 0 {
|
||||
err = f.uploadPart(ctx, server, uploadID, sessID, objectPath, partNo, bytes.NewReader(buf))
|
||||
if err != nil {
|
||||
return fmt.Errorf("upload part %d failed: %w", partNo, err)
|
||||
}
|
||||
}
|
||||
|
||||
err = f.completeMultipart(ctx, server, uploadID, sessID, objectPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("complete multipart failed: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// uploadPart sends a single multipart chunk to the upload server.
|
||||
func (f *Fs) uploadPart(ctx context.Context, server, uploadID, sessID, objectPath string, partNo int, r io.Reader) error {
|
||||
url := fmt.Sprintf("%s?partNumber=%d&uploadId=%s", server, partNo, uploadID)
|
||||
|
||||
req, err := http.NewRequestWithContext(ctx, "PUT", url, r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
req.Header.Set("X-RC-Upload-Id", uploadID)
|
||||
req.Header.Set("X-RC-Part-No", fmt.Sprintf("%d", partNo))
|
||||
req.Header.Set("X-Sess-ID", sessID)
|
||||
req.Header.Set("X-Object-Path", objectPath)
|
||||
|
||||
resp, err := f.client.Do(req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer func() { _ = resp.Body.Close() }()
|
||||
|
||||
if resp.StatusCode != 200 {
|
||||
return fmt.Errorf("uploadPart failed: %s", resp.Status)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// uploadFile uploads a file to FileLu
|
||||
func (f *Fs) uploadFile(ctx context.Context, fileContent io.Reader, fileFullPath string) error {
|
||||
directory := path.Dir(fileFullPath)
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package filelu
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
@@ -88,6 +87,7 @@ func (o *Object) Open(ctx context.Context, options ...fs.OpenOption) (io.ReadClo
|
||||
}
|
||||
}
|
||||
|
||||
// Wrap the response body to handle offset and count
|
||||
var reader io.ReadCloser
|
||||
err = o.fs.pacer.Call(func() (bool, error) {
|
||||
req, err := http.NewRequestWithContext(ctx, "GET", directLink, nil)
|
||||
@@ -109,22 +109,25 @@ func (o *Object) Open(ctx context.Context, options ...fs.OpenOption) (io.ReadClo
|
||||
return false, fmt.Errorf("failed to download file: HTTP %d", resp.StatusCode)
|
||||
}
|
||||
|
||||
// Wrap the response body to handle offset and count
|
||||
currentContents, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("failed to read response body: %w", err)
|
||||
if offset > 0 {
|
||||
_, err = io.CopyN(io.Discard, resp.Body, offset)
|
||||
if err != nil {
|
||||
_ = resp.Body.Close()
|
||||
return false, fmt.Errorf("failed to skip offset: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
if offset > 0 {
|
||||
if offset > int64(len(currentContents)) {
|
||||
return false, fmt.Errorf("offset %d exceeds file size %d", offset, len(currentContents))
|
||||
if count > 0 {
|
||||
reader = struct {
|
||||
io.Reader
|
||||
io.Closer
|
||||
}{
|
||||
Reader: io.LimitReader(resp.Body, count),
|
||||
Closer: resp.Body,
|
||||
}
|
||||
currentContents = currentContents[offset:]
|
||||
} else {
|
||||
reader = resp.Body
|
||||
}
|
||||
if count > 0 && count < int64(len(currentContents)) {
|
||||
currentContents = currentContents[:count]
|
||||
}
|
||||
reader = io.NopCloser(bytes.NewReader(currentContents))
|
||||
|
||||
return false, nil
|
||||
})
|
||||
@@ -137,15 +140,23 @@ func (o *Object) Open(ctx context.Context, options ...fs.OpenOption) (io.ReadClo
|
||||
|
||||
// Update updates the object with new data
|
||||
func (o *Object) Update(ctx context.Context, in io.Reader, src fs.ObjectInfo, options ...fs.OpenOption) error {
|
||||
if src.Size() <= 0 {
|
||||
return fs.ErrorCantUploadEmptyFiles
|
||||
size := src.Size()
|
||||
|
||||
if size <= int64(o.fs.opt.UploadCutoff) {
|
||||
err := o.fs.uploadFile(ctx, in, o.remote)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
fullPath := path.Join(o.fs.root, o.remote)
|
||||
err := o.fs.multipartUpload(ctx, in, fullPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to upload file: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
err := o.fs.uploadFile(ctx, in, o.remote)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to upload file: %w", err)
|
||||
}
|
||||
o.size = src.Size()
|
||||
o.size = size
|
||||
o.modTime = src.ModTime(ctx)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
+10
-10
@@ -355,19 +355,19 @@ type chunkWriter struct {
|
||||
chunkSize int64
|
||||
|
||||
chunksLock sync.Mutex
|
||||
knownChunks map[int][]byte // known chunks to be hashed
|
||||
nextChunkToHash int
|
||||
knownChunks map[int64][]byte // known chunks to be hashed
|
||||
nextChunkToHash int64
|
||||
|
||||
sizeLock sync.Mutex
|
||||
size int64
|
||||
}
|
||||
|
||||
func (cw *chunkWriter) WriteChunk(ctx context.Context, chunkNumber int, reader io.ReadSeeker) (bytesWritten int64, err error) {
|
||||
realChunkNumber := int(int64(chunkNumber) * (cw.chunkSize) / sdk.ChunkSize)
|
||||
realChunkNumber := int64(chunkNumber) * (cw.chunkSize) / sdk.ChunkSize
|
||||
chunk := make([]byte, sdk.ChunkSize, sdk.ChunkSize+cw.EncryptionKey.Cipher.Overhead())
|
||||
|
||||
totalWritten := int64(0)
|
||||
for sliceStart := 0; sliceStart < int(cw.chunkSize); sliceStart += sdk.ChunkSize {
|
||||
for sliceStart := int64(0); sliceStart < cw.chunkSize; sliceStart += sdk.ChunkSize {
|
||||
chunk = chunk[:sdk.ChunkSize]
|
||||
chunkRead := 0
|
||||
for {
|
||||
@@ -415,13 +415,13 @@ func (cw *chunkWriter) WriteChunk(ctx context.Context, chunkNumber int, reader i
|
||||
return totalWritten, err
|
||||
}
|
||||
resp, err := cw.filen.UploadChunk(ctx, &cw.FileUpload, realChunkNumber, chunkReadSlice)
|
||||
if err != nil {
|
||||
return totalWritten, err
|
||||
}
|
||||
select { // only care about getting this once
|
||||
case cw.bucketAndRegion <- *resp:
|
||||
default:
|
||||
}
|
||||
if err != nil {
|
||||
return totalWritten, err
|
||||
}
|
||||
totalWritten += int64(len(chunkReadSlice))
|
||||
realChunkNumber++
|
||||
}
|
||||
@@ -496,7 +496,7 @@ func (f *Fs) OpenChunkWriter(ctx context.Context, remote string, src fs.ObjectIn
|
||||
filen: f.filen,
|
||||
chunkSize: chunkSize,
|
||||
bucketAndRegion: make(chan client.V3UploadResponse, 1),
|
||||
knownChunks: make(map[int][]byte),
|
||||
knownChunks: make(map[int64][]byte),
|
||||
nextChunkToHash: 0,
|
||||
size: 0,
|
||||
}, nil
|
||||
@@ -1122,8 +1122,8 @@ func (f *Fs) About(ctx context.Context) (*fs.Usage, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
total := int64(userInfo.MaxStorage)
|
||||
used := int64(userInfo.UsedStorage)
|
||||
total := userInfo.MaxStorage
|
||||
used := userInfo.UsedStorage
|
||||
free := total - used
|
||||
return &fs.Usage{
|
||||
Total: &total,
|
||||
|
||||
@@ -27,6 +27,8 @@ import (
|
||||
"github.com/rclone/rclone/lib/dircache"
|
||||
"github.com/rclone/rclone/lib/encoder"
|
||||
"github.com/rclone/rclone/lib/pacer"
|
||||
|
||||
"golang.org/x/text/unicode/norm"
|
||||
)
|
||||
|
||||
/*
|
||||
@@ -225,7 +227,8 @@ func (f *Fs) findLeafItem(ctx context.Context, pathID string, leaf string) (item
|
||||
return nil, false, err
|
||||
}
|
||||
for _, item := range items {
|
||||
if strings.EqualFold(item.FullName(), leaf) {
|
||||
// iCloud returns file names in NFD Unicode normalization, so normalized to NFC for consistent comparison
|
||||
if strings.EqualFold(norm.NFC.String(item.FullName()), leaf) {
|
||||
return item, true, nil
|
||||
}
|
||||
}
|
||||
|
||||
+101
-1
@@ -13,8 +13,12 @@ import (
|
||||
"github.com/golang-jwt/jwt/v5"
|
||||
internxtauth "github.com/internxt/rclone-adapter/auth"
|
||||
internxtconfig "github.com/internxt/rclone-adapter/config"
|
||||
sdkerrors "github.com/internxt/rclone-adapter/errors"
|
||||
"github.com/rclone/rclone/fs"
|
||||
"github.com/rclone/rclone/fs/config/configmap"
|
||||
"github.com/rclone/rclone/fs/config/obscure"
|
||||
"github.com/rclone/rclone/fs/fserrors"
|
||||
"github.com/rclone/rclone/fs/fshttp"
|
||||
"github.com/rclone/rclone/lib/oauthutil"
|
||||
"golang.org/x/oauth2"
|
||||
)
|
||||
@@ -101,7 +105,6 @@ func jwtToOAuth2Token(jwtString string) (*oauth2.Token, error) {
|
||||
}
|
||||
|
||||
// computeBasicAuthHeader creates the BasicAuthHeader for bucket operations
|
||||
// Following the pattern from SDK's auth/access.go:96-102
|
||||
func computeBasicAuthHeader(bridgeUser, userID string) string {
|
||||
sum := sha256.Sum256([]byte(userID))
|
||||
hexPass := hex.EncodeToString(sum[:])
|
||||
@@ -144,3 +147,100 @@ func refreshJWTToken(ctx context.Context, name string, m configmap.Mapper) error
|
||||
fs.Debugf(name, "Token refreshed successfully, new expiry: %v", token.Expiry)
|
||||
return nil
|
||||
}
|
||||
|
||||
// reLogin performs a full re-login using stored email+password credentials.
|
||||
// Returns the AccessResponse on success, or an error if 2FA is required or login fails.
|
||||
func (f *Fs) reLogin(ctx context.Context) (*internxtauth.AccessResponse, error) {
|
||||
password, err := obscure.Reveal(f.opt.Pass)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("couldn't decrypt password: %w", err)
|
||||
}
|
||||
|
||||
cfg := internxtconfig.NewDefaultToken("")
|
||||
cfg.HTTPClient = fshttp.NewClient(ctx)
|
||||
|
||||
loginResp, err := internxtauth.Login(ctx, cfg, f.opt.Email)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("re-login check failed: %w", err)
|
||||
}
|
||||
|
||||
if loginResp.TFA {
|
||||
return nil, errors.New("account requires 2FA - please run: rclone config reconnect " + f.name + ":")
|
||||
}
|
||||
|
||||
resp, err := internxtauth.DoLogin(ctx, cfg, f.opt.Email, password, "")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("re-login failed: %w", err)
|
||||
}
|
||||
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// refreshOrReLogin tries to refresh the JWT token first; if that fails with 401,
|
||||
// it falls back to a full re-login using stored credentials.
|
||||
func (f *Fs) refreshOrReLogin(ctx context.Context) error {
|
||||
refreshErr := refreshJWTToken(ctx, f.name, f.m)
|
||||
if refreshErr == nil {
|
||||
newToken, err := oauthutil.GetToken(f.name, f.m)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get refreshed token: %w", err)
|
||||
}
|
||||
f.cfg.Token = newToken.AccessToken
|
||||
f.cfg.BasicAuthHeader = computeBasicAuthHeader(f.bridgeUser, f.userID)
|
||||
fs.Debugf(f, "Token refresh succeeded")
|
||||
return nil
|
||||
}
|
||||
|
||||
var httpErr *sdkerrors.HTTPError
|
||||
if !errors.As(refreshErr, &httpErr) || httpErr.StatusCode() != 401 {
|
||||
if fserrors.ShouldRetry(refreshErr) {
|
||||
return refreshErr
|
||||
}
|
||||
return refreshErr
|
||||
}
|
||||
|
||||
fs.Debugf(f, "Token refresh returned 401, attempting re-login with stored credentials")
|
||||
|
||||
resp, err := f.reLogin(ctx)
|
||||
if err != nil {
|
||||
return fmt.Errorf("re-login fallback failed: %w", err)
|
||||
}
|
||||
|
||||
oauthToken, err := jwtToOAuth2Token(resp.NewToken)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to parse re-login token: %w", err)
|
||||
}
|
||||
err = oauthutil.PutToken(f.name, f.m, oauthToken, true)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to save re-login token: %w", err)
|
||||
}
|
||||
|
||||
f.cfg.Token = oauthToken.AccessToken
|
||||
f.bridgeUser = resp.User.BridgeUser
|
||||
f.userID = resp.User.UserID
|
||||
f.cfg.BasicAuthHeader = computeBasicAuthHeader(f.bridgeUser, f.userID)
|
||||
f.cfg.Bucket = resp.User.Bucket
|
||||
f.cfg.RootFolderID = resp.User.RootFolderID
|
||||
|
||||
fs.Debugf(f, "Re-login succeeded, new token expiry: %v", oauthToken.Expiry)
|
||||
return nil
|
||||
}
|
||||
|
||||
// reAuthorize is called after getting 401 from the server.
|
||||
// It serializes re-auth attempts and uses a circuit-breaker to avoid infinite loops.
|
||||
func (f *Fs) reAuthorize(ctx context.Context) error {
|
||||
f.authMu.Lock()
|
||||
defer f.authMu.Unlock()
|
||||
|
||||
if f.authFailed {
|
||||
return errors.New("re-authorization permanently failed")
|
||||
}
|
||||
|
||||
err := f.refreshOrReLogin(ctx)
|
||||
if err != nil {
|
||||
f.authFailed = true
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
+119
-71
@@ -9,8 +9,8 @@ import (
|
||||
"io"
|
||||
"net"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/internxt/rclone-adapter/auth"
|
||||
@@ -41,16 +41,34 @@ const (
|
||||
decayConstant = 2 // bigger for slower decay, exponential
|
||||
)
|
||||
|
||||
// shouldRetry determines if an error should be retried
|
||||
func shouldRetry(ctx context.Context, err error) (bool, error) {
|
||||
// shouldRetry determines if an error should be retried.
|
||||
// On 401, it attempts to re-authorize before retrying.
|
||||
// On 429, it honours the server's rate limit retry delay.
|
||||
func (f *Fs) shouldRetry(ctx context.Context, err error) (bool, error) {
|
||||
if fserrors.ContextError(ctx, &err) {
|
||||
return false, err
|
||||
}
|
||||
var httpErr *sdkerrors.HTTPError
|
||||
if errors.As(err, &httpErr) && httpErr.StatusCode() == 401 {
|
||||
return true, err
|
||||
if errors.As(err, &httpErr) {
|
||||
switch httpErr.StatusCode() {
|
||||
case 401:
|
||||
if !f.authFailed {
|
||||
authErr := f.reAuthorize(ctx)
|
||||
if authErr != nil {
|
||||
fs.Debugf(f, "Re-authorization failed: %v", authErr)
|
||||
return false, err
|
||||
}
|
||||
return true, err
|
||||
}
|
||||
return false, err
|
||||
case 429:
|
||||
delay := httpErr.RetryAfter()
|
||||
if delay <= 0 {
|
||||
delay = time.Second
|
||||
}
|
||||
return true, pacer.RetryAfterError(err, delay)
|
||||
}
|
||||
}
|
||||
|
||||
return fserrors.ShouldRetry(err), err
|
||||
}
|
||||
|
||||
@@ -184,6 +202,7 @@ type Fs struct {
|
||||
name string
|
||||
root string
|
||||
opt Options
|
||||
m configmap.Mapper
|
||||
dirCache *dircache.DirCache
|
||||
cfg *config.Config
|
||||
features *fs.Features
|
||||
@@ -191,6 +210,8 @@ type Fs struct {
|
||||
tokenRenewer *oauthutil.Renew
|
||||
bridgeUser string
|
||||
userID string
|
||||
authMu sync.Mutex
|
||||
authFailed bool
|
||||
}
|
||||
|
||||
// Object holds the data for a remote file object
|
||||
@@ -263,45 +284,62 @@ func NewFs(ctx context.Context, name, root string, m configmap.Mapper) (fs.Fs, e
|
||||
cfg.SkipHashValidation = opt.SkipHashValidation
|
||||
cfg.HTTPClient = fshttp.NewClient(ctx)
|
||||
|
||||
userInfo, err := getUserInfo(ctx, &userInfoConfig{Token: cfg.Token})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to fetch user info: %w", err)
|
||||
}
|
||||
|
||||
cfg.RootFolderID = userInfo.RootFolderID
|
||||
cfg.Bucket = userInfo.Bucket
|
||||
cfg.BasicAuthHeader = computeBasicAuthHeader(userInfo.BridgeUser, userInfo.UserID)
|
||||
|
||||
f := &Fs{
|
||||
name: name,
|
||||
root: strings.Trim(root, "/"),
|
||||
opt: *opt,
|
||||
cfg: cfg,
|
||||
bridgeUser: userInfo.BridgeUser,
|
||||
userID: userInfo.UserID,
|
||||
name: name,
|
||||
root: strings.Trim(root, "/"),
|
||||
opt: *opt,
|
||||
m: m,
|
||||
cfg: cfg,
|
||||
}
|
||||
|
||||
f.pacer = fs.NewPacer(ctx, pacer.NewDefault(pacer.MinSleep(minSleep), pacer.MaxSleep(maxSleep), pacer.DecayConstant(decayConstant)))
|
||||
|
||||
var userInfo *userInfo
|
||||
const maxRetries = 3
|
||||
for attempt := 1; attempt <= maxRetries; attempt++ {
|
||||
userInfo, err = getUserInfo(ctx, &userInfoConfig{Token: f.cfg.Token})
|
||||
if err == nil {
|
||||
break
|
||||
}
|
||||
|
||||
var httpErr *sdkerrors.HTTPError
|
||||
if errors.As(err, &httpErr) && httpErr.StatusCode() == 401 {
|
||||
fs.Debugf(f, "getUserInfo returned 401, attempting re-auth")
|
||||
authErr := f.refreshOrReLogin(ctx)
|
||||
if authErr != nil {
|
||||
return nil, fmt.Errorf("failed to fetch user info (re-auth failed): %w", err)
|
||||
}
|
||||
userInfo, err = getUserInfo(ctx, &userInfoConfig{Token: f.cfg.Token})
|
||||
if err == nil {
|
||||
break
|
||||
}
|
||||
return nil, fmt.Errorf("failed to fetch user info after re-auth: %w", err)
|
||||
}
|
||||
|
||||
if fserrors.ShouldRetry(err) && attempt < maxRetries {
|
||||
fs.Debugf(f, "getUserInfo transient error (attempt %d/%d): %v", attempt, maxRetries, err)
|
||||
time.Sleep(time.Duration(attempt) * time.Second)
|
||||
continue
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("failed to fetch user info: %w", err)
|
||||
}
|
||||
|
||||
f.cfg.RootFolderID = userInfo.RootFolderID
|
||||
f.cfg.Bucket = userInfo.Bucket
|
||||
f.cfg.BasicAuthHeader = computeBasicAuthHeader(userInfo.BridgeUser, userInfo.UserID)
|
||||
f.bridgeUser = userInfo.BridgeUser
|
||||
f.userID = userInfo.UserID
|
||||
|
||||
f.features = (&fs.Features{
|
||||
CanHaveEmptyDirectories: true,
|
||||
}).Fill(ctx, f)
|
||||
|
||||
if ts != nil {
|
||||
f.tokenRenewer = oauthutil.NewRenew(f.String(), ts, func() error {
|
||||
err := refreshJWTToken(ctx, name, m)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
newToken, err := oauthutil.GetToken(name, m)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get refreshed token: %w", err)
|
||||
}
|
||||
f.cfg.Token = newToken.AccessToken
|
||||
f.cfg.BasicAuthHeader = computeBasicAuthHeader(f.bridgeUser, f.userID)
|
||||
|
||||
return nil
|
||||
f.authMu.Lock()
|
||||
defer f.authMu.Unlock()
|
||||
return f.refreshOrReLogin(ctx)
|
||||
})
|
||||
f.tokenRenewer.Start()
|
||||
}
|
||||
@@ -312,9 +350,19 @@ func NewFs(ctx context.Context, name, root string, m configmap.Mapper) (fs.Fs, e
|
||||
if err != nil {
|
||||
// Assume it might be a file
|
||||
newRoot, remote := dircache.SplitPath(f.root)
|
||||
tempF := *f
|
||||
tempF.dirCache = dircache.New(newRoot, f.cfg.RootFolderID, &tempF)
|
||||
tempF.root = newRoot
|
||||
tempF := &Fs{
|
||||
name: f.name,
|
||||
root: newRoot,
|
||||
opt: f.opt,
|
||||
m: f.m,
|
||||
cfg: f.cfg,
|
||||
features: f.features,
|
||||
pacer: f.pacer,
|
||||
tokenRenewer: f.tokenRenewer,
|
||||
bridgeUser: f.bridgeUser,
|
||||
userID: f.userID,
|
||||
}
|
||||
tempF.dirCache = dircache.New(newRoot, f.cfg.RootFolderID, tempF)
|
||||
|
||||
err = tempF.dirCache.FindRoot(ctx, false)
|
||||
if err != nil {
|
||||
@@ -367,7 +415,7 @@ func (f *Fs) Rmdir(ctx context.Context, dir string) error {
|
||||
err = f.pacer.Call(func() (bool, error) {
|
||||
var err error
|
||||
childFolders, err = folders.ListAllFolders(ctx, f.cfg, id)
|
||||
return shouldRetry(ctx, err)
|
||||
return f.shouldRetry(ctx, err)
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -380,7 +428,7 @@ func (f *Fs) Rmdir(ctx context.Context, dir string) error {
|
||||
err = f.pacer.Call(func() (bool, error) {
|
||||
var err error
|
||||
childFiles, err = folders.ListAllFiles(ctx, f.cfg, id)
|
||||
return shouldRetry(ctx, err)
|
||||
return f.shouldRetry(ctx, err)
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -395,7 +443,7 @@ func (f *Fs) Rmdir(ctx context.Context, dir string) error {
|
||||
if err != nil && strings.Contains(err.Error(), "404") {
|
||||
return false, fs.ErrorDirNotFound
|
||||
}
|
||||
return shouldRetry(ctx, err)
|
||||
return f.shouldRetry(ctx, err)
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -412,7 +460,7 @@ func (f *Fs) FindLeaf(ctx context.Context, pathID, leaf string) (string, bool, e
|
||||
err := f.pacer.Call(func() (bool, error) {
|
||||
var err error
|
||||
entries, err = folders.ListAllFolders(ctx, f.cfg, pathID)
|
||||
return shouldRetry(ctx, err)
|
||||
return f.shouldRetry(ctx, err)
|
||||
})
|
||||
if err != nil {
|
||||
return "", false, err
|
||||
@@ -437,7 +485,7 @@ func (f *Fs) CreateDir(ctx context.Context, pathID, leaf string) (string, error)
|
||||
err := f.pacer.CallNoRetry(func() (bool, error) {
|
||||
var err error
|
||||
resp, err = folders.CreateFolder(ctx, f.cfg, request)
|
||||
return shouldRetry(ctx, err)
|
||||
return f.shouldRetry(ctx, err)
|
||||
})
|
||||
if err != nil {
|
||||
// If folder already exists (409 conflict), try to find it
|
||||
@@ -459,8 +507,8 @@ func (f *Fs) CreateDir(ctx context.Context, pathID, leaf string) (string, error)
|
||||
func (f *Fs) preUploadCheck(ctx context.Context, leaf, directoryID string) (*folders.File, error) {
|
||||
// Parse name and extension from the leaf
|
||||
baseName := f.opt.Encoding.FromStandardName(leaf)
|
||||
name := strings.TrimSuffix(baseName, filepath.Ext(baseName))
|
||||
ext := strings.TrimPrefix(filepath.Ext(baseName), ".")
|
||||
name := strings.TrimSuffix(baseName, path.Ext(baseName))
|
||||
ext := strings.TrimPrefix(path.Ext(baseName), ".")
|
||||
|
||||
checkResult, err := files.CheckFilesExistence(ctx, f.cfg, directoryID, []files.FileExistenceCheck{
|
||||
{
|
||||
@@ -525,20 +573,20 @@ func (f *Fs) List(ctx context.Context, dir string) (fs.DirEntries, error) {
|
||||
err = f.pacer.Call(func() (bool, error) {
|
||||
var err error
|
||||
foldersList, err = folders.ListAllFolders(ctx, f.cfg, dirID)
|
||||
return shouldRetry(ctx, err)
|
||||
return f.shouldRetry(ctx, err)
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, e := range foldersList {
|
||||
remote := filepath.Join(dir, f.opt.Encoding.ToStandardName(e.PlainName))
|
||||
remote := path.Join(dir, f.opt.Encoding.ToStandardName(e.PlainName))
|
||||
out = append(out, fs.NewDir(remote, e.ModificationTime))
|
||||
}
|
||||
var filesList []folders.File
|
||||
err = f.pacer.Call(func() (bool, error) {
|
||||
var err error
|
||||
filesList, err = folders.ListAllFiles(ctx, f.cfg, dirID)
|
||||
return shouldRetry(ctx, err)
|
||||
return f.shouldRetry(ctx, err)
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -548,7 +596,7 @@ func (f *Fs) List(ctx context.Context, dir string) (fs.DirEntries, error) {
|
||||
if len(e.Type) > 0 {
|
||||
remote += "." + e.Type
|
||||
}
|
||||
remote = filepath.Join(dir, f.opt.Encoding.ToStandardName(remote))
|
||||
remote = path.Join(dir, f.opt.Encoding.ToStandardName(remote))
|
||||
out = append(out, newObjectWithFile(f, remote, &e))
|
||||
}
|
||||
return out, nil
|
||||
@@ -616,7 +664,7 @@ func (f *Fs) Remove(ctx context.Context, remote string) error {
|
||||
}
|
||||
err = f.pacer.Call(func() (bool, error) {
|
||||
err := folders.DeleteFolder(ctx, f.cfg, dirID)
|
||||
return shouldRetry(ctx, err)
|
||||
return f.shouldRetry(ctx, err)
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -627,7 +675,7 @@ func (f *Fs) Remove(ctx context.Context, remote string) error {
|
||||
|
||||
// NewObject creates a new object
|
||||
func (f *Fs) NewObject(ctx context.Context, remote string) (fs.Object, error) {
|
||||
parentDir := filepath.Dir(remote)
|
||||
parentDir := path.Dir(remote)
|
||||
|
||||
if parentDir == "." {
|
||||
parentDir = ""
|
||||
@@ -642,12 +690,12 @@ func (f *Fs) NewObject(ctx context.Context, remote string) (fs.Object, error) {
|
||||
err = f.pacer.Call(func() (bool, error) {
|
||||
var err error
|
||||
files, err = folders.ListAllFiles(ctx, f.cfg, dirID)
|
||||
return shouldRetry(ctx, err)
|
||||
return f.shouldRetry(ctx, err)
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
targetName := filepath.Base(remote)
|
||||
targetName := path.Base(remote)
|
||||
for _, e := range files {
|
||||
name := e.PlainName
|
||||
if len(e.Type) > 0 {
|
||||
@@ -720,7 +768,7 @@ func (f *Fs) About(ctx context.Context) (*fs.Usage, error) {
|
||||
err := f.pacer.Call(func() (bool, error) {
|
||||
var err error
|
||||
internxtLimit, err = users.GetLimit(ctx, f.cfg)
|
||||
return shouldRetry(ctx, err)
|
||||
return f.shouldRetry(ctx, err)
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -730,7 +778,7 @@ func (f *Fs) About(ctx context.Context) (*fs.Usage, error) {
|
||||
err = f.pacer.Call(func() (bool, error) {
|
||||
var err error
|
||||
internxtUsage, err = users.GetUsage(ctx, f.cfg)
|
||||
return shouldRetry(ctx, err)
|
||||
return f.shouldRetry(ctx, err)
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -776,7 +824,7 @@ func (o *Object) Open(ctx context.Context, options ...fs.OpenOption) (io.ReadClo
|
||||
err := o.f.pacer.Call(func() (bool, error) {
|
||||
var err error
|
||||
stream, err = buckets.DownloadFileStream(ctx, o.f.cfg, o.id, rangeValue)
|
||||
return shouldRetry(ctx, err)
|
||||
return o.f.shouldRetry(ctx, err)
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -788,9 +836,9 @@ func (o *Object) Open(ctx context.Context, options ...fs.OpenOption) (io.ReadClo
|
||||
func (o *Object) Update(ctx context.Context, in io.Reader, src fs.ObjectInfo, options ...fs.OpenOption) error {
|
||||
remote := o.remote
|
||||
|
||||
origBaseName := filepath.Base(remote)
|
||||
origName := strings.TrimSuffix(origBaseName, filepath.Ext(origBaseName))
|
||||
origType := strings.TrimPrefix(filepath.Ext(origBaseName), ".")
|
||||
origBaseName := path.Base(remote)
|
||||
origName := strings.TrimSuffix(origBaseName, path.Ext(origBaseName))
|
||||
origType := strings.TrimPrefix(path.Ext(origBaseName), ".")
|
||||
|
||||
// Create directory if it doesn't exist
|
||||
_, dirID, err := o.f.dirCache.FindPath(ctx, remote, true)
|
||||
@@ -808,9 +856,9 @@ func (o *Object) Update(ctx context.Context, in io.Reader, src fs.ObjectInfo, op
|
||||
// Step 1: If file exists, rename to backup (preserves old file during upload)
|
||||
if oldUUID != "" {
|
||||
// Generate unique backup name
|
||||
baseName := filepath.Base(remote)
|
||||
name := strings.TrimSuffix(baseName, filepath.Ext(baseName))
|
||||
ext := strings.TrimPrefix(filepath.Ext(baseName), ".")
|
||||
baseName := path.Base(remote)
|
||||
name := strings.TrimSuffix(baseName, path.Ext(baseName))
|
||||
ext := strings.TrimPrefix(path.Ext(baseName), ".")
|
||||
|
||||
backupSuffix := fmt.Sprintf(".rclone-backup-%s", random.String(8))
|
||||
backupName = o.f.opt.Encoding.FromStandardName(name + backupSuffix)
|
||||
@@ -826,7 +874,7 @@ func (o *Object) Update(ctx context.Context, in io.Reader, src fs.ObjectInfo, op
|
||||
return false, nil
|
||||
}
|
||||
}
|
||||
return shouldRetry(ctx, err)
|
||||
return o.f.shouldRetry(ctx, err)
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to rename existing file to backup: %w", err)
|
||||
@@ -842,12 +890,12 @@ func (o *Object) Update(ctx context.Context, in io.Reader, src fs.ObjectInfo, op
|
||||
meta, err = buckets.UploadFileStreamAuto(ctx,
|
||||
o.f.cfg,
|
||||
dirID,
|
||||
o.f.opt.Encoding.FromStandardName(filepath.Base(remote)),
|
||||
o.f.opt.Encoding.FromStandardName(path.Base(remote)),
|
||||
in,
|
||||
src.Size(),
|
||||
src.ModTime(ctx),
|
||||
)
|
||||
return shouldRetry(ctx, err)
|
||||
return o.f.shouldRetry(ctx, err)
|
||||
})
|
||||
|
||||
if err != nil && isEmptyFileLimitError(err) {
|
||||
@@ -885,7 +933,7 @@ func (o *Object) Update(ctx context.Context, in io.Reader, src fs.ObjectInfo, op
|
||||
}
|
||||
}
|
||||
}
|
||||
return shouldRetry(ctx, err)
|
||||
return o.f.shouldRetry(ctx, err)
|
||||
})
|
||||
if err != nil {
|
||||
fs.Errorf(o.f, "Failed to delete backup file %s.%s (UUID: %s): %v. This may leave an orphaned backup file.",
|
||||
@@ -932,18 +980,18 @@ func (o *Object) recoverFromTimeoutConflict(ctx context.Context, uploadErr error
|
||||
return nil, uploadErr
|
||||
}
|
||||
|
||||
baseName := filepath.Base(remote)
|
||||
baseName := path.Base(remote)
|
||||
encodedName := o.f.opt.Encoding.FromStandardName(baseName)
|
||||
|
||||
var meta *buckets.CreateMetaResponse
|
||||
checkErr := o.f.pacer.Call(func() (bool, error) {
|
||||
existingFile, err := o.f.preUploadCheck(ctx, encodedName, dirID)
|
||||
if err != nil {
|
||||
return shouldRetry(ctx, err)
|
||||
return o.f.shouldRetry(ctx, err)
|
||||
}
|
||||
if existingFile != nil {
|
||||
name := strings.TrimSuffix(baseName, filepath.Ext(baseName))
|
||||
ext := strings.TrimPrefix(filepath.Ext(baseName), ".")
|
||||
name := strings.TrimSuffix(baseName, path.Ext(baseName))
|
||||
ext := strings.TrimPrefix(path.Ext(baseName), ".")
|
||||
|
||||
meta = &buckets.CreateMetaResponse{
|
||||
UUID: existingFile.UUID,
|
||||
@@ -978,7 +1026,7 @@ func (o *Object) restoreBackupFile(ctx context.Context, backupUUID, origName, or
|
||||
_ = o.f.pacer.Call(func() (bool, error) {
|
||||
err := files.RenameFile(ctx, o.f.cfg, backupUUID,
|
||||
o.f.opt.Encoding.FromStandardName(origName), origType)
|
||||
return shouldRetry(ctx, err)
|
||||
return o.f.shouldRetry(ctx, err)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -986,6 +1034,6 @@ func (o *Object) restoreBackupFile(ctx context.Context, backupUUID, origName, or
|
||||
func (o *Object) Remove(ctx context.Context) error {
|
||||
return o.f.pacer.Call(func() (bool, error) {
|
||||
err := files.DeleteFile(ctx, o.f.cfg, o.uuid)
|
||||
return shouldRetry(ctx, err)
|
||||
return o.f.shouldRetry(ctx, err)
|
||||
})
|
||||
}
|
||||
@@ -4,6 +4,7 @@ region:
|
||||
eu-west-1: Europe West
|
||||
endpoint:
|
||||
s3.cubbit.eu: Cubbit DS3 Object Storage endpoint
|
||||
s3.{tenant_name}.cubbit.eu: Multi-tenant endpoint - replace {tenant_name} with your actual tenant name. Do not select this directly
|
||||
acl: {}
|
||||
bucket_acl: true
|
||||
quirks:
|
||||
|
||||
@@ -15,7 +15,7 @@ endpoint:
|
||||
acl: {}
|
||||
bucket_acl: true
|
||||
quirks:
|
||||
list_version: 1
|
||||
list_version: 2
|
||||
force_path_style: true
|
||||
list_url_encode: false
|
||||
use_multipart_etag: false
|
||||
+9
-3
@@ -1691,6 +1691,10 @@ func NewFs(ctx context.Context, name, root string, m configmap.Mapper) (fs.Fs, e
|
||||
if opt.Provider == "Rabata" {
|
||||
f.features.Copy = nil
|
||||
}
|
||||
if opt.Provider == "TencentCOS" && strings.Contains(opt.Endpoint, "cos.accelerate.myqcloud.com") {
|
||||
// Global Acceleration endpoint does not support bucket creation.
|
||||
f.opt.NoCheckBucket = true
|
||||
}
|
||||
if opt.DirectoryMarkers {
|
||||
f.features.CanHaveEmptyDirectories = true
|
||||
}
|
||||
@@ -2169,9 +2173,11 @@ func (f *Fs) list(ctx context.Context, opt listOpt, fn listFn) error {
|
||||
opt.directory += "/"
|
||||
}
|
||||
}
|
||||
delimiter := ""
|
||||
// Use nil delimiter for recursive listings to omit the parameter
|
||||
// entirely. Some S3-compatible servers reject an empty delimiter.
|
||||
var delimiter *string
|
||||
if !opt.recurse {
|
||||
delimiter = "/"
|
||||
delimiter = aws.String("/")
|
||||
}
|
||||
// URL encode the listings so we can use control characters in object names
|
||||
// See: https://github.com/aws/aws-sdk-go/issues/1914
|
||||
@@ -2191,7 +2197,7 @@ func (f *Fs) list(ctx context.Context, opt listOpt, fn listFn) error {
|
||||
urlEncodeListings := f.opt.ListURLEncode.Value
|
||||
req := s3.ListObjectsV2Input{
|
||||
Bucket: &opt.bucket,
|
||||
Delimiter: &delimiter,
|
||||
Delimiter: delimiter,
|
||||
Prefix: &opt.directory,
|
||||
MaxKeys: &f.opt.ListChunk,
|
||||
}
|
||||
|
||||
@@ -423,7 +423,7 @@ func (f *Fs) filePath(file string) string {
|
||||
if f.opt.Enc != encoder.EncodeZero {
|
||||
subPath = f.opt.Enc.FromStandardPath(subPath)
|
||||
}
|
||||
return rest.URLPathEscape(subPath)
|
||||
return rest.URLPathEscapeAll(subPath)
|
||||
}
|
||||
|
||||
// dirPath returns a directory path (f.root, dir)
|
||||
|
||||
@@ -80,3 +80,35 @@ func TestHeaders(t *testing.T) {
|
||||
_, err := f.Features().About(context.Background())
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
// TestReservedCharactersInPathAreEscaped verifies that reserved characters
|
||||
// like semicolons and equals signs in file paths are percent-encoded in
|
||||
// HTTP requests to the WebDAV server (RFC 3986 compliance).
|
||||
func TestReservedCharactersInPathAreEscaped(t *testing.T) {
|
||||
var capturedPath string
|
||||
|
||||
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
capturedPath = r.RequestURI
|
||||
// Return a 404 so the NewObject call fails cleanly
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
})
|
||||
ts := httptest.NewServer(handler)
|
||||
defer ts.Close()
|
||||
|
||||
configfile.Install()
|
||||
m := configmap.Simple{
|
||||
"type": "webdav",
|
||||
"url": ts.URL,
|
||||
}
|
||||
|
||||
f, err := webdav.NewFs(context.Background(), remoteName, "", m)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Try to access a file with a semicolon in the name.
|
||||
// We expect the request to fail (404), but the path should be escaped.
|
||||
_, _ = f.NewObject(context.Background(), "my;test")
|
||||
|
||||
// The semicolon must be percent-encoded as %3B
|
||||
assert.Contains(t, capturedPath, "my%3Btest", "semicolons in path should be percent-encoded")
|
||||
assert.NotContains(t, capturedPath, "my;test", "raw semicolons should not appear in path")
|
||||
}
|
||||
@@ -147,6 +147,16 @@ func ArchiveExtract(ctx context.Context, dst fs.Fs, dstDir string, src fs.Fs, sr
|
||||
// extract files
|
||||
err = ex.Extract(ctx, in, func(ctx context.Context, f archives.FileInfo) error {
|
||||
remote := f.NameInArchive
|
||||
// Strip leading "./" from archive paths. Tar files created with
|
||||
// relative paths (e.g. "tar -czf archive.tar.gz .") use "./" prefixed
|
||||
// entries. Without stripping, rclone encodes the "." as a full-width
|
||||
// dot character creating a spurious directory. We only strip "./"
|
||||
// specifically to avoid enabling path traversal attacks via "../".
|
||||
remote = strings.TrimPrefix(remote, "./")
|
||||
// If the entry was exactly "./" (the root dir), skip it
|
||||
if remote == "" && f.IsDir() {
|
||||
return nil
|
||||
}
|
||||
if dstDir != "" {
|
||||
remote = path.Join(dstDir, remote)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
//go:build !plan9
|
||||
|
||||
package extract
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestStripDotSlashPrefix(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
input string
|
||||
expected string
|
||||
}{
|
||||
{
|
||||
name: "strip leading dot-slash from file",
|
||||
input: "./file.txt",
|
||||
expected: "file.txt",
|
||||
},
|
||||
{
|
||||
name: "strip leading dot-slash from nested path",
|
||||
input: "./subdir/file.txt",
|
||||
expected: "subdir/file.txt",
|
||||
},
|
||||
{
|
||||
name: "no prefix unchanged",
|
||||
input: "file.txt",
|
||||
expected: "file.txt",
|
||||
},
|
||||
{
|
||||
name: "nested path unchanged",
|
||||
input: "dir/file.txt",
|
||||
expected: "dir/file.txt",
|
||||
},
|
||||
{
|
||||
name: "dot-dot-slash NOT stripped (path traversal safety)",
|
||||
input: "../etc/passwd",
|
||||
expected: "../etc/passwd",
|
||||
},
|
||||
{
|
||||
name: "dot-slash directory entry becomes empty",
|
||||
input: "./",
|
||||
expected: "",
|
||||
},
|
||||
{
|
||||
name: "only single leading dot-slash stripped",
|
||||
input: "././file.txt",
|
||||
expected: "./file.txt",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
// This mirrors the stripping logic in ArchiveExtract
|
||||
got := strings.TrimPrefix(tc.input, "./")
|
||||
assert.Equal(t, tc.expected, got)
|
||||
})
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -162,7 +162,7 @@ var commandDefinition = &cobra.Command{
|
||||
Long: longHelp,
|
||||
Annotations: map[string]string{
|
||||
"versionIntroduced": "v1.58",
|
||||
"groups": "Filter,Copy,Important",
|
||||
"groups": "Filter,Copy,Important,Sync",
|
||||
},
|
||||
RunE: func(command *cobra.Command, args []string) error {
|
||||
// NOTE: avoid putting too much handling here, as it won't apply to the rc.
|
||||
|
||||
@@ -70,6 +70,15 @@ Note that |--stdout| and |--print-filename| are incompatible with |--urls|.
|
||||
This will do |--transfers| copies in parallel. Note that if |--auto-filename|
|
||||
is desired for all URLs then a file with only URLs and no filename can be used.
|
||||
|
||||
Each FILENAME in the CSV file can start with a relative path which will be appended
|
||||
to the destination path provided at the command line. For example, running the command
|
||||
shown above with the following CSV file will write two files to the destination:
|
||||
|remote:dir/local/path/bar.json| and |remote:dir/another/local/directory/qux.json|
|
||||
|||csv
|
||||
https://example.org/foo/bar.json,local/path/bar.json
|
||||
https://example.org/qux/baz.json,another/local/directory/qux.json
|
||||
|||
|
||||
|
||||
### Troubleshooting
|
||||
|
||||
If you can't get |rclone copyurl| to work then here are some things you can try:
|
||||
|
||||
+17
-15
@@ -1,7 +1,8 @@
|
||||
Rclone @ allows Linux, FreeBSD, macOS and Windows to
|
||||
mount any of Rclone's cloud storage systems as a file system with FUSE.
|
||||
|
||||
First set up your remote using `rclone config`. Check it works with `rclone ls` etc.
|
||||
First set up your remote using `rclone config`. Check it works with `rclone ls`
|
||||
etc.
|
||||
|
||||
On Linux and macOS, you can run mount in either foreground or background (aka
|
||||
daemon) mode. Mount runs in foreground mode by default. Use the `--daemon` flag
|
||||
@@ -29,8 +30,8 @@ The following examples will mount to an automatically assigned drive,
|
||||
to specific drive letter `X:`, to path `C:\path\parent\mount`
|
||||
(where parent directory or drive must exist, and mount must **not** exist,
|
||||
and is not supported when [mounting as a network drive](#mounting-modes-on-windows)),
|
||||
and the last example will mount as network share `\\cloud\remote` and map it to an
|
||||
automatically assigned drive:
|
||||
and the last example will mount as network share `\\cloud\remote` and map it to
|
||||
an automatically assigned drive:
|
||||
|
||||
```console
|
||||
rclone @ remote:path/to/files *
|
||||
@@ -136,8 +137,8 @@ rclone @ remote:path/to/files X: --volname \\server\share
|
||||
|
||||
You may also specify the network share UNC path as the mountpoint itself. Then rclone
|
||||
will automatically assign a drive letter, same as with `*` and use that as
|
||||
mountpoint, and instead use the UNC path specified as the volume name, as if it were
|
||||
specified with the `--volname` option. This will also implicitly set
|
||||
mountpoint, and instead use the UNC path specified as the volume name, as if it
|
||||
were specified with the `--volname` option. This will also implicitly set
|
||||
the `--network-mode` option. This means the following two examples have same result:
|
||||
|
||||
```console
|
||||
@@ -268,7 +269,7 @@ does not suffer from the same limitations.
|
||||
|
||||
Mounting on macOS can be done either via [built-in NFS server](/commands/rclone_serve_nfs/),
|
||||
[macFUSE](https://osxfuse.github.io/) (also known as osxfuse) or
|
||||
[FUSE-T](https://www.fuse-t.org/).macFUSE is a traditional FUSE driver utilizing
|
||||
[FUSE-T](https://www.fuse-t.org/). macFUSE is a traditional FUSE driver utilizing
|
||||
a macOS kernel extension (kext). FUSE-T is an alternative FUSE system which
|
||||
"mounts" via an NFSv4 local server.
|
||||
|
||||
@@ -311,29 +312,30 @@ current as of FUSE-T version 1.0.14.
|
||||
|
||||
As per the [FUSE-T wiki](https://github.com/macos-fuse-t/fuse-t/wiki#caveats):
|
||||
|
||||
> File access and modification times cannot be set separately as it seems to be an
|
||||
> issue with the NFS client which always modifies both. Can be reproduced with
|
||||
> 'touch -m' and 'touch -a' commands
|
||||
> File access and modification times cannot be set separately as it seems to be
|
||||
> an issue with the NFS client which always modifies both. Can be reproduced
|
||||
> with `touch -m` and `touch -a` commands
|
||||
|
||||
This means that viewing files with various tools, notably macOS Finder, will cause
|
||||
rlcone to update the modification time of the file. This may make rclone upload a
|
||||
full new copy of the file.
|
||||
This means that viewing files with various tools, notably macOS Finder, will
|
||||
cause rlcone to update the modification time of the file. This may make rclone
|
||||
upload a full new copy of the file.
|
||||
|
||||
##### Read Only mounts
|
||||
|
||||
When mounting with `--read-only`, attempts to write to files will fail *silently*
|
||||
as opposed to with a clear warning as in macFUSE.
|
||||
|
||||
## Mounting on Linux
|
||||
### Mounting on Linux
|
||||
|
||||
On newer versions of Ubuntu, you may encounter the following error when running
|
||||
`rclone mount`:
|
||||
|
||||
> NOTICE: mount helper error: fusermount3: mount failed: Permission denied
|
||||
> CRITICAL: Fatal error: failed to mount FUSE fs: fusermount: exit status 1
|
||||
|
||||
This may be due to newer [Apparmor](https://wiki.ubuntu.com/AppArmor) restrictions,
|
||||
which can be disabled with `sudo aa-disable /usr/bin/fusermount3` (you may need to
|
||||
`sudo apt install apparmor-utils` beforehand).
|
||||
which can be disabled with `sudo aa-disable /usr/bin/fusermount3` (you may need
|
||||
to `sudo apt install apparmor-utils` beforehand).
|
||||
|
||||
### Limitations
|
||||
|
||||
|
||||
@@ -1049,11 +1049,9 @@ The following backends have known issues that need more investigation:
|
||||
<!--- start list_failures - DO NOT EDIT THIS SECTION - use make commanddocs --->
|
||||
- `TestDropbox` (`dropbox`)
|
||||
- [`TestBisyncRemoteRemote/normalization`](https://pub.rclone.org/integration-tests/current/dropbox-cmd.bisync-TestDropbox-1.txt)
|
||||
- `TestSeafile` (`seafile`)
|
||||
- [`TestBisyncLocalRemote/volatile`](https://pub.rclone.org/integration-tests/current/seafile-cmd.bisync-TestSeafile-1.txt)
|
||||
- `TestSeafileV6` (`seafile`)
|
||||
- [`TestBisyncLocalRemote/volatile`](https://pub.rclone.org/integration-tests/current/seafile-cmd.bisync-TestSeafileV6-1.txt)
|
||||
- Updated: 2026-01-30-010015
|
||||
- [`TestBisyncLocalRemote/rmdirs`](https://pub.rclone.org/integration-tests/current/seafile-cmd.bisync-TestSeafileV6-1.txt)
|
||||
- Updated: 2026-04-19-010011
|
||||
<!--- end list_failures - DO NOT EDIT THIS SECTION - use make commanddocs --->
|
||||
|
||||
The following backends either have not been tested recently or have known issues
|
||||
|
||||
+116
-1
@@ -6,6 +6,121 @@ description: "Rclone Changelog"
|
||||
|
||||
# Changelog
|
||||
|
||||
## v1.73.5 - 2026-04-19
|
||||
|
||||
[See commits](https://github.com/rclone/rclone/compare/v1.73.4...v1.73.5)
|
||||
|
||||
- Bug Fixes
|
||||
- operations: Add AuthRequired to operations/fsinfo to prevent backend creation CVE-2026-41179 (Nick Craig-Wood)
|
||||
- rc
|
||||
- Add AuthRequired to options/set to prevent auth bypass CVE-2026-41176 (Nick Craig-Wood)
|
||||
- Snapshot NoAuth at startup to prevent runtime auth bypass CVE-2026-41176 (Nick Craig-Wood)
|
||||
- filter: Fix debug logs that fire before logger is configured (Nick Craig-Wood)
|
||||
- Azureblob
|
||||
- Add Microsoft Partner Network User-Agent prefix (Nick Craig-Wood)
|
||||
- Drime
|
||||
- Fix User.EntryPermissions JSON unmarshalling (a1pcm)
|
||||
- Iclouddrive
|
||||
- Fix 'directory not found' error when the directory contains accent marks (Brais Couce)
|
||||
- S3
|
||||
- Fix TencentCOS CDN endpoint failing on bucket check (Mozi)
|
||||
- Fix empty delimiter parameter rejected by Archiware P5 server (Nick Craig-Wood)
|
||||
|
||||
## v1.73.4 - 2026-04-08
|
||||
|
||||
[See commits](https://github.com/rclone/rclone/compare/v1.73.3...v1.73.4)
|
||||
|
||||
- Bug Fixes
|
||||
- build
|
||||
- Update to go 1.25.9 to fix multiple CVEs (Nick Craig-Wood)
|
||||
- CVE-2026-32282: os: Root.Chmod can follow symlinks out of the root on Linux
|
||||
- CVE-2026-32289: html/template: JS template literal context incorrectly tracked
|
||||
- CVE-2026-33810: crypto/x509: excluded DNS constraints not properly applied to wildcard domains
|
||||
- CVE-2026-27144: cmd/compile: no-op interface conversion bypasses overlap checking
|
||||
- CVE-2026-27143: cmd/compile: possible memory corruption after bound check elimination
|
||||
- CVE-2026-32288: archive/tar: unbounded allocation when parsing old format GNU sparse map
|
||||
- CVE-2026-32283: crypto/tls: multiple key update handshake messages can cause connection to deadlock
|
||||
- CVE-2026-27140: cmd/go: trust layer bypass when using cgo and SWIG
|
||||
- CVE-2026-32280: crypto/x509: unexpected work during chain building
|
||||
- CVE-2026-32281: crypto/x509: inefficient policy validation
|
||||
- Fix Denial of Service due to Panic in AWS SDK for Go v2 SDK EventStream Decoder (dependabot[bot])
|
||||
- Update golang.org/x/image to 0.38.0 to fix CVE-2026-33809 (dependabot[bot])
|
||||
- docs
|
||||
- Fix header level for metadata option (Clément Notin)
|
||||
- Fix markdown issues in mount docs (albertony)
|
||||
- Fix link to not be language specific (Ross Smith II)
|
||||
- Note macOS 10.15 (Catalina) support with version v1.70.3 (kapitainsky)
|
||||
- Filen
|
||||
- Update SDK version (Enduriel)
|
||||
|
||||
## v1.73.3 - 2026-03-23
|
||||
|
||||
[See commits](https://github.com/rclone/rclone/compare/v1.73.2...v1.73.3)
|
||||
|
||||
- Bug Fixes
|
||||
- build
|
||||
- Update to google.golang.org/grpc 1.79.3 to fix CVE-2026-33186 (dependabot[bot])
|
||||
- Update to github.com/buger/jsonparser 1.1.2 to fix GHSA-6g7g-w4f8-9c9x (dependabot[bot])
|
||||
- doc fixes
|
||||
- Added text to the label showing version-introduced info (Jan-Philipp Reßler)
|
||||
- Clarify Filen password change requires updating both password and API key in rclone config (Jason)
|
||||
- s3: clarify multi tenant support for Cubbit (Marco Ferretti)
|
||||
- jottacloud: Fix broken link (albertony)
|
||||
- lib/rest: Fix URLPathEscapeAll breaking WebDAV servers (eg nzbdav) with strict path matching (Andrew Furman)
|
||||
- list: Fix nil pointer panic in Sorter when temp file creation fails (Nick Craig-Wood)
|
||||
|
||||
## v1.73.2 - 2026-03-06
|
||||
|
||||
[See commits](https://github.com/rclone/rclone/compare/v1.73.1...v1.73.2)
|
||||
|
||||
- Bug Fixes
|
||||
- build
|
||||
- Update to go 1.25.8 to fix CVE-2026-27137 CVE-2026-27138 CVE-2026-25679 CVE-2026-27142 (Nick Craig-Wood)
|
||||
- Update github.com/cloudflare/circl to v1.6.3 to fix CVE-2026-1229 (Nick Craig-Wood)
|
||||
- Update to golang.org/x/net v0.51.0 to fix CVE-2026-27141 (Nick Craig-Wood)
|
||||
- docs fixes:
|
||||
- bisync: Add group Sync to the bisync command (Jan-Philipp Reßler)
|
||||
- Note that --use-server-modtime only works on some backends (Nick Craig-Wood)
|
||||
- Document unsupported S3 object keys with double slashes (Adam Kasztenny)
|
||||
- Fix headers hierarchy for mount.md (Dark Dragon)
|
||||
- Fix new drive flag typo in changelog (razorloves)
|
||||
- Archive
|
||||
- Extract: fix extraction with "./" prefix from tar entry paths (Varun Chawla)
|
||||
- Drime
|
||||
- Fix chunk-uploaded files ignoring workspace ID (a1pcm)
|
||||
- Internxt
|
||||
- Fix Entry doesn't belong in directory errors on windows (jzunigax2)
|
||||
- WebDAV
|
||||
- Escape reserved characters in URL path segments (Varun Chawla)
|
||||
- Add missing headers for CORS (Romāns Potašovs)
|
||||
|
||||
## v1.73.1 - 2026-02-17
|
||||
|
||||
[See commits](https://github.com/rclone/rclone/compare/v1.73.0...v1.73.1)
|
||||
|
||||
- Bug Fixes
|
||||
- accounting: Fix missing server side stats from core/stats rc (Nick Craig-Wood)
|
||||
- build
|
||||
- Fix CVE-2025-68121 by updating go to 1.25.7 or later (Nick Craig-Wood)
|
||||
- Bump github.com/go-chi/chi/v5 from 5.2.3 to 5.2.5 to fix GO-2026-4316 (albertony)
|
||||
- docs: Extend copyurl docs with an example of CSV FILENAMEs starting with a path. (Jack Kelly)
|
||||
- march: Fix runtime: program exceeds 10000-thread limit (Nick Craig-Wood)
|
||||
- pacer
|
||||
- Fix deadlock between pacer token and --max-connections (Nick Craig-Wood)
|
||||
- Re-read the sleep time as it may be stale (Nick Craig-Wood)
|
||||
- Drime
|
||||
- Fix files and directories being created in the default workspace (Nick Craig-Wood)
|
||||
- Filelu
|
||||
- Avoid buffering entire file in memory (kingston125)
|
||||
- Add multipart upload support with configurable cutoff (kingston125)
|
||||
- Filen
|
||||
- Fix 32 bit targets not being able to list directories (Enduriel)
|
||||
- Fix potential panic in case of error during upload (Enduriel)
|
||||
- Internxt
|
||||
- Implement re-login under refresh logic, improve retry logic (José Zúniga)
|
||||
-S3
|
||||
- Set list_version to 2 for FileLu S3 configuration (kingston125)
|
||||
|
||||
## v1.73.0 - 2026-01-30
|
||||
|
||||
[See commits](https://github.com/rclone/rclone/compare/v1.72.0...v1.73.0)
|
||||
@@ -36,7 +151,7 @@ description: "Rclone Changelog"
|
||||
- B2
|
||||
- Support authentication with new bucket restricted application keys (DianaNites)
|
||||
- Drive
|
||||
- Add `--drive-metadata-force-expansive-access` flag (Nick Craig-Wood)
|
||||
- Add `--drive-metadata-enforce-expansive-access` flag (Nick Craig-Wood)
|
||||
- Fix crash when trying to creating shortcut to a Google doc (Nick Craig-Wood)
|
||||
- FTP
|
||||
- Add http proxy authentication support (Nicolas Dessart)
|
||||
|
||||
@@ -329,9 +329,11 @@ rclone [flags]
|
||||
--filefabric-token-expiry string Token expiry time
|
||||
--filefabric-url string URL of the Enterprise File Fabric to connect to
|
||||
--filefabric-version string Version read from the file fabric
|
||||
--filelu-chunk-size SizeSuffix Chunk size to use for uploading. Used for multipart uploads (default 64Mi)
|
||||
--filelu-description string Description of the remote
|
||||
--filelu-encoding Encoding The encoding for the backend (default Slash,LtGt,DoubleQuote,SingleQuote,BackQuote,Dollar,Colon,Question,Asterisk,Pipe,Hash,Percent,BackSlash,CrLf,Del,Ctl,LeftSpace,LeftPeriod,LeftTilde,LeftCrLfHtVt,RightSpace,RightPeriod,RightCrLfHtVt,InvalidUtf8,Dot,SquareBracket,Semicolon,Exclamation)
|
||||
--filelu-key string Your FileLu Rclone key from My Account
|
||||
--filelu-upload-cutoff SizeSuffix Cutoff for switching to chunked upload. Any files larger than this will be uploaded in chunks of chunk_size (default 500Mi)
|
||||
--filen-api-key string API Key for your Filen account (obscured)
|
||||
--filen-auth-version string Authentication Version (internal use only)
|
||||
--filen-base-folder-uuid string UUID of Account Root Directory (internal use only)
|
||||
@@ -1063,7 +1065,7 @@ rclone [flags]
|
||||
--use-json-log Use json log format
|
||||
--use-mmap Use mmap allocator (see docs)
|
||||
--use-server-modtime Use server modified time instead of object metadata
|
||||
--user-agent string Set the user-agent to a specified string (default "rclone/v1.73.0")
|
||||
--user-agent string Set the user-agent to a specified string (default "rclone/v1.73.5")
|
||||
-v, --verbose count Print lots more stuff (repeat for more)
|
||||
-V, --version Print the version number
|
||||
--webdav-auth-redirect Preserve authentication on redirect
|
||||
|
||||
@@ -107,6 +107,26 @@ Flags for anything which can copy a file
|
||||
-u, --update Skip files that are newer on the destination
|
||||
```
|
||||
|
||||
### Sync Options
|
||||
|
||||
Flags used for sync commands
|
||||
|
||||
```text
|
||||
--backup-dir string Make backups into hierarchy based in DIR
|
||||
--delete-after When synchronizing, delete files on destination after transferring (default)
|
||||
--delete-before When synchronizing, delete files on destination before transferring
|
||||
--delete-during When synchronizing, delete files during transfer
|
||||
--fix-case Force rename of case insensitive dest to match source
|
||||
--ignore-errors Delete even if there are I/O errors
|
||||
--list-cutoff int To save memory, sort directory listings on disk above this threshold (default 1000000)
|
||||
--max-delete int When synchronizing, limit the number of deletes (default -1)
|
||||
--max-delete-size SizeSuffix When synchronizing, limit the total size of deletes (default off)
|
||||
--suffix string Suffix to add to changed files
|
||||
--suffix-keep-extension Preserve the extension when using --suffix
|
||||
--track-renames When synchronizing, track file renames and do a server-side move if possible
|
||||
--track-renames-strategy string Strategies to use when synchronizing using track-renames hash|modtime|leaf (default "hash")
|
||||
```
|
||||
|
||||
### Important Options
|
||||
|
||||
Important flags useful for most commands
|
||||
|
||||
@@ -231,12 +231,12 @@ rclone convmv "stories/The Quick Brown Fox!.txt" --name-transform "all,command=e
|
||||
|
||||
```console
|
||||
rclone convmv "stories/The Quick Brown Fox!" --name-transform "date=-{YYYYMMDD}"
|
||||
// Output: stories/The Quick Brown Fox!-20260130
|
||||
// Output: stories/The Quick Brown Fox!-20260419
|
||||
```
|
||||
|
||||
```console
|
||||
rclone convmv "stories/The Quick Brown Fox!" --name-transform "date=-{macfriendlytime}"
|
||||
// Output: stories/The Quick Brown Fox!-2026-01-30 0825PM
|
||||
// Output: stories/The Quick Brown Fox!-2026-04-19 1137AM
|
||||
```
|
||||
|
||||
```console
|
||||
|
||||
@@ -39,6 +39,15 @@ Note that `--stdout` and `--print-filename` are incompatible with `--urls`.
|
||||
This will do `--transfers` copies in parallel. Note that if `--auto-filename`
|
||||
is desired for all URLs then a file with only URLs and no filename can be used.
|
||||
|
||||
Each FILENAME in the CSV file can start with a relative path which will be appended
|
||||
to the destination path provided at the command line. For example, running the command
|
||||
shown above with the following CSV file will write two files to the destination:
|
||||
`remote:dir/local/path/bar.json` and `remote:dir/another/local/directory/qux.json`
|
||||
```csv
|
||||
https://example.org/foo/bar.json,local/path/bar.json
|
||||
https://example.org/qux/baz.json,another/local/directory/qux.json
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
If you can't get `rclone copyurl` to work then here are some things you can try:
|
||||
|
||||
@@ -13,7 +13,8 @@ Mount the remote as file system on a mountpoint.
|
||||
Rclone mount allows Linux, FreeBSD, macOS and Windows to
|
||||
mount any of Rclone's cloud storage systems as a file system with FUSE.
|
||||
|
||||
First set up your remote using `rclone config`. Check it works with `rclone ls` etc.
|
||||
First set up your remote using `rclone config`. Check it works with `rclone ls`
|
||||
etc.
|
||||
|
||||
On Linux and macOS, you can run mount in either foreground or background (aka
|
||||
daemon) mode. Mount runs in foreground mode by default. Use the `--daemon` flag
|
||||
@@ -41,8 +42,8 @@ The following examples will mount to an automatically assigned drive,
|
||||
to specific drive letter `X:`, to path `C:\path\parent\mount`
|
||||
(where parent directory or drive must exist, and mount must **not** exist,
|
||||
and is not supported when [mounting as a network drive](#mounting-modes-on-windows)),
|
||||
and the last example will mount as network share `\\cloud\remote` and map it to an
|
||||
automatically assigned drive:
|
||||
and the last example will mount as network share `\\cloud\remote` and map it to
|
||||
an automatically assigned drive:
|
||||
|
||||
```console
|
||||
rclone mount remote:path/to/files *
|
||||
@@ -148,8 +149,8 @@ rclone mount remote:path/to/files X: --volname \\server\share
|
||||
|
||||
You may also specify the network share UNC path as the mountpoint itself. Then rclone
|
||||
will automatically assign a drive letter, same as with `*` and use that as
|
||||
mountpoint, and instead use the UNC path specified as the volume name, as if it were
|
||||
specified with the `--volname` option. This will also implicitly set
|
||||
mountpoint, and instead use the UNC path specified as the volume name, as if it
|
||||
were specified with the `--volname` option. This will also implicitly set
|
||||
the `--network-mode` option. This means the following two examples have same result:
|
||||
|
||||
```console
|
||||
@@ -280,7 +281,7 @@ does not suffer from the same limitations.
|
||||
|
||||
Mounting on macOS can be done either via [built-in NFS server](/commands/rclone_serve_nfs/),
|
||||
[macFUSE](https://osxfuse.github.io/) (also known as osxfuse) or
|
||||
[FUSE-T](https://www.fuse-t.org/).macFUSE is a traditional FUSE driver utilizing
|
||||
[FUSE-T](https://www.fuse-t.org/). macFUSE is a traditional FUSE driver utilizing
|
||||
a macOS kernel extension (kext). FUSE-T is an alternative FUSE system which
|
||||
"mounts" via an NFSv4 local server.
|
||||
|
||||
@@ -323,29 +324,30 @@ current as of FUSE-T version 1.0.14.
|
||||
|
||||
As per the [FUSE-T wiki](https://github.com/macos-fuse-t/fuse-t/wiki#caveats):
|
||||
|
||||
> File access and modification times cannot be set separately as it seems to be an
|
||||
> issue with the NFS client which always modifies both. Can be reproduced with
|
||||
> 'touch -m' and 'touch -a' commands
|
||||
> File access and modification times cannot be set separately as it seems to be
|
||||
> an issue with the NFS client which always modifies both. Can be reproduced
|
||||
> with `touch -m` and `touch -a` commands
|
||||
|
||||
This means that viewing files with various tools, notably macOS Finder, will cause
|
||||
rlcone to update the modification time of the file. This may make rclone upload a
|
||||
full new copy of the file.
|
||||
This means that viewing files with various tools, notably macOS Finder, will
|
||||
cause rlcone to update the modification time of the file. This may make rclone
|
||||
upload a full new copy of the file.
|
||||
|
||||
#### Read Only mounts
|
||||
|
||||
When mounting with `--read-only`, attempts to write to files will fail *silently*
|
||||
as opposed to with a clear warning as in macFUSE.
|
||||
|
||||
# Mounting on Linux
|
||||
## Mounting on Linux
|
||||
|
||||
On newer versions of Ubuntu, you may encounter the following error when running
|
||||
`rclone mount`:
|
||||
|
||||
> NOTICE: mount helper error: fusermount3: mount failed: Permission denied
|
||||
> CRITICAL: Fatal error: failed to mount FUSE fs: fusermount: exit status 1
|
||||
|
||||
This may be due to newer [Apparmor](https://wiki.ubuntu.com/AppArmor) restrictions,
|
||||
which can be disabled with `sudo aa-disable /usr/bin/fusermount3` (you may need to
|
||||
`sudo apt install apparmor-utils` beforehand).
|
||||
which can be disabled with `sudo aa-disable /usr/bin/fusermount3` (you may need
|
||||
to `sudo apt install apparmor-utils` beforehand).
|
||||
|
||||
## Limitations
|
||||
|
||||
|
||||
@@ -14,7 +14,8 @@ Mount the remote as file system on a mountpoint.
|
||||
Rclone nfsmount allows Linux, FreeBSD, macOS and Windows to
|
||||
mount any of Rclone's cloud storage systems as a file system with FUSE.
|
||||
|
||||
First set up your remote using `rclone config`. Check it works with `rclone ls` etc.
|
||||
First set up your remote using `rclone config`. Check it works with `rclone ls`
|
||||
etc.
|
||||
|
||||
On Linux and macOS, you can run mount in either foreground or background (aka
|
||||
daemon) mode. Mount runs in foreground mode by default. Use the `--daemon` flag
|
||||
@@ -42,8 +43,8 @@ The following examples will mount to an automatically assigned drive,
|
||||
to specific drive letter `X:`, to path `C:\path\parent\mount`
|
||||
(where parent directory or drive must exist, and mount must **not** exist,
|
||||
and is not supported when [mounting as a network drive](#mounting-modes-on-windows)),
|
||||
and the last example will mount as network share `\\cloud\remote` and map it to an
|
||||
automatically assigned drive:
|
||||
and the last example will mount as network share `\\cloud\remote` and map it to
|
||||
an automatically assigned drive:
|
||||
|
||||
```console
|
||||
rclone nfsmount remote:path/to/files *
|
||||
@@ -149,8 +150,8 @@ rclone nfsmount remote:path/to/files X: --volname \\server\share
|
||||
|
||||
You may also specify the network share UNC path as the mountpoint itself. Then rclone
|
||||
will automatically assign a drive letter, same as with `*` and use that as
|
||||
mountpoint, and instead use the UNC path specified as the volume name, as if it were
|
||||
specified with the `--volname` option. This will also implicitly set
|
||||
mountpoint, and instead use the UNC path specified as the volume name, as if it
|
||||
were specified with the `--volname` option. This will also implicitly set
|
||||
the `--network-mode` option. This means the following two examples have same result:
|
||||
|
||||
```console
|
||||
@@ -281,7 +282,7 @@ does not suffer from the same limitations.
|
||||
|
||||
Mounting on macOS can be done either via [built-in NFS server](/commands/rclone_serve_nfs/),
|
||||
[macFUSE](https://osxfuse.github.io/) (also known as osxfuse) or
|
||||
[FUSE-T](https://www.fuse-t.org/).macFUSE is a traditional FUSE driver utilizing
|
||||
[FUSE-T](https://www.fuse-t.org/). macFUSE is a traditional FUSE driver utilizing
|
||||
a macOS kernel extension (kext). FUSE-T is an alternative FUSE system which
|
||||
"mounts" via an NFSv4 local server.
|
||||
|
||||
@@ -324,29 +325,30 @@ current as of FUSE-T version 1.0.14.
|
||||
|
||||
As per the [FUSE-T wiki](https://github.com/macos-fuse-t/fuse-t/wiki#caveats):
|
||||
|
||||
> File access and modification times cannot be set separately as it seems to be an
|
||||
> issue with the NFS client which always modifies both. Can be reproduced with
|
||||
> 'touch -m' and 'touch -a' commands
|
||||
> File access and modification times cannot be set separately as it seems to be
|
||||
> an issue with the NFS client which always modifies both. Can be reproduced
|
||||
> with `touch -m` and `touch -a` commands
|
||||
|
||||
This means that viewing files with various tools, notably macOS Finder, will cause
|
||||
rlcone to update the modification time of the file. This may make rclone upload a
|
||||
full new copy of the file.
|
||||
This means that viewing files with various tools, notably macOS Finder, will
|
||||
cause rlcone to update the modification time of the file. This may make rclone
|
||||
upload a full new copy of the file.
|
||||
|
||||
#### Read Only mounts
|
||||
|
||||
When mounting with `--read-only`, attempts to write to files will fail *silently*
|
||||
as opposed to with a clear warning as in macFUSE.
|
||||
|
||||
# Mounting on Linux
|
||||
## Mounting on Linux
|
||||
|
||||
On newer versions of Ubuntu, you may encounter the following error when running
|
||||
`rclone mount`:
|
||||
|
||||
> NOTICE: mount helper error: fusermount3: mount failed: Permission denied
|
||||
> CRITICAL: Fatal error: failed to mount FUSE fs: fusermount: exit status 1
|
||||
|
||||
This may be due to newer [Apparmor](https://wiki.ubuntu.com/AppArmor) restrictions,
|
||||
which can be disabled with `sudo aa-disable /usr/bin/fusermount3` (you may need to
|
||||
`sudo apt install apparmor-utils` beforehand).
|
||||
which can be disabled with `sudo aa-disable /usr/bin/fusermount3` (you may need
|
||||
to `sudo apt install apparmor-utils` beforehand).
|
||||
|
||||
## Limitations
|
||||
|
||||
|
||||
@@ -2059,7 +2059,7 @@ This is the default.
|
||||
`CAUTIOUS` will try to prevent rclone from reaching the limit. Only applicable
|
||||
for `--max-transfer`.
|
||||
|
||||
## -M, --metadata
|
||||
### -M, --metadata
|
||||
|
||||
Setting this flag enables rclone to copy the metadata from the source
|
||||
to the destination. For local backends this is ownership, permissions,
|
||||
@@ -2961,6 +2961,10 @@ knowing the local file is newer than the time it was last uploaded to the
|
||||
remote is sufficient. In those cases, this flag can speed up the process and
|
||||
reduce the number of API calls necessary.
|
||||
|
||||
This flag is only supported on certain backends and will be silently
|
||||
ignored on unsupported backends. Supported backends include
|
||||
`azureblob`, `oracleobjectstorage`, `s3`, `swift`.
|
||||
|
||||
Using this flag on a sync operation without also using `--update` would cause
|
||||
all files modified at any time other than the last upload time to be uploaded
|
||||
again, which is probably not what you want.
|
||||
|
||||
@@ -143,6 +143,7 @@ The latest `rclone` version working for:
|
||||
| Windows Server 2012 | v1.63.1 |
|
||||
| Windows XP | v1.42 |
|
||||
| Windows Vista | v1.42 |
|
||||
| macOS 10.15 (Catalina) | v1.70.3 |
|
||||
| macOS 10.14 (Mojave) | v1.63.1 |
|
||||
| macOS 10.13 (High Sierra) | v1.63.1 |
|
||||
| macOS 10.12 (Sierra) | v1.56.0 |
|
||||
|
||||
@@ -219,6 +219,28 @@ Properties:
|
||||
|
||||
Here are the Advanced options specific to filelu (FileLu Cloud Storage).
|
||||
|
||||
#### --filelu-upload-cutoff
|
||||
|
||||
Cutoff for switching to chunked upload. Any files larger than this will be uploaded in chunks of chunk_size.
|
||||
|
||||
Properties:
|
||||
|
||||
- Config: upload_cutoff
|
||||
- Env Var: RCLONE_FILELU_UPLOAD_CUTOFF
|
||||
- Type: SizeSuffix
|
||||
- Default: 500Mi
|
||||
|
||||
#### --filelu-chunk-size
|
||||
|
||||
Chunk size to use for uploading. Used for multipart uploads.
|
||||
|
||||
Properties:
|
||||
|
||||
- Config: chunk_size
|
||||
- Env Var: RCLONE_FILELU_CHUNK_SIZE
|
||||
- Type: SizeSuffix
|
||||
- Default: 64Mi
|
||||
|
||||
#### --filelu-encoding
|
||||
|
||||
The encoding for the backend.
|
||||
|
||||
@@ -10,6 +10,8 @@ The initial setup for Filen requires that you get an API key for your account,
|
||||
currently this is only possible using the [Filen CLI](https://github.com/FilenCloudDienste/filen-cli).
|
||||
This means you must first download the CLI, login, and then run the `export-api-key` command.
|
||||
|
||||
**Note:** If you change your Filen account password, you will need to update your rclone configuration with the new password and a re-exported API key (via `export-api-key`).
|
||||
|
||||
Here is an example of how to make a remote called `FilenRemote`. First run:
|
||||
|
||||
rclone config
|
||||
|
||||
@@ -121,7 +121,7 @@ Flags for general networking and HTTP stuff.
|
||||
--tpslimit float Limit HTTP transactions per second to this
|
||||
--tpslimit-burst int Max burst of transactions for --tpslimit (default 1)
|
||||
--use-cookies Enable session cookiejar
|
||||
--user-agent string Set the user-agent to a specified string (default "rclone/v1.73.0")
|
||||
--user-agent string Set the user-agent to a specified string (default "rclone/v1.73.5")
|
||||
```
|
||||
|
||||
|
||||
@@ -605,9 +605,11 @@ Backend-only flags (these can be set in the config file also).
|
||||
--filefabric-token-expiry string Token expiry time
|
||||
--filefabric-url string URL of the Enterprise File Fabric to connect to
|
||||
--filefabric-version string Version read from the file fabric
|
||||
--filelu-chunk-size SizeSuffix Chunk size to use for uploading. Used for multipart uploads (default 64Mi)
|
||||
--filelu-description string Description of the remote
|
||||
--filelu-encoding Encoding The encoding for the backend (default Slash,LtGt,DoubleQuote,SingleQuote,BackQuote,Dollar,Colon,Question,Asterisk,Pipe,Hash,Percent,BackSlash,CrLf,Del,Ctl,LeftSpace,LeftPeriod,LeftTilde,LeftCrLfHtVt,RightSpace,RightPeriod,RightCrLfHtVt,InvalidUtf8,Dot,SquareBracket,Semicolon,Exclamation)
|
||||
--filelu-key string Your FileLu Rclone key from My Account
|
||||
--filelu-upload-cutoff SizeSuffix Cutoff for switching to chunked upload. Any files larger than this will be uploaded in chunks of chunk_size (default 500Mi)
|
||||
--filen-api-key string API Key for your Filen account (obscured)
|
||||
--filen-auth-version string Authentication Version (internal use only)
|
||||
--filen-base-folder-uuid string UUID of Account Root Directory (internal use only)
|
||||
|
||||
@@ -12,7 +12,7 @@ its own datacenters in Norway.
|
||||
In addition to the official service at [jottacloud.com](https://www.jottacloud.com/),
|
||||
it also provides white-label solutions to different companies. The following
|
||||
are currently supported by this backend, using a different authentication setup
|
||||
as described [below](#whitelabel-authentication):
|
||||
as described [below](#traditional):
|
||||
|
||||
- Elkjøp (with subsidiaries):
|
||||
- Elkjøp Cloud (cloud.elkjop.no)
|
||||
|
||||
@@ -62,7 +62,7 @@ handling file names.
|
||||
| / | 0x2F | / |
|
||||
|
||||
When running on Windows the following characters are replaced. This
|
||||
list is based on the [Windows file naming conventions](https://docs.microsoft.com/de-de/windows/desktop/FileIO/naming-a-file#naming-conventions).
|
||||
list is based on the [Windows file naming conventions](https://docs.microsoft.com/windows/desktop/FileIO/naming-a-file#naming-conventions).
|
||||
|
||||
| Character | Value | Replacement |
|
||||
| --------- |:-----:|:-----------:|
|
||||
|
||||
@@ -1659,6 +1659,8 @@ This command does not have a command line equivalent so use this instead:
|
||||
|
||||
rclone rc --loopback operations/fsinfo fs=remote:
|
||||
|
||||
**Authentication is required for this call.**
|
||||
|
||||
### operations/hashsum: Produces a hashsum file for all the objects in the path. {#operations-hashsum}
|
||||
|
||||
Produces a hash file for all the objects in the path using the hash
|
||||
@@ -1980,6 +1982,8 @@ And this sets NOTICE level logs (normal without -v)
|
||||
|
||||
rclone rc options/set --json '{"main": {"LogLevel": "NOTICE"}}'
|
||||
|
||||
**Authentication is required for this call.**
|
||||
|
||||
### pluginsctl/addPlugin: Add a plugin using url {#pluginsctl-addPlugin}
|
||||
|
||||
Used for adding a plugin to the webgui.
|
||||
|
||||
+30
-2
@@ -670,6 +670,20 @@ work with the SDK properly:
|
||||
| . | . |
|
||||
| .. | .. |
|
||||
|
||||
#### Important note about double slashes (`//`)
|
||||
|
||||
Object keys containing consecutive forward slashes (`//`) are **not supported** by rclone.
|
||||
|
||||
When rclone encounters an object key with `//` (e.g., `a//b`), it will normalize the path to use a single slash (e.g., `a/b`). This normalization can cause "object not found" errors when trying to access the original object, as rclone will look for the normalized path instead of the actual object key.
|
||||
|
||||
**Example:**
|
||||
- Original S3 object key: `folder//file.txt`
|
||||
- rclone interprets it as: `folder/file.txt`
|
||||
- Result: "object not found" error when trying to access `folder//file.txt`
|
||||
|
||||
**Workaround:**
|
||||
Avoid using consecutive forward slashes (`//`) in S3 object keys when using rclone. If you have existing objects with `//` in their keys, you will need to rename them to use single slashes or access them through other means.
|
||||
|
||||
### Multipart uploads
|
||||
|
||||
rclone supports multipart uploads with S3 which means that it can
|
||||
@@ -1690,6 +1704,9 @@ Properties:
|
||||
- "s3.cubbit.eu"
|
||||
- Cubbit DS3 Object Storage endpoint
|
||||
- Provider: Cubbit
|
||||
- "s3.{tenant_name}.cubbit.eu"
|
||||
- Multi-tenant endpoint - replace {tenant_name} with your actual tenant name. Do not select this directly
|
||||
- Provider: Cubbit
|
||||
- "syd1.digitaloceanspaces.com"
|
||||
- DigitalOcean Spaces Sydney 1
|
||||
- Provider: DigitalOcean
|
||||
@@ -5086,7 +5103,9 @@ can follow this [guide](https://docs.cubbit.io/getting-started/quickstart#api-ke
|
||||
to retrieve these keys. They will be needed when prompted by `rclone config`.
|
||||
|
||||
Default region will correspond to `eu-west-1` and the endpoint has to be specified
|
||||
as `s3.cubbit.eu`.
|
||||
as `s3.cubbit.eu`. If you set a custom tenant endpoint, you must use
|
||||
`s3.{tenant_name}.cubbit.eu`, because the generic `s3.cubbit.eu` endpoint will not
|
||||
work in this case.
|
||||
|
||||
Going through the whole process of creating a new remote by running `rclone config`,
|
||||
each prompt should be answered as shown below:
|
||||
@@ -5099,7 +5118,7 @@ env_auth> false
|
||||
access_key_id> YOUR_ACCESS_KEY
|
||||
secret_access_key> YOUR_SECRET_KEY
|
||||
region> eu-west-1 (or leave empty)
|
||||
endpoint> s3.cubbit.eu
|
||||
endpoint> s3.cubbit.eu (or s3.{tenant_name}.cubbit.eu)
|
||||
acl>
|
||||
```
|
||||
|
||||
@@ -8986,6 +9005,15 @@ To configure access to Tencent COS, follow the steps below:
|
||||
cos s3
|
||||
```
|
||||
|
||||
#### Tencent COS Global Acceleration Endpoint
|
||||
|
||||
When using the Global Acceleration Endpoint (`cos.accelerate.myqcloud.com`),
|
||||
rclone automatically sets `no_check_bucket = true` because this acceleration
|
||||
endpoint does not support the `CreateBucket` call which is used for ensuring
|
||||
a bucket's existence by rclone. Global Acceleration is a per-bucket feature,
|
||||
so you should first create the bucket in one physical region, then enable it
|
||||
in the Tencent Cloud console.
|
||||
|
||||
### Wasabi
|
||||
|
||||
[Wasabi](https://wasabi.com) is a cloud-based object storage service for a
|
||||
|
||||
@@ -16,16 +16,18 @@ Thank you to our sponsors:
|
||||
{{< sponsor src="/img/logos/rabata.svg" width="300" height="200" title="Visit our sponsor Rabata.io" link="https://rabata.io/?utm_source=banner&utm_medium=rclone&utm_content=general">}}
|
||||
{{< sponsor src="/img/logos/idrive_e2.svg" width="300" height="200" title="Visit our sponsor IDrive e2" link="https://www.idrive.com/e2/?refer=rclone">}}
|
||||
{{< sponsor src="/img/logos/filescom-enterprise-grade-workflows.png" width="300" height="200" title="Start Your Free Trial Today" link="https://files.com/?utm_source=rclone&utm_medium=referral&utm_campaign=banner&utm_term=rclone">}}
|
||||
{{< sponsor src="/img/logos/internxt.jpg" width="300" height="200" title="Visit rclone's sponsor Internxt" link="https://internxt.com/specialoffer/rclone">}}
|
||||
{{< sponsor src="/img/logos/mega-s4.svg" width="300" height="200" title="MEGA S4: New S3 compatible object storage. High scale. Low cost. Free egress." link="https://mega.io/objectstorage?utm_source=rclone&utm_medium=referral&utm_campaign=rclone-mega-s4&mct=rclonepromo">}}
|
||||
{{< sponsor src="/img/logos/sia.svg" width="200" height="200" title="Visit our sponsor sia" link="https://sia.tech">}}
|
||||
{{< sponsor src="/img/logos/route4me.svg" width="400" height="200" title="Visit our sponsor Route4Me" link="https://route4me.com/">}}
|
||||
{{< sponsor src="/img/logos/rcloneview-banner.svg" width="300" height="200" title="Visit our sponsor RcloneView" link="https://rcloneview.com/">}}
|
||||
{{< sponsor src="/img/logos/rcloneview.svg" width="300" height="200" title="Visit our sponsor RcloneView" link="https://rcloneview.com/">}}
|
||||
{{< sponsor src="/img/logos/rcloneui.svg" width="300" height="200" title="Visit our sponsor RcloneUI" link="https://github.com/rclone-ui/rclone-ui">}}
|
||||
{{< sponsor src="/img/logos/shade.svg" width="300" height="200" title="Visit our sponsor Shade" link="https://shade.inc">}}
|
||||
{{< sponsor src="/img/logos/filelu-rclone.svg" width="300" height="200" title="Visit our sponsor FileLu" link="https://filelu.com/">}}
|
||||
{{< sponsor src="/img/logos/torbox.png" width="200" height="200" title="Visit our sponsor TORBOX" link="https://www.torbox.app/">}}
|
||||
{{< sponsor src="/img/logos/spectra-logic.svg" width="300" height="200" title="Visit our sponsor Spectra Logic" link="https://spectralogic.com/">}}
|
||||
{{< sponsor src="/img/logos/servercore.svg" width="300" height="200" title="Visit our sponsor servercore" link="https://servercore.com/services/object-storage/?utm_source=rclone.org&utm_medium=referral&utm_campaign=cloud-s3_rclone_231025_paid">}}
|
||||
{{< sponsor src="/img/logos/exchangerate-api.png" width="300" height="200" title="Visit our sponsor ExchangeRate-API" link="https://www.exchangerate-api.com/">}}
|
||||
|
||||
<!-- markdownlint-restore -->
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
"beta" "This feature is currently in beta must be used with care."
|
||||
}}
|
||||
|
||||
{{ if .Params.versionIntroduced }}<span class="badge badge-pill badge-secondary float-right" style="margin-top: 30px; font-size: 100%" title="This feature needs Rclone {{ .Params.versionIntroduced }} or later.">{{ .Params.versionIntroduced }}</span>{{ end }}
|
||||
{{ if .Params.versionIntroduced }}<span class="badge badge-pill badge-secondary float-right" style="margin-top: 30px; font-size: 100%" title="This feature needs Rclone {{ .Params.versionIntroduced }} or later.">added in {{ .Params.versionIntroduced }}</span>{{ end }}
|
||||
|
||||
{{ with .Params.status | lower }}
|
||||
{{ $statusCode := . }}
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
<div class="card">
|
||||
<div class="card-header">Platinum Sponsor</div>
|
||||
<div class="card-body">
|
||||
<a href="https://rabata.io/?utm_source=banner&utm_medium=rclone&utm_content=general" target="_blank" rel="noopener" title="Visit rclone's sponsor Rabata.io"><img src="/img/logos/rabata.svg"></a><br />
|
||||
<a href="https://internxt.com/specialoffer/rclone" target="_blank" rel="noopener" title="Visit rclone's sponsor Internxt"><img style="max-width: 100%; height: auto;" src="/img/logos/internxt.jpg"></a><br />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -30,13 +30,6 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<div class="card-header">Gold Sponsor</div>
|
||||
<div class="card-body">
|
||||
<a href="https://internxt.com/?utm_source=rclone" target="_blank" rel="noopener" title="Visit rclone's sponsor Internxt"><img style="max-width: 100%; height: auto;" src="/img/logos/internxt.jpg"></a><br />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{if .IsHome}}
|
||||
<div class="card">
|
||||
<div class="card-header">Silver Sponsor</div>
|
||||
@@ -44,12 +37,6 @@
|
||||
<a href="https://rcloneview.com/?utm_source=rclone" target="_blank" rel="noopener" title="Visit rclone's sponsor RcloneView"><img src="/img/logos/rcloneview.svg"></a><br />
|
||||
</div>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="card-header">Silver Sponsor</div>
|
||||
<div class="card-body">
|
||||
<a href="https://rcloneui.com" target="_blank" rel="noopener" title="Visit rclone's sponsor rclone UI"><img src="/img/logos/rcloneui.svg"></a><br />
|
||||
</div>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="card-header">Silver Sponsor</div>
|
||||
<div class="card-body">
|
||||
|
||||
@@ -1 +1 @@
|
||||
v1.73.0
|
||||
v1.73.5
|
||||
@@ -385,12 +385,14 @@ func (sg *statsGroups) sum(ctx context.Context) *StatsInfo {
|
||||
sum.checkQueueSize += stats.checkQueueSize
|
||||
sum.transfers += stats.transfers
|
||||
sum.transferring.merge(stats.transferring)
|
||||
sum.transferQueue += stats.transferQueue
|
||||
sum.transferQueueSize += stats.transferQueueSize
|
||||
sum.listed += stats.listed
|
||||
sum.renames += stats.renames
|
||||
sum.renameQueue += stats.renameQueue
|
||||
sum.renameQueueSize += stats.renameQueueSize
|
||||
sum.deletes += stats.deletes
|
||||
sum.deletesSize += stats.deletesSize
|
||||
sum.deletedDirs += stats.deletedDirs
|
||||
sum.inProgress.merge(stats.inProgress)
|
||||
sum.startedTransfers = append(sum.startedTransfers, stats.startedTransfers...)
|
||||
@@ -399,6 +401,10 @@ func (sg *statsGroups) sum(ctx context.Context) *StatsInfo {
|
||||
stats.average.mu.Lock()
|
||||
sum.average.speed += stats.average.speed
|
||||
stats.average.mu.Unlock()
|
||||
sum.serverSideCopies += stats.serverSideCopies
|
||||
sum.serverSideCopyBytes += stats.serverSideCopyBytes
|
||||
sum.serverSideMoves += stats.serverSideMoves
|
||||
sum.serverSideMoveBytes += stats.serverSideMoveBytes
|
||||
}
|
||||
stats.mu.RUnlock()
|
||||
}
|
||||
|
||||
@@ -198,21 +198,18 @@ func NewFilter(opt *Options) (f *Filter, err error) {
|
||||
// Filter flags
|
||||
if f.Opt.MinAge.IsSet() {
|
||||
f.ModTimeTo = time.Now().Add(-time.Duration(f.Opt.MinAge))
|
||||
fs.Debugf(nil, "--min-age %v to %v", f.Opt.MinAge, f.ModTimeTo)
|
||||
}
|
||||
if f.Opt.MaxAge.IsSet() {
|
||||
f.ModTimeFrom = time.Now().Add(-time.Duration(f.Opt.MaxAge))
|
||||
if !f.ModTimeTo.IsZero() && f.ModTimeTo.Before(f.ModTimeFrom) {
|
||||
return nil, fmt.Errorf("filter: --min-age %q can't be larger than --max-age %q", opt.MinAge, opt.MaxAge)
|
||||
}
|
||||
fs.Debugf(nil, "--max-age %v to %v", f.Opt.MaxAge, f.ModTimeFrom)
|
||||
}
|
||||
if f.Opt.HashFilter != "" {
|
||||
f.hashFilterK, f.hashFilterN, err = parseHashFilter(f.Opt.HashFilter)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
fs.Debugf(nil, "Using --hash-filter %d/%d", f.hashFilterK, f.hashFilterN)
|
||||
}
|
||||
|
||||
err = parseRules(&f.Opt.RulesOpt, f.Add, f.Clear)
|
||||
|
||||
@@ -50,6 +50,7 @@ type Sorter struct {
|
||||
errChan <-chan error // for getting errors from the ext sort
|
||||
sorter *extsort.StringSorter // external string sort
|
||||
errs *errcount.ErrCount // accumulate errors
|
||||
tempDir string // directory for temp files (empty for default)
|
||||
}
|
||||
|
||||
// KeyFn turns an entry into a sort key
|
||||
@@ -144,6 +145,7 @@ func (ls *Sorter) startExtSort() (err error) {
|
||||
ChanBuffSize: 1024, // small effect
|
||||
SortedChanBuffSize: 1024, // makes a lot of difference
|
||||
ChunkSize: 32 * 1024, // tuned for 50 char records (UUID sized)
|
||||
TempFilesDir: ls.tempDir,
|
||||
// Defaults
|
||||
// ChunkSize: int(1e6), // amount of records to store in each chunk which will be written to disk
|
||||
// NumWorkers: 2, // maximum number of workers to use for parallel sorting
|
||||
@@ -152,6 +154,17 @@ func (ls *Sorter) startExtSort() (err error) {
|
||||
// TempFilesDir: "", // empty for use OS default ex: /tmp
|
||||
}
|
||||
ls.sorter, ls.outputChan, ls.errChan = extsort.Strings(ls.inputChan, &opt)
|
||||
if ls.sorter == nil {
|
||||
// extsort.Strings returns nil when it can't create temp
|
||||
// files (e.g. due to permissions or apparmor restrictions).
|
||||
// The error will be on errChan.
|
||||
select {
|
||||
case err = <-ls.errChan:
|
||||
default:
|
||||
err = errors.New("failed to initialise on-disk sort")
|
||||
}
|
||||
return fmt.Errorf("sorter: %w", err)
|
||||
}
|
||||
go ls.sorter.Sort(ls.ctx)
|
||||
|
||||
// Show we are extsorting now
|
||||
|
||||
@@ -4,6 +4,9 @@ import (
|
||||
"cmp"
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"slices"
|
||||
"strings"
|
||||
"testing"
|
||||
@@ -231,6 +234,51 @@ func TestSorterExt(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// Test that startExtSort returns an error instead of panicking when
|
||||
// temp file creation fails (e.g. due to permissions or apparmor).
|
||||
// See: https://github.com/rclone/rclone/issues/9244
|
||||
func TestSorterExtTempFileError(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
ctx, ci := fs.AddConfig(ctx)
|
||||
ci.ListCutoff = 1 // force ext sort on first Add
|
||||
|
||||
callback := func(entries fs.DirEntries) error {
|
||||
return nil
|
||||
}
|
||||
ls, err := NewSorter(ctx, nil, callback, nil)
|
||||
require.NoError(t, err)
|
||||
defer ls.CleanUp()
|
||||
|
||||
// Override tempDir to a path where os.MkdirAll will fail,
|
||||
// simulating apparmor or permission denial. This makes
|
||||
// extsort.Strings return a nil sorter.
|
||||
if runtime.GOOS == "windows" {
|
||||
// On Windows, create a regular file and use a child path.
|
||||
// os.MkdirAll fails because an intermediate component is a file.
|
||||
// Windows stat returns ERROR_PATH_NOT_FOUND (treated as
|
||||
// IsNotExist) so the extsort library won't fall back to a
|
||||
// default directory.
|
||||
blocker := filepath.Join(t.TempDir(), "notadir")
|
||||
require.NoError(t, os.WriteFile(blocker, []byte("x"), 0644))
|
||||
ls.tempDir = filepath.Join(blocker, "sub")
|
||||
} else {
|
||||
// On Unix, create a read-only parent directory. stat on the
|
||||
// child returns ENOENT so the extsort library won't fall
|
||||
// back, but os.MkdirAll fails with EACCES.
|
||||
parent := filepath.Join(t.TempDir(), "roparent")
|
||||
require.NoError(t, os.Mkdir(parent, 0o755))
|
||||
require.NoError(t, os.Chmod(parent, 0o555))
|
||||
t.Cleanup(func() { _ = os.Chmod(parent, 0o755) })
|
||||
ls.tempDir = filepath.Join(parent, "child")
|
||||
}
|
||||
|
||||
// Add enough entries to trigger ext sort. Before the fix this
|
||||
// would panic with nil pointer dereference.
|
||||
err = ls.Add(fs.DirEntries{mockobject.Object("a"), mockobject.Object("b")})
|
||||
require.Error(t, err)
|
||||
assert.Contains(t, err.Error(), "sorter:")
|
||||
}
|
||||
|
||||
// benchFs implements enough of the fs.Fs interface for Sorter
|
||||
type benchFs struct{}
|
||||
|
||||
|
||||
+12
-3
@@ -16,6 +16,7 @@ import (
|
||||
"github.com/rclone/rclone/fs/list"
|
||||
"github.com/rclone/rclone/fs/walk"
|
||||
"github.com/rclone/rclone/lib/transform"
|
||||
"golang.org/x/sync/semaphore"
|
||||
"golang.org/x/text/unicode/norm"
|
||||
)
|
||||
|
||||
@@ -41,9 +42,10 @@ type March struct {
|
||||
NoCheckDest bool // transfer all objects regardless without checking dst
|
||||
NoUnicodeNormalization bool // don't normalize unicode characters in filenames
|
||||
// internal state
|
||||
srcListDir listDirFn // function to call to list a directory in the src
|
||||
dstListDir listDirFn // function to call to list a directory in the dst
|
||||
transforms []matchTransformFn
|
||||
srcListDir listDirFn // function to call to list a directory in the src
|
||||
dstListDir listDirFn // function to call to list a directory in the dst
|
||||
transforms []matchTransformFn
|
||||
newObjectSem *semaphore.Weighted // make sure we don't call too many NewObjects simultaneously
|
||||
}
|
||||
|
||||
// Marcher is called on each match
|
||||
@@ -78,6 +80,8 @@ func (m *March) init(ctx context.Context) {
|
||||
if m.Fdst.Features().CaseInsensitive || ci.IgnoreCaseSync {
|
||||
m.transforms = append(m.transforms, strings.ToLower)
|
||||
}
|
||||
// Only allow ci.Checkers simultaneous calls to NewObject
|
||||
m.newObjectSem = semaphore.NewWeighted(int64(ci.Checkers))
|
||||
}
|
||||
|
||||
// srcOrDstKey turns a directory entry into a sort key using the defined transforms.
|
||||
@@ -461,7 +465,12 @@ func (m *March) processJob(job listDirJob) ([]listDirJob, error) {
|
||||
continue
|
||||
}
|
||||
leaf := path.Base(t.src.Remote())
|
||||
if err := m.newObjectSem.Acquire(m.Ctx, 1); err != nil {
|
||||
t.dstMatch <- nil
|
||||
continue
|
||||
}
|
||||
dst, err := m.Fdst.NewObject(m.Ctx, path.Join(job.dstRemote, leaf))
|
||||
m.newObjectSem.Release(1)
|
||||
if err != nil {
|
||||
dst = nil
|
||||
}
|
||||
|
||||
+4
-3
@@ -430,9 +430,10 @@ func rcPublicLink(ctx context.Context, in rc.Params) (out rc.Params, err error)
|
||||
|
||||
func init() {
|
||||
rc.Add(rc.Call{
|
||||
Path: "operations/fsinfo",
|
||||
Fn: rcFsInfo,
|
||||
Title: "Return information about the remote",
|
||||
Path: "operations/fsinfo",
|
||||
AuthRequired: true,
|
||||
Fn: rcFsInfo,
|
||||
Title: "Return information about the remote",
|
||||
Help: `This takes the following parameters:
|
||||
|
||||
- fs - a remote name string e.g. "drive:"
|
||||
|
||||
+4
-3
@@ -146,9 +146,10 @@ func rcOptionsLocal(ctx context.Context, in Params) (out Params, err error) {
|
||||
|
||||
func init() {
|
||||
Add(Call{
|
||||
Path: "options/set",
|
||||
Fn: rcOptionsSet,
|
||||
Title: "Set an option",
|
||||
Path: "options/set",
|
||||
AuthRequired: true,
|
||||
Fn: rcOptionsSet,
|
||||
Title: "Set an option",
|
||||
Help: `Parameters:
|
||||
|
||||
- option block name containing an object with
|
||||
|
||||
@@ -53,6 +53,7 @@ type Server struct {
|
||||
files http.Handler
|
||||
pluginsHandler http.Handler
|
||||
opt *rc.Options
|
||||
noAuth bool // snapshot of opt.NoAuth at startup to prevent runtime mutation
|
||||
}
|
||||
|
||||
func newServer(ctx context.Context, opt *rc.Options, mux *http.ServeMux) (*Server, error) {
|
||||
@@ -104,6 +105,7 @@ func newServer(ctx context.Context, opt *rc.Options, mux *http.ServeMux) (*Serve
|
||||
opt: opt,
|
||||
files: fileHandler,
|
||||
pluginsHandler: pluginsHandler,
|
||||
noAuth: opt.NoAuth,
|
||||
}
|
||||
|
||||
var err error
|
||||
@@ -263,7 +265,7 @@ func (s *Server) handlePost(w http.ResponseWriter, r *http.Request, path string)
|
||||
}
|
||||
|
||||
// Check to see if it requires authorisation
|
||||
if !s.opt.NoAuth && call.AuthRequired && !s.server.UsingAuth() {
|
||||
if !s.noAuth && call.AuthRequired && !s.server.UsingAuth() {
|
||||
writeError(path, in, w, fmt.Errorf("authentication must be set up on the rc server to use %q or the --rc-no-auth flag must be in use", path), http.StatusForbidden)
|
||||
return
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package fs
|
||||
|
||||
// VersionTag of rclone
|
||||
var VersionTag = "v1.73.0"
|
||||
var VersionTag = "v1.73.5"
|
||||
@@ -1,6 +1,6 @@
|
||||
module github.com/rclone/rclone
|
||||
|
||||
go 1.24.4
|
||||
go 1.25.0
|
||||
|
||||
godebug x509negativeserial=1
|
||||
|
||||
@@ -11,7 +11,7 @@ require (
|
||||
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.6.3
|
||||
github.com/Azure/azure-sdk-for-go/sdk/storage/azfile v1.5.3
|
||||
github.com/Azure/go-ntlmssp v0.0.2-0.20251110135918-10b7b7e7cd26
|
||||
github.com/FilenCloudDienste/filen-sdk-go v0.0.35
|
||||
github.com/FilenCloudDienste/filen-sdk-go v0.0.38
|
||||
github.com/Files-com/files-sdk-go/v3 v3.2.264
|
||||
github.com/Max-Sum/base32768 v0.0.0-20230304063302-18e6ce5945fd
|
||||
github.com/a1ex3/zstd-seekable-format-go/pkg v0.10.0
|
||||
@@ -21,13 +21,13 @@ require (
|
||||
github.com/anacrolix/dms v1.7.2
|
||||
github.com/anacrolix/log v0.17.0
|
||||
github.com/atotto/clipboard v0.1.4
|
||||
github.com/aws/aws-sdk-go-v2 v1.39.6
|
||||
github.com/aws/aws-sdk-go-v2/config v1.31.17
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.18.21
|
||||
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.20.4
|
||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.90.0
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.39.1
|
||||
github.com/aws/smithy-go v1.23.2
|
||||
github.com/aws/aws-sdk-go-v2 v1.41.5
|
||||
github.com/aws/aws-sdk-go-v2/config v1.32.8
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.19.8
|
||||
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.22.1
|
||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.97.3
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.41.6
|
||||
github.com/aws/smithy-go v1.24.2
|
||||
github.com/buengese/sgzip v0.1.1
|
||||
github.com/cloudinary/cloudinary-go/v2 v2.13.0
|
||||
github.com/cloudsoda/go-smb2 v0.0.0-20250228001242-d4c70e6251cc
|
||||
@@ -39,13 +39,13 @@ require (
|
||||
github.com/dropbox/dropbox-sdk-go-unofficial/v6 v6.0.5
|
||||
github.com/gabriel-vasile/mimetype v1.4.11
|
||||
github.com/gdamore/tcell/v2 v2.9.0
|
||||
github.com/go-chi/chi/v5 v5.2.3
|
||||
github.com/go-chi/chi/v5 v5.2.5
|
||||
github.com/go-darwin/apfs v0.0.0-20211011131704-f84b94dbf348
|
||||
github.com/go-git/go-billy/v5 v5.6.2
|
||||
github.com/golang-jwt/jwt/v5 v5.3.0
|
||||
github.com/google/uuid v1.6.0
|
||||
github.com/hanwen/go-fuse/v2 v2.9.0
|
||||
github.com/internxt/rclone-adapter v0.0.0-20260130171252-c3c6ebb49276
|
||||
github.com/internxt/rclone-adapter v0.0.0-20260220172730-613f4cc8b8fd
|
||||
github.com/jcmturner/gokrb5/v8 v8.4.4
|
||||
github.com/jlaffaye/ftp v0.2.1-0.20240918233326-1b970516f5d3
|
||||
github.com/josephspurrier/goversioninfo v1.5.0
|
||||
@@ -92,12 +92,12 @@ require (
|
||||
github.com/zeebo/xxh3 v1.0.2
|
||||
go.etcd.io/bbolt v1.4.3
|
||||
goftp.io/server/v2 v2.0.2
|
||||
golang.org/x/crypto v0.45.0
|
||||
golang.org/x/net v0.47.0
|
||||
golang.org/x/oauth2 v0.33.0
|
||||
golang.org/x/sync v0.18.0
|
||||
golang.org/x/sys v0.38.0
|
||||
golang.org/x/text v0.31.0
|
||||
golang.org/x/crypto v0.48.0
|
||||
golang.org/x/net v0.51.0
|
||||
golang.org/x/oauth2 v0.34.0
|
||||
golang.org/x/sync v0.20.0
|
||||
golang.org/x/sys v0.41.0
|
||||
golang.org/x/text v0.35.0
|
||||
golang.org/x/time v0.14.0
|
||||
google.golang.org/api v0.255.0
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.2.1
|
||||
@@ -125,18 +125,19 @@ require (
|
||||
github.com/andybalholm/brotli v1.2.0 // indirect
|
||||
github.com/andybalholm/cascadia v1.3.3 // indirect
|
||||
github.com/appscode/go-querystring v0.0.0-20170504095604-0126cfb3f1dc // indirect
|
||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.3 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.13 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.13 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.13 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.8 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.17 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.21 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.21 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.4 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.13 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.3 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.4 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.13 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.13 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.30.1 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.5 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.22 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.7 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.13 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.21 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.21 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/signin v1.0.5 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.30.9 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.14 // indirect
|
||||
github.com/bahlo/generic-list-go v0.2.0 // indirect
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/bodgit/plumbing v1.3.0 // indirect
|
||||
@@ -145,13 +146,13 @@ require (
|
||||
github.com/boombuler/barcode v1.1.0 // indirect
|
||||
github.com/bradenaw/juniper v0.15.3 // indirect
|
||||
github.com/bradfitz/iter v0.0.0-20191230175014-e8f45d346db8 // indirect
|
||||
github.com/buger/jsonparser v1.1.1 // indirect
|
||||
github.com/buger/jsonparser v1.1.2 // indirect
|
||||
github.com/calebcase/tmpfile v1.0.3 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||
github.com/chilts/sid v0.0.0-20190607042430-660e94789ec9 // indirect
|
||||
github.com/clipperhouse/stringish v0.1.1 // indirect
|
||||
github.com/clipperhouse/uax29/v2 v2.3.0 // indirect
|
||||
github.com/cloudflare/circl v1.6.1 // indirect
|
||||
github.com/cloudflare/circl v1.6.3 // indirect
|
||||
github.com/cloudsoda/sddl v0.0.0-20250224235906-926454e91efc // indirect
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.7 // indirect
|
||||
github.com/creasty/defaults v1.8.0 // indirect
|
||||
@@ -252,17 +253,17 @@ require (
|
||||
go.mongodb.org/mongo-driver v1.17.6 // indirect
|
||||
go.opentelemetry.io/auto/sdk v1.2.1 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.63.0 // indirect
|
||||
go.opentelemetry.io/otel v1.38.0 // indirect
|
||||
go.opentelemetry.io/otel/metric v1.38.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.38.0 // indirect
|
||||
go.opentelemetry.io/otel v1.39.0 // indirect
|
||||
go.opentelemetry.io/otel/metric v1.39.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.39.0 // indirect
|
||||
go.yaml.in/yaml/v2 v2.4.3 // indirect
|
||||
go4.org v0.0.0-20230225012048-214862532bf5 // indirect
|
||||
golang.org/x/exp v0.0.0-20251023183803-a4bb9ffd2546 // indirect
|
||||
golang.org/x/image v0.32.0 // indirect
|
||||
golang.org/x/mod v0.29.0 // indirect
|
||||
golang.org/x/tools v0.38.0 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20251103181224-f26f9409b101 // indirect
|
||||
google.golang.org/grpc v1.76.0 // indirect
|
||||
golang.org/x/image v0.38.0 // indirect
|
||||
golang.org/x/mod v0.33.0 // indirect
|
||||
golang.org/x/tools v0.42.0 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20251202230838-ff82c1b0f217 // indirect
|
||||
google.golang.org/grpc v1.79.3 // indirect
|
||||
google.golang.org/protobuf v1.36.10 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
moul.io/http2curl/v2 v2.3.0 // indirect
|
||||
@@ -281,5 +282,5 @@ require (
|
||||
github.com/pkg/xattr v0.4.12
|
||||
github.com/pquerna/otp v1.5.0
|
||||
golang.org/x/mobile v0.0.0-20251021151156-188f512ec823
|
||||
golang.org/x/term v0.37.0
|
||||
golang.org/x/term v0.40.0
|
||||
)
|
||||
@@ -61,8 +61,8 @@ github.com/AzureAD/microsoft-authentication-library-for-go v1.6.0 h1:XRzhVemXdgv
|
||||
github.com/AzureAD/microsoft-authentication-library-for-go v1.6.0/go.mod h1:HKpQxkWaGLJ+D/5H8QRpyQXA1eKjxkFlOMwck5+33Jk=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||
github.com/FilenCloudDienste/filen-sdk-go v0.0.35 h1:geuYpD/1ZXSp1H3kdW7si+KRUIrHHqM1kk8lqoA8Y9M=
|
||||
github.com/FilenCloudDienste/filen-sdk-go v0.0.35/go.mod h1:0cBhKXQg49XbKZZfk5TCDa3sVLP+xMxZTWL+7KY0XR0=
|
||||
github.com/FilenCloudDienste/filen-sdk-go v0.0.38 h1:YCyHs3wUXEe2BEWn40vcoyaQ2ruHNmNwkasfo3Th16A=
|
||||
github.com/FilenCloudDienste/filen-sdk-go v0.0.38/go.mod h1:0cBhKXQg49XbKZZfk5TCDa3sVLP+xMxZTWL+7KY0XR0=
|
||||
github.com/Files-com/files-sdk-go/v3 v3.2.264 h1:lMHTplAYI9FtmCo/QOcpRxmPA5REVAct1r2riQmDQKw=
|
||||
github.com/Files-com/files-sdk-go/v3 v3.2.264/go.mod h1:wGqkOzRu/ClJibvDgcfuJNAqI2nLhe8g91tPlDKRCdE=
|
||||
github.com/IBM/go-sdk-core/v5 v5.18.5 h1:g0JRl3sYXJczB/yuDlrN6x22LJ6jIxhp0Sa4ARNW60c=
|
||||
@@ -118,44 +118,46 @@ github.com/appscode/go-querystring v0.0.0-20170504095604-0126cfb3f1dc h1:LoL75er
|
||||
github.com/appscode/go-querystring v0.0.0-20170504095604-0126cfb3f1dc/go.mod h1:w648aMHEgFYS6xb0KVMMtZ2uMeemhiKCuD2vj6gY52A=
|
||||
github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z4=
|
||||
github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI=
|
||||
github.com/aws/aws-sdk-go-v2 v1.39.6 h1:2JrPCVgWJm7bm83BDwY5z8ietmeJUbh3O2ACnn+Xsqk=
|
||||
github.com/aws/aws-sdk-go-v2 v1.39.6/go.mod h1:c9pm7VwuW0UPxAEYGyTmyurVcNrbF6Rt/wixFqDhcjE=
|
||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.3 h1:DHctwEM8P8iTXFxC/QK0MRjwEpWQeM9yzidCRjldUz0=
|
||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.3/go.mod h1:xdCzcZEtnSTKVDOmUZs4l/j3pSV6rpo1WXl5ugNsL8Y=
|
||||
github.com/aws/aws-sdk-go-v2/config v1.31.17 h1:QFl8lL6RgakNK86vusim14P2k8BFSxjvUkcWLDjgz9Y=
|
||||
github.com/aws/aws-sdk-go-v2/config v1.31.17/go.mod h1:V8P7ILjp/Uef/aX8TjGk6OHZN6IKPM5YW6S78QnRD5c=
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.18.21 h1:56HGpsgnmD+2/KpG0ikvvR8+3v3COCwaF4r+oWwOeNA=
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.18.21/go.mod h1:3YELwedmQbw7cXNaII2Wywd+YY58AmLPwX4LzARgmmA=
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.13 h1:T1brd5dR3/fzNFAQch/iBKeX07/ffu/cLu+q+RuzEWk=
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.13/go.mod h1:Peg/GBAQ6JDt+RoBf4meB1wylmAipb7Kg2ZFakZTlwk=
|
||||
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.20.4 h1:2fjfz3/G9BRvIKuNZ655GwzpklC2kEH0cowZQGO7uBg=
|
||||
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.20.4/go.mod h1:Ymws824lvMypLFPwyyUXM52SXuGgxpu0+DISLfKvB+c=
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.13 h1:a+8/MLcWlIxo1lF9xaGt3J/u3yOZx+CdSveSNwjhD40=
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.13/go.mod h1:oGnKwIYZ4XttyU2JWxFrwvhF6YKiK/9/wmE3v3Iu9K8=
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.13 h1:HBSI2kDkMdWz4ZM7FjwE7e/pWDEZ+nR95x8Ztet1ooY=
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.13/go.mod h1:YE94ZoDArI7awZqJzBAZ3PDD2zSfuP7w6P2knOzIn8M=
|
||||
github.com/aws/aws-sdk-go-v2 v1.41.5 h1:dj5kopbwUsVUVFgO4Fi5BIT3t4WyqIDjGKCangnV/yY=
|
||||
github.com/aws/aws-sdk-go-v2 v1.41.5/go.mod h1:mwsPRE8ceUUpiTgF7QmQIJ7lgsKUPQOUl3o72QBrE1o=
|
||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.8 h1:eBMB84YGghSocM7PsjmmPffTa+1FBUeNvGvFou6V/4o=
|
||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.8/go.mod h1:lyw7GFp3qENLh7kwzf7iMzAxDn+NzjXEAGjKS2UOKqI=
|
||||
github.com/aws/aws-sdk-go-v2/config v1.32.8 h1:iu+64gwDKEoKnyTQskSku72dAwggKI5sV6rNvgSMpMs=
|
||||
github.com/aws/aws-sdk-go-v2/config v1.32.8/go.mod h1:MI2XvA+qDi3i9AJxX1E2fu730syEBzp/jnXrjxuHwgI=
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.19.8 h1:Jp2JYH1lRT3KhX4mshHPvVYsR5qqRec3hGvEarNYoR0=
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.19.8/go.mod h1:fZG9tuvyVfxknv1rKibIz3DobRaFw1Poe8IKtXB3XYY=
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.17 h1:I0GyV8wiYrP8XpA70g1HBcQO1JlQxCMTW9npl5UbDHY=
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.17/go.mod h1:tyw7BOl5bBe/oqvoIeECFJjMdzXoa/dfVz3QQ5lgHGA=
|
||||
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.22.1 h1:IbWiN670htmBioc+Zj32vSpJgQ2+OYSlvTvfQ1nCORQ=
|
||||
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.22.1/go.mod h1:tw/B596EUhBWDFGdDGuLC21fVU4A3s4/5Efy8S39W18=
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.21 h1:Rgg6wvjjtX8bNHcvi9OnXWwcE0a2vGpbwmtICOsvcf4=
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.21/go.mod h1:A/kJFst/nm//cyqonihbdpQZwiUhhzpqTsdbhDdRF9c=
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.21 h1:PEgGVtPoB6NTpPrBgqSE5hE/o47Ij9qk/SEZFbUOe9A=
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.21/go.mod h1:p+hz+PRAYlY3zcpJhPwXlLC4C+kqn70WIHwnzAfs6ps=
|
||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.4 h1:WKuaxf++XKWlHWu9ECbMlha8WOEGm0OUEZqm4K/Gcfk=
|
||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.4/go.mod h1:ZWy7j6v1vWGmPReu0iSGvRiise4YI5SkR3OHKTZ6Wuc=
|
||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.13 h1:eg/WYAa12vqTphzIdWMzqYRVKKnCboVPRlvaybNCqPA=
|
||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.13/go.mod h1:/FDdxWhz1486obGrKKC1HONd7krpk38LBt+dutLcN9k=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.3 h1:x2Ibm/Af8Fi+BH+Hsn9TXGdT+hKbDd5XOTZxTMxDk7o=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.3/go.mod h1:IW1jwyrQgMdhisceG8fQLmQIydcT/jWY21rFhzgaKwo=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.4 h1:NvMjwvv8hpGUILarKw7Z4Q0w1H9anXKsesMxtw++MA4=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.4/go.mod h1:455WPHSwaGj2waRSpQp7TsnpOnBfw8iDfPfbwl7KPJE=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.13 h1:kDqdFvMY4AtKoACfzIGD8A0+hbT41KTKF//gq7jITfM=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.13/go.mod h1:lmKuogqSU3HzQCwZ9ZtcqOc5XGMqtDK7OIc2+DxiUEg=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.13 h1:zhBJXdhWIFZ1acfDYIhu4+LCzdUS2Vbcum7D01dXlHQ=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.13/go.mod h1:JaaOeCE368qn2Hzi3sEzY6FgAZVCIYcC2nwbro2QCh8=
|
||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.90.0 h1:ef6gIJR+xv/JQWwpa5FYirzoQctfSJm7tuDe3SZsUf8=
|
||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.90.0/go.mod h1:+wArOOrcHUevqdto9k1tKOF5++YTe9JEcPSc9Tx2ZSw=
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.30.1 h1:0JPwLz1J+5lEOfy/g0SURC9cxhbQ1lIMHMa+AHZSzz0=
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.30.1/go.mod h1:fKvyjJcz63iL/ftA6RaM8sRCtN4r4zl4tjL3qw5ec7k=
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.5 h1:OWs0/j2UYR5LOGi88sD5/lhN6TDLG6SfA7CqsQO9zF0=
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.5/go.mod h1:klO+ejMvYsB4QATfEOIXk8WAEwN4N0aBfJpvC+5SZBo=
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.39.1 h1:mLlUgHn02ue8whiR4BmxxGJLR2gwU6s6ZzJ5wDamBUs=
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.39.1/go.mod h1:E19xDjpzPZC7LS2knI9E6BaRFDK43Eul7vd6rSq2HWk=
|
||||
github.com/aws/smithy-go v1.23.2 h1:Crv0eatJUQhaManss33hS5r40CG3ZFH+21XSkqMrIUM=
|
||||
github.com/aws/smithy-go v1.23.2/go.mod h1:LEj2LM3rBRQJxPZTB4KuzZkaZYnZPnvgIhb4pu07mx0=
|
||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.22 h1:rWyie/PxDRIdhNf4DzRk0lvjVOqFJuNnO8WwaIRVxzQ=
|
||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.22/go.mod h1:zd/JsJ4P7oGfUhXn1VyLqaRZwPmZwg44Jf2dS84Dm3Y=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.7 h1:5EniKhLZe4xzL7a+fU3C2tfUN4nWIqlLesfrjkuPFTY=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.7/go.mod h1:x0nZssQ3qZSnIcePWLvcoFisRXJzcTVvYpAAdYX8+GI=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.13 h1:JRaIgADQS/U6uXDqlPiefP32yXTda7Kqfx+LgspooZM=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.13/go.mod h1:CEuVn5WqOMilYl+tbccq8+N2ieCy0gVn3OtRb0vBNNM=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.21 h1:c31//R3xgIJMSC8S6hEVq+38DcvUlgFY0FM6mSI5oto=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.21/go.mod h1:r6+pf23ouCB718FUxaqzZdbpYFyDtehyZcmP5KL9FkA=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.21 h1:ZlvrNcHSFFWURB8avufQq9gFsheUgjVD9536obIknfM=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.21/go.mod h1:cv3TNhVrssKR0O/xxLJVRfd2oazSnZnkUeTf6ctUwfQ=
|
||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.97.3 h1:HwxWTbTrIHm5qY+CAEur0s/figc3qwvLWsNkF4RPToo=
|
||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.97.3/go.mod h1:uoA43SdFwacedBfSgfFSjjCvYe8aYBS7EnU5GZ/YKMM=
|
||||
github.com/aws/aws-sdk-go-v2/service/signin v1.0.5 h1:VrhDvQib/i0lxvr3zqlUwLwJP4fpmpyD9wYG1vfSu+Y=
|
||||
github.com/aws/aws-sdk-go-v2/service/signin v1.0.5/go.mod h1:k029+U8SY30/3/ras4G/Fnv/b88N4mAfliNn08Dem4M=
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.30.9 h1:v6EiMvhEYBoHABfbGB4alOYmCIrcgyPPiBE1wZAEbqk=
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.30.9/go.mod h1:yifAsgBxgJWn3ggx70A3urX2AN49Y5sJTD1UQFlfqBw=
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.14 h1:0jbJeuEHlwKJ9PfXtpSFc4MF+WIWORdhN1n30ITZGFM=
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.14/go.mod h1:sTGThjphYE4Ohw8vJiRStAcu3rbjtXRsdNB0TvZ5wwo=
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.41.6 h1:5fFjR/ToSOzB2OQ/XqWpZBmNvmP/pJ1jOWYlFDJTjRQ=
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.41.6/go.mod h1:qgFDZQSD/Kys7nJnVqYlWKnh0SSdMjAi0uSwON4wgYQ=
|
||||
github.com/aws/smithy-go v1.24.2 h1:FzA3bu/nt/vDvmnkg+R8Xl46gmzEDam6mZ1hzmwXFng=
|
||||
github.com/aws/smithy-go v1.24.2/go.mod h1:YE2RhdIuDbA5E5bTdciG9KrW3+TiEONeUWCqxX9i1Fc=
|
||||
github.com/bahlo/generic-list-go v0.2.0 h1:5sz/EEAK+ls5wF+NeqDpk5+iNdMDXrh3z3nPnH1Wvgk=
|
||||
github.com/bahlo/generic-list-go v0.2.0/go.mod h1:2KvAjgMlE5NNynlg/5iLrrCCZ2+5xWbdbCW3pNTGyYg=
|
||||
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||
@@ -175,8 +177,8 @@ github.com/bradfitz/iter v0.0.0-20191230175014-e8f45d346db8 h1:GKTyiRCL6zVf5wWaq
|
||||
github.com/bradfitz/iter v0.0.0-20191230175014-e8f45d346db8/go.mod h1:spo1JLcs67NmW1aVLEgtA8Yy1elc+X8y5SRW1sFW4Og=
|
||||
github.com/buengese/sgzip v0.1.1 h1:ry+T8l1mlmiWEsDrH/YHZnCVWD2S3im1KLsyO+8ZmTU=
|
||||
github.com/buengese/sgzip v0.1.1/go.mod h1:i5ZiXGF3fhV7gL1xaRRL1nDnmpNj0X061FQzOS8VMas=
|
||||
github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs=
|
||||
github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0=
|
||||
github.com/buger/jsonparser v1.1.2 h1:frqHqw7otoVbk5M8LlE/L7HTnIq2v9RX6EJ48i9AxJk=
|
||||
github.com/buger/jsonparser v1.1.2/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0=
|
||||
github.com/bwesterb/go-ristretto v1.2.0/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0=
|
||||
github.com/bytedance/sonic v1.13.2 h1:8/H1FempDZqC4VqjptGo14QQlJx8VdZJegxs6wwfqpQ=
|
||||
github.com/bytedance/sonic v1.13.2/go.mod h1:o68xyaF9u2gvVBuGHPlUVCy+ZfmNNO5ETf1+KgkJhz4=
|
||||
@@ -198,8 +200,8 @@ github.com/clipperhouse/stringish v0.1.1/go.mod h1:v/WhFtE1q0ovMta2+m+UbpZ+2/HEX
|
||||
github.com/clipperhouse/uax29/v2 v2.3.0 h1:SNdx9DVUqMoBuBoW3iLOj4FQv3dN5mDtuqwuhIGpJy4=
|
||||
github.com/clipperhouse/uax29/v2 v2.3.0/go.mod h1:Wn1g7MK6OoeDT0vL+Q0SQLDz/KpfsVRgg6W7ihQeh4g=
|
||||
github.com/cloudflare/circl v1.1.0/go.mod h1:prBCrKB9DV4poKZY1l9zBXg2QJY7mvgRvtMxxK7fi4I=
|
||||
github.com/cloudflare/circl v1.6.1 h1:zqIqSPIndyBh1bjLVVDHMPpVKqp8Su/V+6MeDzzQBQ0=
|
||||
github.com/cloudflare/circl v1.6.1/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs=
|
||||
github.com/cloudflare/circl v1.6.3 h1:9GPOhQGF9MCYUeXyMYlqTR6a5gTrgR/fBLXvUgtVcg8=
|
||||
github.com/cloudflare/circl v1.6.3/go.mod h1:2eXP6Qfat4O/Yhh8BznvKnJ+uzEoTQ6jVKJRn81BiS4=
|
||||
github.com/cloudinary/cloudinary-go/v2 v2.13.0 h1:ugiQwb7DwpWQnete2AZkTh94MonZKmxD7hDGy1qTzDs=
|
||||
github.com/cloudinary/cloudinary-go/v2 v2.13.0/go.mod h1:ireC4gqVetsjVhYlwjUJwKTbZuWjEIynbR9zQTlqsvo=
|
||||
github.com/cloudsoda/go-smb2 v0.0.0-20250228001242-d4c70e6251cc h1:t8YjNUCt1DimB4HCIXBztwWMhgxr5yG5/YaRl9Afdfg=
|
||||
@@ -280,8 +282,8 @@ github.com/gin-contrib/sse v1.0.0 h1:y3bT1mUWUxDpW4JLQg/HnTqV4rozuW4tC9eFKTxYI9E
|
||||
github.com/gin-contrib/sse v1.0.0/go.mod h1:zNuFdwarAygJBht0NTKiSi3jRf6RbqeILZ9Sp6Slhe0=
|
||||
github.com/gin-gonic/gin v1.10.0 h1:nTuyha1TYqgedzytsKYqna+DfLos46nTv2ygFy86HFU=
|
||||
github.com/gin-gonic/gin v1.10.0/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y=
|
||||
github.com/go-chi/chi/v5 v5.2.3 h1:WQIt9uxdsAbgIYgid+BpYc+liqQZGMHRaUwp0JUcvdE=
|
||||
github.com/go-chi/chi/v5 v5.2.3/go.mod h1:L2yAIGWB3H+phAw1NxKwWM+7eUH/lU8pOMm5hHcoops=
|
||||
github.com/go-chi/chi/v5 v5.2.5 h1:Eg4myHZBjyvJmAFjFvWgrqDTXFyOzjj7YIm3L3mu6Ug=
|
||||
github.com/go-chi/chi/v5 v5.2.5/go.mod h1:X7Gx4mteadT3eDOMTsXzmI4/rwUpOwBHLpAfupzFJP0=
|
||||
github.com/go-darwin/apfs v0.0.0-20211011131704-f84b94dbf348 h1:JnrjqG5iR07/8k7NqrLNilRsl3s1EPRQEGvbPyOce68=
|
||||
github.com/go-darwin/apfs v0.0.0-20211011131704-f84b94dbf348/go.mod h1:Czxo/d1g948LtrALAZdL04TL/HnkopquAjxYUuI02bo=
|
||||
github.com/go-git/go-billy/v5 v5.6.2 h1:6Q86EsPXMa7c3YZ3aLAQsMA0VlWmy43r6FHqa/UNbRM=
|
||||
@@ -423,8 +425,8 @@ github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyf
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
||||
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
||||
github.com/internxt/rclone-adapter v0.0.0-20260130171252-c3c6ebb49276 h1:PTJPYovznNqc9t/9MjvtqhrgEVC9OiK75ZPL6hqm6gM=
|
||||
github.com/internxt/rclone-adapter v0.0.0-20260130171252-c3c6ebb49276/go.mod h1:vdPya4AIcDjvng4ViaAzqjegJf0VHYpYHQguFx5xBp0=
|
||||
github.com/internxt/rclone-adapter v0.0.0-20260220172730-613f4cc8b8fd h1:dSIuz2mpJAPQfhHYtG57D0qwSkgC/vQ69gHfeyQ4kxA=
|
||||
github.com/internxt/rclone-adapter v0.0.0-20260220172730-613f4cc8b8fd/go.mod h1:vdPya4AIcDjvng4ViaAzqjegJf0VHYpYHQguFx5xBp0=
|
||||
github.com/jcmturner/aescts/v2 v2.0.0 h1:9YKLH6ey7H4eDBXW8khjYslgyqG2xZikXP0EQFKrle8=
|
||||
github.com/jcmturner/aescts/v2 v2.0.0/go.mod h1:AiaICIRyfYg35RUkr8yESTqvSy7csK90qZ5xfvvsoNs=
|
||||
github.com/jcmturner/dnsutils/v2 v2.0.0 h1:lltnkeZGL0wILNvrNiVCR6Ro5PGU/SeBvVO/8c/iPbo=
|
||||
@@ -727,16 +729,16 @@ go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ
|
||||
go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.63.0 h1:RbKq8BG0FI8OiXhBfcRtqqHcZcka+gU3cskNuf05R18=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.63.0/go.mod h1:h06DGIukJOevXaj/xrNjhi/2098RZzcLTbc0jDAUbsg=
|
||||
go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8=
|
||||
go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM=
|
||||
go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA=
|
||||
go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI=
|
||||
go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E=
|
||||
go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA=
|
||||
go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE=
|
||||
go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs=
|
||||
go.opentelemetry.io/otel v1.39.0 h1:8yPrr/S0ND9QEfTfdP9V+SiwT4E0G7Y5MO7p85nis48=
|
||||
go.opentelemetry.io/otel v1.39.0/go.mod h1:kLlFTywNWrFyEdH0oj2xK0bFYZtHRYUdv1NklR/tgc8=
|
||||
go.opentelemetry.io/otel/metric v1.39.0 h1:d1UzonvEZriVfpNKEVmHXbdf909uGTOQjA0HF0Ls5Q0=
|
||||
go.opentelemetry.io/otel/metric v1.39.0/go.mod h1:jrZSWL33sD7bBxg1xjrqyDjnuzTUB0x1nBERXd7Ftcs=
|
||||
go.opentelemetry.io/otel/sdk v1.39.0 h1:nMLYcjVsvdui1B/4FRkwjzoRVsMK8uL/cj0OyhKzt18=
|
||||
go.opentelemetry.io/otel/sdk v1.39.0/go.mod h1:vDojkC4/jsTJsE+kh+LXYQlbL8CgrEcwmt1ENZszdJE=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.39.0 h1:cXMVVFVgsIf2YL6QkRF4Urbr/aMInf+2WKg+sEJTtB8=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.39.0/go.mod h1:xq9HEVH7qeX69/JnwEfp6fVq5wosJsY1mt4lLfYdVew=
|
||||
go.opentelemetry.io/otel/trace v1.39.0 h1:2d2vfpEDmCJ5zVYz7ijaJdOF59xLomrvj7bjt6/qCJI=
|
||||
go.opentelemetry.io/otel/trace v1.39.0/go.mod h1:88w4/PnZSazkGzz/w84VHpQafiU4EtqqlVdxWy+rNOA=
|
||||
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
||||
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
|
||||
go.uber.org/mock v0.5.0 h1:KAMbZvZPyBPWgD14IrIQ38QCyjwpvVVV6K/bHl1IwQU=
|
||||
@@ -764,8 +766,8 @@ golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliY
|
||||
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
|
||||
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
|
||||
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
|
||||
golang.org/x/crypto v0.45.0 h1:jMBrvKuj23MTlT0bQEOBcAE0mjg8mK9RXFhRH6nyF3Q=
|
||||
golang.org/x/crypto v0.45.0/go.mod h1:XTGrrkGJve7CYK7J8PEww4aY7gM3qMCElcJQ8n8JdX4=
|
||||
golang.org/x/crypto v0.48.0 h1:/VRzVqiRSggnhY7gNRxPauEQ5Drw9haKdM0jqfcCFts=
|
||||
golang.org/x/crypto v0.48.0/go.mod h1:r0kV5h3qnFPlQnBSrULhlsRfryS2pmewsg+XfMgkVos=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||
@@ -780,8 +782,8 @@ golang.org/x/exp v0.0.0-20251023183803-a4bb9ffd2546 h1:mgKeJMpvi0yx/sU5GsxQ7p6s2
|
||||
golang.org/x/exp v0.0.0-20251023183803-a4bb9ffd2546/go.mod h1:j/pmGrbnkbPtQfxEe5D0VQhZC6qKbfKifgD0oM7sR70=
|
||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/image v0.32.0 h1:6lZQWq75h7L5IWNk0r+SCpUJ6tUVd3v4ZHnbRKLkUDQ=
|
||||
golang.org/x/image v0.32.0/go.mod h1:/R37rrQmKXtO6tYXAjtDLwQgFLHmhW+V6ayXlxzP2Pc=
|
||||
golang.org/x/image v0.38.0 h1:5l+q+Y9JDC7mBOMjo4/aPhMDcxEptsX+Tt3GgRQRPuE=
|
||||
golang.org/x/image v0.38.0/go.mod h1:/3f6vaXC+6CEanU4KJxbcUZyEePbyKbaLoDOe4ehFYY=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
@@ -808,8 +810,8 @@ golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/mod v0.29.0 h1:HV8lRxZC4l2cr3Zq1LvtOsi/ThTgWnUk/y64QSs8GwA=
|
||||
golang.org/x/mod v0.29.0/go.mod h1:NyhrlYXJ2H4eJiRy/WDBO6HMqZQ6q9nk4JzS3NuCK+w=
|
||||
golang.org/x/mod v0.33.0 h1:tHFzIWbBifEmbwtGz65eaWyGiGZatSrT9prnU8DbVL8=
|
||||
golang.org/x/mod v0.33.0/go.mod h1:swjeQEj+6r7fODbD2cqrnje9PnziFuw4bmLbBZFrQ5w=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
@@ -849,16 +851,16 @@ golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
|
||||
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
|
||||
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
|
||||
golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
|
||||
golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY=
|
||||
golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU=
|
||||
golang.org/x/net v0.51.0 h1:94R/GTO7mt3/4wIKpcR5gkGmRLOuE/2hNGeWq/GBIFo=
|
||||
golang.org/x/net v0.51.0/go.mod h1:aamm+2QF5ogm02fjy5Bb7CQ0WMt1/WVM7FtyaTLlA9Y=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.33.0 h1:4Q+qn+E5z8gPRJfmRy7C2gGG3T4jIprK6aSYgTXGRpo=
|
||||
golang.org/x/oauth2 v0.33.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA=
|
||||
golang.org/x/oauth2 v0.34.0 h1:hqK/t4AKgbqWkdkcAeI8XLmbK+4m4G5YeQRrmiotGlw=
|
||||
golang.org/x/oauth2 v0.34.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
@@ -874,8 +876,8 @@ golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
|
||||
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I=
|
||||
golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
|
||||
golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4=
|
||||
golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
@@ -925,8 +927,8 @@ golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc=
|
||||
golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||
golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k=
|
||||
golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||
golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
@@ -938,8 +940,8 @@ golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=
|
||||
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
|
||||
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
|
||||
golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM=
|
||||
golang.org/x/term v0.37.0 h1:8EGAD0qCmHYZg6J17DvsMy9/wJ7/D/4pV/wfnld5lTU=
|
||||
golang.org/x/term v0.37.0/go.mod h1:5pB4lxRNYYVZuTLmy8oR2BH8dflOR+IbTYFD8fi3254=
|
||||
golang.org/x/term v0.40.0 h1:36e4zGLqU4yhjlmxEaagx2KuYbJq3EwY8K943ZsHcvg=
|
||||
golang.org/x/term v0.40.0/go.mod h1:w2P8uVp06p2iyKKuvXIm7N/y0UCRt3UfJTfZ7oOpglM=
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
@@ -955,8 +957,8 @@ golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
|
||||
golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM=
|
||||
golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM=
|
||||
golang.org/x/text v0.35.0 h1:JOVx6vVDFokkpaq1AEptVzLTpDe9KGpj5tR4/X+ybL8=
|
||||
golang.org/x/text v0.35.0/go.mod h1:khi/HExzZJ2pGnjenulevKNX1W67CUy0AsXcNubPGCA=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
@@ -1010,8 +1012,8 @@ golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc
|
||||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
|
||||
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
|
||||
golang.org/x/tools v0.38.0 h1:Hx2Xv8hISq8Lm16jvBZ2VQf+RLmbd7wVUsALibYI/IQ=
|
||||
golang.org/x/tools v0.38.0/go.mod h1:yEsQ/d/YK8cjh0L6rZlY8tgtlKiBNTL14pGDJPJpYQs=
|
||||
golang.org/x/tools v0.42.0 h1:uNgphsn75Tdz5Ji2q36v/nsFSfR/9BRFvqhGBaJGd5k=
|
||||
golang.org/x/tools v0.42.0/go.mod h1:Ma6lCIwGZvHK6XtgbswSoWroEkhugApmsXyrUmBhfr0=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
@@ -1073,10 +1075,10 @@ google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6D
|
||||
google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20250603155806-513f23925822 h1:rHWScKit0gvAPuOnu87KpaYtjK5zBMLcULh7gxkCXu4=
|
||||
google.golang.org/genproto v0.0.0-20250603155806-513f23925822/go.mod h1:HubltRL7rMh0LfnQPkMH4NPDFEWp0jw3vixw7jEM53s=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250804133106-a7a43d27e69b h1:ULiyYQ0FdsJhwwZUwbaXpZF5yUE3h+RA+gxvBu37ucc=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250804133106-a7a43d27e69b/go.mod h1:oDOGiMSXHL4sDTJvFvIB9nRQCGdLP1o/iVaqQK8zB+M=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20251103181224-f26f9409b101 h1:tRPGkdGHuewF4UisLzzHHr1spKw92qLM98nIzxbC0wY=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20251103181224-f26f9409b101/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20251202230838-ff82c1b0f217 h1:fCvbg86sFXwdrl5LgVcTEvNC+2txB5mgROGmRL5mrls=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20251202230838-ff82c1b0f217/go.mod h1:+rXWjjaukWZun3mLfjmVnQi18E1AsFbDN9QdJ5YXLto=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20251202230838-ff82c1b0f217 h1:gRkg/vSppuSQoDjxyiGfN4Upv/h/DQmIR10ZU8dh4Ww=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20251202230838-ff82c1b0f217/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
||||
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
||||
@@ -1089,8 +1091,8 @@ google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKa
|
||||
google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
|
||||
google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||
google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||
google.golang.org/grpc v1.76.0 h1:UnVkv1+uMLYXoIz6o7chp59WfQUYA2ex/BXQ9rHZu7A=
|
||||
google.golang.org/grpc v1.76.0/go.mod h1:Ju12QI8M6iQJtbcsV+awF5a4hfJMLi4X0JLo94ULZ6c=
|
||||
google.golang.org/grpc v1.79.3 h1:sybAEdRIEtvcD68Gx7dmnwjZKlyfuc61Dyo9pGXXkKE=
|
||||
google.golang.org/grpc v1.79.3/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ=
|
||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||
|
||||
@@ -189,7 +189,7 @@ func MiddlewareCORS(allowOrigin string) Middleware {
|
||||
|
||||
if allowOrigin != "" {
|
||||
w.Header().Add("Access-Control-Allow-Origin", allowOrigin)
|
||||
w.Header().Add("Access-Control-Allow-Headers", "authorization, Content-Type")
|
||||
w.Header().Add("Access-Control-Allow-Headers", "Authorization, Content-Type, Depth, Destination, If, Lock-Token, Overwrite, TimeOut, Translate")
|
||||
w.Header().Add("Access-Control-Allow-Methods", "COPY, DELETE, GET, HEAD, LOCK, MKCOL, MOVE, OPTIONS, POST, PROPFIND, PROPPATCH, PUT, TRACE, UNLOCK")
|
||||
w.Header().Add("Access-Control-Max-Age", "86400")
|
||||
}
|
||||
|
||||
+21
-9
@@ -159,18 +159,30 @@ func (p *Pacer) beginCall(limitConnections bool) {
|
||||
// XXX ms later we put another in. We could do this with a
|
||||
// Ticker more accurately, but then we'd have to work out how
|
||||
// not to run it when it wasn't needed
|
||||
<-p.pacer
|
||||
|
||||
p.mu.Lock()
|
||||
sleepTime := p.state.SleepTime
|
||||
p.mu.Unlock()
|
||||
|
||||
if sleepTime > 0 {
|
||||
<-p.pacer
|
||||
|
||||
// Re-read the sleep time as it may be stale
|
||||
// after waiting for the pacer token
|
||||
p.mu.Lock()
|
||||
sleepTime = p.state.SleepTime
|
||||
p.mu.Unlock()
|
||||
|
||||
// Restart the timer
|
||||
go func(t time.Duration) {
|
||||
time.Sleep(t)
|
||||
p.pacer <- struct{}{}
|
||||
}(sleepTime)
|
||||
}
|
||||
|
||||
if limitConnections {
|
||||
<-p.connTokens
|
||||
}
|
||||
|
||||
p.mu.Lock()
|
||||
// Restart the timer
|
||||
go func(t time.Duration) {
|
||||
time.Sleep(t)
|
||||
p.pacer <- struct{}{}
|
||||
}(p.state.SleepTime)
|
||||
p.mu.Unlock()
|
||||
}
|
||||
|
||||
// endCall implements the pacing algorithm
|
||||
|
||||
@@ -367,6 +367,43 @@ func TestCallMaxConnectionsRecursiveDeadlock(t *testing.T) {
|
||||
assert.Equal(t, errFoo, err)
|
||||
}
|
||||
|
||||
func TestCallMaxConnectionsRecursiveDeadlock2(t *testing.T) {
|
||||
p := New(CalculatorOption(NewDefault(MinSleep(1*time.Millisecond), MaxSleep(2*time.Millisecond))))
|
||||
p.SetMaxConnections(1)
|
||||
dp := &dummyPaced{retry: false}
|
||||
wg := new(sync.WaitGroup)
|
||||
|
||||
// Normal
|
||||
for range 100 {
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
err := p.Call(func() (bool, error) {
|
||||
// check we have taken the connection token
|
||||
assert.Equal(t, 0, len(p.connTokens))
|
||||
return false, nil
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
}()
|
||||
|
||||
// Now attempt a recursive call
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
err := p.Call(func() (bool, error) {
|
||||
// check we have taken the connection token
|
||||
assert.Equal(t, 0, len(p.connTokens))
|
||||
// Do recursive call
|
||||
return false, p.Call(dp.fn)
|
||||
})
|
||||
assert.Equal(t, errFoo, err)
|
||||
}()
|
||||
}
|
||||
|
||||
// Tidy up
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
func TestRetryAfterError_NonNilErr(t *testing.T) {
|
||||
orig := errors.New("test failure")
|
||||
dur := 2 * time.Second
|
||||
|
||||
+5
-2
@@ -28,7 +28,9 @@ func URLPathEscape(in string) string {
|
||||
|
||||
// URLPathEscapeAll escapes URL path the in string using URL escaping rules
|
||||
//
|
||||
// It escapes every character except [A-Za-z0-9] and /
|
||||
// It escapes every character except the RFC 3986 unreserved characters
|
||||
// [A-Za-z0-9-._~] and the path separator /. Unreserved characters MUST NOT
|
||||
// be percent-encoded per RFC 3986 §2.3.
|
||||
func URLPathEscapeAll(in string) string {
|
||||
var b strings.Builder
|
||||
b.Grow(len(in) * 3) // worst case: every byte escaped
|
||||
@@ -36,7 +38,8 @@ func URLPathEscapeAll(in string) string {
|
||||
for i := range len(in) {
|
||||
c := in[i]
|
||||
if (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') ||
|
||||
(c >= '0' && c <= '9') || c == '/' {
|
||||
(c >= '0' && c <= '9') || c == '/' ||
|
||||
c == '-' || c == '.' || c == '_' || c == '~' {
|
||||
b.WriteByte(c)
|
||||
} else {
|
||||
b.WriteByte('%')
|
||||
|
||||
@@ -66,7 +66,10 @@ func TestURLPathEscapeAll(t *testing.T) {
|
||||
want string
|
||||
}{
|
||||
{"", ""},
|
||||
{"/hello.txt", "/hello%2Etxt"},
|
||||
// RFC 3986 unreserved characters must not be encoded
|
||||
{"/hello.txt", "/hello.txt"},
|
||||
{"file-name_v2.~bak", "file-name_v2.~bak"},
|
||||
// Reserved and other characters must be encoded
|
||||
{"With Space", "With%20Space"},
|
||||
{"With Colon:", "With%20Colon%3A"},
|
||||
{"With Percent%", "With%20Percent%25"},
|
||||
|
||||
@@ -218,12 +218,12 @@ rclone convmv "stories/The Quick Brown Fox!.txt" --name-transform "all,command=e
|
||||
|
||||
```console
|
||||
rclone convmv "stories/The Quick Brown Fox!" --name-transform "date=-{YYYYMMDD}"
|
||||
// Output: stories/The Quick Brown Fox!-20260130
|
||||
// Output: stories/The Quick Brown Fox!-20260419
|
||||
```
|
||||
|
||||
```console
|
||||
rclone convmv "stories/The Quick Brown Fox!" --name-transform "date=-{macfriendlytime}"
|
||||
// Output: stories/The Quick Brown Fox!-2026-01-30 0852PM
|
||||
// Output: stories/The Quick Brown Fox!-2026-04-19 1141AM
|
||||
```
|
||||
|
||||
```console
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
. ftr VB CB
|
||||
. ftr VBI CBI
|
||||
.\}
|
||||
.TH "rclone" "1" "Jan 30, 2026" "User Manual" ""
|
||||
.TH "rclone" "1" "Apr 19, 2026" "User Manual" ""
|
||||
.hy
|
||||
.SH NAME
|
||||
.PP
|
||||
@@ -4489,6 +4489,27 @@ Flags for anything which can copy a file
|
||||
-u, --update Skip files that are newer on the destination
|
||||
\f[R]
|
||||
.fi
|
||||
.SS Sync Options
|
||||
.PP
|
||||
Flags used for sync commands
|
||||
.IP
|
||||
.nf
|
||||
\f[C]
|
||||
--backup-dir string Make backups into hierarchy based in DIR
|
||||
--delete-after When synchronizing, delete files on destination after transferring (default)
|
||||
--delete-before When synchronizing, delete files on destination before transferring
|
||||
--delete-during When synchronizing, delete files during transfer
|
||||
--fix-case Force rename of case insensitive dest to match source
|
||||
--ignore-errors Delete even if there are I/O errors
|
||||
--list-cutoff int To save memory, sort directory listings on disk above this threshold (default 1000000)
|
||||
--max-delete int When synchronizing, limit the number of deletes (default -1)
|
||||
--max-delete-size SizeSuffix When synchronizing, limit the total size of deletes (default off)
|
||||
--suffix string Suffix to add to changed files
|
||||
--suffix-keep-extension Preserve the extension when using --suffix
|
||||
--track-renames When synchronizing, track file renames and do a server-side move if possible
|
||||
--track-renames-strategy string Strategies to use when synchronizing using track-renames hash|modtime|leaf (default \[dq]hash\[dq])
|
||||
\f[R]
|
||||
.fi
|
||||
.SS Important Options
|
||||
.PP
|
||||
Important flags useful for most commands
|
||||
@@ -6292,14 +6313,14 @@ rclone convmv \[dq]stories/The Quick Brown Fox!.txt\[dq] --name-transform \[dq]a
|
||||
.nf
|
||||
\f[C]
|
||||
rclone convmv \[dq]stories/The Quick Brown Fox!\[dq] --name-transform \[dq]date=-{YYYYMMDD}\[dq]
|
||||
// Output: stories/The Quick Brown Fox!-20260130
|
||||
// Output: stories/The Quick Brown Fox!-20260419
|
||||
\f[R]
|
||||
.fi
|
||||
.IP
|
||||
.nf
|
||||
\f[C]
|
||||
rclone convmv \[dq]stories/The Quick Brown Fox!\[dq] --name-transform \[dq]date=-{macfriendlytime}\[dq]
|
||||
// Output: stories/The Quick Brown Fox!-2026-01-30 0825PM
|
||||
// Output: stories/The Quick Brown Fox!-2026-04-19 1137AM
|
||||
\f[R]
|
||||
.fi
|
||||
.IP
|
||||
@@ -6832,6 +6853,20 @@ incompatible with \f[V]--urls\f[R].
|
||||
This will do \f[V]--transfers\f[R] copies in parallel.
|
||||
Note that if \f[V]--auto-filename\f[R] is desired for all URLs then a
|
||||
file with only URLs and no filename can be used.
|
||||
.PP
|
||||
Each FILENAME in the CSV file can start with a relative path which will
|
||||
be appended to the destination path provided at the command line.
|
||||
For example, running the command shown above with the following CSV file
|
||||
will write two files to the destination:
|
||||
\f[V]remote:dir/local/path/bar.json\f[R] and
|
||||
\f[V]remote:dir/another/local/directory/qux.json\f[R]
|
||||
.IP
|
||||
.nf
|
||||
\f[C]
|
||||
https://example.org/foo/bar.json,local/path/bar.json
|
||||
https://example.org/qux/baz.json,another/local/directory/qux.json
|
||||
\f[R]
|
||||
.fi
|
||||
.SS Troubleshooting
|
||||
.PP
|
||||
If you can\[aq]t get \f[V]rclone copyurl\f[R] to work then here are some
|
||||
@@ -8309,8 +8344,9 @@ not suffer from the same limitations.
|
||||
Mounting on macOS can be done either via built-in NFS
|
||||
server (https://rclone.org/commands/rclone_serve_nfs/),
|
||||
macFUSE (https://osxfuse.github.io/) (also known as osxfuse) or
|
||||
FUSE-T (https://www.fuse-t.org/).macFUSE is a traditional FUSE driver
|
||||
utilizing a macOS kernel extension (kext).
|
||||
FUSE-T (https://www.fuse-t.org/).
|
||||
macFUSE is a traditional FUSE driver utilizing a macOS kernel extension
|
||||
(kext).
|
||||
FUSE-T is an alternative FUSE system which \[dq]mounts\[dq] via an NFSv4
|
||||
local server.
|
||||
.SS Unicode Normalization
|
||||
@@ -8364,7 +8400,7 @@ wiki (https://github.com/macos-fuse-t/fuse-t/wiki#caveats):
|
||||
.PP
|
||||
File access and modification times cannot be set separately as it seems
|
||||
to be an issue with the NFS client which always modifies both.
|
||||
Can be reproduced with \[aq]touch -m\[aq] and \[aq]touch -a\[aq]
|
||||
Can be reproduced with \f[V]touch -m\f[R] and \f[V]touch -a\f[R]
|
||||
commands
|
||||
.RE
|
||||
.PP
|
||||
@@ -8376,7 +8412,7 @@ This may make rclone upload a full new copy of the file.
|
||||
When mounting with \f[V]--read-only\f[R], attempts to write to files
|
||||
will fail \f[I]silently\f[R] as opposed to with a clear warning as in
|
||||
macFUSE.
|
||||
.SH Mounting on Linux
|
||||
.SS Mounting on Linux
|
||||
.PP
|
||||
On newer versions of Ubuntu, you may encounter the following error when
|
||||
running \f[V]rclone mount\f[R]:
|
||||
@@ -8384,11 +8420,13 @@ running \f[V]rclone mount\f[R]:
|
||||
.PP
|
||||
NOTICE: mount helper error: fusermount3: mount failed: Permission denied
|
||||
CRITICAL: Fatal error: failed to mount FUSE fs: fusermount: exit status
|
||||
1 This may be due to newer Apparmor (https://wiki.ubuntu.com/AppArmor)
|
||||
1
|
||||
.RE
|
||||
.PP
|
||||
This may be due to newer Apparmor (https://wiki.ubuntu.com/AppArmor)
|
||||
restrictions, which can be disabled with
|
||||
\f[V]sudo aa-disable /usr/bin/fusermount3\f[R] (you may need to
|
||||
\f[V]sudo apt install apparmor-utils\f[R] beforehand).
|
||||
.RE
|
||||
.SS Limitations
|
||||
.PP
|
||||
Without the use of \f[V]--vfs-cache-mode\f[R] this can only write files
|
||||
@@ -9963,8 +10001,9 @@ not suffer from the same limitations.
|
||||
Mounting on macOS can be done either via built-in NFS
|
||||
server (https://rclone.org/commands/rclone_serve_nfs/),
|
||||
macFUSE (https://osxfuse.github.io/) (also known as osxfuse) or
|
||||
FUSE-T (https://www.fuse-t.org/).macFUSE is a traditional FUSE driver
|
||||
utilizing a macOS kernel extension (kext).
|
||||
FUSE-T (https://www.fuse-t.org/).
|
||||
macFUSE is a traditional FUSE driver utilizing a macOS kernel extension
|
||||
(kext).
|
||||
FUSE-T is an alternative FUSE system which \[dq]mounts\[dq] via an NFSv4
|
||||
local server.
|
||||
.SS Unicode Normalization
|
||||
@@ -10018,7 +10057,7 @@ wiki (https://github.com/macos-fuse-t/fuse-t/wiki#caveats):
|
||||
.PP
|
||||
File access and modification times cannot be set separately as it seems
|
||||
to be an issue with the NFS client which always modifies both.
|
||||
Can be reproduced with \[aq]touch -m\[aq] and \[aq]touch -a\[aq]
|
||||
Can be reproduced with \f[V]touch -m\f[R] and \f[V]touch -a\f[R]
|
||||
commands
|
||||
.RE
|
||||
.PP
|
||||
@@ -10030,7 +10069,7 @@ This may make rclone upload a full new copy of the file.
|
||||
When mounting with \f[V]--read-only\f[R], attempts to write to files
|
||||
will fail \f[I]silently\f[R] as opposed to with a clear warning as in
|
||||
macFUSE.
|
||||
.SH Mounting on Linux
|
||||
.SS Mounting on Linux
|
||||
.PP
|
||||
On newer versions of Ubuntu, you may encounter the following error when
|
||||
running \f[V]rclone mount\f[R]:
|
||||
@@ -10038,11 +10077,13 @@ running \f[V]rclone mount\f[R]:
|
||||
.PP
|
||||
NOTICE: mount helper error: fusermount3: mount failed: Permission denied
|
||||
CRITICAL: Fatal error: failed to mount FUSE fs: fusermount: exit status
|
||||
1 This may be due to newer Apparmor (https://wiki.ubuntu.com/AppArmor)
|
||||
1
|
||||
.RE
|
||||
.PP
|
||||
This may be due to newer Apparmor (https://wiki.ubuntu.com/AppArmor)
|
||||
restrictions, which can be disabled with
|
||||
\f[V]sudo aa-disable /usr/bin/fusermount3\f[R] (you may need to
|
||||
\f[V]sudo apt install apparmor-utils\f[R] beforehand).
|
||||
.RE
|
||||
.SS Limitations
|
||||
.PP
|
||||
Without the use of \f[V]--vfs-cache-mode\f[R] this can only write files
|
||||
@@ -22761,6 +22802,11 @@ the remote is sufficient.
|
||||
In those cases, this flag can speed up the process and reduce the number
|
||||
of API calls necessary.
|
||||
.PP
|
||||
This flag is only supported on certain backends and will be silently
|
||||
ignored on unsupported backends.
|
||||
Supported backends include \f[V]azureblob\f[R],
|
||||
\f[V]oracleobjectstorage\f[R], \f[V]s3\f[R], \f[V]swift\f[R].
|
||||
.PP
|
||||
Using this flag on a sync operation without also using
|
||||
\f[V]--update\f[R] would cause all files modified at any time other than
|
||||
the last upload time to be uploaded again, which is probably not what
|
||||
@@ -27207,6 +27253,8 @@ instead:
|
||||
rclone rc --loopback operations/fsinfo fs=remote:
|
||||
\f[R]
|
||||
.fi
|
||||
.PP
|
||||
\f[B]Authentication is required for this call.\f[R]
|
||||
.SS operations/hashsum: Produces a hashsum file for all the objects in the path.
|
||||
.PP
|
||||
Produces a hash file for all the objects in the path using the hash
|
||||
@@ -27628,6 +27676,8 @@ And this sets NOTICE level logs (normal without -v)
|
||||
rclone rc options/set --json \[aq]{\[dq]main\[dq]: {\[dq]LogLevel\[dq]: \[dq]NOTICE\[dq]}}\[aq]
|
||||
\f[R]
|
||||
.fi
|
||||
.PP
|
||||
\f[B]Authentication is required for this call.\f[R]
|
||||
.SS pluginsctl/addPlugin: Add a plugin using url
|
||||
.PP
|
||||
Used for adding a plugin to the webgui.
|
||||
@@ -29878,7 +29928,7 @@ Flags for general networking and HTTP stuff.
|
||||
--tpslimit float Limit HTTP transactions per second to this
|
||||
--tpslimit-burst int Max burst of transactions for --tpslimit (default 1)
|
||||
--use-cookies Enable session cookiejar
|
||||
--user-agent string Set the user-agent to a specified string (default \[dq]rclone/v1.73.0\[dq])
|
||||
--user-agent string Set the user-agent to a specified string (default \[dq]rclone/v1.73.5\[dq])
|
||||
\f[R]
|
||||
.fi
|
||||
.SS Performance
|
||||
@@ -30362,9 +30412,11 @@ Backend-only flags (these can be set in the config file also).
|
||||
--filefabric-token-expiry string Token expiry time
|
||||
--filefabric-url string URL of the Enterprise File Fabric to connect to
|
||||
--filefabric-version string Version read from the file fabric
|
||||
--filelu-chunk-size SizeSuffix Chunk size to use for uploading. Used for multipart uploads (default 64Mi)
|
||||
--filelu-description string Description of the remote
|
||||
--filelu-encoding Encoding The encoding for the backend (default Slash,LtGt,DoubleQuote,SingleQuote,BackQuote,Dollar,Colon,Question,Asterisk,Pipe,Hash,Percent,BackSlash,CrLf,Del,Ctl,LeftSpace,LeftPeriod,LeftTilde,LeftCrLfHtVt,RightSpace,RightPeriod,RightCrLfHtVt,InvalidUtf8,Dot,SquareBracket,Semicolon,Exclamation)
|
||||
--filelu-key string Your FileLu Rclone key from My Account
|
||||
--filelu-upload-cutoff SizeSuffix Cutoff for switching to chunked upload. Any files larger than this will be uploaded in chunks of chunk_size (default 500Mi)
|
||||
--filen-api-key string API Key for your Filen account (obscured)
|
||||
--filen-auth-version string Authentication Version (internal use only)
|
||||
--filen-base-folder-uuid string UUID of Account Root Directory (internal use only)
|
||||
@@ -33145,19 +33197,13 @@ The following backends have known issues that need more investigation:
|
||||
\f[V]TestBisyncRemoteRemote/normalization\f[R] (https://pub.rclone.org/integration-tests/current/dropbox-cmd.bisync-TestDropbox-1.txt)
|
||||
.RE
|
||||
.IP \[bu] 2
|
||||
\f[V]TestSeafile\f[R] (\f[V]seafile\f[R])
|
||||
.RS 2
|
||||
.IP \[bu] 2
|
||||
\f[V]TestBisyncLocalRemote/volatile\f[R] (https://pub.rclone.org/integration-tests/current/seafile-cmd.bisync-TestSeafile-1.txt)
|
||||
.RE
|
||||
.IP \[bu] 2
|
||||
\f[V]TestSeafileV6\f[R] (\f[V]seafile\f[R])
|
||||
.RS 2
|
||||
.IP \[bu] 2
|
||||
\f[V]TestBisyncLocalRemote/volatile\f[R] (https://pub.rclone.org/integration-tests/current/seafile-cmd.bisync-TestSeafileV6-1.txt)
|
||||
\f[V]TestBisyncLocalRemote/rmdirs\f[R] (https://pub.rclone.org/integration-tests/current/seafile-cmd.bisync-TestSeafileV6-1.txt)
|
||||
.RE
|
||||
.IP \[bu] 2
|
||||
Updated: 2026-01-30-010015
|
||||
Updated: 2026-04-19-010011
|
||||
.PP
|
||||
The following backends either have not been tested recently or have
|
||||
known issues that are deemed unfixable for the time being:
|
||||
@@ -35860,6 +35906,28 @@ T}@T{
|
||||
..
|
||||
T}
|
||||
.TE
|
||||
.SS Important note about double slashes (\f[V]//\f[R])
|
||||
.PP
|
||||
Object keys containing consecutive forward slashes (\f[V]//\f[R]) are
|
||||
\f[B]not supported\f[R] by rclone.
|
||||
.PP
|
||||
When rclone encounters an object key with \f[V]//\f[R] (e.g.,
|
||||
\f[V]a//b\f[R]), it will normalize the path to use a single slash (e.g.,
|
||||
\f[V]a/b\f[R]).
|
||||
This normalization can cause \[dq]object not found\[dq] errors when
|
||||
trying to access the original object, as rclone will look for the
|
||||
normalized path instead of the actual object key.
|
||||
.PP
|
||||
\f[B]Example:\f[R] - Original S3 object key: \f[V]folder//file.txt\f[R]
|
||||
- rclone interprets it as: \f[V]folder/file.txt\f[R] - Result:
|
||||
\[dq]object not found\[dq] error when trying to access
|
||||
\f[V]folder//file.txt\f[R]
|
||||
.PP
|
||||
\f[B]Workaround:\f[R] Avoid using consecutive forward slashes
|
||||
(\f[V]//\f[R]) in S3 object keys when using rclone.
|
||||
If you have existing objects with \f[V]//\f[R] in their keys, you will
|
||||
need to rename them to use single slashes or access them through other
|
||||
means.
|
||||
.SS Multipart uploads
|
||||
.PP
|
||||
rclone supports multipart uploads with S3 which means that it can upload
|
||||
@@ -38168,6 +38236,16 @@ Cubbit DS3 Object Storage endpoint
|
||||
Provider: Cubbit
|
||||
.RE
|
||||
.IP \[bu] 2
|
||||
\[dq]s3.{tenant_name}.cubbit.eu\[dq]
|
||||
.RS 2
|
||||
.IP \[bu] 2
|
||||
Multi-tenant endpoint - replace {tenant_name} with your actual tenant
|
||||
name.
|
||||
Do not select this directly
|
||||
.IP \[bu] 2
|
||||
Provider: Cubbit
|
||||
.RE
|
||||
.IP \[bu] 2
|
||||
\[dq]syd1.digitaloceanspaces.com\[dq]
|
||||
.RS 2
|
||||
.IP \[bu] 2
|
||||
@@ -44022,6 +44100,9 @@ They will be needed when prompted by \f[V]rclone config\f[R].
|
||||
.PP
|
||||
Default region will correspond to \f[V]eu-west-1\f[R] and the endpoint
|
||||
has to be specified as \f[V]s3.cubbit.eu\f[R].
|
||||
If you set a custom tenant endpoint, you must use
|
||||
\f[V]s3.{tenant_name}.cubbit.eu\f[R], because the generic
|
||||
\f[V]s3.cubbit.eu\f[R] endpoint will not work in this case.
|
||||
.PP
|
||||
Going through the whole process of creating a new remote by running
|
||||
\f[V]rclone config\f[R], each prompt should be answered as shown below:
|
||||
@@ -44035,7 +44116,7 @@ env_auth> false
|
||||
access_key_id> YOUR_ACCESS_KEY
|
||||
secret_access_key> YOUR_SECRET_KEY
|
||||
region> eu-west-1 (or leave empty)
|
||||
endpoint> s3.cubbit.eu
|
||||
endpoint> s3.cubbit.eu (or s3.{tenant_name}.cubbit.eu)
|
||||
acl>
|
||||
\f[R]
|
||||
.fi
|
||||
@@ -48333,6 +48414,16 @@ cos s3
|
||||
\f[R]
|
||||
.fi
|
||||
.RE
|
||||
.SS Tencent COS Global Acceleration Endpoint
|
||||
.PP
|
||||
When using the Global Acceleration Endpoint
|
||||
(\f[V]cos.accelerate.myqcloud.com\f[R]), rclone automatically sets
|
||||
\f[V]no_check_bucket = true\f[R] because this acceleration endpoint does
|
||||
not support the \f[V]CreateBucket\f[R] call which is used for ensuring a
|
||||
bucket\[aq]s existence by rclone.
|
||||
Global Acceleration is a per-bucket feature, so you should first create
|
||||
the bucket in one physical region, then enable it in the Tencent Cloud
|
||||
console.
|
||||
.SS Wasabi
|
||||
.PP
|
||||
Wasabi (https://wasabi.com) is a cloud-based object storage service for
|
||||
@@ -56514,6 +56605,34 @@ Required: true
|
||||
.SS Advanced options
|
||||
.PP
|
||||
Here are the Advanced options specific to filelu (FileLu Cloud Storage).
|
||||
.SS --filelu-upload-cutoff
|
||||
.PP
|
||||
Cutoff for switching to chunked upload.
|
||||
Any files larger than this will be uploaded in chunks of chunk_size.
|
||||
.PP
|
||||
Properties:
|
||||
.IP \[bu] 2
|
||||
Config: upload_cutoff
|
||||
.IP \[bu] 2
|
||||
Env Var: RCLONE_FILELU_UPLOAD_CUTOFF
|
||||
.IP \[bu] 2
|
||||
Type: SizeSuffix
|
||||
.IP \[bu] 2
|
||||
Default: 500Mi
|
||||
.SS --filelu-chunk-size
|
||||
.PP
|
||||
Chunk size to use for uploading.
|
||||
Used for multipart uploads.
|
||||
.PP
|
||||
Properties:
|
||||
.IP \[bu] 2
|
||||
Config: chunk_size
|
||||
.IP \[bu] 2
|
||||
Env Var: RCLONE_FILELU_CHUNK_SIZE
|
||||
.IP \[bu] 2
|
||||
Type: SizeSuffix
|
||||
.IP \[bu] 2
|
||||
Default: 64Mi
|
||||
.SS --filelu-encoding
|
||||
.PP
|
||||
The encoding for the backend.
|
||||
@@ -56563,6 +56682,10 @@ CLI (https://github.com/FilenCloudDienste/filen-cli).
|
||||
This means you must first download the CLI, login, and then run the
|
||||
\f[V]export-api-key\f[R] command.
|
||||
.PP
|
||||
\f[B]Note:\f[R] If you change your Filen account password, you will need
|
||||
to update your rclone configuration with the new password and a
|
||||
re-exported API key (via \f[V]export-api-key\f[R]).
|
||||
.PP
|
||||
Here is an example of how to make a remote called \f[V]FilenRemote\f[R].
|
||||
First run:
|
||||
.IP
|
||||
@@ -85633,7 +85756,7 @@ T}
|
||||
.PP
|
||||
When running on Windows the following characters are replaced.
|
||||
This list is based on the Windows file naming
|
||||
conventions (https://docs.microsoft.com/de-de/windows/desktop/FileIO/naming-a-file#naming-conventions).
|
||||
conventions (https://docs.microsoft.com/windows/desktop/FileIO/naming-a-file#naming-conventions).
|
||||
.PP
|
||||
.TS
|
||||
tab(@);
|
||||
@@ -86814,6 +86937,287 @@ Options:
|
||||
.IP \[bu] 2
|
||||
\[dq]error\[dq]: Return an error based on option value.
|
||||
.SH Changelog
|
||||
.SS v1.73.5 - 2026-04-19
|
||||
.PP
|
||||
See commits (https://github.com/rclone/rclone/compare/v1.73.4...v1.73.5)
|
||||
.IP \[bu] 2
|
||||
Bug Fixes
|
||||
.RS 2
|
||||
.IP \[bu] 2
|
||||
operations: Add AuthRequired to operations/fsinfo to prevent backend
|
||||
creation CVE-2026-41179 (Nick Craig-Wood)
|
||||
.IP \[bu] 2
|
||||
rc
|
||||
.RS 2
|
||||
.IP \[bu] 2
|
||||
Add AuthRequired to options/set to prevent auth bypass CVE-2026-41176
|
||||
(Nick Craig-Wood)
|
||||
.IP \[bu] 2
|
||||
Snapshot NoAuth at startup to prevent runtime auth bypass CVE-2026-41176
|
||||
(Nick Craig-Wood)
|
||||
.RE
|
||||
.IP \[bu] 2
|
||||
filter: Fix debug logs that fire before logger is configured (Nick
|
||||
Craig-Wood)
|
||||
.RE
|
||||
.IP \[bu] 2
|
||||
Azureblob
|
||||
.RS 2
|
||||
.IP \[bu] 2
|
||||
Add Microsoft Partner Network User-Agent prefix (Nick Craig-Wood)
|
||||
.RE
|
||||
.IP \[bu] 2
|
||||
Drime
|
||||
.RS 2
|
||||
.IP \[bu] 2
|
||||
Fix User.EntryPermissions JSON unmarshalling (a1pcm)
|
||||
.RE
|
||||
.IP \[bu] 2
|
||||
Iclouddrive
|
||||
.RS 2
|
||||
.IP \[bu] 2
|
||||
Fix \[aq]directory not found\[aq] error when the directory contains
|
||||
accent marks (Brais Couce)
|
||||
.RE
|
||||
.IP \[bu] 2
|
||||
S3
|
||||
.RS 2
|
||||
.IP \[bu] 2
|
||||
Fix TencentCOS CDN endpoint failing on bucket check (Mozi)
|
||||
.IP \[bu] 2
|
||||
Fix empty delimiter parameter rejected by Archiware P5 server (Nick
|
||||
Craig-Wood)
|
||||
.RE
|
||||
.SS v1.73.4 - 2026-04-08
|
||||
.PP
|
||||
See commits (https://github.com/rclone/rclone/compare/v1.73.3...v1.73.4)
|
||||
.IP \[bu] 2
|
||||
Bug Fixes
|
||||
.RS 2
|
||||
.IP \[bu] 2
|
||||
build
|
||||
.RS 2
|
||||
.IP \[bu] 2
|
||||
Update to go 1.25.9 to fix multiple CVEs (Nick Craig-Wood)
|
||||
.RS 2
|
||||
.IP \[bu] 2
|
||||
CVE-2026-32282: os: Root.Chmod can follow symlinks out of the root on
|
||||
Linux
|
||||
.IP \[bu] 2
|
||||
CVE-2026-32289: html/template: JS template literal context incorrectly
|
||||
tracked
|
||||
.IP \[bu] 2
|
||||
CVE-2026-33810: crypto/x509: excluded DNS constraints not properly
|
||||
applied to wildcard domains
|
||||
.IP \[bu] 2
|
||||
CVE-2026-27144: cmd/compile: no-op interface conversion bypasses overlap
|
||||
checking
|
||||
.IP \[bu] 2
|
||||
CVE-2026-27143: cmd/compile: possible memory corruption after bound
|
||||
check elimination
|
||||
.IP \[bu] 2
|
||||
CVE-2026-32288: archive/tar: unbounded allocation when parsing old
|
||||
format GNU sparse map
|
||||
.IP \[bu] 2
|
||||
CVE-2026-32283: crypto/tls: multiple key update handshake messages can
|
||||
cause connection to deadlock
|
||||
.IP \[bu] 2
|
||||
CVE-2026-27140: cmd/go: trust layer bypass when using cgo and SWIG
|
||||
.IP \[bu] 2
|
||||
CVE-2026-32280: crypto/x509: unexpected work during chain building
|
||||
.IP \[bu] 2
|
||||
CVE-2026-32281: crypto/x509: inefficient policy validation
|
||||
.RE
|
||||
.IP \[bu] 2
|
||||
Fix Denial of Service due to Panic in AWS SDK for Go v2 SDK EventStream
|
||||
Decoder (dependabot[bot])
|
||||
.IP \[bu] 2
|
||||
Update golang.org/x/image to 0.38.0 to fix CVE-2026-33809
|
||||
(dependabot[bot])
|
||||
.RE
|
||||
.IP \[bu] 2
|
||||
docs
|
||||
.RS 2
|
||||
.IP \[bu] 2
|
||||
Fix header level for metadata option (Clément Notin)
|
||||
.IP \[bu] 2
|
||||
Fix markdown issues in mount docs (albertony)
|
||||
.IP \[bu] 2
|
||||
Fix link to not be language specific (Ross Smith II)
|
||||
.IP \[bu] 2
|
||||
Note macOS 10.15 (Catalina) support with version v1.70.3 (kapitainsky)
|
||||
.RE
|
||||
.RE
|
||||
.IP \[bu] 2
|
||||
Filen
|
||||
.RS 2
|
||||
.IP \[bu] 2
|
||||
Update SDK version (Enduriel)
|
||||
.RE
|
||||
.SS v1.73.3 - 2026-03-23
|
||||
.PP
|
||||
See commits (https://github.com/rclone/rclone/compare/v1.73.2...v1.73.3)
|
||||
.IP \[bu] 2
|
||||
Bug Fixes
|
||||
.RS 2
|
||||
.IP \[bu] 2
|
||||
build
|
||||
.RS 2
|
||||
.IP \[bu] 2
|
||||
Update to google.golang.org/grpc 1.79.3 to fix CVE-2026-33186
|
||||
(dependabot[bot])
|
||||
.IP \[bu] 2
|
||||
Update to github.com/buger/jsonparser 1.1.2 to fix GHSA-6g7g-w4f8-9c9x
|
||||
(dependabot[bot])
|
||||
.RE
|
||||
.IP \[bu] 2
|
||||
doc fixes
|
||||
.RS 2
|
||||
.IP \[bu] 2
|
||||
Added text to the label showing version-introduced info (Jan-Philipp
|
||||
Reßler)
|
||||
.IP \[bu] 2
|
||||
Clarify Filen password change requires updating both password and API
|
||||
key in rclone config (Jason)
|
||||
.IP \[bu] 2
|
||||
s3: clarify multi tenant support for Cubbit (Marco Ferretti)
|
||||
.IP \[bu] 2
|
||||
jottacloud: Fix broken link (albertony)
|
||||
.RE
|
||||
.IP \[bu] 2
|
||||
lib/rest: Fix URLPathEscapeAll breaking WebDAV servers (eg nzbdav) with
|
||||
strict path matching (Andrew Furman)
|
||||
.IP \[bu] 2
|
||||
list: Fix nil pointer panic in Sorter when temp file creation fails
|
||||
(Nick Craig-Wood)
|
||||
.RE
|
||||
.SS v1.73.2 - 2026-03-06
|
||||
.PP
|
||||
See commits (https://github.com/rclone/rclone/compare/v1.73.1...v1.73.2)
|
||||
.IP \[bu] 2
|
||||
Bug Fixes
|
||||
.RS 2
|
||||
.IP \[bu] 2
|
||||
build
|
||||
.RS 2
|
||||
.IP \[bu] 2
|
||||
Update to go 1.25.8 to fix CVE-2026-27137 CVE-2026-27138 CVE-2026-25679
|
||||
CVE-2026-27142 (Nick Craig-Wood)
|
||||
.IP \[bu] 2
|
||||
Update github.com/cloudflare/circl to v1.6.3 to fix CVE-2026-1229 (Nick
|
||||
Craig-Wood)
|
||||
.IP \[bu] 2
|
||||
Update to golang.org/x/net v0.51.0 to fix CVE-2026-27141 (Nick
|
||||
Craig-Wood)
|
||||
.RE
|
||||
.IP \[bu] 2
|
||||
docs fixes:
|
||||
.RS 2
|
||||
.IP \[bu] 2
|
||||
bisync: Add group Sync to the bisync command (Jan-Philipp Reßler)
|
||||
.IP \[bu] 2
|
||||
Note that --use-server-modtime only works on some backends (Nick
|
||||
Craig-Wood)
|
||||
.IP \[bu] 2
|
||||
Document unsupported S3 object keys with double slashes (Adam Kasztenny)
|
||||
.IP \[bu] 2
|
||||
Fix headers hierarchy for mount.md (Dark Dragon)
|
||||
.IP \[bu] 2
|
||||
Fix new drive flag typo in changelog (razorloves)
|
||||
.RE
|
||||
.RE
|
||||
.IP \[bu] 2
|
||||
Archive
|
||||
.RS 2
|
||||
.IP \[bu] 2
|
||||
Extract: fix extraction with \[dq]./\[dq] prefix from tar entry paths
|
||||
(Varun Chawla)
|
||||
.RE
|
||||
.IP \[bu] 2
|
||||
Drime
|
||||
.RS 2
|
||||
.IP \[bu] 2
|
||||
Fix chunk-uploaded files ignoring workspace ID (a1pcm)
|
||||
.RE
|
||||
.IP \[bu] 2
|
||||
Internxt
|
||||
.RS 2
|
||||
.IP \[bu] 2
|
||||
Fix Entry doesn\[aq]t belong in directory errors on windows (jzunigax2)
|
||||
.RE
|
||||
.IP \[bu] 2
|
||||
WebDAV
|
||||
.RS 2
|
||||
.IP \[bu] 2
|
||||
Escape reserved characters in URL path segments (Varun Chawla)
|
||||
.IP \[bu] 2
|
||||
Add missing headers for CORS (Romāns Potašovs)
|
||||
.RE
|
||||
.SS v1.73.1 - 2026-02-17
|
||||
.PP
|
||||
See commits (https://github.com/rclone/rclone/compare/v1.73.0...v1.73.1)
|
||||
.IP \[bu] 2
|
||||
Bug Fixes
|
||||
.RS 2
|
||||
.IP \[bu] 2
|
||||
accounting: Fix missing server side stats from core/stats rc (Nick
|
||||
Craig-Wood)
|
||||
.IP \[bu] 2
|
||||
build
|
||||
.RS 2
|
||||
.IP \[bu] 2
|
||||
Fix CVE-2025-68121 by updating go to 1.25.7 or later (Nick Craig-Wood)
|
||||
.IP \[bu] 2
|
||||
Bump github.com/go-chi/chi/v5 from 5.2.3 to 5.2.5 to fix GO-2026-4316
|
||||
(albertony)
|
||||
.RE
|
||||
.IP \[bu] 2
|
||||
docs: Extend copyurl docs with an example of CSV FILENAMEs starting with
|
||||
a path.
|
||||
(Jack Kelly)
|
||||
.IP \[bu] 2
|
||||
march: Fix runtime: program exceeds 10000-thread limit (Nick Craig-Wood)
|
||||
.IP \[bu] 2
|
||||
pacer
|
||||
.RS 2
|
||||
.IP \[bu] 2
|
||||
Fix deadlock between pacer token and --max-connections (Nick Craig-Wood)
|
||||
.IP \[bu] 2
|
||||
Re-read the sleep time as it may be stale (Nick Craig-Wood)
|
||||
.RE
|
||||
.RE
|
||||
.IP \[bu] 2
|
||||
Drime
|
||||
.RS 2
|
||||
.IP \[bu] 2
|
||||
Fix files and directories being created in the default workspace (Nick
|
||||
Craig-Wood)
|
||||
.RE
|
||||
.IP \[bu] 2
|
||||
Filelu
|
||||
.RS 2
|
||||
.IP \[bu] 2
|
||||
Avoid buffering entire file in memory (kingston125)
|
||||
.IP \[bu] 2
|
||||
Add multipart upload support with configurable cutoff (kingston125)
|
||||
.RE
|
||||
.IP \[bu] 2
|
||||
Filen
|
||||
.RS 2
|
||||
.IP \[bu] 2
|
||||
Fix 32 bit targets not being able to list directories (Enduriel)
|
||||
.IP \[bu] 2
|
||||
Fix potential panic in case of error during upload (Enduriel)
|
||||
.RE
|
||||
.IP \[bu] 2
|
||||
Internxt
|
||||
.RS 2
|
||||
.IP \[bu] 2
|
||||
Implement re-login under refresh logic, improve retry logic (José
|
||||
Zúniga) -S3
|
||||
.IP \[bu] 2
|
||||
Set list_version to 2 for FileLu S3 configuration (kingston125)
|
||||
.RE
|
||||
.SS v1.73.0 - 2026-01-30
|
||||
.PP
|
||||
See commits (https://github.com/rclone/rclone/compare/v1.72.0...v1.73.0)
|
||||
@@ -86894,7 +87298,7 @@ Support authentication with new bucket restricted application keys
|
||||
Drive
|
||||
.RS 2
|
||||
.IP \[bu] 2
|
||||
Add \f[V]--drive-metadata-force-expansive-access\f[R] flag (Nick
|
||||
Add \f[V]--drive-metadata-enforce-expansive-access\f[R] flag (Nick
|
||||
Craig-Wood)
|
||||
.IP \[bu] 2
|
||||
Fix crash when trying to creating shortcut to a Google doc (Nick
|
||||
|
||||
Reference in new issue
Block a user