Commit Graph
10699 Commits
Author SHA1 Message Date
Nick Craig-Wood f0cb5dd6d3 lib/http: replace github.com/abbot/go-http-auth with built in htpasswd support
The go-http-auth library is unmaintained and rclone only used a small
part of it, so this replaces it with a small implementation of basic
auth and htpasswd file checking supporting the same bcrypt,
MD5-crypt ($1$ and $apr1$) and {SHA} formats.

It is tested against hashes made by htpasswd, openssl, mkpasswd and
Python bcrypt, expecting the same results as go-http-auth gave.

A missing or unreadable htpasswd file now logs an error and rejects
requests rather than panicking, malformed lines are logged and skipped,
and entries in unsupported formats are logged when the file is loaded.
2026-11-01 11:34:25 +00:00
Nick Craig-Wood ba11197157 fstest: move the Sia and Owncloud test servers out of the ephemeral port range
Their fixed ports, 39980 and 38081, are in Linux's ephemeral range
(32768-60999), so a socket from another concurrent test could hold
them and stop the server starting. This made all 5 tries of the Sia
fs/operations tests fail with "address already in use".
2026-10-31 17:22:39 +00:00
Nick Craig-Wood 8c2a650661 chunker: skip norename overwrite tests on remotes without metadata
The server-side overwrite tests ran norename transactions on the
nometa test remotes, which can't support them, so they failed with
"readXactID requires valid metaobject".
2026-10-31 17:22:39 +00:00
Guillaume MALLERET 5118e0c32a kdrive: add backend for Infomaniak kDrive
- fixes #8456
2026-10-31 16:57:03 +00:00
Guillaume MALLERET 47e22cac82 lib/oauthutil: add PKCE support 2026-10-31 16:57:03 +00:00
b84330808andClaude Opus 5.5 4e19a969f5 operations: fix cat --offset before the start of a file printing its end
When a negative --offset reached back past the start of a file and
--count was set, rclone cat printed bytes from the end of the file
instead of from its start. For example on a 10 byte file

    rclone cat --offset -12 --count 5 file

printed the last 2 bytes rather than the first 5. With several files
of different sizes, each file shorter than -offset was affected.

The start of the range stayed negative after the file size was added,
and a negative Start with an End set is a suffix range (the last End
bytes). Clamp the start to 0 instead, which matches what
`tail -c 12 file | head -c 5` prints. --tail and --offset without
--count were not affected.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 15:29:07 +00:00
kevin a4a2a78b90 lib/transform: make titlecase capitalise words instead of upper-casing them
The titlecase transform is documented as converting the file name to
Title Case, but it used strings.ToTitle, which maps every letter to its
title case form - upper case for nearly all letters - so it did the
same as uppercase: "hello world.txt" became "HELLO WORLD.TXT".

Use golang.org/x/text/cases instead, so it becomes "Hello World.txt".
2026-10-31 15:26:48 +00:00
Robert Kubiś 68906658fd ftp: fix ranged reads failing when the server answers 425 to an early close - Fixes #10200
A ranged read through the VFS opens the object at offset 0 and then
seeks, so the first RETR is closed before anything was read. Egnyte
answers that close with 425 instead of 426.

425 was not masked, so ftpReadCloser.Close quit the connection and
returned an error. The VFS then retried and closed the same reader
again; the second Close got nil from the already closed response, put
the connection that had been quit back in the pool and returned its
token a second time. Later operations failed with "use of closed
network connection" and serve s3 returned InternalError.

Now a second Close does nothing, a connection is never pooled after
Quit, and 425 is masked only when nothing was read, so a transfer cut
after data was read is still an error.
2026-10-31 15:22:04 +00:00
Soujas K a89766467e fs: reject NaN durations instead of wrapping
strconv.ParseFloat accepts "NaN", and NaN compares false with every
bound, so it got past the overflow check added for 300y and was then
converted to a time.Duration, which gives the minimum int64 on amd64.
--max-age NaN or --min-age NaNM silently became about -292 years,
which moves the filter's ModTimeFrom into the future and excludes every
file, instead of being rejected.
2026-10-31 15:18:08 +00:00
Soujas K 0a0661ade0 onedrive: poll async copy status with the configured HTTP client
waitForJob polled the copy monitor URL with http.Get, which uses
http.DefaultClient and no context. The poll ignored the configured
transport (--ca-cert, --no-check-certificate, --timeout, --user-agent,
--dump and so on) and could not be cancelled, so a monitor that stopped
answering blocked a server-side copy indefinitely.

Build the request with the context and send it through the unAuth
client, which uses the configured transport without adding the
Authorization header the monitor URL does not need.
2026-10-31 15:17:16 +00:00
ilya lavrenov b44c24cfca accounting: fix totalBytes counting server-side copies and moves twice
When a server-side copy or move finished without reporting progress
along the way, its bytes were added to the stats but not to the
transfer, so until the transfer ended core/stats reported totalBytes as
the bytes done plus the whole size of the transfer still in progress.
A 1 GiB server-side copy on the local backend showed 1 GiB of 2 GiB
while rclone checked the hashes.

The bytes now go on the transfer as well, as they already did for
backends which report progress through NewServerSideCopyAccounter.
2026-10-31 13:17:30 +00:00
albertony 941f6a7217 jottacloud: fix traditional authentication failing with invalid_client
Configuring traditional authentication set client_id but kept any
existing client_secret, for example one left in the config from legacy
authentication with a machine specific API key. Whitelabel services
that have moved to an Ory Hydra based identity provider, such as elkjop
and elko, reject a client secret for their public clients, so the token
exchange failed with:

  invalid_client: The OAuth 2.0 Client supports client authentication
  method 'none', but method 'client_secret_post' was requested.

Clear client_secret, as standard authentication already does.
2026-10-31 13:16:23 +00:00
albertony 8df62024e9 jottacloud: fix authentication with whitelabel services elkjop and elko
Elkjøp Cloud and ELKO Cloud have moved from Keycloak to an Ory Hydra
based identity provider. rclone picks up the new endpoints from the
OpenID discovery document, but authentication failed with:

  invalid_scope: The OAuth 2.0 Client is not allowed to request scope
  'jotta-default'.

The discovery documents now only list openid, offline and
offline_access as supported scopes, so drop jotta-default and request
openid and offline_access, as already done for phonero and letsgo,
which are also on Hydra.

Existing remotes must be reconnected with "rclone config reconnect",
as tokens issued by the old provider are rejected with invalid_grant
when refreshed.
2026-10-31 13:16:23 +00:00
ashwinibailangadi e6308417a2 docs: fix description of directory times when they are unknown 2026-10-31 13:15:36 +00:00
Florian Josef AltendorferandFlorian Josef Altendorfer f17291df25 seafile,pcloud,pikpak,zoho,imagekit: stop multipart writers after failed uploads - fixes #10168
Co-authored-by: Florian Josef Altendorfer <341419330+florianaltendorfer@users.noreply.github.com>
2026-10-31 13:11:08 +00:00
Fred b2664e513a seafile: fix operations on files whose names are not in Unicode NFC form
Seafile stores file and directory names in NFC whatever form they are
uploaded in, but looks them up byte for byte. A file uploaded with a
decomposed (NFD) name, as macOS produces, could therefore not be found,
renamed, copied or moved afterwards, and the operations integration
test TestMoveUnicodeEquivalentWithoutServerSideMove failed.

This normalizes paths inside a library to NFC before they are sent to
the server. Library names are left as they are since Seafile stores
them verbatim.
2026-10-31 12:41:17 +00:00
berce d1ae66cac0 iclouddrive: mark the backend as case insensitive - fixes #10162
findLeafItem matches names with EqualFold, but the backend did not set
CaseInsensitive, so a case-only rename was not seen as the same object
and the file being renamed was trashed before the move.
2026-10-31 12:38:53 +00:00
kevin9327 64a68c7380 fs: reject --bwlimit times without a colon or with signed digits
validateHour only checked the length of the hh:mm field and then
parsed the two halves with strconv.Atoi. It never checked the third
character, so "10h20" or "Mon-10.20" were accepted as 10:20, and
since Atoi accepts a sign, "+1:00" and "Mon-10:+5" were accepted
as 01:00 and 10:05.

Require the colon and four digits so these are reported as invalid
time specifications like other malformed times.
2026-10-31 12:36:13 +00:00
kevin9327 18c7de0920 fs: reject NaN sizes and CountSuffix values that overflow
SizeSuffix.Set and CountSuffix.Set accepted "nan" before a suffix, so
--max-transfer nank became -1 ("off") without an error. CountSuffix.Set
also had no overflow check, unlike SizeSuffix, so 10E or infk wrapped
to the same value.
2026-10-31 12:27:06 +00:00
kevin9327 0de32e2269 filter: make [^...] in globs exclude / and document it
A glob like file[^a].txt was translated to (^|/)file[^a]\.txt$ in path
mode, so it matched file/.txt across a directory boundary, unlike ?
and the [!...] form.

Treat a leading ^ in a character class the same as a leading !: in
path mode it now also excludes /, and [^] is rejected as an empty
character class. Document both negation forms in the filtering
grammar.
2026-10-31 12:26:02 +00:00
kevin9327 c434df94d1 filter: make [!...] in globs a negated character class
The filtering docs give the character class syntax as [ [ ! ]
{ character-range } ], but globToRegexp copied the ! into the regexp
unchanged, so file[!a].txt matched filea.txt and file!.txt and
excluded fileb.txt - the opposite of what was asked for.

Translate a ! at the start of a character class to ^. In path mode
the class also excludes /, in the same way ? does. [!] is rejected
as an empty character class.
2026-10-31 12:26:02 +00:00
kevin dee8b7e285 fs: accept multi-unit relative times like 1d12h in Time options
The docs say Time options take the same relative forms as Duration
options, with "1d12h" as an example, but ParseTime only tried
time.ParseDuration and single-suffix values, so --max-age style
Time options such as --s3-version-at 1d12h were rejected.
2026-10-31 12:24:46 +00:00
Nick Craig-Wood 989fd82b13 build: disable Multipath TCP listeners by default to mitigate CVE-2026-98432
Go enables MPTCP on listening sockets on Linux by default, which
exposes rclone servers (rcd, serve http/webdav/s3/sftp/ftp etc) to the
Linux kernel use-after-free CVE-2026-98432, demonstrated as remote code
execution via an MPTCP listener.

This sets `godebug multipathtcp=0` in go.mod so rclone listens with
plain TCP. Outgoing connections are unaffected as Go does not use MPTCP
for them by default.

This is a mitigation only - the fix is to upgrade to a patched kernel.
Users who need MPTCP can re-enable it with GODEBUG=multipathtcp=2.

See: https://go.dev/issue/82717
2026-10-30 17:11:15 +00:00
Nick Craig-Wood 5f50a4ce61 Add 3 new contributors
- hahahahahayesyeseys
- qodelicious
- fixfon
2026-10-30 17:11:15 +00:00
fixfon 5152a0d96e crypt: fix nil pointer panic in ObjectInfo.Hash - fixes #10173
OverrideRemote.UnWrap returns nil when the wrapped ObjectInfo is not an
fs.Object, as when serve s3 uploads through a combine remote over crypt.
Hash then called Fs() on that nil object and panicked. Return an empty
hash instead, as for other sources which cannot be unwrapped.
2026-10-29 18:51:30 +00:00
qodelicious be698038d8 docs: fix dead links in the box, sftp and webdav docs
The Box OAuth page, the SSH CBC paper on isg.rhul.ac.uk and the
nextcloud/nextcloud-snap issue all 404 now. Point them at the current
Box refresh token guide, the IEEE S&P 2009 copy of the paper and the
moved nextcloud-snap/nextcloud-snap repo.
2026-10-29 18:48:05 +00:00
Sven Rebhan 5f4d7c0e97 build: put google.golang.org/grpc back onto a released version
Downgrade the google.golang.org/grpc dependency from  a dev-version
(v1.85.0-dev.0.20260825072537-93e31b48545e) to the latest stable version
(v1.84.0). The downgrade does not introduce any vulnerabilities according to
govulncheck. The -dev version got carried forward from a110fa5d4 when it was
needed.
2026-10-29 18:45:55 +00:00
kevin9327 337c130c12 lib/readers: return the cache length when RepeatableReader.Seek goes past it
Seek documents that a position past the cached data returns the maximum
usable offset with an error, but it returned offset - (abs - cacheLen),
which is only the cache length for io.SeekStart. For io.SeekCurrent and
io.SeekEnd it returned an arbitrary, possibly negative, number.
2026-10-29 18:40:46 +00:00
Dirk Petersen 11b681a1f0 lib/transform: fix flaky date test at the end of a minute
TestVarious computed the expected date when it built the test table and
the transformed name later. When a minute ended between the two, the
macfriendlytime case failed, for example 0243PM against 0244PM.

The date cases are now in TestDate, which reads the clock before and
after the call to Path and accepts either date.
2026-10-29 18:33:48 +00:00
Dirk Petersen e906ecf25f local: set only the ownership a non-root user may set
With --metadata rclone applied the uid and gid of the source with
chown, which fails with "operation not permitted" for a user other than
root whenever the source belongs to another user or group (a file of
root or of a colleague), so the copy of such a file failed.

As a user other than root, leave the uid as it is (only root can give
a file away) and set the gid only to a group the process is a member
of, as rsync -a does; skip the chown if neither applies. Root is
unchanged.
2026-10-29 18:32:22 +00:00
Rohit Behera f17b89b0c2 lib/http: return 416 for ranges --rc-serve and serve restic can't satisfy - fixes #10140
Before this change, a Range request starting at or after the end of the
object, or ending before it started, was answered with a 206 and a
malformed Content-Range such as "bytes 10-9/10". Resuming a complete
download with curl -C - or wget -c, which send such a range and expect a
416, saw a broken partial response instead.

After this change these requests get a 416 with "Content-Range: bytes */size",
and a Range on an empty object is ignored, the same as http.ServeContent
does for rclone serve http.
2026-10-29 18:28:49 +00:00
hahahahahayesyeseys fe813c53f2 chunker: clean stale chunks after server-side overwrite - fixes #10123 2026-10-29 18:26:10 +00:00
jxj 6e01cb6e22 webdav: fix memory leak uploading to Infinite Scale - fixes #10131
Remove the unused progress notification goroutine, which kept each
Uploader and its buffered Upload alive after uploading finished or failed.

Test that uploads can be collected after success, failure and empty uploads,
while preserving retries and repeated Upload calls.
2026-10-29 18:23:37 +00:00
Nick Craig-Wood e236d983a6 serve s3: fix tests leaving multipart uploads open on Windows
newPutTestBackend returned a second backend rather than the server's
own, so the server's Shutdown never aborted the multipart uploads made
through it. Their temporary files were left open, which stopped the
test's temporary directory being removed on Windows:

    TempDir RemoveAll cleanup: unlinkat ...\test-37: The directory is not empty.
2026-10-29 17:31:57 +00:00
Nick Craig-Wood 94319c360b vfs: retry finding the object in the test which checks modtime support
canSetModTime looked up the object it had just written without any
retries, so on backends with read-after-write lag such as Internxt the
lookup failed. As the result is only worked out once, the remaining
TestFileSetModTime subtests then ran assuming the modtime could be set.
2026-10-29 15:11:33 +00:00
Nick Craig-Wood 7935d517fb fstest: raise the Seafile API throttle limits for the integration tests
Seahub throttles anonymous API calls, which includes logging in, to 60
per minute. When cmd/bisync and backend/seafile ran concurrently they
exceeded this and every new remote failed with "failed to
authenticate" until the end of the retries.
2026-10-29 14:30:25 +00:00
Nick Craig-Wood 396b38e7bc huaweidrive: fix creating, copying and renaming files with non-ASCII names
Huawei Drive doesn't decode JSON request bodies as UTF-8 unless the
charset is given. This meant creating directories or empty files with
non-ASCII names failed with "The fileName can not be blank and can not
contain..." and server-side copies mangled the names, eg `équivalent.txt`
became `�quivalent.txt`.

Send "application/json; charset=UTF-8" on all requests with a JSON
body as is already done for the multipart upload metadata.
2026-10-29 14:19:10 +00:00
Nick Craig-Wood 67472a7c08 fstest: remove the vsftpd per-IP connection limit for the integration tests
The fauria/vsftpd image limits each IP to 50 connections. When
cmd/bisync and backend/ftp ran concurrently against the shared server
the backend tests were refused with 421 "There are too many
connections from your internet address" on every retry.
2026-10-29 14:19:09 +00:00
Nick Craig-Wood 283277aa2b serve s3: document the design goals
Explain the choices behind many of the limitations of serve s3, such as
keeping metadata in memory rather than in a database, and link the
limitations to them. Also fix the statement that empty directories
can't be made below the buckets, as they can by putting a directory
marker.
2026-10-29 11:01:49 +00:00
Nick Craig-Wood ba5c6c89fd serve s3: make --no-cleanup a deprecated alias of --directory-markers
--no-cleanup was documented as keeping the directories emptied by
DeleteObject, but has never been implemented. --directory-markers
keeps them, listing them as directory markers so the listings stay
consistent, so make --no-cleanup do that, logging that it is
deprecated.
2026-10-29 11:01:47 +00:00
Nick Craig-Wood 41aafbdb92 serve s3: test the s3 backend with directory markers against serve s3
Run the s3 backend integration tests with --s3-directory-markers
against serve s3 with --directory-markers.
2026-10-29 11:01:47 +00:00
Nick Craig-Wood 399fd8e102 serve s3: remove a directory with its last key after its marker is deleted
With --directory-markers, deleting the directory marker of a directory
holding other keys had no effect, so the directory was still listed
and wasn't removed when the last key below it was deleted. This left
directories behind when the keys of a directory were deleted in an
order other than deepest first, as rclone's s3 backend does when
purging.

Remember the deletion in memory, so the marker isn't listed and the
directory is removed with the last key below it.
2026-10-29 11:01:46 +00:00
Nick Craig-Wood 98a8e793bd s3: fix rmdir of the root directory with --s3-directory-markers
Rmdir only removed the directory marker of a directory below the root
of the remote, so `rclone rmdir remote:bucket/dir` left the marker of
dir behind, and with it the directory.
2026-10-29 11:01:45 +00:00
Nick Craig-Wood cb73c3ae0b serve s3: document that the Content-MD5 and checksum of all request bodies are checked
gofakes3 v0.0.12 checks the bodies of requests which aren't object
data, such as DeleteObjects, against their Content-MD5 and
x-amz-checksum-* headers.

See #10082
2026-10-29 11:01:44 +00:00
Nick Craig-Wood 19902ee657 serve s3: document that x-amz-expected-bucket-owner is ignored
See #10082
2026-10-29 11:01:43 +00:00
Nick Craig-Wood 4dfbe7f320 serve s3: add --directory-markers to list every directory as a marker
Clients which rely on directory markers, such as rclone's s3 backend
with --s3-directory-markers, need the markers of directories holding
other keys listed, which serve s3 only does while it remembers the
marker was put.

With --directory-markers every directory is listed as a directory
marker, and isn't removed when the last key below it is deleted.

See #10082
2026-10-29 11:01:41 +00:00
Nick Craig-Wood cb150c014d serve s3: list objects with the storage class they were put with
Listings gave every object the STANDARD storage class, while HEAD and
GET gave the one it was put with.

See #10082
2026-10-29 11:01:40 +00:00
Nick Craig-Wood be847e8be6 serve s3: let a failed CompleteMultipartUpload be retried
A CompleteMultipartUpload which failed because the parts it listed
didn't match those uploaded, or had a gap in the part numbers, aborted
the whole upload. Leave the upload open instead, as S3 does, so the
client can upload any missing parts and complete it again.

See #10082
2026-10-29 11:01:39 +00:00
Nick Craig-Wood e670d0b9e4 serve s3: test Last-Modified of HEAD and GET of objects put with an mtime
Check the Last-Modified of HEAD and GET is the modification time set
from the X-Amz-Meta-Mtime or mtime metadata, as in listings, rather
than the time of the PUT.

See #10082
2026-10-29 11:01:38 +00:00
Nick Craig-Wood 85f1f9d39b serve s3: list the directory markers put for directories holding other keys
A directory marker such as dir/ was only listed while its directory
was empty, as nothing recorded whether it had been put or the
directory made by putting a key below it. On S3 a marker which was put
is listed until it is deleted, which some clients rely on.

The markers put are now remembered with the object metadata, in memory,
and listed while the directory holds other keys, and their directories
are no longer removed when the last key below them is deleted.

See #10082
2026-10-29 11:01:37 +00:00