commit 9b9fd3f4936e91fcc534645e9756972e10e160cf
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Mon Sep 7 17:01:41 2026 +0100

    serve ftp: fix VFS leak when the server fails to start
    
    The deferred cleanup in the constructor checked a local error variable
    rather than the error being returned, so failures after the VFS was
    created (such as an invalid --passive-port) never shut it down. Name
    the error return so the cleanup sees the returned error.

commit f2a390b2d4510afd87fd5b0053f5404b27e84e16
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Mon Sep 7 16:55:51 2026 +0100

    serve webdav,http: fix crash when the server fails to start - fixes #9882
    
    When the HTTP server failed to initialise, for example because the
    listen address was already in use, rclone panicked with a nil pointer
    dereference instead of reporting the error.
    
    The deferred cleanup in the constructor read the provider from the
    named return value, but `return nil, err` sets that to nil before the
    deferred function runs. Use a local variable for the server instead.

commit 3351c33937db5d4ec8b629bf46dfdc80b6a405d8
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Tue Sep 8 10:28:32 2026 +0100

    gui: update embedded release to 1.1.12

commit c99f09060c7d3ce3a3fa10248b5abd53fe576d72
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Tue Sep 8 10:27:37 2026 +0100

    Add Dhevenddra K G to contributors

commit 3d7b101c7f4bc3ebdcfc882c063fffd1c16bf196
Author: Dhevenddra K G <121691114+Dhevenddra@users.noreply.github.com>
Date:   Sat Sep 5 22:23:08 2026 +0530

    docs: fix duplicated words in vfs and backend documentation

commit e855d2ed36b6dc56f9238d8f312be267823a8b41
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Fri Sep 4 11:14:56 2026 +0100

    serve docker: fix tests leaving unkillable processes and stale FUSE mounts
    
    Writing to the mount with os.WriteFile made the Go runtime register
    the file with its poller so the kernel then polled the file from
    epoll_ctl and epoll_wait, sending POLL requests to the FUSE server
    running in this same process. A thread waiting inside epoll cannot be
    preempted by the runtime, so a garbage collection starting while such
    a POLL was outstanding stopped the world for good - the test binary
    could not be killed even with SIGKILL and the mount was left behind,
    wedging anything that touched it.
    
    Now we write through the mount with a descriptor straight from
    open(2), which os.NewFile keeps out of the poller, check that it
    really is out of the poller with SetDeadline, and check at the end of
    the test that the mountpoint is unmounted.
    
    In this commit we fixed the same problem for mount by running in a
    subprocess however changing one write file routine here was much
    easier than re-arranging the tests.
    
    4a382c09ecab5cee mount: run tests in a subprocess to fix deadlock - #3259
    
    Note that go-fuse (and hence mount2) works around this problem it by
    forcing an early POLL it can answer with ENOSYS.
    
    See: https://github.com/golang/go/issues/21014

commit b88e237e8c6006ca0426c0364f5020340efb38fd
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Wed Sep 2 15:42:43 2026 +0100

    archive: fix listing entries with a leading slash as if they were in the root
    
    The check that an entry returned by an archiver is a direct child of
    the directory being listed normalised a parent of "/" to the root, so
    an entry named "/x" passed as a child of the root while "x/" and
    "dir//x" were rejected.
    
    Decide by stripping the directory prefix and checking what is left
    with sanitize.Leaf, which rejects an empty name, ".", ".." and any
    name containing a "/". This also covers the leading slash case.

commit da352a2a1b1f1aa99ec1cb46ad82012deeb0c5e9
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Wed Sep 2 15:41:51 2026 +0100

    archive: fix zip file entries named for a directory causing confusion
    
    A file entry in a zip whose name refers to a directory, such as ".",
    "/", "" or "sub/.", was only skipped when it named the root of an
    archive which was itself the root of the remote. When the archive was
    found by listing its parent directory the entry appeared as a file
    with the same name as the archive alongside the directory for it, and
    copying the archive tried to write both. When the entry named a
    subdirectory it appeared as a file alongside that directory, and with
    that subdirectory mounted as the archive root the entry was taken to
    be the single file the root points at, hiding every real entry.
    
    Skip any file entry whose last path component is "", "." or "..",
    checked on the raw name before it is cleaned or joined on the prefix.

commit 68eab60564a936716aa4df0aefd0929bb5c2902b
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Wed Sep 2 15:41:51 2026 +0100

    archive: fix corrupt listings when listing a zip directory more than once
    
    The zip archiver handed out its cached directory tree directly. Any
    caller which filters a listing in place (as the core listing code
    does) altered the cache, so later listings of the same directory could
    be corrupted.
    
    Return a copy of the cached listing instead.

commit 6cdd0ea7610267997a93f984cf8f0af9ac5dd949
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Sat Sep 5 11:49:37 2026 +0100

    seafile: fix corrupted uploads after a retried upload error
    
    When an upload failed with a 500 error the upload was retried with a
    new upload link but the same input stream. The stream had already been
    consumed by the first attempt so the retry uploaded an empty file.
    
    This fixes it by returning a RetryError instead so the caller retries
    the upload with a fresh stream, which will fetch a new upload link.

commit fa43f10af232373b4d724b40dccc73493e25e761
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Sat Sep 5 11:49:36 2026 +0100

    filescom: fix corrupted uploads after a retried upload error
    
    When an upload failed with a retryable error the pacer retried the
    whole upload with the same input stream. The stream had already been
    consumed by the first attempt so the retry uploaded an empty file.
    
    This fixes it by using CallNoRetry for the upload, as the other
    backends do, so retryable errors are returned wrapped in a RetryError
    for the caller to retry the upload with a fresh stream.
    
    It also makes 5xx errors from the upload storage servers retryable.
    These come back from the SDK as a different error type to API errors
    so were not being retried at all.

commit f4cd80a5352b670a51cfab172456267c9265f2a2
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Sat Sep 5 11:49:36 2026 +0100

    pixeldrain: fix corrupted uploads after a retried upload error
    
    When an upload failed with a retryable error the pacer retried the
    whole PUT with the same input stream. The stream had already been
    consumed by the first attempt so the retry uploaded an empty file.
    
    This fixes it by using CallNoRetry for the upload, as the other
    backends do, so retryable errors are returned wrapped in a RetryError
    for the caller to retry the upload with a fresh stream.

commit b940ce64c7653814934f7e29682f1d0cf64c4cfe
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Tue Sep 1 12:42:42 2026 +0100

    operations: fix making a directory with modtime asking twice with --interactive
    
    MkdirModTime checked --interactive/--dry-run itself and then called
    MkdirMetadata or Mkdir which check again, so --interactive asked twice
    about making the same directory and --dry-run skipped before the
    operation could be shown in the progress display or counted as a
    check.
    
    Now MkdirModTime decides how to make the directory first and delegates
    entirely to MkdirMetadata, or Mkdir followed by SetDirModTime, each of
    which does its own --interactive/--dry-run check exactly once. This
    also means the modtime setting fallback shows in the progress display,
    respects --no-update-dir-modtime and has its errors counted.

commit 351d70f694c2f4a092cff07ec424e05fc94cabe0
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Mon Aug 31 20:45:43 2026 +0100

    sync: fix directory modtimes being set twice
    
    When syncing to a backend which supports directory modtimes, a
    directory which needed its modtime updated and which had files
    transferred into it would get its modtime set twice - once when the
    directory was checked and once in the pass at the end of the sync.
    
    Now, when the end of sync pass is in use (which it is for all default
    syncs), directories which need their modtime (or metadata) updating
    are marked for that pass instead of being updated immediately. This
    halves the number of directory modtime updates in a typical sync and
    makes the "Updated dirs" stat count each directory once.

commit 6afb98b758fc1a50a6f983c53a6d6c98514b3e86
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Tue Aug 11 19:44:48 2026 +0100

    accounting: add "Updated dirs" count of directory modtime/metadata updates to the stats
    
    Syncs to backends which preserve directory modification times (eg
    sftp, local) can update the modtime or metadata on many directories.
    This count makes that work visible in the stats output, the core/stats
    rc and the prometheus metrics (as dirs_updated_total).

commit f998f5bb999b235658f87f52c6c06964abf53b1f
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Tue Aug 11 19:42:07 2026 +0100

    operations: show directory operations in the --progress display
    
    Syncs which update lots of directories (eg to sftp) could spend a long
    time setting directory modification times, making directories or
    removing directories with no feedback in the --progress display or
    stats, making rclone appear to have hung.
    
    This shows directory operations (setting modtime, updating metadata,
    making and removing directories) in the Checking section of the stats
    and counts them as checks, in the same way file deletes are shown.

commit 7fe402585e17b70724841d54df1b2f6d251a093b
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Tue Sep 1 10:57:48 2026 +0100

    accounting: add NewCheckingTransferNoHistory constructor
    
    This creates a checking transfer which is shown in the progress
    display while it is running but is not kept in the completed
    transfers history, so it never appears in core/transferred and is not
    retained in memory after it finishes.
    
    This is for repeated bookkeeping operations (eg directory modtime
    updates) which would otherwise crowd file transfers out of the
    history.

commit ffe855f350fefd7f050580434aef7935c16e3e61
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Sat Sep 5 12:14:02 2026 +0100

    Add Shane McCarron to contributors

commit 1b4dea8dac20cab6387d43fa2a45a8ac45088c89
Author: Shane McCarron <shane.mccarron@corvexconnect.com>
Date:   Sun Aug 30 09:16:42 2026 -0500

    fs/fshttp: fix TestCertificates leaking client cert/key onto global config
    
    This was fixed in this commit in an inelegant way
    
    399bc6a6a610dec4 fshttp: don't send --header values to other hosts on redirect
    
    The current commit fixes it properly with AddConfig.
    
    Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

commit 73119d368f26d62059c0158ee25f0208e12d142a
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Fri Sep 4 18:15:14 2026 +0100

    Changelog updates from Version v1.75.1

commit 399bc6a6a610dec4bfee28edb47b51a0a2c60296
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Tue Aug 25 18:07:15 2026 +0100

    fshttp: don't send --header values to other hosts on redirect GHSA-486v-q2wf-fp2r CVE-PENDING
    
    The headers set with --header and --header-download are added to
    every request by the rclone transport, including redirect hops which
    net/http makes to other hosts, so a credential passed with --header
    for one host could be sent to any host that server chose to redirect
    to.
    
    The transport now walks the redirect chain net/http records on each
    redirected request and, once the chain has visited a host other than
    the one originally requested, removes the headers rather than adding
    them.
    
    Also restore the global --client-cert and --client-key config after
    TestCertificates so its temporary files are not used by later tests.

commit aef94cd0e71d45955df09223096d6c33e15584b0
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Tue Aug 25 18:07:15 2026 +0100

    http: don't leak configured headers to other hosts or over plaintext on redirect GHSA-486v-q2wf-fp2r CVE-PENDING
    
    The headers set with --http-headers are documented for passing
    credentials such as Authorization or Cookie. The backend used the
    default net/http redirect policy which copies all but a handful of
    well known headers to any redirect target, so a redirect from the
    configured server to another host would send those credentials to
    that host, and a redirect from https to http would send them in
    plaintext.
    
    When headers are configured this installs a CheckRedirect function
    which:
    
    - removes the configured headers from every hop once the redirect
      chain has left the originally requested host
    - refuses a redirect from https to http with an error

commit 31a81648152618a3e57ab7b64f96ddc45dad9335
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Tue Aug 25 18:07:15 2026 +0100

    rest: add SameHost and check HTTPS downgrades against the original request GHSA-486v-q2wf-fp2r CVE-PENDING
    
    SameHost compares two URLs by host name (case insensitively) and port
    (treating the scheme's default port as no port) so redirect policies
    can tell a real change of host from a server spelling its own host
    differently, e.g. redirecting "https://example.com/" to
    "https://EXAMPLE.com:443/".
    
    The HTTPS downgrade check now compares the redirect target against
    the original request rather than the previous hop, so a chain which
    started on plaintext http, passed through an https server and came
    back to http is no longer refused - nothing is being downgraded
    relative to what the user asked for. A chain which started on https
    and reaches http via any number of hops is still refused.

commit e1b0c090406c989dd0b62aeb58410f6e5c6522bd
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Tue Aug 25 12:46:11 2026 +0100

    archive: hide any archive entry which escapes the directory being listed GHSA-66hp-wgxq-6f5q
    
    Whether an archive entry name can escape the archive's namespace was
    left entirely to each archiver. Enforce it in the archive backend too.
    
    List only passes on direct children of the directory listed and
    NewObject only returns the object asked for, so a future archiver
    which forgets to validate names cannot expose a traversal to fs/sync
    and fs/operations.

commit 32175374bae475582bdd2c4252716f79e4979d0d
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Tue Aug 25 12:44:39 2026 +0100

    archive: fix "directory not found" for archive paths containing "./" or "//" GHSA-66hp-wgxq-6f5q
    
    The path inside the archive was compared against the cleaned entry
    names without being cleaned itself, so `archive.zip/sub/./dir` or
    `archive.zip/sub//dir` failed to list even though `archive.zip/sub/dir`
    worked.

commit 45391c04ffcbecb712dc6e0e549a501786d92969
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Tue Aug 25 12:43:34 2026 +0100

    archive: fix zip entry named "." hiding every other file GHSA-66hp-wgxq-6f5q
    
    A zip containing a file entry whose name refers to the archive's own
    root (".", "/" or "") was presented as a single file called "." and
    all its other entries disappeared. A file at the root can only be the
    archive member the backend was pointed at, so with no root such an
    entry is skipped like any other unsafe name.

commit 7a00e13cd04addf21f7d0b1ada2c45d88b498d26
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Tue Aug 25 12:13:34 2026 +0100

    archive: reject unsafe entry names when mounting squashfs images GHSA-66hp-wgxq-6f5q
    
    Entry names read from a squashfs directory are not sanitized by
    go-diskfs. The squashfs backend joined each leaf name onto its
    directory to form the object's remote, so a crafted image could escape
    its directory.
    
    Use sanitize.Leaf to skip unsafe entries in List. A "\" is an
    ordinary character in a file name on the systems squashfs images are
    made on and in an rclone remote path, so it is deliberately not
    rejected; making it safe for the destination is the destination
    backend's job.
    
    Skipped entries are logged at DEBUG with a single NOTICE count per
    listing so a crafted image under a mount cannot flood the log.

commit f75008de07d2b4b81f6329702719f02eca66a02b
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Thu Aug 20 12:10:44 2026 +0100

    archive: fix zip subdirectory root matching sibling directories GHSA-66hp-wgxq-6f5q
    
    When a zip archive was mounted at a subdirectory root, readZip used a bare
    strings.HasPrefix to decide which entries fell inside the root. This
    matched on a raw string prefix rather than a path boundary, so mounting
    root "foo" also exposed sibling entries such as "foobar/..." with their
    names left uncorrected.
    
    Require a path boundary when filtering by root.

commit 842430d2d4e13b7c93abe94a82690f08b0888832
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Tue Aug 25 10:14:27 2026 +0100

    archive: fix zip slip path traversal in untrusted zip files GHSA-66hp-wgxq-6f5q CVE-PENDING
    
    The zip backend mounts a zip file as a browsable Fs. Go's archive/zip
    does not sanitize entry names, and readZip applied path.Clean but did
    not reject a cleaned name that still pointed outside the archive. A
    crafted zip could make rclone copy/sync attempt writes outside the
    intended destination.
    
    Sanitize entry names with sanitize.Path - the same check used by
    rclone archive extract - skipping any entry with a ".." path
    component, whether separated by "/" or "\". A backslash is otherwise
    kept as an ordinary character in the name, as archive extract does. It
    is up to the destination backend to make names safe for its storage.
    
    Skipped entries are logged as a single count per archive so a crafted
    archive with many escaping entries cannot flood the log.

commit 2b7d0b16ed14663bbc39165514cd1d8665c49a4b
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Tue Aug 25 10:13:39 2026 +0100

    lib/sanitize: factor untrusted path sanitization out of archive extract
    
    Move the archive entry name validation added for CVE-2026-59732 from
    cmd/archive/extract into a new lib/sanitize package as sanitize.Path,
    so the same check can be shared with the archive backend which mounts
    archives as a filesystem.
    
    sanitize.Path keeps the extract semantics - reject any name with a
    ".." path component, treating both "/" and "\" as separators - and
    additionally cleans the name with path.Clean. This corrects two edge
    cases in extract: a repeated "./" prefix ("././file.txt") is now fully
    stripped rather than only the first, and a bare "." entry is now
    treated as the archive root and skipped.
    
    Add sanitize.Leaf, which rejects a name that is empty, ".", ".." or
    contains a "/", for checking a single directory entry name read from
    an archive.
    
    The names handled are rclone remote paths, in which "/" is the only
    separator and "\" an ordinary character, so Leaf does not reject a
    backslash: making a name safe for its storage is the destination
    backend's job (the local backend encodes "\" on Windows and refuses
    paths which escape its root). Path's rejection of ".." between
    backslashes is kept as defence in depth for extract.

commit 6453374403afd44e6936c90e468b0832c05becf3
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Thu Aug 20 11:43:39 2026 +0100

    local: fix panic on Range request past the end of a symlink GHSA-p6m2-r3w9-mpxw CVE-PENDING
    
    With --links/-l, a symlink is served as a .rclonelink object whose
    content is the target path. A Range request with a start offset beyond
    the target length (e.g. "Range: bytes=99999999999-") reached
    openTranslatedLink and sliced the target string at that offset, panicking
    with "slice bounds out of range".
    
    Clamp the offset to the target length so an out-of-range start reads
    empty, matching how a real file read past EOF behaves.

commit 215e6dbc6517f2f48285545f98e7367777c8bc8a
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Wed Aug 12 11:16:57 2026 +0100

    local: fix btime escaping the root via a planted symlink GHSA-f8g7-2xjc-7mfh CVE-PENDING
    
    The birth-time (btime) write in writeMetadataToFile followed symlinks for
    any object that was not a translated link, so under -l/--links a symlink
    planted by an untrusted source at the destination path could redirect the
    btime write to a target outside the backup destination on OSes where
    birth time is settable (Windows).
    
    Use the NOFOLLOW birth-time write whenever translating symlinks, not only
    for translated links. It is a no-op on a real file or directory and stops
    a planted symlink from being followed out of the destination.

commit 29bb1e11347c79d80b54d714e2e38cfcaf286190
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Wed Aug 12 11:10:24 2026 +0100

    local: fix dir metadata escaping the root through a planted symlink GHSA-f8g7-2xjc-7mfh CVE-PENDING
    
    With -l/--links the local backend faithfully recreates a source ".rclonelink" as
    a real symlink at the destination. Directory metadata (chmod/chown/chtimes),
    however, was applied with the raw following syscalls
    os.Chmod/os.Chown/os.Chtimes rather than through the os.Root sandbox used for
    content writes. A Directory is never a translatedLink, so when the destination
    path already existed as a symlink planted by an untrusted source, the metadata
    was applied through it to a target outside the backup destination.
    
    Route directory metadata through os.Root when translating symlinks, so a planted
    symlink can no longer redirect chmod/chown/chtimes out of the destination, while
    legitimate in-tree directories are unaffected.

commit 142172c21fd41b7f421c4df25eef3d9856696712
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Thu Aug 20 12:05:14 2026 +0100

    serve docker: reject volume names resolving to the base directory itself GHSA-p6vx-hf7p-98j6
    
    An empty or "." volume name joined onto the base directory resolves to the
    base directory itself. newVolume does not call validate, so such a name
    would mount a remote over the base directory and shadow every other
    volume's mountpoint.
    
    Require the resolved mountpoint to be a strict descendant of the base
    directory so these degenerate names are refused.

commit f5795d00c27ccda7dbdc1b87e697c94f911482d9
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Thu Aug 20 11:59:21 2026 +0100

    serve docker: re-derive volume mountpoint from name when restoring state GHSA-p6vx-hf7p-98j6
    
    When the plugin restarts it reads its persisted state file and used the
    stored mountpoint verbatim. A state file written by an older rclone that
    allowed escaping volume names, or one that was tampered with, could point
    the mountpoint outside the base directory, so upgrading did not remediate
    an already-escaped volume.
    
    Re-derive the mountpoint from the base directory and the volume name on
    restore, confined to the base directory, rather than trusting the stored
    path.

commit 756b5e4293147afb9d8b8a0798daf6f65fce71c5
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Thu Aug 20 11:58:39 2026 +0100

    serve docker: reject volume names that escape the base directory GHSA-p6vx-hf7p-98j6
    
    A Docker VolumeDriver.Create request carries a raw volume name that was
    joined onto the base directory with filepath.Join and used verbatim as the
    mountpoint. filepath.Join collapses ".." components, so a crafted name such
    as "../../../etc/foo" resolved to a host path outside the base directory,
    where the plugin then created a directory and mounted the remote.
    
    Confine the mountpoint to the base directory and refuse any name that
    resolves outside it.

commit f6c81d7a4f683ffd23b8b6b102cc921305c29834
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Wed Aug 12 11:43:54 2026 +0100

    serve ftp: fix auth-proxy sessions sharing credentials by username GHSA-c476-6w5q-jw77 CVE-PENDING
    
    When serving FTP with --auth-proxy, the obscured password was cached in a
    driver-global map keyed only by the username. Two sessions that logged in
    with the same username but different credentials shared one map entry, so a
    later login overwrote it and every subsequent operation on the earlier,
    still-authenticated session was re-authorized with the later session's
    credential and executed against the later session's backend.
    
    Bind the credential to the FTP session by storing the obscured password in
    the per-session goftp Session.Data map instead, so each session always
    resolves the backend it authenticated for.

commit e8e883c35e20d14e4bd6cdc4bbb0e6cd7df6b853
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Mon Aug 24 09:37:37 2026 +0100

    serve s3: fix auth proxy accepting any request signed with an empty secret GHSA-xwwr-4h3p-r22c CVE-PENDING
    
    With --auth-proxy set and --auth-key unset, serve s3 registered every client
    supplied access key ID with an empty secret and verified the SigV4 signature
    against that, so anyone could sign a request for an arbitrary access key ID with
    an empty secret and be let in. The proxy program was only ever given the access
    key ID (as both user and pass) so it had nothing with which to authenticate the
    client either.
    
    An S3 client never sends its secret, only a signature made with it, so the
    server has to know the secret to check the request. The auth proxy protocol as
    been changed to handle this. For serve s3 the proxy program is given just the
    access key ID as the user (no pass or public_key) and must return the matching
    secret as _secret_access_key in its output. rclone verifies the request's
    signature against that secret, refusing the request if the proxy rejects the
    access key ID, doesn't return a secret or returns an empty one, or the signature
    doesn't match. The secret is only used for this server's own verification and is
    never registered with gofakes3, so other serve s3 instances in the same process
    don't honour it.
    
    The proxy's answers are cached. If a signature fails against a cached secret the
    proxy is consulted again so a rotated secret takes effect immediately - but only
    for a signature mismatch, and at most once every 10 seconds per access key ID
    and client IP, so a stream of bad signatures can't make the proxy program run
    for every request. A rotation never shuts down the cached backend under requests
    still using it. A cached answer is checked with the proxy again once it is 5
    minutes old even if in constant use, so revoking an access key ID takes effect
    within 5 minutes.
    
    This means --auth-key is no longer needed with --auth-proxy: it is ignored and a
    warning is given at startup if both are set. The proxy is the source of truth
    for both the credentials and the backend they map to. Presigned URLs (credential
    in the query string) are now recognised by the proxy middleware too. The auth
    proxy docs are added to serve s3.
    
    Note that the serve s3 auth proxy protocol has changed. The proxy program is now
    given the access key ID as "user" (it was previously given an MD5 hash of it,
    with the access key ID as "pass") and must return the matching secret as
    "_secret_access_key".
    
    This needs gofakes3 v0.0.9 for signature.V4SignVerifyWithSecret.

commit d1e6e2f925f2688b5d19b9f8a83d1233fdcc91c8
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Mon Aug 24 09:37:26 2026 +0100

    serve s3: fix each server accepting the --auth-key credentials of all the others
    
    gofakes3 kept the keys given with --auth-key in a store global to the process,
    so when more than one serve s3 was running in one rclone (eg started via the rc)
    each accepted the others' credentials and a client with the key for one server
    could read and write the backend of another.
    
    This updates gofakes3 to v0.0.9 which keeps auth keys per instance and adds a
    test that two servers only accept their own keys.

commit 65735be4da673abeb1f8dacc59de3286ba2ddc44
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Wed Aug 12 11:56:07 2026 +0100

    serve sftp: fix auth proxy configured via rc being silently ignored GHSA-p569-5gjg-9cmj CVE-PENDING
    
    From v1.70.0, an SFTP server started through the rc serve/start API with
    a per-server proxyOpt.AuthProxy decided whether to enable proxy
    authentication by checking the process-global proxy.Opt.AuthProxy
    instead of the supplied proxyOpt.AuthProxy. In the normal rc case the
    global is empty, so the auth proxy was silently ignored: the server
    either failed to start with "no authorization found" or authenticated
    against the local authorized_keys file instead of routing each login
    through the proxy the operator configured.
    
    The serve Provider refactor (f425f8d46) fixed the constructor by building the
    provider from the supplied proxyOpt, but the authorized-keys handling in
    configure() still consulted the global option. Make it depend on whether
    proxy mode is actually active, and add a regression test for the
    per-server option.

commit 46d09fd52e703732ac499da43e7ef2e41fc73a76
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Wed Aug 12 11:55:17 2026 +0100

    serve s3: fix misleading anonymous access log and add test for auth proxy via rc GHSA-p569-5gjg-9cmj CVE-PENDING
    
    From v1.70.0 until the serve Provider refactor (f425f8d46), an S3 server started
    through the rc serve/start API with a per-server proxyOpt.AuthProxy
    decided whether to enable proxy authentication by checking the
    process-global proxy.Opt.AuthProxy instead of the supplied
    proxyOpt.AuthProxy. In the normal rc case the global is empty, so the
    auth proxy was silently ignored and the server served the fixed
    filesystem supplied to serve/start rather than routing each access key
    to the backend chosen by the proxy, bypassing the operator's intended
    per-key authorization.
    
    The Provider refactor fixed this incidentally by building the provider
    from the proxyOpt passed to the constructor. This adds a regression test
    so the per-server option cannot silently stop working again, and only
    logs "allowing anonymous access" when neither an auth key nor an auth
    proxy is configured so the log reflects the effective mode.

commit 212178eea1a6f96c8cbeec544935aad1c8b23a54
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Wed Aug 12 11:54:17 2026 +0100

    serve ftp: add test for auth proxy configured via rc GHSA-p569-5gjg-9cmj CVE-PENDING
    
    From v1.70.0 until the serve Provider refactor (f425f8d46), an FTP server started
    through the rc serve/start API with a per-server proxyOpt.AuthProxy
    decided whether to enable proxy authentication by checking the
    process-global proxy.Opt.AuthProxy instead of the supplied
    proxyOpt.AuthProxy. In the normal rc case the global is empty, so the
    auth proxy was silently ignored and the server fell back to its
    fixed-backend mode, whose default account accepts user "anonymous" with
    any password - a complete authentication bypass.
    
    The Provider refactor fixed this incidentally by building the provider
    from the proxyOpt passed to the constructor. This adds a regression test
    so the per-server option cannot silently stop working again.

commit 120324c86088f2c8f5530ab4d7f15001e16af36b
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Wed Aug 12 11:35:23 2026 +0100

    serve s3: reject bogus multipart part sizes in the reorder buffer GHSA-2p48-j3qc-rx9f
    
    The multipart reorder-buffer admission trusted the client-declared part length.
    A negative length was accepted, and `buffered + size` could overflow int64 for
    a huge declared length, wrapping the running total negative and admitting
    further parts past --multipart-streaming-buffer-limit.
    
    Reject a negative length and use the overflow-safe comparison `size <=
    bufferLimit - buffered` so an untrusted Content-Length can neither poison nor
    overflow the budget.

commit efc8adb0e5208ba5eb436dce95b204c82bd873c5
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Wed Aug 12 11:26:40 2026 +0100

    serve s3: fix memory exhaustion from client-declared multipart part size GHSA-2p48-j3qc-rx9f CVE-PENDING
    
    Streamed multipart UploadPart called Reserve(contentLength) before reading any
    body bytes, so the pool immediately allocated one 1 MiB page per MiB of the
    client-declared Content-Length (or X-Amz-Decoded-Content-Length). An client
    could declare a huge part size, send no body, and force an arbitrarily large
    allocation without paying the bandwidth cost of the declared body.
    
    Drop the Reserve so the pool-backed buffer grows a page at a time as the body
    is actually read: memory now tracks the bytes received, not the unverified
    header.

commit 935197b06220e83a2ef71d60f98cc2991b1f5de1
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Wed Aug 19 16:37:59 2026 +0100

    fs: confine directory listing entries that escape the root GHSA-3vxh-3pcx-9m8q GHSA-38xv-hf3p-h7mq CVE-PENDING
    
    The rclone core does not sanitise ".." in an object's Remote(). Such a name can
    arrive from a malicious or buggy backend - an object store permits keys
    containing ".." or a leading "/" - and, if acted on, lets a listing or transfer
    escape the configured root. A source object named "../../other/x" is copied to
    "other/x" outside the destination root, and a crafted listing name surfaces
    outside the directory being listed.
    
    Add list.RemoteEscapesRoot, which reports whether a Remote climbs above the
    root when joined onto it, and list.RemoveEscaping, which drops and logs such
    entries.
    
    Apply RemoveEscaping unconditionally - independent of the include/exclude
    filters - at the three per-entry filtering points every listing passes through:
    filterDir, walk.listR and walk.walkRDirTree (recursive ListR).
    operations.StatJSON calls List and NewObject directly, bypassing those, so it
    rejects an escaping remote up front.
    
    This confines every backend at once, so no per-backend change is needed.

commit 1615434cbe765ca59ab7290f60322fd6573e8e09
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Fri Sep 4 19:00:03 2026 +0100

    Add PSR94 to contributors

commit b4c598dbe4a82fd6398197575b2111952c9a602d
Author: PSR94 <88868390+PSR94@users.noreply.github.com>
Date:   Tue Sep 1 11:48:43 2026 -0400

    docs: update Huawei Drive client ID setup

commit f55031759060af9ff0074c66bae5ef1331c60172
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Thu Sep 3 10:41:19 2026 +0100

    build: update golang.org/x/crypto to v0.56.0 to fix CVE-2026-78662 and CVE-2026-56855
    
    CVE-2026-78662: a malicious peer could flood an undecided channel's
    incoming requests, deadlocking the whole connection in
    golang.org/x/crypto/ssh (GO-2026-6354)
    
    CVE-2026-56855: a malicious peer could send crafted messages on an
    established channel, deadlocking the whole connection in
    golang.org/x/crypto/ssh (GO-2026-6355)

commit 7e17e1b90d89eeda0afe83216601b3e5f37cb1b8
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Wed Sep 2 16:32:13 2026 +0100

    bisync: fix failed transfers of empty files being recorded as synced
    
    When bisync is interrupted with a graceful shutdown it keeps the files
    which transferred successfully in its listings and rolls the rest back.
    An operator precedence mistake in that check meant a transfer of an
    empty file (or one of unknown size) was kept even when it had failed,
    so bisync recorded it as synced when it had not been.

commit 220fe761921548520a6ff2272bf8011fb7773c8b
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Mon Aug 31 15:30:17 2026 +0100

    docs: describe how backends should allocate memory

commit 891fddc28c2801c37ad962fb66686eaa4a626bd6
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Sun Aug 30 17:49:59 2026 +0100

    s3: avoid buffering Object Lock uploads when the source MD5 is known
    
    Single part uploads with Object Lock parameters need a Content-MD5
    header, which the SDK can't compute from a stream, so the whole body
    was read into memory with io.ReadAll to hash it - up to
    --s3-upload-cutoff per file. prepareUpload already sets Content-MD5
    from the source object's hash when it has one, so skip the buffering
    entirely in that case and only buffer when the hash is unavailable.
    
    When buffering is needed, read the body into a multipart.NewRW buffer
    from the global pool, hashing in transit, so the memory is reused
    across uploads and released after the request. The presigned request
    path hands the body straight to http.NewRequest, so wrap it in
    readers.NoCloser there to stop the transport closing the pooled buffer.

commit 921c149f7e4c321794345c4795ac9ff80eb48792
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Sun Aug 30 17:39:11 2026 +0100

    mailru: buffer speedup hashing in the global memory pool and fix upload retries
    
    With speedup enabled, files up to --mailru-speedup-max-memory are read
    into memory so their hash can be tried against the server before
    uploading. This used io.ReadAll, which allocates a fresh heap slice per
    file and grows it by doubling, so with the default 32 MiB limit and
    several transfers this churned a lot of garbage outside rclone's memory
    accounting.
    
    Buffer the file with multipart.NewRW instead, hashing it in transit,
    so the memory comes from the global pool and is reused.
    
    When the hash isn't known to the server the buffered file is uploaded
    from the same buffer. Previously a low level retry of that upload
    resent an already drained reader, so the retry always failed. Rewind
    seekable bodies at the start of each attempt so retries resend the
    whole file. Add a test which drops the connection on the first attempt
    and checks the retried body is complete.
    
    The body is sent through lib/rest, which wraps it in readers.NoCloser,
    so the transport can't close the pooled buffer early; Update closes it
    when it returns.

commit 91e7942da5218cea3f1069c45cb8d782c72f20be
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Sun Aug 30 17:35:38 2026 +0100

    linkbox: buffer the hashed 10 MiB file prefix in the global memory pool
    
    The Linkbox API needs the MD5 of the first 10 MiB of each uploaded
    file, so Update reads that prefix into memory before the upload. This
    used io.ReadAll, which allocates a fresh heap slice per file and grows
    it by doubling, churning well over 10 MiB of garbage per upload.
    
    Read the prefix into a multipart.NewRW buffer instead so the memory
    comes from rclone's global pool and is reused across uploads, and hash
    it in transit rather than computing the same MD5 twice.
    
    The PUT body goes through lib/rest, which stops the http transport
    closing it, so Update owns the buffer and closes it on every exit path.

commit 885e2478e7758633530ac1c07fdf6b7110b9edbe
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Sun Aug 30 17:34:25 2026 +0100

    jottacloud: buffer MD5 pre-reads in the global memory pool
    
    When the source has no MD5, Update reads the whole file into memory to
    hash it before uploading if it is under --jottacloud-md5-memory-limit.
    This used io.ReadAll, which grows a fresh heap slice per file (up to
    10 MiB by default, roughly doubled by the growth strategy), so syncs
    of many files churned allocations and GC.
    
    Buffer the data with multipart.NewRW instead so the memory comes from
    rclone's global pool, is reused across uploads and is released by the
    existing cleanup function.
    
    Unknown sized streams previously took the in-memory branch regardless
    of the limit, so an rcat of an arbitrarily large stream could read it
    all into memory. Spool those to the temporary file instead, as is
    already done for files over the limit.
    
    The buffered body is sent through lib/rest, which wraps request bodies
    in readers.NoCloser, so the transport can't close the pooled buffer
    early.

commit f5bdceab49c47652ce086e0a9abc240d06291ed5
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Sun Aug 30 17:33:16 2026 +0100

    filelu: reuse multipart upload buffers via the global pool and retry failed parts
    
    The multipart upload allocated a fresh chunk-sized buffer (64 MiB by
    default) plus a 1 MiB scratch buffer per large file, copying every byte
    twice, and never returned them to rclone's memory pool.
    
    Buffer each part with multipart.NewRW instead so the memory is reused
    across uploads and part of rclone's central memory management.
    
    The pooled buffer is seekable, so a part can now be re-sent.
    uploadPart previously had no retry at all and any transient error
    failed the whole upload. It is now wrapped in the pacer with the
    backend's usual shouldRetry rules, seeking to the start before each
    attempt. The body is wrapped in readers.NoCloser so the http transport
    can't close the pooled buffer between attempts, and Content-Length is
    set explicitly since net/http can't infer it from a pool.RW.
    
    The FsPutRetry integration test covers the retry of a failed upload
    request and checks the buffers are returned to the pool.

commit fb8783732d6b276fc33780ca596d816bf2694bc6
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Sun Aug 30 17:34:38 2026 +0100

    box: reuse multipart upload part buffers via the global pool
    
    Each part of a multipart upload allocated a fresh part-sized buffer
    (the size is chosen by Box, typically 8-32 MiB) with up to --transfers
    parts in flight, so large uploads churned allocations and GC.
    
    Buffer parts with multipart.NewRW instead so the memory comes from
    rclone's global pool, is reused across parts and files, and is part of
    rclone's central memory management.
    
    The pool.RW is seekable so the retry closure seeks back to the start
    before each attempt instead of rebuilding a bytes.Reader, and the
    per-part SHA1 digest is computed by reading the buffer and seeking
    back. The body goes through lib/rest which already stops the transport
    from closing it; the uploading goroutine owns and closes the buffer.
    The whole-file SHA1 used for the commit is unchanged.
    
    The FsPutRetry integration test covers the retry of a failed upload
    request and checks the buffers are returned to the pool.

commit 6613d4ec637b46bcf320dfbaefc5bd98ccef407b
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Sun Aug 30 17:39:17 2026 +0100

    opendrive: reuse upload chunk buffers via the global memory pool
    
    Each upload allocated a fresh chunk-sized buffer (10 MiB by default)
    regardless of the file size, so bulk transfers of many files churned
    allocations and GC.
    
    Buffer chunks with multipart.NewRW instead so chunk memory is reused
    across uploads and is part of rclone's central memory management. The
    pool.RW is seekable, so the existing rewind on retry carries over.
    
    The body goes through lib/rest which already wraps it so the transport
    can't close the pool buffer. The upload loop closes it after every
    chunk, on error paths included. A source which ends before the
    declared size is now reported as a short read before the chunk is sent
    rather than as an incomplete write afterwards.
    
    The FsPutRetry integration test covers the retry of a failed upload
    request and checks the buffers are returned to the pool.

commit 738eadf8dfe503b48f452ab0bd9eae79939b85ac
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Sun Aug 30 17:37:55 2026 +0100

    dropbox: reuse upload chunk buffers via the global memory pool
    
    Each chunked upload allocated a fresh chunk-sized buffer (48 MiB by
    default), so bulk transfers of many files churned allocations and GC.
    
    Buffer chunks with multipart.NewRW instead so chunk memory is reused
    across uploads and is part of rclone's central memory management. The
    pool.RW is seekable, so the existing IncorrectOffset recovery which
    skips already-received bytes on retry carries over unchanged, and the
    "chunk received OK" check now compares against the bytes actually
    buffered so a short final chunk is recognised too.
    
    The Dropbox SDK wraps the request body in io.NopCloser, so the transport
    never closes the pool buffer. The upload loop closes it after every
    chunk, on error paths included.
    
    The FsPutRetry integration test covers the retry of a failed upload
    request and checks the buffers are returned to the pool.

commit cdabcc7cc42d3735ed1ffaf75ce5561d484fbebc
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Sun Aug 30 17:35:43 2026 +0100

    putio: reuse upload chunk buffers via the global memory pool
    
    Each upload allocated a fresh 48 MiB chunk buffer, so bulk transfers of
    many files churned allocations and GC, and small files paid for the full
    buffer.
    
    Buffer chunks with multipart.NewRW instead so chunk memory is reused
    across uploads and is part of rclone's central memory management.
    
    The pool.RW implements io.Closer, so the PATCH request body is wrapped in
    readers.NoCloser to stop the http transport closing it after a failed
    attempt and freeing its pages before the retry. The retry closure now
    seeks the chunk back to the start explicitly before resending, a short
    read of the source is reported as an error rather than sent as an
    under-length chunk, and the request carries an explicit ContentLength.
    
    The FsPutRetry integration test covers the retry of a failed upload
    request and checks the buffers are returned to the pool.

commit da868b06f8e02dad5abbcc95f37d1c77017e30a6
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Sun Aug 30 17:34:35 2026 +0100

    compress: stop buffering the compressibility check output in memory
    
    The compressibility heuristic compressed a 1 MiB sample of each upload
    into a bytes.Buffer only to read its length, growing up to ~1 MiB of
    garbage per file. Write the sample through a counting io.Discard-style
    writer instead so no output buffer is allocated at all.

commit 03c1c08a27d0b3557e2996c01efb77f0f38656aa
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Sun Aug 30 17:33:25 2026 +0100

    compress: buffer small uploads in the global memory pool
    
    Every compressed upload allocated a fresh buffer the size of
    --compress-ram-cache-limit (20 MiB by default) regardless of how big
    the file actually was, so uploading many small files churned large
    allocations and the memory sat outside rclone's pool accounting.
    
    Read the head of the stream into a multipart.NewRW instead, which takes
    pages from the global pool only for the bytes actually read and returns
    them when the upload finishes. The pool.RW is seekable, so a wrapped
    backend which needs to retry a small upload can rewind the body, which
    the previous bytes.Buffer did not allow. A read error while filling the
    cache is returned rather than falling through to the streaming path.
    
    Add a unit test covering the buffered, streamed and spooled paths which
    checks the body handed to the wrapped remote, that it can be re-read
    for a retry, and that the pool pages are returned.

commit 204f8171000cb091e286f9c780949bbb8d3424b7
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Sun Aug 30 17:35:45 2026 +0100

    huaweidrive: reuse resumable-upload chunk buffers via the global pool
    
    Each resumable upload allocated a fresh chunk-sized buffer (8 MiB by
    default, up to 64 MiB), so bulk transfers of large files churned
    allocations and GC.
    
    Buffer each chunk in a pool.RW from the global page pool instead so
    the memory is reused across uploads and bounded by rclone's central
    memory management.
    
    The pool.RW is seekable, so the chunk is rewound at the start of each
    retry rather than re-wrapped. lib/rest wraps request bodies in
    readers.NoCloser so the transport cannot return the pages to the pool
    between attempts - the Content-Length is set through rest.Opts because
    the wrapped body is not a *bytes.Reader net/http can measure. A source
    that runs dry before its declared size is reported as an unexpected EOF
    rather than sending the short chunk.

commit 57eb80f182f5ce89bd0d0fee341130c275593ced
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Sun Aug 30 17:35:02 2026 +0100

    huaweidrive: build small uploads in pooled memory instead of a growing buffer
    
    Files below upload_cutoff (up to 20 MiB) were assembled into a bytes.Buffer
    which grows by doubling, so each upload allocated roughly twice its size
    and threw it away afterwards, churning the GC on bulk transfers. Write the
    multipart/related body into a pool.RW from the global page pool instead so
    the memory is reused across uploads and bounded by rclone's memory
    management.
    
    The pool.RW is seekable, so the same body is rewound at the start of each
    retry rather than being re-wrapped. lib/rest already wraps request bodies
    in readers.NoCloser so the transport cannot free the pages between
    attempts; the Content-Length is passed explicitly because the wrapped body
    is no longer a *bytes.Reader net/http can measure.
    
    The FsPutRetry integration test covers the retry of a failed upload
    request and checks the buffers are returned to the pool.

commit bd217a1082809a8644cd7c44a05eb3e89b6e94af
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Mon Aug 31 12:37:44 2026 +0100

    hidrive: buffer small file updates from the global memory pool
    
    Updating a file below --hidrive-upload-cutoff copied the whole file into
    an append-grown slice so the request could be retried, costing roughly
    twice the file size in transient allocations for every such update.
    
    Buffer the file in a multipart.NewRW from rclone's global page pool
    instead and return it to the pool once the request has finished. The
    pool.RW is seekable so retries re-send the same buffer. Accounting is
    applied as the buffer is sent so bandwidth limits and progress still
    track the upload. The request now carries an explicit Content-Length
    rather than being sent chunked.
    
    The upload is bounded by the size the source declares - a source that
    delivers more bytes than its declared size has the excess ignored, where
    previously the stream was sent to EOF.
    
    The FsPutRetry integration test covers the retry of a failed upload
    request and checks the buffers are returned to the pool.

commit e8034e654856f355a438efecde1c825d33a5f054
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Mon Aug 31 12:37:44 2026 +0100

    hidrive: reuse chunked upload buffers via the global memory pool
    
    Each chunk of a chunked upload allocated a fresh buffer of
    --hidrive-chunk-size bytes (48 MiB by default), with up to
    --hidrive-upload-concurrency of them in flight, so large uploads churned
    allocations and GC and a short final chunk still cost a whole chunk.
    
    Buffer chunks with multipart.NewRW from rclone's global page pool
    instead, sized to the data actually read, and return each buffer to the
    pool once its PATCH request has finished. The pool.RW is seekable, so a
    chunk which fails with a retryable error is re-sent from the same
    buffer. Accounting is applied as a chunk is sent so bandwidth limits
    and progress still track the upload. Chunk requests now carry an
    explicit Content-Length rather than being sent chunked.
    
    The prefix sent with the creating request in PutUnchecked is buffered
    through the same helper.
    
    The FsPutRetry integration test covers the retry of a failed upload
    request and checks the buffers are returned to the pool.

commit e8f421d28536b50773f372b22a46be3d71a9f0c7
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Mon Aug 31 12:37:44 2026 +0100

    hidrive: buffer the start of each upload from the global memory pool
    
    Every upload allocated a fresh buffer of --hidrive-upload-cutoff bytes
    (96 MiB by default) to hold the part of the file sent with the creating
    request, however small the file was, so copying many small files churned
    large allocations and GC.
    
    Buffer that prefix in a multipart.NewRW from rclone's global page pool
    instead, sized to the smaller of the declared file size and the cutoff,
    and return it to the pool once the file has been created. Accounting is
    applied as the buffer is sent so bandwidth limits and progress still
    track the upload. The request now carries an explicit Content-Length
    rather than being sent chunked.
    
    The upload is bounded by the size the source declares - a source that
    delivers more bytes than its declared size has the excess ignored,
    where previously they were read up to the cutoff.
    
    The FsPutRetry integration test covers the retry of a failed upload
    request and checks the buffers are returned to the pool.

commit 2a492cc355c0f0cb67a259e5385cf8f1b7099e83
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Sun Aug 30 17:37:30 2026 +0100

    hidrive: stop copying every upload chunk a second time
    
    Upload chunks are buffered into a bytes.Reader and then, when transfer
    accounting is active (always for a real copy), re-wrapped in accounting
    before being handed to cachedReader. cachedReader only recognised a bare
    *bytes.Reader, so the accounted chunk fell through to
    readers.NewRepeatableReader, which copied the whole chunk again into an
    append-grown slice. Every chunk (and the upload-cutoff prefix of every
    file) therefore cost roughly twice its size in memory.
    
    Look through the accounting wrapper when deciding whether the reader is
    already a seekable buffer and, if so, seek the buffer underneath while
    still reading through the accounting, so retries rewind without a copy.

commit 689081b410fd6c6c4a8dcbacdac2d286a9ab2dfd
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Sun Aug 30 17:42:45 2026 +0100

    onedrive: reuse upload chunk buffers via the global memory pool
    
    Each chunk of a resumable upload was buffered in a fresh RepeatableReader
    which grew by appending, so bulk transfers churned up to a chunk size (10
    MiB by default) of heap per chunk and GC pressure.
    
    Buffer chunks instead with multipart.NewRW from the global page pool
    instead so memory is reused across uploads and bounded by rclone's
    central memory management.
    
    A source which delivers fewer bytes than its declared size now fails
    before the chunk is sent with an unexpected EOF error rather than being
    rejected by the transport.
    
    Note that accounting now happens as the chunk is read into the buffer
    rather than as it is sent, as in the drive backend.

commit 2ed0c688f6e2e3db5d293b0ba47a80d0222a036a
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Sun Aug 30 17:38:52 2026 +0100

    pikpak: use pooled memory for the gcid hash buffer and spool unknown-size uploads to disk
    
    When the source can't be re-opened, the whole input is read once to
    compute its gcid before upload and held back for the upload proper. For
    inputs at or below --pikpak-hash-memory-limit this used a bytes.Buffer,
    a fresh heap allocation of up to the limit (and more while growing) per
    file.
    
    Hold the data in a buffer from the global memory pool instead so the
    pages are reused and released on cleanup.
    
    Inputs of unknown size were also always held in memory regardless of
    their length, as only sizes above the limit chose the temp file.
    
    Spool unknown sizes to the temp file so a large stream can't exhaust
    memory.

commit b6b3a0a485f6f8f9c06c852aaeb79d7d3976c8de
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Sun Aug 30 17:37:43 2026 +0100

    pikpak: share upload chunk buffers with the global memory pool
    
    The multipart uploader kept its own private buffer pool, a copy of the
    one in lib/pool with identical settings, so its chunk memory was never
    shared with the rest of rclone. Pages cached here were invisible to
    other backends and vice versa, costing up to 64 MiB of extra idle cache.
    
    Allocate chunks with multipart.NewRW, the global pool used by the
    other backends instead.

commit 337f762c799998331308a047a05d143e0704c4ea
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Sun Aug 30 17:35:18 2026 +0100

    shade: stop copying each upload chunk into a second heap buffer
    
    WriteChunk copied the whole chunk, which lib/multipart already hands over
    in a buffer from the global memory pool, into a bytes.Buffer so that
    retries could re-send it. That doubled the per-part memory and made a
    fresh chunk-sized heap allocation (64 MiB by default) for every part,
    times the upload concurrency.
    
    The chunk reader is seekable, so find its size with Seek and rewind it
    inside the pacer closure instead, sending the pooled buffer directly.
    
    Also fix the error for a part that fails to upload, which formatted the
    buffer instead of the part number.

commit 2f0228029eb71a61b58d6a987e7910edd020dba2
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Sun Aug 30 17:32:31 2026 +0100

    quatrix: fix chunk upload retries and fix memory leak
    
    Each upload chunk is buffered in a pool.RW from the global memory pool
    but was never closed, so its pages were never returned to the pool.
    
    Close the buffer after each chunk is uploaded and on the read error
    path.
    
    A chunk that failed with a retryable error was also retried without
    rewinding the buffer, so the retry sent an empty body with the original
    Content-Length and Content-Range and failed.
    
    Seek the chunk back to the start inside the pacer closure so each
    attempt re-sends it in full.
    
    The FsPutRetry integration test covers the retry of a failed upload
    request and checks the buffers are returned to the pool.

commit 76016d9947e5f057aa05537bf4d0726df384af97
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Mon Aug 31 12:36:28 2026 +0100

    huaweidrive: run the chunked upload integration tests
    
    Implement SetUploadChunkSizer and SetUploadCutoffer in the tests so
    fstests can exercise the resumable upload path with small chunk sizes.

commit 76b5ee825950e65ff732c6061137431bf22ba741
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Mon Aug 31 12:36:28 2026 +0100

    filelu: run the chunked upload integration tests
    
    Implement SetUploadChunkSizer and SetUploadCutoffer in the tests so
    fstests can exercise the multipart upload path with small chunk sizes.

commit 5fef6a84a86078f3e4ca0fe2842c2ed1cb93cd80
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Mon Aug 31 12:36:28 2026 +0100

    opendrive: run the chunked upload integration tests
    
    Implement SetUploadChunkSizer in the tests so fstests can exercise the
    chunked upload path with small chunk sizes.

commit a18d9a6886a96bb2099e277597a82f2362328cf3
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Mon Aug 31 17:12:37 2026 +0100

    rest: fix retries reading the request body after the request has finished
    
    Before this change the transport could still be reading the request
    body when Call returned, in two ways:
    
    - the goroutine writing a multipart upload form was never stopped or
      waited for, so after a failed request it kept reading the file body
      while the caller retried
    - the transport itself is documented to close the request body,
      possibly in a different goroutine after the request has finished,
      and hiding the body's Close method removed any way to wait for that
    
    Both of these raced with callers which seek to the start of a pooled
    buffer and retry the request, corrupting the retried body, and the
    abandoned multipart goroutine could read pooled pages after they had
    been returned to the pool.
    
    Call now waits for the transport to finish with the request body
    before returning, and the multipart form writer is stopped and waited
    for once the request has finished.

commit 05ac69e123b91459f01ce00358e75536051e228a
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Mon Aug 31 12:19:48 2026 +0100

    fstests: test uploads survive a transient HTTP error and return pooled buffers
    
    Add an FsPutRetry integration test which uses the fshttp fault injector
    to fail the first request carrying upload data, before it is sent, with
    either a synthetic 500 or a connection reset, and then checks that Put
    either succeeds with the correct contents or fails cleanly without
    leaving a corrupt object behind.
    
    It runs a single part upload and, for backends implementing
    SetUploadChunkSizer, a chunked one. This catches backends which retry
    an upload from a buffer which has already been consumed or returned to
    the memory pool. Backends which don't use HTTP skip the test.
    
    Also check in FsPutRetry and the large upload tests that the number of
    buffers in use in the global memory pool is unchanged after an upload,
    to catch backends which leak pooled buffers.

commit 8d8b82ba6f8127a910acd8434aa90a8ce8f6773b
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Mon Aug 31 12:14:16 2026 +0100

    fshttp: add a fault injector for testing transient HTTP failures
    
    Add fshttp.SetFaultInjector, which installs a function consulted by
    every Transport before a request is sent. The injector can synthesise
    an error status code or a transport error for chosen requests. The
    request body is drained and closed as a real round trip would, but
    nothing reaches the server.
    
    This lets the integration tests check that backends cope with a
    transient failure part way through an upload - in particular that a
    retry re-sends the same data rather than an already consumed or
    freed buffer - without needing a fake server for each backend.

commit 7744f98960fdd88b44a112c5668f6e8e94ae7419
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Mon Aug 31 17:43:27 2026 +0100

    readers: add NoCloserNotify to find out when a request body has been closed
    
    NoCloserNotify hides the Close method of the reader passed in like
    NoCloser, but calls a notify function (once only) when the returned
    body is closed. This lets callers of http.NewRequest find out when the
    transport has finished with a request body, as it is documented to
    possibly close it in a different goroutine after the request has
    finished.

commit 03fe2ef794288690dd241d2c59a7d230d1404d4e
Author: SillyZir <269283839+SillyZir@users.noreply.github.com>
Date:   Mon Aug 31 15:50:30 2026 -0400

    onedrive: fall back to manual drive ID entry when drive listing fails
    
    When both /me/drives and /me/drive fail during config (for example an
    account-level 403 serviceReadOnly "Database Is Read Only"), send the
    config state machine to the existing manual drive ID entry state
    instead of dead-ending at choose_type with the raw error. The drive
    itself remains usable when only the enumeration API is blocked.
    
    Fixes #9794

commit 4479a3b09bea3f824c56aec33b6675a95d694506
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Fri Aug 28 21:02:49 2026 +0100

    accounting: stop --max-transfer overshoot in Account.WriteTo
    
    Account.WriteTo wrote each buffer to the destination in full before
    trimming the byte count for --max-transfer, so up to one buffer past
    the limit could reach the wire and go unaccounted. This matters now
    that NoCloser forwards WriteTo.
    
    Truncate the write to the remaining allowance before writing.

commit 6c84963297c156d5f2f4d05fb0c7a0a28cd74117
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Fri Aug 28 20:52:15 2026 +0100

    readers: make NoCloser pass through WriteTo so io.Copy keeps its fast path
    
    NoCloser hides the Close method of an io.Reader but in doing so it
    also hid io.WriterTo if the underlying reader implemented it, forcing
    io.Copy to fall back to a buffered Read loop.
    
    Following io.NopCloser, return a variant which forwards WriteTo when
    the wrapped reader supports it.

commit 670bf345869ea130e15d49d01167017b510fbe98
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Sun Aug 30 17:12:49 2026 +0100

    Add Splainte to contributors

commit 393544b1162c0043a3dcee6ef0479a0e516cfad5
Author: SillyZir <269283839+SillyZir@users.noreply.github.com>
Date:   Mon Aug 3 10:04:09 2026 -0400

    drive: reuse resumable-upload chunk buffers via multipart.NewRW
    
    Each resumable upload allocated a fresh chunk-sized buffer (8 MiB by
    default), so bulk transfers of many files churned allocations and GC.
    Buffer chunks with multipart.NewRW instead — the global page pool used
    by the other backends — so chunk memory is reused across uploads and
    bounded by rclone's central memory management. The pool.RW is seekable,
    which also keeps chunk reads repeatable for retries.
    
    The pool.RW implements io.Closer, so http.NewRequestWithContext upgraded
    it to the request body and the transport closed it after each attempt,
    returning its pages to the global pool — a chunk retried after a 5xx
    then read a freed buffer and panicked in pool.(*RW).readPage. Wrap the
    request body in readers.NoCloser so the transport can't take ownership
    and the upload loop remains solely responsible for the buffer's
    lifetime. Add a regression test that fails a chunk with a 500 and then
    accepts the retry; it reproduces the panic without the fix.
    
    Fixes #9684

commit 4722b94d1acb98b3bd4ee9c5af68e6d2f7ccc783
Author: Splainte <r.wycke@hotmail.fr>
Date:   Fri Aug 28 22:21:16 2026 +0200

    sftp: implement multi-thread uploads - fixes #8185
    
    The sftp backend could be used as the source of a multi-thread copy -
    each chunk of a download is read on its own connection - but not as the
    destination, because it did not implement OpenWriterAt. Uploading a
    single large file was therefore limited to one connection while
    downloading the same file was not, capping upload throughput well below
    the link speed on high latency connections.
    
    This implements OpenWriterAt for the sftp backend using lib/filepool. A
    small pool of open write handles, each backed by its own connection,
    lets the core write the chunks of a large file concurrently over several
    connections. The file is created and truncated once up front so every
    chunk offset is valid before the concurrent writes start.
    
    Multi-thread uploads are off by default and turned on with the new
    --sftp-multithread-upload flag, since many sftp servers only accept
    sequential writes and would fail large uploads otherwise. Even when
    enabled they fall back to a single connection when
    --sftp-disable-concurrent-writes is set (a server that can't take
    out-of-order packets on one handle won't take several handles either) or
    when --sftp-connections caps the pool (the per-file fan-out would
    otherwise deadlock waiting on it).
    
    The OpenSSH test server (TestSFTPOpenssh) enables
    --sftp-multithread-upload so the feature is exercised in CI against a
    real server.
    
    Tested against OpenSSH: a single large upload over a high latency link
    went from ~12 MB/s to ~90 MB/s.
    
    Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
    Signed-off-by: Splainte <r.wycke@hotmail.fr>

commit 613b335962c427d028085c01ba602c92ded6b715
Author: Splainte <r.wycke@hotmail.fr>
Date:   Fri Aug 28 22:21:16 2026 +0200

    filepool: add generic file handle pool in lib/filepool
    
    Factor the connection-backed write handle pool out of the smb backend
    into a generic lib/filepool.Pool[T] with its own tests, so it can be
    reused by other backends that implement fs.OpenWriterAter over a
    connection pool.
    
    The smb backend keeps its behaviour, opening and releasing handles
    through small closures passed to the pool.
    
    Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
    Signed-off-by: Splainte <r.wycke@hotmail.fr>

commit 6a617a379bc9883d015370cf9dc4320f6e0138e4
Author: Mikel Olasagasti Uranga <mikel@olasagasti.info>
Date:   Thu Aug 27 23:28:33 2026 +0200

    protondrive: fix Go 1.27 vet warning in retry test
    
    Pass the wrapped API error through the error-typed test helper so the
    %w operand satisfies Go 1.27's printf analyzer without changing test
    behavior.

commit 55fa9b6ab2b746fb8ddefdebb8db04941f8acf1e
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Fri Aug 28 14:52:09 2026 +0100

    pool: return an error instead of panicking when an RW is used after Close
    
    *pool.RW implements io.Closer, so when one is used directly as an
    http.Request body the transport closes it after each attempt. A retry
    which then seeks and re-reads the RW would index the freed pages and
    panic with "index out of range" in readPage.
    
    Read, Write, ReadFrom, WriteTo and Seek now return ErrClosed (which
    wraps io/fs.ErrClosed) after Close, and Close is safe to call more
    than once.

commit e5e1ee3e96808b31cf856eab152de4bba8d9406d
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Fri Aug 28 17:33:52 2026 +0100

    build: update golang.org/x/crypto to v0.55.0 to fix CVE-2026-56854
    
    CVE-2026-56854: source-address critical option not enforced for
    non-public-key auth callbacks in golang.org/x/crypto/ssh (GO-2026-6303)

commit e88141c4ef2db954d4f7fd0a2b4a90e71cfd9100
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Fri Aug 28 17:38:39 2026 +0100

    Add Dhevenddra to contributors

commit 5fc1cc3ca1c39f2c3cdec37089491b1e5aa3564e
Author: Dhevenddra <dhevg20020402@gmail.com>
Date:   Thu Aug 27 16:33:10 2026 +0530

    test: skip the symlink tests when the platform won't allow symlinks
    
    Nine tests fail on an ordinary Windows machine, eight in backend/local and
    TestEnvironmentVariables in cmdtest, all with
    
        symlink file.txt \?\C:\Users\...\symlink.txt: A required privilege is not
        held by the client.
    
    Windows grants SeCreateSymbolicLinkPrivilege only to an elevated process or one
    running with Developer Mode enabled, and a default install gives an ordinary
    user neither. CI does not see this because the windows-latest runner is
    elevated, so the failures only show up on a contributor's own machine, where
    AGENTS.md asks for make quicktest to pass before opening a pull request.
    
    cmdtest already recognised the situation and attached a note to the failure
    saying the test could safely be ignored. If it is safe to ignore then the test
    knows it cannot run, so skip it and say why instead.
    
    backend/local gains a helper that tries a symlink in t.TempDir() and skips if it
    cannot make one, called from the six tests that need the privilege. Where a
    platform can create symlinks the probe succeeds and nothing is skipped, so other
    platforms are unchanged.
    
    TestMetadata is skipped whole because it creates its symlink before anything
    else and the object built from it is used throughout.
    TestSymlinkEscapeConcurrent is left alone: it goes through putLink and ignores
    the error, so it never needed the privilege.

commit 1583cce1e28340e5d064ed955179f5f2b31e7757
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Thu Aug 27 15:56:31 2026 +0100

    crypt: warn about directories with legacy version-like encrypted names
    
    Directory names which look like they have a --b2-versions version
    string are now encrypted in full, so directories created by older
    rclone (which left the version string in plain text) no longer
    decrypt and vanished silently from listings.
    
    DecryptDirName now falls back to the old form for such names so the
    directory is listed, and logs the name it needs to be renamed to on
    the underlying remote to make it accessible again. Document this in
    the crypt docs.

commit 1fd40d06abb148148e60bf6d1f5f29f4d6544a7c
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Thu Aug 27 17:27:38 2026 +0100

    Add no-hup to contributors

commit 02a6f8bae6f28de3077c9920539ebd7dab9fe4f1
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Thu Aug 27 17:27:37 2026 +0100

    Add shaurya to contributors

commit aa2b879c67a71fd31738430d08fd562bf032da95
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Thu Aug 27 17:27:37 2026 +0100

    Add cyphercodes to contributors

commit 0c4f61b972ba7c09aa7c94714c9a0a2d461c8f56
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Thu Aug 27 17:27:37 2026 +0100

    Add Anatoly Tarnavsky to contributors

commit 8494fc74987659e3b973c870fa0af0ee3d9a67f0
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Thu Aug 27 17:27:37 2026 +0100

    Add Sune Mølgaard to contributors

commit a00f9bf4e140bddf2db061ea9d071da111888add
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Thu Aug 27 17:27:37 2026 +0100

    Add Vijay Misal to contributors

commit 5d2fe5e52f6aee26f3601d133a7d5a58ec0b5297
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Thu Aug 27 17:27:37 2026 +0100

    Add Rayan Salhab to contributors

commit a93a062f4a130994c01a0b0277d2d4a02d720587
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Thu Aug 27 17:27:37 2026 +0100

    Add water to contributors

commit 7897f1d30f63503990792fd1cba04ebe84540309
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Thu Aug 27 17:27:37 2026 +0100

    Add shaurya to contributors

commit e3aeaee13d9c49a0d3ea807911a6747e58634493
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Thu Aug 27 17:27:37 2026 +0100

    Add CAOShurong to contributors

commit 413138f56b626e7d090e7faa432149e1a6d35092
Author: CAOShurong <3502119616@qq.com>
Date:   Thu Aug 27 23:59:08 2026 +0800

    docs: fix dead links in sia and storj backends

commit 66761670daf8a8780a8b1afd8584e972f2307058
Author: 0rangeSeaW0lf <0sw-8m4k2v@waku.li>
Date:   Wed Jul 8 17:59:43 2026 +0200

    internxt: persist rotated token returned by the user info call
    
    The refresh endpoint returns a rotated token with a fresh expiry on
    every successful call, but getUserInfo discarded it, so routine use
    never extended the stored token's life. Once the stored token aged
    out, accounts with 2FA enabled could not recover non-interactively
    and required a manual reconnect.
    
    Carry the rotated token out of getUserInfo and persist it in NewFs
    via the same jwtToOAuth2Token + oauthutil.PutToken path that
    refreshJWTToken uses, keeping f.cfg.Token in sync (same pattern as
    refreshOrReLogin).
    
    Fixes #9584
    
    Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

commit 67b184d6e720f522a15a844057e9fdc814a29cad
Author: TowyTowy <towy@airreps.link>
Date:   Sun Jul 12 11:26:47 2026 +0200

    crypt: fix directory names which look like versioned file names
    
    The --b2-versions support added in 3fe2aaf96 strips a version string
    from the last segment of a path before encrypting it, so that the
    plain text version suffixes which the underlying backend appends to
    encrypted file leaf names can be handled. EncryptDirName and
    DecryptDirName share that code, so the last segment of a *directory*
    name was version stripped too. Only file leaf names are ever given a
    version string by the backend - a directory gets a
    version-string-like name from the user, and such a name is encrypted
    verbatim when it appears as the parent of a file name, so the same
    directory ended up with two different encryptions.
    
    Before this change, with a directory whose name matches rclone's
    version format, eg dir-v2001-02-03-040506-123:
    
        rclone copy file.txt crypt:dir-v2001-02-03-040506-123/
        rclone ls crypt:dir-v2001-02-03-040506-123
        # => "directory not found" - the file is invisible to listings
        rclone mkdir crypt:dir-v2001-02-03-040506-123
        # => creates a second directory with the same decrypted name
    
    After this change EncryptDirName and DecryptDirName encrypt directory
    names verbatim, so a directory encrypts the same way whether it is
    named on its own or as the parent of a file. Version strings are only
    added to file names by the underlying backend, so --b2-versions is
    unaffected and the existing version tests are untouched.
    
    A directory which was created by the old EncryptDirName will no longer
    decrypt and will be reported as undecryptable in listings. Such
    directories were already unusable - anything copied into one was
    written to a different encrypted directory - so nothing which worked
    before is broken by this.
    
    Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

commit 6df7b8aba1a73c8e889fb49f3268d0e25eb9fd53
Author: Anatoly Tarnavsky <anatolyt@gmail.com>
Date:   Sun Jul 19 19:54:01 2026 +0300

    s3: fix server side copy failing with --s3-no-head-object - fixes #9629
    
    With no_head_object set, NewObject does not read any metadata, so the
    destination object returned from a server side copy had a size of 0.
    The size check in operations.Copy then failed with "corrupted on
    transfer: sizes differ N vs 0" and deleted the newly copied object.
    This also broke Move and hence renames through rclone mount.
    
    Populate the destination object's size and MD5 from the source object
    when no_head_object is set, as a server side copy produces an object
    with identical content.
    
    Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

commit 4af64270cc4d978027782ca68e801bab0446345d
Author: Loi Nguyen <vanloi999@gmail.com>
Date:   Thu Aug 27 12:22:09 2026 +0100

    dropbox: fix ChangeNotify when the root's case differs from Dropbox's - fixes #9692
    
    Dropbox is case insensitive and the path_display it returns in
    change notifications may not match the case of the configured root.
    Before this change the root was trimmed with a case sensitive prefix
    match, so when the cases differed the full path was passed to the
    ChangeNotify callback and the notification was ignored.
    
    This trims the root case insensitively while preserving the display
    case of the remaining path.

commit bdeb95ae012d64ffb0ae0597fa6a433db7ab3876
Author: Sune Mølgaard <sune@molgaard.org>
Date:   Sat Aug 15 10:59:06 2026 +0200

    serve http: prevent scrolling to the top on page reload - fixes #9771

commit efa5e8fcc1abe17a61629708185fd260b2a56433
Author: Vijay Misal <misalvijay153@gmail.com>
Date:   Sun Aug 16 15:09:04 2026 +0530

    vfscache: fix log message growing without bound on repeated write errors
    
    Write() overwrote a successful write's nil error with the stale
    lastErr returned by kickWaiters() once the downloader had recorded
    too many errors. download() then wrapped that stale error again and
    stored it back as the new lastErr, so every subsequent write added
    another "vfs reader: failed to write to cache file:" prefix - fixes #4998

commit 468eccb122628c9ae1d17229d46967ff3abed410
Author: Rayan Salhab <r.salhab@aiyexpertsolutions.com>
Date:   Thu Aug 27 14:07:18 2026 +0300

    accounting: fix bwlimit burst overflow - fixes #9820
    
    Co-authored-by: cyphercodes <cyphercodes@users.noreply.github.com>

commit 5d1feea7e862d135fb3452fa33e52a8bcec86b60
Author: water <672684719@qq.com>
Date:   Thu Aug 13 21:45:47 2026 +0800

    fix: do not retry multipart upload chunk on 404 (upload session not found)

commit 9dbfd9d8523104785969c9283c1db09b3d044851
Author: shaurya <shauryajaiswal.dev@gmail.com>
Date:   Wed Aug 26 22:12:57 2026 +0530

    docs: fix broken links and wrong s3 directory bucket flag name
    
    Several documentation links pointed at anchors or paths that no longer
    resolve, and the S3 directory buckets section named the config option
    and flag in the plural, which does not match the backend.
    
    Co-authored-by: shaurya <19599684+no-hup@users.noreply.github.com>
    Co-authored-by: no-hup <shauryaj.finance@gmail.com>

commit 660144d311efaaee9e1b48a707d6b17dcaee7d24
Author: CAOShurong <3502119616@qq.com>
Date:   Wed Aug 26 21:26:37 2026 +0800

    s3: treat UploadPart success without ETag as retryable error
    
    A successful UploadPart whose response carries no ETag header made
    WriteChunk panic dereferencing uout.ETag in a debug log line. The part
    ETag is required by CompleteMultipartUpload, so an ETag-less 200 is
    unusable: return a retryable error from inside the pacer callback so
    the chunk is retried instead of crashing the transfer or completing
    the upload with a broken part list.
    
    Fixes #9822
    
    Co-authored-by: Shurong Cao <170531907+CAOShurong@users.noreply.github.com>

commit c140d36a1f372cdf331e8f02abf7df39410646a4
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Tue Aug 18 12:10:09 2026 +0100

    docs: update sponsors

commit 4369d16a1ca20e1b362faab66dc520bb82b50eec
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Wed Aug 26 11:17:49 2026 +0100

    test_all: pikpak: ignore TestRcatSizeChecksum/Corrupted
    
    Pikpak never returns MD5 for uploads which causes this test to fail.
    
    Perhaps Pikpak should not declare MD5 but that is a bigger decision
    being discussed in #9826

commit f7c510af4900930304d8a653f95da4da376e0293
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Tue Aug 25 12:39:50 2026 +0100

    webdav: fix SetModTime failing and hashes missing on Nextcloud
    
    Nextcloud only stores a checksum which is supplied in the OC-Checksum
    header of an upload, and discards it again when the modification time
    is set with PROPPATCH. Re-sending the checksum in the PROPPATCH (as is
    done for ownCloud) is rejected by Nextcloud with 403 Forbidden which
    made the whole PROPPATCH fail, so SetModTime returned an error on any
    object which had a hash. Uploads from sources without hashes, eg
    streamed uploads with `rclone rcat`, were stored with no hash at all.
    
    Use the Nextcloud PATCH extension with the X-Recalculate-Hash header
    to have the server calculate and store the SHA1 of an object after a
    streamed upload and after setting the modification time. This gives
    a server side hash of the stored data which also lets rclone verify
    streamed uploads.

commit 8e744de5e6c40ef612295fe084fe887fe759aa0a
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Tue Aug 25 12:18:22 2026 +0100

    pikpak: fix truncated single part uploads reported as ok when source ends early
    
    If the source supplied fewer bytes than its declared size, the single
    part upload path accepted the short body and stored a truncated file
    recorded with the declared size, reporting a successful upload. The
    multipart path already checks for this.
    
    Count the bytes actually read and fail the upload if they do not match
    the declared size, which cancels the partially created file.
    
    This was found by the FsPutShortEOF integration test.

commit a893df601a11f0f9a563f3c25ff7410f1e85c1ea
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Wed Aug 26 12:00:09 2026 +0100

    Add machsix to contributors

commit 8869a848f2290681a44f681ce57e3754876a4a8f
Author: machsix <28209092+machsix@users.noreply.github.com>
Date:   Mon Aug 24 14:17:59 2026 -0400

    onedrive: fix 403 Forbidden for configuration personal onedrive

commit d3a71eea3636b4f1ac071568fd0a785ee94cfdb4
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Tue Aug 25 09:29:20 2026 +0100

    azureblob: fix test which didn't compile
    
    We accidentally merged this commit with non compiling tests.
    
    bee45bccfd54b55e azureblob: fix spurious vfs cache corruption errors during chunked reads #9782

commit d68ecd17170385ea8367a3de8c4f5b2470a4861e
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Tue Aug 25 09:31:10 2026 +0100

    Add Sanjay Kanth A to contributors

commit f3a7aaf635cc3843090080a8c9f23d6e3ca2bf8c
Author: Sanjay Kanth A <sanjaykanthsk09@gmail.com>
Date:   Fri Aug 21 11:48:41 2026 +0530

    dropbox: decode received shared-file names - fixes #9707
    
    listSharedFolders already decoded shared-folder names with
    f.opt.Enc.ToStandardName, but listReceivedFiles stored the raw name
    returned by the Dropbox API unchanged. Names that require encoding
    (e.g. a trailing space, which Dropbox itself rejects, so rclone
    stores it as "name␠" via EncodeRightSpace) were therefore shown under
    their raw, encoded form for received files instead of being decoded
    back to the standard name, and findSharedFile could not resolve such
    a file by its standard name.
    
    Apply the same ToStandardName conversion listSharedFolders uses.

commit bee45bccfd54b55e3bfc17f652e1e87e7b38be5c
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Mon Aug 17 12:35:14 2026 +0100

    azureblob: fix spurious vfs cache corruption errors during chunked reads - fixes #9782
    
    On a ranged download the metadata decoder stored the response's
    Content-Length (the length of the range, not the blob) in the object's
    size and only corrected it from the Content-Range total afterwards.
    Object.Size() is read concurrently by the VFS cache and chunked reader
    while a download is in progress, so with --vfs-read-chunk-size a reader
    could observe the chunk length (e.g. 67108864 for 64M chunks) as the
    object size. The VFS cache then logged
    
        vfs cache: cached file (N) is unexpectedly larger than the remote
        object (67108864). The cached file is likely corrupted after an
        unclean shutdown; recovering ...
    
    and truncated the read request against the bogus size, breaking
    sequential reads of large blobs with --vfs-cache-mode full.
    
    This applies the Content-Range correction before the size is stored so
    the range length is never published as the object size.

commit 2a8d8afd0fbbfd2b94c9a118c98418c2d3db75f6
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Mon Aug 17 12:35:14 2026 +0100

    lib/rest: make ParseContentRange public

commit 6ee1d851ec27eebf3d8f3b626c054a2a722cc5e8
Author: kingston125 <support@filelu.com>
Date:   Sun Aug 23 08:10:21 2026 -0400

    filelu: fix duplicate root path during multipart folder creation

commit 83b143103c53c040964b9694dd24b44254bdc2c5
Author: Rohit Behera <126186063+r0h1tb@users.noreply.github.com>
Date:   Sat Aug 22 03:39:32 2026 +0530

    huaweidrive: fix truncated files being uploaded successfully when the source ends early
    
    The multipart upload copied the source into the request buffer without
    checking how many bytes it had read, so a source that supplied fewer
    bytes than its declared size was accepted by the server and reported as
    a success with a truncated file stored.
    
    Count the bytes actually read and fail the upload if they do not match
    the declared size.
    
    Signed-off-by: Rohit Behera <126186063+r0h1tb@users.noreply.github.com>

commit d9aa903358f5c1a053a2f5543b78d37b154b6c8f
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Sat Aug 1 19:16:29 2026 +0100

    protondrive: fix files uploaded with v1.75.0 not being readable in the Proton apps
    
    rclone v1.75.0 started creating files in Proton Drive's new
    crypto-refresh encryption format, following guidance from Proton that
    new file node keys should use the v6/AEAD profile. It turns out the
    official Proton web app cannot decrypt files whose node key is a v6
    key (but the Android app can), so every file uploaded with v1.75.0 (or
    a beta after 2026-07-13) shows 'Item cannot be decrypted' in the web
    app, even though rclone itself reads the files fine. Inspecting a file
    created by the web app shows Proton itself still creates v4 node keys,
    using the new format only for the file content.
    
    New files are now created with the same fully pre-crypto-refresh
    format as v1.74.4 (v4 node key, v3 PKESK content key, v1 SEIPD
    blocks), which every Proton client can read. Reading files in the new
    format still works, new revisions of files which already use the new
    content format keep it, and the auxiliary fields (name, node
    passphrase, extended attributes, block signatures) are pinned to the
    old format regardless of the recipient key's preferences, as Proton
    requires.
    
    Files already uploaded with v1.75.0 cannot be repaired in place -
    uploading a new revision does not change the file's node key. To make
    such a file readable by the Proton apps again, delete it from the
    remote and upload it again with a fixed version of rclone.
    
    This updates Proton-API-Bridge to v1.0.5 and go-proton-api to v1.0.4.
    
    See: https://forum.rclone.org/t/proton-drive-unable-to-decrypt/54087

commit c7be826d7b00526c773f6d48d30ac4d622b63737
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Mon Aug 24 17:47:03 2026 +0100

    Add Rahman Yilmaz to contributors

commit 3c1a265842e5d85c61c117922c1179403ea42c6f
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Mon Aug 24 17:47:03 2026 +0100

    Add Rohit Behera to contributors

commit 64ab1ac32260238eefca3c61327f5faf1c6e106f
Author: Rohit Behera <126186063+r0h1tb@users.noreply.github.com>
Date:   Mon Aug 17 16:13:14 2026 +0530

    box: fix truncated files being uploaded successfully when the source ends early
    
    The single-shot upload path sent the source straight to Box as a multipart
    body with no Content-Length, so a source that supplied fewer bytes than its
    declared size produced a short request that Box accepted and stored, and the
    upload was reported as a success.
    
    Count the bytes actually read and fail the upload if they do not match the
    declared size. The multipart path already reads each chunk with io.ReadFull
    and so already fails in this case.

commit 5eb5c01e36de8f4518f7fa58f71ba236c22c6e18
Author: Rahman Yilmaz <85690773+Sudo-Rahman@users.noreply.github.com>
Date:   Fri Aug 21 18:48:29 2026 +0200

    walk: stop directory traversal when the context is cancelled - fixes #9788
    
    The concurrent walker created by walk() only stopped when the callback
    returned an error or the whole tree had been listed. Cancelling the
    context (for example via the rc job/stop endpoint for an async
    operations/size or recursive operations/list call) was therefore
    ignored: the checkers kept pulling list jobs from the channel and kept
    listing the entire tree, burning CPU and making job cancellation
    useless for every backend without a native ListR implementation.
    
    Make every checker select on ctx.Done() so a cancelled walk shuts down
    promptly through the existing quit/drain path and reports the context
    error. Also check the context between directory read chunks in the
    local backend so a single huge directory does not block cancellation.

commit 1128693468851f38de801a4627f759cbec3a28b9
Author: Rohit Behera <126186063+r0h1tb@users.noreply.github.com>
Date:   Mon Aug 17 16:18:41 2026 +0530

    yandex: fix truncated files being uploaded successfully when the source ends early
    
    Update already wrapped the source in a counting reader but never looked at the
    count, so a source that supplied fewer bytes than its declared size was
    uploaded as a chunked request, accepted by the server and reported as a
    success with a truncated file stored.
    
    Compare the bytes actually read against the declared size.

commit e2352201d112f36f05abc5dc91768000fb23f927
Author: Dominik Sander <git@dsander.de>
Date:   Fri Aug 21 18:40:53 2026 +0200

    local: speed up default checksummed copies by writing in larger blocks
    
    When copying to the local backend with checksums enabled (the default),
    rclone hashed the incoming data by wrapping the source reader in an
    io.TeeReader. TeeReader has no WriteTo method, so io.Copy could not use
    the source's fast path and fell back to its generic 32 KiB buffer loop.
    The same wrapping also stopped the destination *os.File using
    copy_file_range, since the source was no longer a raw fd.
    
    This meant checksummed copies were written in 32 KiB chunks whereas
    --ignore-checksum copies were written in much larger blocks (typically
    1 MiB). On filesystems where small writes are expensive, such as FUSE
    mounts like LucidLink, this made a big difference: copying a 100 MiB
    file took 3203 x 32 KiB writes in 3.6s, and now takes 108 x ~1 MiB
    writes in 0.47s.

commit be7f9b38b053c97ac335e2038d36199a08663865
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Fri Aug 21 12:50:44 2026 +0100

    build: untap aws/tap to silence homebrew tap trust warnings on macOS

commit 002767897754d3efd6f08e33dcc3fff98bf44dcd
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Thu Aug 20 15:18:17 2026 +0100

    huaweidrive: simplify chunk size clamping found by "go fix -minmax"

commit a017a54bef81e4b60a9a9ed7130ca231e62b3821
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Thu Aug 20 15:17:16 2026 +0100

    build: modernize with "go fix -waitgroupgo": use WaitGroup.Go

commit 2d1a3386a85ca827c10bb81a2c675cbaa2354ae6
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Thu Aug 20 15:16:02 2026 +0100

    build: modernize with "go fix -stringsseq": use SplitSeq iterators

commit aed06f9052f0a87970fd1308578e9c336d233c60
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Thu Aug 20 15:15:36 2026 +0100

    build: modernize with "go fix -stringscutprefix": use strings.CutPrefix

commit 7b002153bd1da25a9c409b95703b2370712c8bfb
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Thu Aug 20 15:15:09 2026 +0100

    build: modernize with "go fix -stringscut": use strings.Cut

commit 4e9577ed76041a8d79d10ed4beafaf3f8a90ba67
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Thu Aug 20 15:14:45 2026 +0100

    build: modernize with "go fix -stringsbuilder": use strings.Builder

commit 9f9fd82923b250700f3ba33f80457784989dff69
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Thu Aug 20 15:03:21 2026 +0100

    build: modernize with "go fix -slicescontains": use slices.Contains

commit 237719bb8d401f2b600660b4f7ea025c9e7c1d91
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Thu Aug 20 15:02:47 2026 +0100

    build: modernize with "go fix -slicesbackward": use slices.Backward

commit e20e18d2e0e2e1d3ceae19214b0925c180d89350
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Thu Aug 20 15:01:51 2026 +0100

    build: modernize with "go fix -reflecttypefor": use reflect.TypeFor

commit a64c0a0fde9ef9cbcd5ce98472c3e4920505952c
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Thu Aug 20 15:01:28 2026 +0100

    build: modernize with "go fix -rangeint": use range over int

commit 67728ce37d2ecefe8bc1fc72b1d126c8a5f4b818
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Thu Aug 20 14:52:28 2026 +0100

    huaweidrive: remove no-op omitempty found by "go fix -omitzero"

commit 53d9f7f95613d8a06c1a61f8985ab37fc1862a16
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Thu Aug 20 14:51:59 2026 +0100

    build: modernize with "go fix -newexpr": use go1.26 new(expr)
    
    Also inline and remove the now unneeded pointer helper functions.

commit b5bea683c56e9ac0fbc1bdac3af76de7c8d5d37c
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Thu Aug 20 14:49:05 2026 +0100

    build: modernize with "go fix -minmax": use min and max builtins

commit bfd0e3f3c27b9acf02e4cbdda9796c49dfb2b6c3
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Thu Aug 20 14:48:47 2026 +0100

    build: modernize with "go fix -mapsloop": use maps.Copy

commit 33e9251b5222bbb045f69c1797b45f41960819fe
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Thu Aug 20 14:47:43 2026 +0100

    build: modernize with "go fix -errorsastype": use errors.AsType

commit 77f9c70cf6a5d06894d608f9075b31b28edcfb34
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Thu Aug 20 14:45:46 2026 +0100

    build: modernize with "go fix -atomictypes": use sync/atomic types

commit 7929921ed838bf737c4c0621e477e75f6743cf90
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Thu Aug 20 14:45:19 2026 +0100

    build: modernize with "go fix -any": replace interface{} with any

commit 357c2a2b4453de74cc73d1f5a33b5f09095cbb00
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Thu Aug 20 14:39:05 2026 +0100

    build: disable staticcheck SA4023 to fix lint job timeout
    
    The dataflow analysis behind SA4023, new in the staticcheck 0.8.0
    bundled with golangci-lint v2.13.0, makes linting large packages more
    than 10x slower (89s vs 7s for backend/s3 alone) which took the CI
    lint job past its 30 minute limit. golangci-lint no longer enforces
    its run timeout during analysis so the job ran until cancelled, and
    the cancellation meant the lint cache was never saved, making every
    subsequent run cold and guaranteeing the timeout repeated.
    
    The check also produces false positives (eg claiming operations.Delete
    never returns nil).

commit 152adfcd2a0a8c2e4471af99aecf545814e31797
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Thu Aug 20 17:49:01 2026 +0100

    serve s3: update to gofakes3 v0.0.8 which fixes 500 errors with go1.27

commit e189f3812273ba4b9033419c543e761af6042345
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Thu Aug 20 12:16:48 2026 +0100

    build: update to go1.27 and make go1.26 the minimum required version

commit ec3a95c279959242bf0c0b39697aac1c59808d5a
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Thu Aug 20 12:12:00 2026 +0100

    s3: Mega: update endpoints

commit 2f7d4e3f9f5bd11934969312164a77b442470e71
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Tue Aug 18 14:53:06 2026 +0100

    rc: deprecate --rc-web-gui flag
    
    This commit removes the workings of the old web ui which hasn't been
    maintained for 6 years. If users supply --rc-web-gui then rclone will
    exit with an error pointing users at the maintained `rclone gui`
    command.

commit 00496f5dfbfd630c4472de613e621933b22a2e7d
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Tue Aug 18 14:29:43 2026 +0100

    docs: take gui out of beta

commit 2c1174af0dfdd8711d7b092a372d8f709fb723e1
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Tue Aug 18 12:28:18 2026 +0100

    docs: add assigned CVE numbers to the v1.75.0 security advisories in the changelog
    
    Five of the advisories released with v1.75.0 now have CVEs assigned:
    
    - GHSA-45pq-889g-fcgh serve restic path traversal: CVE-2026-71309
    - GHSA-xhf4-832v-7xcr lib/proxy CONNECT header OOM: CVE-2026-71310
    - GHSA-8c48-q9wj-3w37 ftp command injection: CVE-2026-71311
    - GHSA-2m8m-jhrm-w6j2 sftp PowerShell command injection: CVE-2026-71312
    - GHSA-7p4m-qxvv-g567 local file name escape: CVE-2026-71313
    
    GHSA-6jcg-q3wp-x2f4 (squashfs) loses its CVE-PENDING marker as GitHub
    declined to issue a CVE from the rclone repository - the vulnerable code
    is in go-diskfs so any CVE must come from an advisory there.
    
    GHSA-mfvx-7rcj-9m5g (pprof) keeps its CVE-PENDING marker as the CVE
    request is still awaiting allocation.

commit b13f62237a3cf375c86ebe9c6d34b35d32d69991
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Tue Aug 18 12:29:20 2026 +0100

    Add VXNCXNX to contributors

commit 8da69d877560ca2469ece75736bf9c13a5d39423
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Tue Aug 18 12:29:20 2026 +0100

    Add Shantanav Mukherjee to contributors

commit 5b417ce5a1731f56b8bd0cc66bccd7bb575eeb97
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Tue Aug 18 12:29:20 2026 +0100

    Add Hakan İSMAİL to contributors

commit 47b1ac9540cae1c7bc477292a0e0a956d599341c
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Tue Aug 18 12:29:20 2026 +0100

    Add max to contributors

commit c667e53638513b465dc04b7eae4476aa038c678a
Author: VXNCXNX <VXNCXNX@users.noreply.github.com>
Date:   Sat Aug 15 17:28:34 2026 +0000

    lib/transform: fix panic in truncate_keep_extension
    
    Return error when extension is longer than truncation limit.

commit 4f22d62c660bb14ec41fdae614d9f1adeb2549c1
Author: Shantanav Mukherjee <shantanav7@gmail.com>
Date:   Tue Aug 18 14:19:42 2026 +0530

    docs: clarify VFS cache age semantics

commit 30e79a017bdc48c7a1be3f5fce308e629019b67b
Author: Hakan İSMAİL <hakanismail53@gmail.com>
Date:   Fri Aug 14 22:26:32 2026 +0300

    serve, mountlib: test VFS release on shutdown and mount failure

commit 216d2a8c7611555cf6905c458de82fce854a6c3d
Author: Hakan İSMAİL <hakanismail53@gmail.com>
Date:   Fri Aug 14 22:26:01 2026 +0300

    serve: fix VFS instance leaks on server startup failures and shutdown

commit 45ddf3a5f28cccdd3da805aaf52694c6b33f880f
Author: Hakan İSMAİL <hakanismail53@gmail.com>
Date:   Fri Aug 14 22:24:44 2026 +0300

    mountlib: fix VFS instance leaks on mount failures and unmounts

commit f425f8d46630936a26e0c8e412dcc9138b9e5bf1
Author: Hakan İSMAİL <hakanismail53@gmail.com>
Date:   Fri Aug 14 22:24:34 2026 +0300

    serve: refactor VFS and proxy handling into Provider

commit a1f98b49dfa8535467908dce148d106303f9e35a
Author: max <max@maxmax.ch>
Date:   Mon Aug 17 04:17:40 2026 +0000

    asyncreader: run the skip-bytes test under the race detector again
    
    The test skipped every buffer count above 1 under -race, pointing at
    golang/go#27070. That issue was closed in September 2018, so the
    workaround outlived its cause: -race covered 137 of the 681 subtests.
    
    Without the guard the race build runs all 681 and passes.

commit f0b210a886ddc6171c92b6e21520dd890c3f2d21
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Fri Aug 14 18:34:18 2026 +0100

    build: fix multiple CVEs by upgrading to go1.26.6
    
    - CVE-2026-56860: net/url: quadratic complexity in resolvePath
    - CVE-2026-56858: html/template: JavaScript regexp context tracking
    - CVE-2026-56862: crypto/tls: limit handshake messages accepted post-handshake
    - CVE-2026-56853: net/http: apply ReadHeaderTimeout to unencrypted HTTP/2 check
    - CVE-2026-56859: encoding/xml: recursion depth guard during decode
    - CVE-2026-33818: encoding/asn1: enforce maximum recursion depth
    - CVE-2026-46600: net: panic parsing an invalid SVCB or HTTPS RR in dnsmessage
    - CVE-2026-39821: net/http: reject ASCII-only Punycode-encoded labels in idna
    
    This also updates the go1.25 test job to go1.25.13 which contains the
    same fixes.

commit 00593a96fe9b435fecd784453dbc64cd54e8fc23
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Fri Aug 14 18:34:08 2026 +0100

    build: update golang.org/x/image to v0.45.0 to fix CVE-2026-46603
    
    CVE-2026-46603: excessive memory allocation during VP8L decoding
    
    This also updates golang.org/x/text to v0.41.0 as a dependency.

commit 64c9a28651fa200419fbd7a04c000f7609fb6b73
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Fri Aug 14 19:18:10 2026 +0100

    Add Dave to contributors

commit f81ccdf786cb7300575da305d511b71d655267ff
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Fri Aug 14 19:18:10 2026 +0100

    Add Shurong Cao to contributors

commit 8aba1c4378f21109067f160f9fb02a09fd90dc8e
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Fri Aug 14 19:18:10 2026 +0100

    Add Morax to contributors

commit 6e0c71bd276bd587403fd00e88ef195aa6996789
Author: Dave <davixk83@gmail.com>
Date:   Fri Aug 14 08:14:01 2026 +0200

    vfs/vfscache: fix reader deadlock when the item size drops below the read offset
    
    _dispatchWaiters decided whether a waiter was satisfied by clipping its
    range against dls.src.Size(), the size of the fs.Object snapshot taken
    when the Downloaders was created. _ensureDownloader decided whether to
    start a downloader from Item.FindMissing, which clips against
    item.info.Size instead.
    
    When item.info.Size dropped below the offset a waiter was parked on while
    the source object still reported the full size, the two disagreed.
    _ensureDownloader found nothing missing so it started no downloader, and
    _dispatchWaiters found the range absent so it never released the waiter.
    Nothing was downloaded and no error was produced, so the error count never
    reached maxErrorCount and the waiter was never woken. The reader blocked
    forever with nothing logged at any level.
    
    Wake a waiter when FindMissing reports nothing left to download for it as
    well as when its data has arrived. Since _ensureDownloader starts a
    downloader only when FindMissing is non empty, a waiter with nothing
    missing has nothing that could ever wake it.
    
    Fixes #9769

commit bb7c081ec520aa5f3feff22a731082f3483766d6
Author: Shurong Cao <170531907+CAOShurong@users.noreply.github.com>
Date:   Thu Aug 13 15:02:02 2026 +0800

    sync: add pattern-based transfer ordering
    
    Allow --order-by to rank files using comma-separated rclone path globs. Patterns are evaluated in order, unmatched files are placed last, and path ordering makes ties deterministic.
    
    Fixes #3975

commit 9f93da3299f66ce37857aa9ccd0956bd114be5d5
Author: Morax <james20081204@gmail.com>
Date:   Thu Aug 13 20:24:25 2026 +0200

    operations: fall back when source ignores ranges
    
    When a multi-thread source ignores ranged reads, abort the partial
    destination and retry the copy as a single stream. Reset accounting
    before the fallback so transfer progress remains accurate.

commit 1003280bb14747184731bb3050d66a743eccc636
Author: Morax <james20081204@gmail.com>
Date:   Thu Aug 13 20:23:19 2026 +0200

    webdav: reject ignored ranged responses
    
    Validate ranged GET responses before returning their bodies. Close invalid
    responses, retry malformed partial responses through the pacer, and return
    without retrying when a server deterministically ignores Range.
    
    Fixes #6980

commit 69e5aff2a93bebbf4183a3b433154ebedd6ecf50
Author: Morax <james20081204@gmail.com>
Date:   Thu Aug 13 20:22:26 2026 +0200

    lib/rest: validate ranged responses
    
    Add response validation for calls made with Range open options. Verify
    Content-Range, Content-Length, response status, and the complete
    representation size before a backend accepts the response body.
    
    Return a shared sentinel when a server ignores a partial range so callers
    can avoid retrying the same unsupported request.

commit 5a0b7d6746ccbcb59833b49a940162847fa4216a
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Tue Aug 11 19:43:20 2026 +0100

    crypt: fix hash mismatches with no_data_encryption on backends which check upload hashes
    
    Before this change, when no_data_encryption was set, uploads from
    local disk advertised the hash of the encrypted data even though the
    data was uploaded unencrypted.
    
    On backends which check upload hashes (eg b2) this made uploads of
    small files fail with errors like "Checksum did not match data
    received", and made chunked uploads store an incorrect hash so the
    files failed their checksum on download with "corrupted on transfer:
    SHA1 hashes differ".
    
    See: https://forum.rclone.org/t/sha1-mismatches-on-b2-with-no-data-encryption-true/54121

commit afb4fa5f2bb3bf8236b2559354bc67e0a0b4ea34
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Fri Aug 14 09:53:40 2026 +0100

    Add Pastalikek65 to contributors

commit d22c4509aa838245b2d5a12a968e462b47825113
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Fri Aug 14 09:53:40 2026 +0100

    Add Dean Chen to contributors

commit f49e0515072575b42567e9b6d350de283a280b43
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Fri Aug 14 09:53:40 2026 +0100

    Add Teddy Tennant to contributors

commit 926ccdac5de267bf4b4bab92683547a8eb1aa0e6
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Fri Aug 14 09:53:40 2026 +0100

    Add Jiacheng Xu to contributors

commit 49dc9fb91922e9a0c8d1e43b4b971c9b84f8d8eb
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Fri Aug 14 09:53:40 2026 +0100

    Add Recoordinate to contributors

commit 7c7635bae36750f6dadd6ca96873b7c46bd68e12
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Fri Aug 14 09:53:40 2026 +0100

    Add Rodrigo Rodrigues to contributors

commit 86f981a05e2f278f36b11dba501801939e7a2440
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Fri Aug 14 09:53:40 2026 +0100

    Add Christian De Santis to contributors

commit adc7f2ebfa3fe412430944a36ef5e61910d21145
Author: Pastalikek65 <Pastalikek65@users.noreply.github.com>
Date:   Wed Aug 12 10:20:10 2026 +0300

    config: redact env var config values in logs
    
    Before this change the environment variable getters in fs/configmap.go
    logged the option value with %q, so a password set via
    RCLONE_CONFIG_remote_pass (or RCLONE_remote_pass) was printed in full
    to the debug log. Values from the config file were already redacted,
    which made the leak easy to miss.
    
    This change routes both getters through fs.RedactOptionValue, which
    looks up the option in the backend's option list: options marked
    IsPassword or Sensitive log as XXX, unknown options are conservatively
    redacted, and --dump auth still shows the value for debugging.
    
    Fixes #5794

commit c785ff90d71a6bc858dff5502c8875eb6d89d3a5
Author: Dean Chen <862469039@qq.com>
Date:   Sun Aug 9 20:10:23 2026 +0500

    docs/mount: mention nfsmount for macOS NFS mounts
    
    The NFS section under Mounting on macOS talked about serve nfs without
    pointing at rclone nfsmount, which is the command that actually does the
    NFS-based mount on macOS.
    
    Fixes #7869
    
    Signed-off-by: Dean Chen <862469039@qq.com>

commit a182fcbce8b7baa987c4819f3b76986517281cf5
Author: Teddy Tennant <teddytennant@icloud.com>
Date:   Sat Aug 8 16:05:20 2026 -0400

    operations: speed up checksum by hashing files in parallel - fixes #9727
    
    rclone checksum and rclone check --checkfile hashed one file at a time
    unless --download was in use. The non-download branch of CheckSum called
    Object.Hash synchronously from inside the listing callback, so --checkers
    had no effect there; only the --download branch used the checker token
    pool.
    
    Both branches now do their work in the same goroutine bounded by
    --checkers, so --checkers means the same thing with and without
    --download. Checking a sum file against 2.6 GiB of local files with
    --checkers 8 went from 1.70s to 0.31s here.
    
    As a result the "hashing" checking transfer now covers the hashing work
    in both branches, rather than being finished as soon as the download
    goroutine had been started.

commit fc348fcb0bb866bd401266a248c45536bb768ed7
Author: phatlc <phatle.hsd@gmail.com>
Date:   Sun Aug 2 09:12:28 2026 +0700

    operations: check checksums in rcat with known size - fixes #6305
    
    RcatSize streams the body straight into Put behind an ObjectInfo with no
    hashes, so a known-size upload had its size checked but its checksum
    never verified, unlike the unknown-size path through Rcat which hashes as
    it goes.
    
    The stream can only be read once, so hash it on the way past and compare
    with the destination after the upload, as operations.Copy does. A
    destination which reports no usable hash is still checked by size, and one
    which fails either check has the failed copy removed.

commit 35f052e29a00e40d1053e8162d271c0d866258f0
Author: Jiacheng Xu <169599847+Stardust0831@users.noreply.github.com>
Date:   Wed Aug 5 02:19:10 2026 +0800

    size: include source in JSON output - fixes #5429

commit cfdc9d05584f4bc97e6279394a3e2e8a207988a9
Author: Recoordinate <296084221+latent-9@users.noreply.github.com>
Date:   Wed Aug 12 21:59:44 2026 +1200

    docs: fix doubled words

commit 8b42a38e9d749a0a46869a6c193c910c43a669b7
Author: Rodrigo Rodrigues <191260313+MVP0TAT0@users.noreply.github.com>
Date:   Tue Aug 11 21:27:34 2026 +0100

    docs: fix typo in drive client_id section

commit aba403fa79ea8f4fc9a9e2cbe4c333412e0eb257
Author: Christian De Santis <41491267+christiandesantis@users.noreply.github.com>
Date:   Tue Aug 11 16:17:13 2026 -0400

    iclouddrive: fix uploads into an app container failing with 412 - fixes #9729
    
    Writing any file into a third-party app container - the Obsidian, Pages or
    Shortcuts folders that iCloud Drive shows alongside your own - failed with
    
        HTTP error 412 (412 Precondition Failed) returned body:
        "{ ... \"error_code\" : \"VALIDATING_REFERENCE_ERROR\", \"reason\" :
        \"Request has out of order children to be chained but the parents were
        missing\" }"
    
    Reading from those paths worked, and so did creating directories in them, so
    the failure looked like a missing parent when the parent was plainly there.
    
    Items in an app container live in a different zone from ordinary iCloud Drive
    folders: a folder under Documents has a drive ID like
    FOLDER::com.apple.CloudDocs::<uuid>, while the Obsidian container has
    FOLDER::iCloud.md.obsidian::documents#o2v. DownloadFile already accounts for
    this - it deconstructs the item's own ID and addresses the zone it finds - but
    CreateUpload and UpdateFile hardcoded defaultZone, and UpdateFile built the
    resulting Drivewsid with a hardcoded com.apple.CloudDocs as well.
    
    So rclone asked Apple to chain the new document to a parent in
    com.apple.CloudDocs while the parent lived in iCloud.md.obsidian. The parent
    really was missing from the zone being addressed, which is what the error said.
    
    Take the zone from the parent's drive ID instead, the same way the download
    path does, and build the new item's ID with ConstructDriveID. Uploads outside
    an app container are unaffected: their parents are in com.apple.CloudDocs, so
    the derived zone is the value that was previously hardcoded.
    
    Verified against a real remote: files now upload into an Obsidian vault inside
    the container and read back correctly with an unpatched binary afterwards.

commit abae66ee1a0efe4cb7191fad06c995903d588549
Author: nielash <nielronash@gmail.com>
Date:   Fri Aug 7 09:15:13 2026 -0400

    accounting: fix memory leak from stats groups on long-running rcd
    
    Before this change, `NewStats` stored the context it was created from on the
    `StatsInfo`. Stats groups are never freed -- they are only evicted once there are
    `--max-stats-groups` of them -- so each one kept its context, and everything reachable
    from it, alive for the life of the process. As the rc creates a group per call,
    that included the call's filters and their compiled regexps.
    
    The context was only ever used to get `ci.StatsFileNameLength` from the config.
    `StatsInfo` already stores that same `*fs.ConfigInfo`, read from the same
    context in `NewStats`.
    
    This change fixes the issue by passing the stored ci to `transferMap.String` and
    dropping the context from `StatsInfo`.

commit 71a09321266d5ed425c936c4fe98cb4d20450b6f
Author: nielash <nielronash@gmail.com>
Date:   Fri Aug 7 07:48:56 2026 -0400

    accounting: fix memory leak on long-running rcd
    
    Before this change, Transfer.Done closed the account of a completed transfer but
    never released it, because it assigned nil to only a local copy of the pointer.
    As a result, every completed transfer continued to reference its account.
    
    An Account holds the transfer context and the source reader, and the stats keep
    completed transfers around up to `MaxCompletedTransfers` per group, with groups
    discarded only at --max-stats-groups. On a long-running `rclone rcd`, this adds up.
    
    It was noticeable when running bisync repeatedly via the rc, where the transfer
    context carries `b.WriteResults` (bisync's `LoggerFn`). A `*bisyncRun` holds
    Path1 and Path2 listings, which can be quite large, and are not supposed to be
    retained between runs. (Naturally they aren't, when running bisync on the
    command line -- which is probably why we didn't notice this issue sooner.)
    
    This change fixes the issue by releasing `tr.acc` in Done, instead of the local
    copy. `tr.Snapshot` reads the byte counts off the account, so the progress is
    recorded on the transfer first. That read happens before taking `tr.mu`, because
    `acc.progress()` locks `acc.values.mu`, `checkReadBefore` holds that lock while
    calling `StatsInfo.GetBytes`, and `StatsInfo` locks back into `Transfer` in
    `Transferred` and `_removeTransfer`.

commit 1947e4217c63b529371e46dcd413969210d32ba3
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Tue Aug 4 16:33:12 2026 +0100

    serve s3: clean up abandoned multipart uploads after --multipart-expiry
    
    A client which started a multipart upload and vanished without either
    completing or aborting it used to hold on to its resources forever.
    
    Incomplete multipart uploads which have had no activity for
    --multipart-expiry (default 24h) are now aborted and cleaned up
    exactly as if the client had called AbortMultipartUpload, with a
    NOTICE logged.
    
    An upload with a part still being received is never expired, and each
    completed part restarts the clock. Late operations on an expired
    upload fail with NoSuchUpload, as they do on real S3 when a lifecycle
    rule has aborted the upload.
    
    Set --multipart-expiry 0 to keep incomplete uploads forever.

commit b4db289d0a02e23bf9ded883acd90bfd2c800a66
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Tue Aug 4 10:49:12 2026 +0100

    serve s3: upload all multipart uploads via the VFS
    
    Multipart uploads used to be streamed directly to the remote with their
    own PutStream machinery, bypassing the VFS, a design left over from
    before the VFS could abandon a streaming write.
    
    They are now written through the VFS exactly like plain object PUTs in
    every cache mode. The parts are written, in part-number order, to a
    temporary object which is renamed into place server-side on
    completion.
    
    With the default --vfs-cache-mode off the parts stream through the VFS
    to the remote as they arrive. With --vfs-cache-mode writes or above
    they are buffered in the VFS cache and uploaded by its write-back.
    
    User visible changes:
    
    - Multipart uploads now show in rclone's transfer stats and obey
      --bwlimit (previously they bypassed both).
    - Remotes without streaming upload support now spool the upload to a
      temporary file on local disk instead of buffering it in memory.
    - Multipart uploads are never buffered in memory because of missing
      remote capabilities - only --disable-multipart-streaming does that.
    - Remotes that upload atomically now also write to a temporary object
      renamed into place, so an in-progress multipart upload is no longer
      briefly visible under its final key.
    - On the few remotes with no server-side move or copy the parts are
      written straight to the final object in all cache modes.
    - With --vfs-cache-mode writes, plain PUTs and multipart uploads to the
      same key go through the same cache entry, so an earlier PUT still in
      the write-back window can no longer be written back over a newer
      multipart upload.
    - Failed write-backs are retried by the VFS without the client having
      to restart the upload, and completed objects are served from the
      cache for read-after-write.

commit 0aa90200bd6667374c2161793434d6cc859e41e0
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Tue Aug 4 10:27:25 2026 +0100

    serve s3: reserve the .rclone_temp_ prefix for temporary objects
    
    The temporary objects that uploads are written to before being renamed
    into place are now named .rclone_temp_put_* and .rclone_temp_multipart_*,
    and the whole .rclone_temp_ prefix is reserved: any object whose name
    starts with it is hidden from S3 listings. This gives a single pattern
    for cleaning up leftovers from killed servers:
    
        rclone delete --min-age 24h --include ".rclone_temp_*" remote:path
    
    The .rclone_multipart_upload_* objects rclone v1.75 used are still
    hidden from listings so leftovers from an older server stay invisible
    to S3 clients.

commit a3489456de86e2a60a3cdeb73a9326e07c724533
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Mon Aug 3 12:46:43 2026 +0100

    serve s3: fix modtime not being set when only mtime metadata is supplied on PUT
    
    The mtime metadata fallback was nested inside the X-Amz-Meta-Mtime
    branch, so it only ran when X-Amz-Meta-Mtime was present but invalid -
    and then set the modtime from the invalid value's failed parse rather
    than parsing mtime. An object PUT with only mtime metadata kept the
    upload time as its modtime.
    
    Now the two keys are checked independently, as TouchObject already
    does.

commit 531d873bd71045f839c88338964748f1aec0ae1e
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Mon Aug 3 11:04:18 2026 +0100

    serve s3: fix crash when a multipart upload is aborted while a part is uploading
    
    streamPart did not check whether the upload had been torn down, but
    AbortMultipartUpload sets the reorder buffer map to nil, so an abort
    arriving while a part body was still being received panicked with an
    assignment to a nil map once the part was buffered.
    
    Now a part whose upload has been aborted or completed under it is
    rejected with NoSuchUpload.

commit 84298fc090ed29acbd85cb69881969befd329d8a
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Sun Aug 2 19:08:02 2026 +0100

    serve s3: fix failed uploads deleting or corrupting the object at the key - fixes #9718
    
    A PUT which failed part way through removed the object at the
    destination key. As well as differing from real S3 (where a failed PUT
    never affects the stored object), this raced with the client's
    automatic retry of the same PUT: the retry stored the object and
    returned 200 OK, then the failed first attempt's cleanup deleted it,
    silently losing an acknowledged upload. The interrupted upload could
    also be committed as a truncated object, since closing the write handle
    gave the streaming upload a clean end of stream.
    
    Now a failed or interrupted PUT never disturbs the object at the key:
    
    - The object at the key is never removed on error.
    - On backends where a partial upload is visible at its final name
      (PartialUploads), and when the VFS cache mode is writes or above, the
      upload is written to a temporary object which is renamed into place
      on success and removed on failure, as streamed multipart uploads
      already do. Backends which upload atomically are still streamed
      straight to the destination.
    - An interrupted or short body fails the upload via
      WriteFileHandle.CloseWithError instead of committing truncated data,
      and a body which ends cleanly short of its declared size is rejected
      with IncompleteBody.

commit 2f0657c35b0f47a684611e5821ea2e13f9e3af0a
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Sun Aug 2 19:07:54 2026 +0100

    vfs: add WriteFileHandle.CloseWithError to abandon streaming writes
    
    Closing a streaming write handle sends a clean EOF to the backend
    upload, so a writer which knows its data source failed part way through
    had no way to stop the truncated file being stored as if it were
    complete.
    
    CloseWithError closes the handle failing the upload with the given
    reason instead. EOF-like reasons are rewritten so the layers reading
    the pipe can't mistake them for a clean end of stream and commit the
    partial file.
    
    Needed by serve s3 to abort interrupted PUTs - see #9718

commit 7357fb82a9ef29eef7902694a871247398baa177
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Fri Aug 7 14:02:09 2026 +0100

    internetarchive: fix corrupted files being created when the source ends early
    
    If the source supplied fewer bytes than its declared size, the upload
    request failed but a retry could report success even though the stored
    file was truncated, because the retry re-sent an already exhausted
    reader.
    
    Count the bytes actually read from the source and if they do not match
    the declared size return an error.
    
    This was found by the new FsPutShortEOF integration test.

commit 5d057549b9fcfc277fc815e67e3d7146d0981617
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Fri Aug 7 14:01:16 2026 +0100

    sia: fix corrupted files being created when the source ends early
    
    If the source supplied fewer bytes than its declared size, the upload
    request failed but a retry could report success even though the stored
    file was truncated, because the retry re-sent an already exhausted
    reader.
    
    Count the bytes actually read from the source and if they do not match
    the declared size, remove the partially uploaded file and return an
    error.
    
    This was found by the new FsPutShortEOF integration test.

commit a2baa978dbf0ba3dec93472b26c05b78a59e93c4
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Fri Aug 7 13:51:16 2026 +0100

    pikpak: fix truncated files being created when the source ends early
    
    If the source supplied fewer bytes than its declared size, the
    multipart upload was completed anyway, storing a truncated file and
    reporting a successful upload.
    
    Check the number of bytes read from the source against the declared
    size before finalising and abort the upload with an error if they do
    not match.
    
    This was found by the new FsPutShortEOF integration test.

commit 5b7cc097e3300324aa7718b5a4e7b6c69e02c871
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Fri Aug 7 13:51:16 2026 +0100

    multipart: fix chunked uploads storing truncated objects when the source ends early
    
    If the source supplied fewer bytes than its declared size, the
    multipart upload was completed anyway, storing a truncated object and
    reporting a successful upload.
    
    Check the number of bytes read from the source against the declared
    size before finalising and abort the upload with an error if they do
    not match.
    
    This affects all backends which use lib/multipart for chunked uploads:
    azureblob, b2, drime, internxt, oracleobjectstorage, s3 and shade.
    
    This was found by the new FsPutShortEOF and TestRcatSizeShortEOF
    integration tests.

commit e1bf9405e2eb1b17fd77fc75f2eb9a501511af4f
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Fri Aug 7 12:51:42 2026 +0100

    filelu: fix truncated files being uploaded successfully when the source ends early
    
    If the source supplied fewer bytes than its declared size, the
    truncated file was stored and the upload reported success with the
    object claiming the declared size.
    
    Count the bytes actually read from the source and if they do not match
    the declared size, remove the truncated file and return an error.
    
    This was found by the new TestRcatSizeShortEOF integration test.

commit 884b28c203c59f7ce95df43be1a828c2c802b6a5
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Fri Aug 7 12:50:46 2026 +0100

    azurefiles: fix zero padded files being created when the source ends early
    
    The file is created at the declared size and the data then written
    with ranged writes, so if the source supplied fewer bytes than
    declared, the remainder of the file was left as zeroes and the upload
    reported success.
    
    Count the bytes actually read from the source and if they do not match
    the declared size, delete the partially uploaded file (if newly
    created) and return an error.
    
    This was found by the new FsPutShortEOF and TestRcatSizeShortEOF
    integration tests.

commit 387b4b5e11d611780a283db01c493e21ba7826f0
Author: nielash <nielronash@gmail.com>
Date:   Fri Aug 7 09:15:13 2026 -0400

    bisync: fix memory leak when running via the rc
    
    Before this change, `fastCopy` created a cancellable context for the sync and
    stored its cancel func on the `bisyncRun`, but only ever called it when
    gracefully shutting down. On a normal run, it was never called, and until it is
    cancelled, a context from `context.WithCancel` stays registered with its nearest
    cancellable ancestor.
    
    For an rc job, that ancestor is the job's own context, which the job registry
    retains for `--rc-job-expire-duration`. The sync context carries bisync's
    `LoggerOpt`, whose `LoggerFn` is a method value on `*bisyncRun`, so a finished
    run was kept alive -- including the Path1 and Path2 listings -- for as long as the
    job was.
    
    This change fixes the issue by cancelling the sync context when `fastCopy`
    returns. The cancel func is still stored on the `bisyncRun`, so a graceful
    shutdown can still interrupt a sync that is in progress.

commit 1aa9efef17eafc8c3fc1e8da2889a7ba44f3898b
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Thu Aug 6 15:50:35 2026 +0100

    docs: update sponsor links

commit 345758454ce4e687a17ee10511931aed6ff8cf65
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Fri Aug 7 16:28:33 2026 +0100

    Add Edward Klesel to contributors

commit e4c7aca6bda5b35b42080a9a4056230c8339285c
Author: Edward Klesel <eklesel@bluecove.com>
Date:   Wed Aug 5 10:11:45 2026 +0100

    azureblob: fix Entra ID server-side copy source authentication
    
    When using Microsoft Entra ID credentials, Azure Blob server-side copy
    uses a user delegation SAS URL for the private copy source.
    
    The SAS start time was set to the current local time. Azure Storage
    validates the copy source from the service side, and small clock
    differences can make that SAS appear not yet valid. The service then
    returns 403 CannotVerifyCopySource with AuthenticationFailed.
    
    Start the copy-source SAS 15 minutes in the past, matching Microsoft SAS
    guidance for clock skew.

commit 5629f2668c69149bf3d9d8e2a25bb32a2648606e
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Mon Aug 3 21:03:32 2026 +0100

    overview: fix "internal error: no overview data found" on 32 bit architectures - fixes #9723
    
    The precision field in the backend overview YAML files can hold
    fs.ModTimeNotSupported (100 years in nanoseconds) which overflows int
    on 32 bit platforms, making the YAML for those backends fail to parse
    and causing rclone to log 18 internal errors on every invocation.
    
    Use int64 for the precision field and add a test that parses every
    embedded backend YAML file so this is caught on 32 bit test runs.

commit a06df7a2de46ee15932a0fbfa27bc4bb0045acf8
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Mon Aug 3 21:40:28 2026 +0100

    protondrive: fix corrupted uploads after a retried upload error - fixes #9722
    
    When an upload failed part way through with a retryable error (eg a
    502 from the block storage servers) the pacer retried the whole upload
    call with the same input stream. The stream had already been partially
    consumed, so the retry re-created the upload draft and committed just
    the remainder of the stream as a complete file, silently truncating
    it. With restic over serve restic this corrupted the repository as the
    truncated pack was reported as successfully uploaded.
    
    This fixes it by using CallNoRetry for the upload, as the other
    backends do, so retryable errors are returned wrapped in a RetryError
    for the caller to retry the upload with a fresh stream.

commit 9b13247ba8ea1d2afbe97d1a127e4ae3523819bd
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Mon Aug 3 23:03:15 2026 +0100

    operations: fix silent truncation of streaming uploads whose source ends early
    
    Uploads through RcatSize with a known size - used by rcat --size, the
    rc operations/uploadfile and the serve backends, eg serve restic - did
    not check the size of the uploaded object. If the source stream ended
    before the declared size worth of data had been read, the truncated
    object was reported as a successful upload. This could corrupt data
    for callers which trust the result, eg a restic repository accessed
    via serve restic (see #9722).
    
    This adds the same size check operations.Copy performs after a copy,
    respecting --ignore-size and backends which do not report sizes.

commit 1318962a963b6b8a4147f3babe06b93bf37d8b45
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Tue Aug 4 18:28:38 2026 +0100

    docs: fix width of sponsor images on very big screens

commit 52b5c4d6c2610c094b74727ac3ca29f3f142ed27
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Tue Aug 4 19:28:52 2026 +0100

    Add Anton Karpov to contributors

commit 6cb4732cc349dd0c05cc96d8ceac7ba7ddb96945
Author: Anton Karpov <karpovantonme@gmail.com>
Date:   Mon Aug 3 03:45:43 2026 +0300

    docs: use the --dump form for the obsolete --dump-* flags
    
    The SFTP page said `--dump-auth`, which no longer exists: it became a
    value of `--dump`, so the docs asked for a flag rclone would reject.
    
    The same line, and a line in the Swift troubleshooting section, also
    used `--dump-headers` and `--dump-bodies`. Those still parse, but
    SetFlags logs "--dump-headers is obsolete - please use --dump headers
    instead", so the docs were steering readers onto a deprecated form.
    
    The generated flag listings in docs/content/flags.md and
    docs/content/commands/rclone.md are left alone: those flags do still
    exist, so `--help` output should keep showing them.

commit 18fa445ffcad3abccb86136938965b2765c63c62
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Mon Aug 3 17:45:42 2026 +0100

    compress: fix corrupted objects being created when the source ends early
    
    When the source supplied fewer bytes than its declared size, the
    compressed data file was stored under a name containing the declared
    size while the metadata recorded the actual number of bytes read.
    NewObject looks the data file up by the size in the metadata, so the
    resulting object could never be read again, and the upload reported
    success.
    
    Check that the number of bytes read matches the declared size after
    uploading the data and before writing the metadata, and remove the
    data file and return an error if it does not.
    
    This was found by the new FsPutShortEOF integration test.

commit e0701daea005c9bf65e573ad416c711d23d3a2b1
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Sun Aug 2 18:25:46 2026 +0100

    dropbox: don't retry chunked upload requests when the upload has been cancelled
    
    The append loop retries everything once the upload session has
    started, so a cancelled context error was retried through all the low
    level retries with exponential backoff before the upload gave up.

commit bff17664ad2dc68956e4ed1099a754b0573c088f
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Sun Aug 2 18:25:32 2026 +0100

    dropbox: fix chunked uploads of truncated files never finishing - fixes #9704
    
    A source which returned EOF before supplying as many bytes as it
    declared would either commit a truncated file (if the shortfall was
    within the final chunk) or loop forever appending empty chunks to the
    upload session. Return an error wrapping io.ErrUnexpectedEOF instead.
    
    Note that all dropbox uploads use the chunked upload path with the
    default batch_mode of sync, so this affected uploads of every size.

commit 03f8582a55f5ab090279b99a3cf552779744b263
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Sun Aug 2 12:53:57 2026 +0100

    fstests: check uploads terminate when the source ends before its declared size
    
    A source reader which returns EOF before supplying as many bytes as it
    declared should not cause a backend Put to hang, panic or create an
    object claiming the declared size.
    
    The layers above detect a truncated transfer by comparing sizes after
    the upload, so a backend may either return an error or create a
    shorter object.
    
    See #9704

commit 5024425ba8bde8cf7f9ab152abc0d7979fd3650b
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Mon Aug 3 20:57:53 2026 +0100

    Add alliasgher to contributors

commit ea9a64c751839f59f5b2be8f83080c6751529b61
Author: alliasgher <alliasgher123@gmail.com>
Date:   Sun Aug 2 22:50:21 2026 +0500

    smb: reuse the upload connection for SetModTime - fixes #9675
    
    Object.Update held its connection until the deferred putConnection ran at
    function exit, so the SetModTime it does at the end of every upload had to take
    a second connection from the pool, dialling a whole new SMB session when the
    pool was empty. With N transfers in flight the pool grew to roughly 2N sessions
    for no reason.
    
    Return the connection as soon as the file is closed. At that point the upload
    has succeeded and remove() can no longer be reached, so nothing else needs it,
    and SetModTime picks the same connection straight back out of the pool.
    putConnection nils the pointer, so the deferred putConnection becomes a no-op
    and the connection is not returned twice.

commit 065af8963550268a9ad426528638299e06333465
Author: alliasgher <alliasgher123@gmail.com>
Date:   Sun Aug 2 18:46:48 2026 +0500

    drive: don't list trashed files when removing a directory into the trash - fixes #9681
    
    purgeCheck listed a directory's children with includeAll set, so the Drive API
    returned trashed children as well as live ones. The only thing that came of
    that was the trashedFiles flag, which is used solely to decide whether to trash
    the directory or delete it permanently, and when use_trash is on the directory
    gets trashed either way.
    
    That made the common case pay for nothing: after trashing N files in a
    directory, removing the now empty directory paged through all N trashed entries,
    about one API call and pacer delay per 1000, instead of running a single query
    that returns nothing.
    
    Ask the server to filter out trashed children when the directory is going to be
    trashed anyway. Hard deletes still enumerate them, since there the distinction
    decides whether the directory can be removed permanently (#1040), and
    --drive-trashed-only is left alone because it deliberately lists trashed items.

commit 3f9d583cffd94105f3ae2cde2cc6c0d5a2c9d631
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Sat Aug 1 19:42:58 2026 +0100

    gitannex: reduce subprocess launches in end to end test setup
    
    Write the git configuration for each test's fake home directory as a
    file instead of running three "git config --global" commands, and drop
    the "git annex version" invocation from repository setup. This removes
    four subprocess launches from each of the fifteen test cases.

commit b6a82ee56c4379695a35e1136ac0c6d25578bc2e
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Sat Aug 1 19:42:17 2026 +0100

    gitannex: run the end to end test functions in parallel
    
    The subtests within each end to end test function already run in
    parallel, but the three test functions themselves ran one after
    another.
    
    Marking the functions parallel lets all their subtests overlap.

commit c9cd065458e81c9165a708155194ee90130812c9
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Sat Aug 1 19:41:38 2026 +0100

    gitannex: skip end to end tests under the race detector
    
    The end to end tests exercise rclone via a separate subprocess spawned
    by git-annex, and that subprocess is not built with race
    instrumentation.
    
    Running them in the race test therefore adds several minutes to CI
    without providing any race coverage. The unit tests in this package
    still run under the race detector.

commit b3168b3ad6ef4dc24ffd2970a8bde8aae25c6946
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Sat Aug 1 19:41:00 2026 +0100

    gitannex: speed up the end to end tests with testremote --fast
    
    Run the full "git annex testremote" suite for a single layout mode and
    use "testremote --fast" for the rest.
    
    The full suite repeats the same protocol operations across a matrix of
    key sizes and chunk configurations, which exercises client side
    git-annex behaviour rather than rclone.

commit c4e82700cb9fef16ae1b41354fd2c42abb7dbe76
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Sat Aug 1 19:40:23 2026 +0100

    gitannex: speed up the end to end tests by removing redundant checks
    
    The migration test ran the full "git annex testremote" suite for every
    layout mode after verifying the migration with "git annex fsck".
    
    The fsck calls already prove the migrated data is accessible via the
    builtin special remote, and TestEndToEnd covers the special remote
    protocol with testremote, so the extra five full testremote runs
    duplicated coverage at a cost of tens of seconds each on CI.

commit 01d32dbde5b429970687d0254e514eecc3d9cec7
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Sat Aug 1 13:45:45 2026 +0100

    build: fix intermittent CI failures by raising the test timeout to 20m
    
    The cmd/gitannex end to end tests routinely take 230-530s and on slow
    CI runners the package exceeds the go test default timeout of 10m.
    
    Raise the per-package timeout to 20m in quicktest and racequicktest to
    give slow runners headroom.

commit c59083f3b45058ef82cbecb1a14548515baff457
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Sun Aug 2 18:25:01 2026 +0100

    Add debaditya to contributors

commit a15551a838ae7ca41c0685cdcb43a53d51f329de
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Sun Aug 2 18:25:01 2026 +0100

    Add Loi Nguyen to contributors

commit 40dbc9ba229d456b46a07ad09bd518aca01c2ba0
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Sun Aug 2 18:25:01 2026 +0100

    Add am-at-enrollvb to contributors

commit ce8caf0daa1110621fa5543d7e025b03bae43446
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Sun Aug 2 18:25:01 2026 +0100

    Add SillyZir to contributors

commit 49e41e7f0be70438827c7453f08e061545c23d7c
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Sun Aug 2 18:25:01 2026 +0100

    Add acoeur to contributors

commit 23f1dbfe503de46d4fe92eb9eccf6c735e480f59
Author: Loi Nguyen <vanloi999@gmail.com>
Date:   Sun Aug 2 17:53:25 2026 +0700

    smb: test closing failed dial connections
    
    Followup to:
    
    74f9f182aa0b3050 smb: fix TCP connection leak when connection setup fails - #9678

commit c97ab80ca1c803db47bda45d1b02736a44010245
Author: debaditya <82204129+DebadityaHait@users.noreply.github.com>
Date:   Sun Aug 2 16:16:27 2026 +0530

    dropbox: fix context cancellation (e.g. --max-duration limit) not stopping in-flight requests
    
    This switches the calls to the dropbox SDK over to use the context taking
    variants. This allows context cancellation to propagate properly.
    
    Fixes #9688

commit 1d03a771727b6b158d4675442c41d3280d9eee88
Author: Loi Nguyen <vanloi999@gmail.com>
Date:   Fri Jul 31 13:58:04 2026 +0700

    vfs: make poll shutdown lifecycle deterministic

commit d5275c4ebb82ef7ffe8406c2049f29c78a8b6446
Author: Loi Nguyen <vanloi999@gmail.com>
Date:   Fri Jul 31 12:39:05 2026 +0700

    vfs: test poll interval update lifecycle

commit f132aef2958f21d127d614db8ea150d33eef4412
Author: Loi Nguyen <vanloi999@gmail.com>
Date:   Fri Jul 31 12:38:22 2026 +0700

    vfs: synchronize poll updates with shutdown - fixes #9689

commit f4e231b094f9bb26b2d8cc3c081c8601ab4fa8fd
Author: Loi Nguyen <vanloi999@gmail.com>
Date:   Sat Aug 1 18:36:59 2026 +0700

    drive: fetch metadata permissions concurrently - fixes #9682
    
    Before this change permission metadata fetches were serialized by the permission cache mutex.

commit 8c8062da782e7cb5e6dca977736350aee6b5a7be
Author: Loi Nguyen <vanloi999@gmail.com>
Date:   Sat Aug 1 18:33:32 2026 +0700

    dropbox: preserve Paper export paths on lookup - fixes #9691
    
    Direct lookups of exported Dropbox Paper files retained the
    caller-visible extension before export metadata processing appended it
    again. Track when metadata was resolved through an export path so the
    object keeps the requested remote name while listing behavior remains
    unchanged.

commit 7f6207fae2386d747347199936d56a105cbdf557
Author: Loi Nguyen <vanloi999@gmail.com>
Date:   Fri Jul 31 00:06:00 2026 +0700

    lib/batcher: prevent commits racing shutdown - fixes #9687

commit 5dd34275dcbb485de2f6f7ce5d52242237c191f3
Author: am-at-enrollvb <arthur.melton@enrollvb.com>
Date:   Sat Aug 1 11:25:06 2026 +0000

    serve: pass the client IP address to the auth proxy - fixes #4499
    
    The auth proxy was only given the user and their password or public
    key, so a proxy program had no way to restrict logins to particular
    networks, or to record where an authentication attempt came from.
    
    The JSON sent to the program now has a client_ip key holding the bare
    IP the client connected from, with the port stripped so IPv6 arrives
    as 2001:db8::1 rather than [2001:db8::1]:52344. An IPv4-mapped IPv6
    address is reported as plain IPv4 so that a client arriving over a
    dual-stack listener still matches IPv4 networks. The key is omitted
    when the client has no IP address.
    
    The IP is also mixed into the backend cache key. That is needed as the
    program is only run on a cache miss, so a client from a
    non-allowlisted address presenting valid credentials within the 5
    minute cache lifetime would get a cache hit and be let in without the
    program being consulted at all.

commit 7804c1b315a5e74378611aada900c791a9fa7cd8
Author: SillyZir <269283839+SillyZir@users.noreply.github.com>
Date:   Mon Jul 20 22:49:57 2026 -0400

    serve nfs: fix EIO when creating symlinks with --vfs-links
    
    The macOS NFS client sends SETATTR after SYMLINK, which arrives as
    Chmod/Chown on the link path. These opened the target with vfs.Open,
    which follows symlinks - a freshly created symlink usually dangles, so
    the open failed with ENOENT, surfaced to the client as NFS3ERR_IO even
    though the link was created.
    
    Add path-based VFS.Chmod and VFS.Chown mirroring VFS.Chtimes. They do
    not follow symlinks (lstat semantics, matching VFS.Stat) and return
    ENOSYS when the node exists, since the VFS stores neither permissions
    nor ownership; serve nfs calls them and masks ENOSYS as before.
    
    Fixes #9627

commit 060b9975951d1d9dfa9f576384934d46b02d99f6
Author: acoeur <7315110+forestrock@users.noreply.github.com>
Date:   Fri Jul 31 19:41:46 2026 -0400

    azureblob: enable on Solaris
    
    The azure SDK didn't used to compile on Solaris, but now it does.

commit 39d8e83a12c0d265ceee981cd4495cf6ac4890f5
Author: Nick Craig-Wood <nick@craig-wood.com>
Date:   Fri Jul 31 18:21:36 2026 +0100

    Start v1.76.0-DEV development
