Compare commits
50 Commits
master
...
branch-v1.
Author | SHA1 | Date |
---|---|---|
Nick Craig-Wood | ffcaa6cd92 | |
Nick Craig-Wood | 98e81a6c2b | |
Nick Craig-Wood | 9e60a065b4 | |
nielash | 95e18bdc6f | |
dependabot[bot] | a4c7b3da15 | |
Tera | be10debded | |
kapitainsky | a7cb8b71f0 | |
Harshit Budhraja | 322d683997 | |
Harshit Budhraja | 964753b2d5 | |
Nick Craig-Wood | 8b3bd74565 | |
Nick Craig-Wood | c394786c95 | |
Nick Craig-Wood | 824d01065a | |
Nick Craig-Wood | 07bf3a4ccc | |
dependabot[bot] | 19274ed78d | |
Nick Craig-Wood | 6276c7123a | |
Nick Craig-Wood | 863b4125c3 | |
Vincent Murphy | 576ecf559d | |
Nick Craig-Wood | cfd581a986 | |
Nick Craig-Wood | ad8bde69b3 | |
Nick Craig-Wood | 771ec943f2 | |
Nick Craig-Wood | 4a297b35e5 | |
Nick Craig-Wood | 6b61967507 | |
Nick Craig-Wood | e174c8f822 | |
Nick Craig-Wood | bff56d0b24 | |
Nick Craig-Wood | 59ff59e45a | |
dependabot[bot] | c27ab0211c | |
rkonfj | 9979b9d082 | |
WeidiDeng | 2be627aa56 | |
Nick Craig-Wood | 3f7abd278d | |
nielash | 489c36b101 | |
albertony | df65aced2e | |
rarspace01 | 141e97edb8 | |
Oksana | 8571eaf425 | |
Manoj Ghosh | 6ccbebd903 | |
Nick Craig-Wood | 8b8156f7c3 | |
keongalvin | a0b19fefdf | |
Nick Craig-Wood | d0e68480be | |
Nick Craig-Wood | ab6c5252f1 | |
emyarod | 29a23c5e18 | |
dependabot[bot] | caacf55b69 | |
Eli Orzitzer | f62ae71b4c | |
Nick Craig-Wood | 4245a042c0 | |
Nick Craig-Wood | 3f3245fcd4 | |
Nick Craig-Wood | 5742a61d23 | |
ben-ba | 768c57c1ba | |
Manoj Ghosh | 9f42ed3380 | |
halms | 40a7edab2d | |
Nick Craig-Wood | 5a22dad9a7 | |
Nick Craig-Wood | b3c2985544 | |
Nick Craig-Wood | 938753ddc3 |
|
@ -104,7 +104,7 @@ jobs:
|
|||
fetch-depth: 0
|
||||
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v4
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: ${{ matrix.go }}
|
||||
check-latest: true
|
||||
|
@ -168,7 +168,7 @@ jobs:
|
|||
env
|
||||
|
||||
- name: Go module cache
|
||||
uses: actions/cache@v3
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ~/go/pkg/mod
|
||||
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
|
||||
|
@ -241,7 +241,7 @@ jobs:
|
|||
|
||||
# Run govulncheck on the latest go version, the one we build binaries with
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v4
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: '1.21'
|
||||
check-latest: true
|
||||
|
@ -266,12 +266,12 @@ jobs:
|
|||
|
||||
# Upgrade together with NDK version
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v4
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: '1.21'
|
||||
|
||||
- name: Go module cache
|
||||
uses: actions/cache@v3
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ~/go/pkg/mod
|
||||
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
FROM golang AS builder
|
||||
FROM golang:alpine AS builder
|
||||
|
||||
COPY . /go/src/github.com/rclone/rclone/
|
||||
WORKDIR /go/src/github.com/rclone/rclone/
|
||||
|
||||
RUN apk add --no-cache make bash gawk git
|
||||
RUN \
|
||||
CGO_ENABLED=0 \
|
||||
make
|
||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -1,5 +1,7 @@
|
|||
[<img src="https://rclone.org/img/logo_on_light__horizontal_color.svg" width="50%" alt="rclone logo">](https://rclone.org/#gh-light-mode-only)
|
||||
[<img src="https://rclone.org/img/logo_on_dark__horizontal_color.svg" width="50%" alt="rclone logo">](https://rclone.org/#gh-dark-mode-only)
|
||||
[<img src="https://rclone.org/img/logos/warp-github-light.svg" title="Visit warp.dev to learn more." align="right">](https://www.warp.dev/?utm_source=github&utm_medium=referral&utm_campaign=rclone_20231103#gh-light-mode-only)
|
||||
[<img src="https://rclone.org/img/logos/warp-github-dark.svg" title="Visit warp.dev to learn more." align="right">](https://www.warp.dev/?utm_source=github&utm_medium=referral&utm_campaign=rclone_20231103#gh-dark-mode-only)
|
||||
|
||||
[Website](https://rclone.org) |
|
||||
[Documentation](https://rclone.org/docs/) |
|
||||
|
@ -46,6 +48,7 @@ Rclone *("rsync for cloud storage")* is a command-line program to sync files and
|
|||
* HiDrive [:page_facing_up:](https://rclone.org/hidrive/)
|
||||
* HTTP [:page_facing_up:](https://rclone.org/http/)
|
||||
* Huawei Cloud Object Storage Service(OBS) [:page_facing_up:](https://rclone.org/s3/#huawei-obs)
|
||||
* ImageKit [:page_facing_up:](https://rclone.org/imagekit/)
|
||||
* Internet Archive [:page_facing_up:](https://rclone.org/internetarchive/)
|
||||
* Jottacloud [:page_facing_up:](https://rclone.org/jottacloud/)
|
||||
* IBM COS S3 [:page_facing_up:](https://rclone.org/s3/#ibm-cos-s3)
|
||||
|
@ -120,6 +123,7 @@ These backends adapt or modify other storage providers
|
|||
* Partial syncs supported on a whole file basis
|
||||
* [Copy](https://rclone.org/commands/rclone_copy/) mode to just copy new/changed files
|
||||
* [Sync](https://rclone.org/commands/rclone_sync/) (one way) mode to make a directory identical
|
||||
* [Bisync](https://rclone.org/bisync/) (two way) to keep two directories in sync bidirectionally
|
||||
* [Check](https://rclone.org/commands/rclone_check/) mode to check for file hash equality
|
||||
* Can sync to and from network, e.g. two different cloud accounts
|
||||
* Optional large file chunking ([Chunker](https://rclone.org/chunker/))
|
||||
|
|
39
RELEASE.md
39
RELEASE.md
|
@ -124,32 +124,21 @@ Cherry pick any changes back to master and the stable branch if it is active.
|
|||
|
||||
## Making a manual build of docker
|
||||
|
||||
The rclone docker image should autobuild on via GitHub actions. If it doesn't
|
||||
or needs to be updated then rebuild like this.
|
||||
|
||||
See: https://github.com/ilteoood/docker_buildx/issues/19
|
||||
See: https://github.com/ilteoood/docker_buildx/blob/master/scripts/install_buildx.sh
|
||||
To do a basic build of rclone's docker image to debug builds locally:
|
||||
|
||||
```
|
||||
docker buildx build --load -t rclone/rclone:testing --progress=plain .
|
||||
docker run --rm rclone/rclone:testing version
|
||||
```
|
||||
|
||||
To test the multipatform build
|
||||
|
||||
```
|
||||
docker buildx build -t rclone/rclone:testing --progress=plain --platform linux/amd64,linux/386,linux/arm64,linux/arm/v7,linux/arm/v6 .
|
||||
```
|
||||
|
||||
To make a full build then set the tags correctly and add `--push`
|
||||
|
||||
```
|
||||
git co v1.54.1
|
||||
docker pull golang
|
||||
export DOCKER_CLI_EXPERIMENTAL=enabled
|
||||
docker buildx create --name actions_builder --use
|
||||
docker run --rm --privileged docker/binfmt:820fdd95a9972a5308930a2bdfb8573dd4447ad3
|
||||
docker run --rm --privileged multiarch/qemu-user-static --reset -p yes
|
||||
SUPPORTED_PLATFORMS=$(docker buildx inspect --bootstrap | grep 'Platforms:*.*' | cut -d : -f2,3)
|
||||
echo "Supported platforms: $SUPPORTED_PLATFORMS"
|
||||
docker buildx build --platform linux/amd64,linux/386,linux/arm64,linux/arm/v7 -t rclone/rclone:1.54.1 -t rclone/rclone:1.54 -t rclone/rclone:1 -t rclone/rclone:latest --push .
|
||||
docker buildx stop actions_builder
|
||||
```
|
||||
|
||||
### Old build for linux/amd64 only
|
||||
|
||||
```
|
||||
docker pull golang
|
||||
docker build --rm --ulimit memlock=67108864 -t rclone/rclone:1.52.0 -t rclone/rclone:1.52 -t rclone/rclone:1 -t rclone/rclone:latest .
|
||||
docker push rclone/rclone:1.52.0
|
||||
docker push rclone/rclone:1.52
|
||||
docker push rclone/rclone:1
|
||||
docker push rclone/rclone:latest
|
||||
```
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
"context"
|
||||
"crypto/md5"
|
||||
"encoding/base64"
|
||||
"encoding/binary"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
|
@ -1966,21 +1967,9 @@ func (rs *readSeekCloser) Close() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// increment the array as LSB binary
|
||||
func increment(xs *[8]byte) {
|
||||
for i, digit := range xs {
|
||||
newDigit := digit + 1
|
||||
xs[i] = newDigit
|
||||
if newDigit >= digit {
|
||||
// exit if no carry
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// record chunk number and id for Close
|
||||
type azBlock struct {
|
||||
chunkNumber int
|
||||
chunkNumber uint64
|
||||
id string
|
||||
}
|
||||
|
||||
|
@ -1992,7 +1981,6 @@ type azChunkWriter struct {
|
|||
ui uploadInfo
|
||||
blocksMu sync.Mutex // protects the below
|
||||
blocks []azBlock // list of blocks for finalize
|
||||
binaryBlockID [8]byte // block counter as LSB first 8 bytes
|
||||
o *Object
|
||||
}
|
||||
|
||||
|
@ -2081,13 +2069,14 @@ func (w *azChunkWriter) WriteChunk(ctx context.Context, chunkNumber int, reader
|
|||
transactionalMD5 := md5sum[:]
|
||||
|
||||
// increment the blockID and save the blocks for finalize
|
||||
increment(&w.binaryBlockID)
|
||||
blockID := base64.StdEncoding.EncodeToString(w.binaryBlockID[:])
|
||||
var binaryBlockID [8]byte // block counter as LSB first 8 bytes
|
||||
binary.LittleEndian.PutUint64(binaryBlockID[:], uint64(chunkNumber))
|
||||
blockID := base64.StdEncoding.EncodeToString(binaryBlockID[:])
|
||||
|
||||
// Save the blockID for the commit
|
||||
w.blocksMu.Lock()
|
||||
w.blocks = append(w.blocks, azBlock{
|
||||
chunkNumber: chunkNumber,
|
||||
chunkNumber: uint64(chunkNumber),
|
||||
id: blockID,
|
||||
})
|
||||
w.blocksMu.Unlock()
|
||||
|
@ -2152,9 +2141,20 @@ func (w *azChunkWriter) Close(ctx context.Context) (err error) {
|
|||
return w.blocks[i].chunkNumber < w.blocks[j].chunkNumber
|
||||
})
|
||||
|
||||
// Create a list of block IDs
|
||||
// Create and check a list of block IDs
|
||||
blockIDs := make([]string, len(w.blocks))
|
||||
for i := range w.blocks {
|
||||
if w.blocks[i].chunkNumber != uint64(i) {
|
||||
return fmt.Errorf("internal error: expecting chunkNumber %d but got %d", i, w.blocks[i].chunkNumber)
|
||||
}
|
||||
chunkBytes, err := base64.StdEncoding.DecodeString(w.blocks[i].id)
|
||||
if err != nil {
|
||||
return fmt.Errorf("internal error: bad block ID: %w", err)
|
||||
}
|
||||
chunkNumber := binary.LittleEndian.Uint64(chunkBytes)
|
||||
if w.blocks[i].chunkNumber != chunkNumber {
|
||||
return fmt.Errorf("internal error: expecting decoded chunkNumber %d but got %d", w.blocks[i].chunkNumber, chunkNumber)
|
||||
}
|
||||
blockIDs[i] = w.blocks[i].id
|
||||
}
|
||||
|
||||
|
|
|
@ -17,21 +17,3 @@ func (f *Fs) InternalTest(t *testing.T) {
|
|||
enabled = f.Features().GetTier
|
||||
assert.True(t, enabled)
|
||||
}
|
||||
|
||||
func TestIncrement(t *testing.T) {
|
||||
for _, test := range []struct {
|
||||
in [8]byte
|
||||
want [8]byte
|
||||
}{
|
||||
{[8]byte{0, 0, 0, 0}, [8]byte{1, 0, 0, 0}},
|
||||
{[8]byte{0xFE, 0, 0, 0}, [8]byte{0xFF, 0, 0, 0}},
|
||||
{[8]byte{0xFF, 0, 0, 0}, [8]byte{0, 1, 0, 0}},
|
||||
{[8]byte{0, 1, 0, 0}, [8]byte{1, 1, 0, 0}},
|
||||
{[8]byte{0xFF, 0xFF, 0xFF, 0xFE}, [8]byte{0, 0, 0, 0xFF}},
|
||||
{[8]byte{0xFF, 0xFF, 0xFF, 0xFF}, [8]byte{0, 0, 0, 0, 1}},
|
||||
{[8]byte{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, [8]byte{0, 0, 0, 0, 0, 0, 0}},
|
||||
} {
|
||||
increment(&test.in)
|
||||
assert.Equal(t, test.want, test.in)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -65,7 +65,7 @@ import (
|
|||
const (
|
||||
maxFileSize = 4 * fs.Tebi
|
||||
defaultChunkSize = 4 * fs.Mebi
|
||||
storageDefaultBaseURL = "core.windows.net" // FIXME not sure this is correct
|
||||
storageDefaultBaseURL = "file.core.windows.net"
|
||||
)
|
||||
|
||||
func init() {
|
||||
|
|
|
@ -325,6 +325,14 @@ func NewFs(ctx context.Context, name, rpath string, m configmap.Mapper) (fs.Fs,
|
|||
}
|
||||
}
|
||||
|
||||
// Correct root if definitely pointing to a file
|
||||
if err == fs.ErrorIsFile {
|
||||
f.root = path.Dir(f.root)
|
||||
if f.root == "." || f.root == "/" {
|
||||
f.root = ""
|
||||
}
|
||||
}
|
||||
|
||||
// Note 1: the features here are ones we could support, and they are
|
||||
// ANDed with the ones from wrappedFs.
|
||||
// Note 2: features.Fill() points features.PutStream to our PutStream,
|
||||
|
|
|
@ -14,6 +14,7 @@ import (
|
|||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"path"
|
||||
"regexp"
|
||||
"strings"
|
||||
"time"
|
||||
|
@ -172,6 +173,13 @@ func NewFs(ctx context.Context, name, rpath string, m configmap.Mapper) (fs.Fs,
|
|||
opt: *opt,
|
||||
mode: compressionModeFromName(opt.CompressionMode),
|
||||
}
|
||||
// Correct root if definitely pointing to a file
|
||||
if err == fs.ErrorIsFile {
|
||||
f.root = path.Dir(f.root)
|
||||
if f.root == "." || f.root == "/" {
|
||||
f.root = ""
|
||||
}
|
||||
}
|
||||
// the features here are ones we could support, and they are
|
||||
// ANDed with the ones from wrappedFs
|
||||
f.features = (&fs.Features{
|
||||
|
|
|
@ -253,6 +253,13 @@ func NewFs(ctx context.Context, name, rpath string, m configmap.Mapper) (fs.Fs,
|
|||
cipher: cipher,
|
||||
}
|
||||
cache.PinUntilFinalized(f.Fs, f)
|
||||
// Correct root if definitely pointing to a file
|
||||
if err == fs.ErrorIsFile {
|
||||
f.root = path.Dir(f.root)
|
||||
if f.root == "." || f.root == "/" {
|
||||
f.root = ""
|
||||
}
|
||||
}
|
||||
// the features here are ones we could support, and they are
|
||||
// ANDed with the ones from wrappedFs
|
||||
f.features = (&fs.Features{
|
||||
|
|
|
@ -1231,18 +1231,21 @@ func (f *Fs) About(ctx context.Context) (usage *fs.Usage, err error) {
|
|||
return nil, err
|
||||
}
|
||||
var total uint64
|
||||
var used = q.Used
|
||||
if q.Allocation != nil {
|
||||
if q.Allocation.Individual != nil {
|
||||
total += q.Allocation.Individual.Allocated
|
||||
}
|
||||
if q.Allocation.Team != nil {
|
||||
total += q.Allocation.Team.Allocated
|
||||
// Override used with Team.Used as this includes q.Used already
|
||||
used = q.Allocation.Team.Used
|
||||
}
|
||||
}
|
||||
usage = &fs.Usage{
|
||||
Total: fs.NewUsageValue(int64(total)), // quota of bytes that can be used
|
||||
Used: fs.NewUsageValue(int64(q.Used)), // bytes in use
|
||||
Free: fs.NewUsageValue(int64(total - q.Used)), // bytes which can be uploaded before reaching the quota
|
||||
Used: fs.NewUsageValue(int64(used)), // bytes in use
|
||||
Free: fs.NewUsageValue(int64(total - used)), // bytes which can be uploaded before reaching the quota
|
||||
}
|
||||
return usage, nil
|
||||
}
|
||||
|
|
|
@ -1143,6 +1143,9 @@ func (o *Object) Update(ctx context.Context, in io.Reader, src fs.ObjectInfo, op
|
|||
info = results[0]
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to commit batch: %w", err)
|
||||
}
|
||||
|
||||
o.setMetaData(info)
|
||||
|
||||
|
|
|
@ -80,6 +80,14 @@ func (f *Fs) dbDump(ctx context.Context, full bool, root string) error {
|
|||
}
|
||||
root = fspath.JoinRootPath(remoteFs.Root(), f.Root())
|
||||
}
|
||||
if f.db == nil {
|
||||
if f.opt.MaxAge == 0 {
|
||||
fs.Errorf(f, "db not found. (disabled with max_age = 0)")
|
||||
} else {
|
||||
fs.Errorf(f, "db not found.")
|
||||
}
|
||||
return kv.ErrInactive
|
||||
}
|
||||
op := &kvDump{
|
||||
full: full,
|
||||
root: root,
|
||||
|
|
|
@ -114,6 +114,13 @@ func NewFs(ctx context.Context, fsname, rpath string, cmap configmap.Mapper) (fs
|
|||
root: rpath,
|
||||
opt: opt,
|
||||
}
|
||||
// Correct root if definitely pointing to a file
|
||||
if err == fs.ErrorIsFile {
|
||||
f.root = path.Dir(f.root)
|
||||
if f.root == "." || f.root == "/" {
|
||||
f.root = ""
|
||||
}
|
||||
}
|
||||
baseFeatures := baseFs.Features()
|
||||
f.fpTime = baseFs.Precision() != fs.ModTimeNotSupported
|
||||
|
||||
|
@ -411,7 +418,9 @@ func (f *Fs) DirMove(ctx context.Context, src fs.Fs, srcRemote, dstRemote string
|
|||
|
||||
// Shutdown the backend, closing any background tasks and any cached connections.
|
||||
func (f *Fs) Shutdown(ctx context.Context) (err error) {
|
||||
if f.db != nil {
|
||||
err = f.db.Stop(false)
|
||||
}
|
||||
if do := f.Fs.Features().Shutdown; do != nil {
|
||||
if err2 := do(ctx); err2 != nil {
|
||||
err = err2
|
||||
|
|
|
@ -60,9 +60,11 @@ func (f *Fs) testUploadFromCrypt(t *testing.T) {
|
|||
assert.NotNil(t, dst)
|
||||
|
||||
// check that hash was created
|
||||
if f.opt.MaxAge > 0 {
|
||||
hash, err = f.getRawHash(ctx, hashType, fileName, anyFingerprint, longTime)
|
||||
assert.NoError(t, err)
|
||||
assert.NotEmpty(t, hash)
|
||||
}
|
||||
//t.Logf("hash is %q", hash)
|
||||
_ = operations.Purge(ctx, f, dirName)
|
||||
}
|
||||
|
|
|
@ -37,4 +37,9 @@ func TestIntegration(t *testing.T) {
|
|||
opt.QuickTestOK = true
|
||||
}
|
||||
fstests.Run(t, &opt)
|
||||
// test again with MaxAge = 0
|
||||
if *fstest.RemoteName == "" {
|
||||
opt.ExtraConfig = append(opt.ExtraConfig, fstests.ExtraConfigItem{Name: "TestHasher", Key: "max_age", Value: "0"})
|
||||
fstests.Run(t, &opt)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,6 +27,7 @@ import (
|
|||
"github.com/rclone/rclone/fs/config/configstruct"
|
||||
"github.com/rclone/rclone/fs/config/obscure"
|
||||
"github.com/rclone/rclone/fs/fserrors"
|
||||
"github.com/rclone/rclone/fs/fshttp"
|
||||
"github.com/rclone/rclone/fs/hash"
|
||||
"github.com/rclone/rclone/fs/operations"
|
||||
"github.com/rclone/rclone/fs/walk"
|
||||
|
@ -688,6 +689,7 @@ type Fs struct {
|
|||
ci *fs.ConfigInfo // global config
|
||||
features *fs.Features // optional features
|
||||
srv *rest.Client // the connection to the OneDrive server
|
||||
unAuth *rest.Client // no authentication connection to the OneDrive server
|
||||
dirCache *dircache.DirCache // Map of directory path to directory id
|
||||
pacer *fs.Pacer // pacer for API calls
|
||||
tokenRenewer *oauthutil.Renew // renew the token on expiry
|
||||
|
@ -946,8 +948,9 @@ func NewFs(ctx context.Context, name, root string, m configmap.Mapper) (fs.Fs, e
|
|||
TokenURL: authEndpoint[opt.Region] + tokenPath,
|
||||
}
|
||||
|
||||
client := fshttp.NewClient(ctx)
|
||||
root = parsePath(root)
|
||||
oAuthClient, ts, err := oauthutil.NewClient(ctx, name, m, oauthConfig)
|
||||
oAuthClient, ts, err := oauthutil.NewClientWithBaseClient(ctx, name, m, oauthConfig, client)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to configure OneDrive: %w", err)
|
||||
}
|
||||
|
@ -961,6 +964,7 @@ func NewFs(ctx context.Context, name, root string, m configmap.Mapper) (fs.Fs, e
|
|||
driveID: opt.DriveID,
|
||||
driveType: opt.DriveType,
|
||||
srv: rest.NewClient(oAuthClient).SetRoot(rootURL),
|
||||
unAuth: rest.NewClient(client).SetRoot(rootURL),
|
||||
pacer: fs.NewPacer(ctx, pacer.NewDefault(pacer.MinSleep(minSleep), pacer.MaxSleep(maxSleep), pacer.DecayConstant(decayConstant))),
|
||||
hashType: QuickXorHashType,
|
||||
}
|
||||
|
@ -1241,10 +1245,14 @@ func (f *Fs) List(ctx context.Context, dir string) (entries fs.DirEntries, err e
|
|||
}
|
||||
err = f.listAll(ctx, directoryID, false, false, func(info *api.Item) error {
|
||||
entry, err := f.itemToDirEntry(ctx, dir, info)
|
||||
if err == nil {
|
||||
entries = append(entries, entry)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if entry == nil {
|
||||
return nil
|
||||
}
|
||||
entries = append(entries, entry)
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -1339,6 +1347,9 @@ func (f *Fs) ListR(ctx context.Context, dir string, callback fs.ListRCallback) (
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if entry == nil {
|
||||
return nil
|
||||
}
|
||||
err = list.Add(entry)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -2232,7 +2243,7 @@ func (o *Object) uploadFragment(ctx context.Context, url string, start int64, to
|
|||
Options: options,
|
||||
}
|
||||
_, _ = chunk.Seek(skip, io.SeekStart)
|
||||
resp, err = o.fs.srv.Call(ctx, &opts)
|
||||
resp, err = o.fs.unAuth.Call(ctx, &opts)
|
||||
if err != nil && resp != nil && resp.StatusCode == http.StatusRequestedRangeNotSatisfiable {
|
||||
fs.Debugf(o, "Received 416 error - reading current position from server: %v", err)
|
||||
pos, posErr := o.getPosition(ctx, url)
|
||||
|
|
|
@ -70,6 +70,9 @@ func newObjectStorageClient(ctx context.Context, opt *Options) (*objectstorage.O
|
|||
if opt.Region != "" {
|
||||
client.SetRegion(opt.Region)
|
||||
}
|
||||
if opt.Endpoint != "" {
|
||||
client.Host = opt.Endpoint
|
||||
}
|
||||
modifyClient(ctx, opt, &client.BaseClient)
|
||||
return &client, err
|
||||
}
|
||||
|
|
|
@ -399,13 +399,17 @@ func (o *Object) prepareUpload(ctx context.Context, src fs.ObjectInfo, options [
|
|||
func (o *Object) createMultipartUpload(ctx context.Context, putReq *objectstorage.PutObjectRequest) (
|
||||
uploadID string, existingParts map[int]objectstorage.MultipartUploadPartSummary, err error) {
|
||||
bucketName, bucketPath := o.split()
|
||||
f := o.fs
|
||||
if f.opt.AttemptResumeUpload {
|
||||
err = o.fs.makeBucket(ctx, bucketName)
|
||||
if err != nil {
|
||||
fs.Errorf(o, "failed to create bucket: %v, err: %v", bucketName, err)
|
||||
return uploadID, existingParts, err
|
||||
}
|
||||
if o.fs.opt.AttemptResumeUpload {
|
||||
fs.Debugf(o, "attempting to resume upload for %v (if any)", o.remote)
|
||||
resumeUploads, err := o.fs.findLatestMultipartUpload(ctx, bucketName, bucketPath)
|
||||
if err == nil && len(resumeUploads) > 0 {
|
||||
uploadID = *resumeUploads[0].UploadId
|
||||
existingParts, err = f.listMultipartUploadParts(ctx, bucketName, bucketPath, uploadID)
|
||||
existingParts, err = o.fs.listMultipartUploadParts(ctx, bucketName, bucketPath, uploadID)
|
||||
if err == nil {
|
||||
fs.Debugf(o, "resuming with existing upload id: %v", uploadID)
|
||||
return uploadID, existingParts, err
|
||||
|
|
|
@ -5678,6 +5678,13 @@ func (f *Fs) OpenChunkWriter(ctx context.Context, remote string, src fs.ObjectIn
|
|||
var mOut *s3.CreateMultipartUploadOutput
|
||||
err = f.pacer.Call(func() (bool, error) {
|
||||
mOut, err = f.c.CreateMultipartUploadWithContext(ctx, &mReq)
|
||||
if err == nil {
|
||||
if mOut == nil {
|
||||
err = fserrors.RetryErrorf("internal error: no info from multipart upload")
|
||||
} else if mOut.UploadId == nil {
|
||||
err = fserrors.RetryErrorf("internal error: no UploadId in multpart upload: %#v", *mOut)
|
||||
}
|
||||
}
|
||||
return f.shouldRetry(ctx, err)
|
||||
})
|
||||
if err != nil {
|
||||
|
|
|
@ -40,7 +40,7 @@ func (f *Fs) dial(ctx context.Context, network, addr string) (*conn, error) {
|
|||
},
|
||||
}
|
||||
|
||||
session, err := d.DialContext(ctx, tconn)
|
||||
session, err := d.DialConn(ctx, tconn, addr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -877,6 +877,13 @@ func NewFs(ctx context.Context, name, root string, m configmap.Mapper) (fs.Fs, e
|
|||
opt: *opt,
|
||||
upstreams: usedUpstreams,
|
||||
}
|
||||
// Correct root if definitely pointing to a file
|
||||
if fserr == fs.ErrorIsFile {
|
||||
f.root = path.Dir(f.root)
|
||||
if f.root == "." || f.root == "/" {
|
||||
f.root = ""
|
||||
}
|
||||
}
|
||||
err = upstream.Prepare(f.upstreams)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
|
@ -10,3 +10,4 @@
|
|||
<stoesser@yay-digital.de>
|
||||
<services+github@simjo.st>
|
||||
<seb•ɑƬ•chezwam•ɖɵʈ•org>
|
||||
<allllaboutyou@gmail.com>
|
|
@ -1,29 +1,38 @@
|
|||
//go:build darwin && !cmount
|
||||
// +build darwin,!cmount
|
||||
//go:build unix
|
||||
// +build unix
|
||||
|
||||
// Package nfsmount implements mounting functionality using serve nfs command
|
||||
//
|
||||
// NFS mount is only needed for macOS since it has no
|
||||
// support for FUSE-based file systems
|
||||
// This can potentially work on all unix like systems which can mount NFS.
|
||||
package nfsmount
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"net"
|
||||
"os/exec"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"github.com/rclone/rclone/cmd/mountlib"
|
||||
"github.com/rclone/rclone/cmd/serve/nfs"
|
||||
"github.com/rclone/rclone/fs"
|
||||
"github.com/rclone/rclone/fs/config/flags"
|
||||
"github.com/rclone/rclone/vfs"
|
||||
)
|
||||
|
||||
var (
|
||||
sudo = false
|
||||
)
|
||||
|
||||
func init() {
|
||||
cmd := mountlib.NewMountCommand("mount", false, mount)
|
||||
cmd.Aliases = append(cmd.Aliases, "nfsmount")
|
||||
mountlib.AddRc("nfsmount", mount)
|
||||
name := "nfsmount"
|
||||
cmd := mountlib.NewMountCommand(name, false, mount)
|
||||
cmd.Annotations["versionIntroduced"] = "v1.65"
|
||||
cmd.Annotations["status"] = "Experimental"
|
||||
mountlib.AddRc(name, mount)
|
||||
cmdFlags := cmd.Flags()
|
||||
flags.BoolVarP(cmdFlags, &sudo, "sudo", "", sudo, "Use sudo to run the mount command as root.", "")
|
||||
}
|
||||
|
||||
func mount(VFS *vfs.VFS, mountpoint string, opt *mountlib.Options) (asyncerrors <-chan error, unmount func() error, err error) {
|
||||
|
@ -42,24 +51,46 @@ func mount(VFS *vfs.VFS, mountpoint string, opt *mountlib.Options) (asyncerrors
|
|||
err = fmt.Errorf("cannot find port number in %s", s.Addr().String())
|
||||
return
|
||||
}
|
||||
optionsString := strings.Join(opt.ExtraOptions, ",")
|
||||
err = exec.Command("mount", fmt.Sprintf("-oport=%s,mountport=%s,%s", port, port, optionsString), "localhost:", mountpoint).Run()
|
||||
|
||||
// Options
|
||||
options := []string{
|
||||
"-o", fmt.Sprintf("port=%s", port),
|
||||
"-o", fmt.Sprintf("mountport=%s", port),
|
||||
}
|
||||
for _, option := range opt.ExtraOptions {
|
||||
options = append(options, "-o", option)
|
||||
}
|
||||
options = append(options, opt.ExtraFlags...)
|
||||
|
||||
cmd := []string{}
|
||||
if sudo {
|
||||
cmd = append(cmd, "sudo")
|
||||
}
|
||||
cmd = append(cmd, "mount")
|
||||
cmd = append(cmd, options...)
|
||||
cmd = append(cmd, "localhost:", mountpoint)
|
||||
fs.Debugf(nil, "Running mount command: %q", cmd)
|
||||
|
||||
out, err := exec.Command(cmd[0], cmd[1:]...).CombinedOutput()
|
||||
if err != nil {
|
||||
err = fmt.Errorf("failed to mount NFS volume %e", err)
|
||||
out = bytes.TrimSpace(out)
|
||||
err = fmt.Errorf("%s: failed to mount NFS volume: %v", out, err)
|
||||
return
|
||||
}
|
||||
asyncerrors = errChan
|
||||
unmount = func() error {
|
||||
var umountErr error
|
||||
var out []byte
|
||||
if runtime.GOOS == "darwin" {
|
||||
umountErr = exec.Command("diskutil", "umount", "force", mountpoint).Run()
|
||||
out, umountErr = exec.Command("diskutil", "umount", "force", mountpoint).CombinedOutput()
|
||||
} else {
|
||||
umountErr = exec.Command("umount", "-f", mountpoint).Run()
|
||||
out, umountErr = exec.Command("umount", "-f", mountpoint).CombinedOutput()
|
||||
}
|
||||
shutdownErr := s.Shutdown()
|
||||
VFS.Shutdown()
|
||||
if umountErr != nil {
|
||||
return fmt.Errorf("failed to umount the NFS volume %e", umountErr)
|
||||
out = bytes.TrimSpace(out)
|
||||
return fmt.Errorf("%s: failed to umount the NFS volume %e", out, umountErr)
|
||||
} else if shutdownErr != nil {
|
||||
return fmt.Errorf("failed to shutdown NFS server: %e", shutdownErr)
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
// Build for nfsmount for unsupported platforms to stop go complaining
|
||||
// about "no buildable Go source files "
|
||||
|
||||
//go:build !darwin || cmount
|
||||
// +build !darwin cmount
|
||||
//go:build !unix
|
||||
// +build !unix
|
||||
|
||||
// Package nfsmount implements mount command using NFS, not needed on most platforms
|
||||
// Package nfsmount implements mount command using NFS.
|
||||
package nfsmount
|
||||
|
|
|
@ -92,6 +92,7 @@ This feature is only available on Unix platforms.
|
|||
Annotations: map[string]string{
|
||||
"versionIntroduced": "v1.65",
|
||||
"groups": "Filter",
|
||||
"status": "Experimental",
|
||||
},
|
||||
Run: Run,
|
||||
}
|
||||
|
|
|
@ -36,7 +36,7 @@ together, if |--auth-proxy| is set the authorized keys option will be
|
|||
ignored.
|
||||
|
||||
There is an example program
|
||||
[bin/test_proxy.py](https://github.com/rclone/rclone/blob/master/test_proxy.py)
|
||||
[bin/test_proxy.py](https://github.com/rclone/rclone/blob/master/bin/test_proxy.py)
|
||||
in the rclone source code.
|
||||
|
||||
The program's job is to take a |user| and |pass| on the input and turn
|
||||
|
|
|
@ -77,13 +77,9 @@ func (b *s3Backend) ListBucket(bucket string, prefix *gofakes3.Prefix, page gofa
|
|||
}
|
||||
|
||||
response := gofakes3.NewObjectList()
|
||||
if b.vfs.Fs().Features().BucketBased || prefix.HasDelimiter && prefix.Delimiter != "/" {
|
||||
err = b.getObjectsListArbitrary(bucket, prefix, response)
|
||||
} else {
|
||||
path, remaining := prefixParser(prefix)
|
||||
err = b.entryListR(bucket, path, remaining, prefix.HasDelimiter, response)
|
||||
}
|
||||
|
||||
err = b.entryListR(bucket, path, remaining, prefix.HasDelimiter, response)
|
||||
if err == gofakes3.ErrNoSuchKey {
|
||||
// AWS just returns an empty list
|
||||
response = gofakes3.NewObjectList()
|
||||
|
@ -366,9 +362,7 @@ func (b *s3Backend) deleteObject(bucketName, objectName string) error {
|
|||
}
|
||||
|
||||
// FIXME: unsafe operation
|
||||
if b.vfs.Fs().Features().CanHaveEmptyDirectories {
|
||||
rmdirRecursive(fp, b.vfs)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
@ -1,16 +1,13 @@
|
|||
package s3
|
||||
|
||||
import (
|
||||
"context"
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
"github.com/Mikubill/gofakes3"
|
||||
"github.com/rclone/rclone/fs"
|
||||
"github.com/rclone/rclone/fs/walk"
|
||||
)
|
||||
|
||||
func (b *s3Backend) entryListR(bucket, fdPath, name string, acceptComPrefix bool, response *gofakes3.ObjectList) error {
|
||||
func (b *s3Backend) entryListR(bucket, fdPath, name string, addPrefix bool, response *gofakes3.ObjectList) error {
|
||||
fp := path.Join(bucket, fdPath)
|
||||
|
||||
dirEntries, err := getDirEntries(fp, b.vfs)
|
||||
|
@ -29,7 +26,7 @@ func (b *s3Backend) entryListR(bucket, fdPath, name string, acceptComPrefix bool
|
|||
}
|
||||
|
||||
if entry.IsDir() {
|
||||
if acceptComPrefix {
|
||||
if addPrefix {
|
||||
response.AddPrefix(gofakes3.URLEncode(objectPath))
|
||||
continue
|
||||
}
|
||||
|
@ -50,36 +47,3 @@ func (b *s3Backend) entryListR(bucket, fdPath, name string, acceptComPrefix bool
|
|||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// getObjectsList lists the objects in the given bucket.
|
||||
func (b *s3Backend) getObjectsListArbitrary(bucket string, prefix *gofakes3.Prefix, response *gofakes3.ObjectList) error {
|
||||
// ignore error - vfs may have uncommitted updates, such as new dir etc.
|
||||
_ = walk.ListR(context.Background(), b.vfs.Fs(), bucket, false, -1, walk.ListObjects, func(entries fs.DirEntries) error {
|
||||
for _, entry := range entries {
|
||||
entry := entry.(fs.Object)
|
||||
objName := entry.Remote()
|
||||
object := strings.TrimPrefix(objName, bucket)[1:]
|
||||
|
||||
var matchResult gofakes3.PrefixMatch
|
||||
if prefix.Match(object, &matchResult) {
|
||||
if matchResult.CommonPrefix {
|
||||
response.AddPrefix(gofakes3.URLEncode(object))
|
||||
continue
|
||||
}
|
||||
|
||||
item := &gofakes3.Content{
|
||||
Key: gofakes3.URLEncode(object),
|
||||
LastModified: gofakes3.NewContentTime(entry.ModTime(context.Background())),
|
||||
ETag: getFileHash(entry),
|
||||
Size: entry.Size(),
|
||||
StorageClass: gofakes3.StorageStandard,
|
||||
}
|
||||
response.Add(item)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -92,6 +92,7 @@ Rclone helps you:
|
|||
- Can use multi-threaded downloads to local disk
|
||||
- [Copy](/commands/rclone_copy/) new or changed files to cloud storage
|
||||
- [Sync](/commands/rclone_sync/) (one way) to make a directory identical
|
||||
- [Bisync](/bisync/) (two way) to keep two directories in sync bidirectionally
|
||||
- [Move](/commands/rclone_move/) files to cloud storage deleting the local after verification
|
||||
- [Check](/commands/rclone_check/) hashes and for missing/extra files
|
||||
- [Mount](/commands/rclone_mount/) your cloud storage as a network disk
|
||||
|
@ -130,6 +131,7 @@ WebDAV or S3, that work out of the box.)
|
|||
{{< provider name="Hetzner Storage Box" home="https://www.hetzner.com/storage/storage-box" config="/sftp/#hetzner-storage-box" >}}
|
||||
{{< provider name="HiDrive" home="https://www.strato.de/cloud-speicher/" config="/hidrive/" >}}
|
||||
{{< provider name="HTTP" home="https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol" config="/http/" >}}
|
||||
{{< provider name="ImageKit" home="https://imagekit.io" config="/imagekit/" >}}
|
||||
{{< provider name="Internet Archive" home="https://archive.org/" config="/internetarchive/" >}}
|
||||
{{< provider name="Jottacloud" home="https://www.jottacloud.com/en/" config="/jottacloud/" >}}
|
||||
{{< provider name="IBM COS S3" home="http://www.ibm.com/cloud/object-storage" config="/s3/#ibm-cos-s3" >}}
|
||||
|
|
|
@ -57,7 +57,7 @@ put them back in again.` >}}
|
|||
* Scott McGillivray <scott.mcgillivray@gmail.com>
|
||||
* Bjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>
|
||||
* Lukas Loesche <lukas@mesosphere.io>
|
||||
* emyarod <allllaboutyou@gmail.com>
|
||||
* emyarod <emyarod@users.noreply.github.com>
|
||||
* T.C. Ferguson <tcf909@gmail.com>
|
||||
* Brandur <brandur@mutelight.org>
|
||||
* Dario Giovannetti <dev@dariogiovannetti.net>
|
||||
|
|
|
@ -5,6 +5,68 @@ description: "Rclone Changelog"
|
|||
|
||||
# Changelog
|
||||
|
||||
## v1.65.2 - 2024-01-24
|
||||
|
||||
[See commits](https://github.com/rclone/rclone/compare/v1.65.1...v1.65.2)
|
||||
|
||||
* Bug Fixes
|
||||
* build: bump github.com/cloudflare/circl from 1.3.6 to 1.3.7 (dependabot)
|
||||
* docs updates (Nick Craig-Wood, kapitainsky, nielash, Tera, Harshit Budhraja)
|
||||
* VFS
|
||||
* Fix stale data when using `--vfs-cache-mode` full (Nick Craig-Wood)
|
||||
* Azure Blob
|
||||
* **IMPORTANT** Fix data corruption bug - see [#7590](https://github.com/rclone/rclone/issues/7590) (Nick Craig-Wood)
|
||||
|
||||
## v1.65.1 - 2024-01-08
|
||||
|
||||
[See commits](https://github.com/rclone/rclone/compare/v1.65.0...v1.65.1)
|
||||
|
||||
* Bug Fixes
|
||||
* build
|
||||
* Bump golang.org/x/crypto to fix ssh terrapin CVE-2023-48795 (dependabot)
|
||||
* Update to go1.21.5 to fix Windows path problems (Nick Craig-Wood)
|
||||
* Fix docker build on arm/v6 (Nick Craig-Wood)
|
||||
* install.sh: fix harmless error message on install (Nick Craig-Wood)
|
||||
* accounting: fix stats to show server side transfers (Nick Craig-Wood)
|
||||
* doc fixes (albertony, ben-ba, Eli Orzitzer, emyarod, keongalvin, rarspace01)
|
||||
* nfsmount: Compile for all unix oses, add `--sudo` and fix error/option handling (Nick Craig-Wood)
|
||||
* operations: Fix files moved by rclone move not being counted as transfers (Nick Craig-Wood)
|
||||
* oauthutil: Avoid panic when `*token` and `*ts.token` are the same (rkonfj)
|
||||
* serve s3: Fix listing oddities (Nick Craig-Wood)
|
||||
* VFS
|
||||
* Note that `--vfs-refresh` runs in the background (Nick Craig-Wood)
|
||||
* Azurefiles
|
||||
* Fix storage base url (Oksana)
|
||||
* Crypt
|
||||
* Fix rclone move a file over itself deleting the file (Nick Craig-Wood)
|
||||
* Chunker
|
||||
* Fix rclone move a file over itself deleting the file (Nick Craig-Wood)
|
||||
* Compress
|
||||
* Fix rclone move a file over itself deleting the file (Nick Craig-Wood)
|
||||
* Dropbox
|
||||
* Fix used space on dropbox team accounts (Nick Craig-Wood)
|
||||
* FTP
|
||||
* Fix multi-thread copy (WeidiDeng)
|
||||
* Googlephotos
|
||||
* Fix nil pointer exception when batch failed (Nick Craig-Wood)
|
||||
* Hasher
|
||||
* Fix rclone move a file over itself deleting the file (Nick Craig-Wood)
|
||||
* Fix invalid memory address error when MaxAge == 0 (nielash)
|
||||
* Onedrive
|
||||
* Fix error listing: unknown object type `<nil>` (Nick Craig-Wood)
|
||||
* Fix "unauthenticated: Unauthenticated" errors when uploading (Nick Craig-Wood)
|
||||
* Oracleobjectstorage
|
||||
* Fix object storage endpoint for custom endpoints (Manoj Ghosh)
|
||||
* Multipart copy create bucket if it doesn't exist. (Manoj Ghosh)
|
||||
* Protondrive
|
||||
* Fix CVE-2023-45286 / GHSA-xwh9-gc39-5298 (Nick Craig-Wood)
|
||||
* S3
|
||||
* Fix crash if no UploadId in multipart upload (Nick Craig-Wood)
|
||||
* Smb
|
||||
* Fix shares not listed by updating go-smb2 (halms)
|
||||
* Union
|
||||
* Fix rclone move a file over itself deleting the file (Nick Craig-Wood)
|
||||
|
||||
## v1.65.0 - 2023-11-26
|
||||
|
||||
[See commits](https://github.com/rclone/rclone/compare/v1.64.0...v1.65.0)
|
||||
|
|
|
@ -831,7 +831,7 @@ rclone [flags]
|
|||
--use-json-log Use json log format
|
||||
--use-mmap Use mmap allocator (see docs)
|
||||
--use-server-modtime Use server modified time instead of object metadata
|
||||
--user-agent string Set the user-agent to a specified string (default "rclone/v1.65.0")
|
||||
--user-agent string Set the user-agent to a specified string (default "rclone/v1.65.2")
|
||||
-v, --verbose count Print lots more stuff (repeat for more)
|
||||
-V, --version Print the version number
|
||||
--webdav-bearer-token string Bearer token instead of user/pass (e.g. a Macaroon)
|
||||
|
@ -895,6 +895,7 @@ rclone [flags]
|
|||
* [rclone move](/commands/rclone_move/) - Move files from source to dest.
|
||||
* [rclone moveto](/commands/rclone_moveto/) - Move file or directory from source to dest.
|
||||
* [rclone ncdu](/commands/rclone_ncdu/) - Explore a remote with a text based user interface.
|
||||
* [rclone nfsmount](/commands/rclone_nfsmount/) - Mount the remote as file system on a mountpoint.
|
||||
* [rclone obscure](/commands/rclone_obscure/) - Obscure password for use in the rclone config file.
|
||||
* [rclone purge](/commands/rclone_purge/) - Remove the path and all of its contents.
|
||||
* [rclone rc](/commands/rclone_rc/) - Run a command against a running rclone.
|
||||
|
|
|
@ -40,6 +40,10 @@ Run without a hash to see the list of all supported hashes, e.g.
|
|||
* whirlpool
|
||||
* crc32
|
||||
* sha256
|
||||
* dropbox
|
||||
* hidrive
|
||||
* mailru
|
||||
* quickxor
|
||||
|
||||
Then
|
||||
|
||||
|
|
|
@ -856,7 +856,7 @@ rclone mount remote:path /path/to/mountpoint [flags]
|
|||
--vfs-read-chunk-size SizeSuffix Read the source objects in chunks (default 128Mi)
|
||||
--vfs-read-chunk-size-limit SizeSuffix If greater than --vfs-read-chunk-size, double the chunk size after each chunk read, until the limit is reached ('off' is unlimited) (default off)
|
||||
--vfs-read-wait Duration Time to wait for in-sequence read before seeking (default 20ms)
|
||||
--vfs-refresh Refreshes the directory cache recursively on start
|
||||
--vfs-refresh Refreshes the directory cache recursively in the background on start
|
||||
--vfs-used-is-size rclone size Use the rclone size algorithm for Used size
|
||||
--vfs-write-back Duration Time to writeback files after last use when using cache (default 5s)
|
||||
--vfs-write-wait Duration Time to wait for in-sequence write before giving error (default 1s)
|
||||
|
|
|
@ -0,0 +1,904 @@
|
|||
---
|
||||
title: "rclone nfsmount"
|
||||
description: "Mount the remote as file system on a mountpoint."
|
||||
slug: rclone_nfsmount
|
||||
url: /commands/rclone_nfsmount/
|
||||
groups: Filter
|
||||
status: Experimental
|
||||
versionIntroduced: v1.65
|
||||
# autogenerated - DO NOT EDIT, instead edit the source code in cmd/nfsmount/ and as part of making a release run "make commanddocs"
|
||||
---
|
||||
# rclone nfsmount
|
||||
|
||||
Mount the remote as file system on a mountpoint.
|
||||
|
||||
## Synopsis
|
||||
|
||||
rclone nfsmount allows Linux, FreeBSD, macOS and Windows to
|
||||
mount any of Rclone's cloud storage systems as a file system with
|
||||
FUSE.
|
||||
|
||||
First set up your remote using `rclone config`. Check it works with `rclone ls` etc.
|
||||
|
||||
On Linux and macOS, you can run mount in either foreground or background (aka
|
||||
daemon) mode. Mount runs in foreground mode by default. Use the `--daemon` flag
|
||||
to force background mode. On Windows you can run mount in foreground only,
|
||||
the flag is ignored.
|
||||
|
||||
In background mode rclone acts as a generic Unix mount program: the main
|
||||
program starts, spawns background rclone process to setup and maintain the
|
||||
mount, waits until success or timeout and exits with appropriate code
|
||||
(killing the child process if it fails).
|
||||
|
||||
On Linux/macOS/FreeBSD start the mount like this, where `/path/to/local/mount`
|
||||
is an **empty** **existing** directory:
|
||||
|
||||
rclone nfsmount remote:path/to/files /path/to/local/mount
|
||||
|
||||
On Windows you can start a mount in different ways. See [below](#mounting-modes-on-windows)
|
||||
for details. If foreground mount is used interactively from a console window,
|
||||
rclone will serve the mount and occupy the console so another window should be
|
||||
used to work with the mount until rclone is interrupted e.g. by pressing Ctrl-C.
|
||||
|
||||
The following examples will mount to an automatically assigned drive,
|
||||
to specific drive letter `X:`, to path `C:\path\parent\mount`
|
||||
(where parent directory or drive must exist, and mount must **not** exist,
|
||||
and is not supported when [mounting as a network drive](#mounting-modes-on-windows)), and
|
||||
the last example will mount as network share `\\cloud\remote` and map it to an
|
||||
automatically assigned drive:
|
||||
|
||||
rclone nfsmount remote:path/to/files *
|
||||
rclone nfsmount remote:path/to/files X:
|
||||
rclone nfsmount remote:path/to/files C:\path\parent\mount
|
||||
rclone nfsmount remote:path/to/files \\cloud\remote
|
||||
|
||||
When the program ends while in foreground mode, either via Ctrl+C or receiving
|
||||
a SIGINT or SIGTERM signal, the mount should be automatically stopped.
|
||||
|
||||
When running in background mode the user will have to stop the mount manually:
|
||||
|
||||
# Linux
|
||||
fusermount -u /path/to/local/mount
|
||||
# OS X
|
||||
umount /path/to/local/mount
|
||||
|
||||
The umount operation can fail, for example when the mountpoint is busy.
|
||||
When that happens, it is the user's responsibility to stop the mount manually.
|
||||
|
||||
The size of the mounted file system will be set according to information retrieved
|
||||
from the remote, the same as returned by the [rclone about](https://rclone.org/commands/rclone_about/)
|
||||
command. Remotes with unlimited storage may report the used size only,
|
||||
then an additional 1 PiB of free space is assumed. If the remote does not
|
||||
[support](https://rclone.org/overview/#optional-features) the about feature
|
||||
at all, then 1 PiB is set as both the total and the free size.
|
||||
|
||||
## Installing on Windows
|
||||
|
||||
To run rclone nfsmount on Windows, you will need to
|
||||
download and install [WinFsp](http://www.secfs.net/winfsp/).
|
||||
|
||||
[WinFsp](https://github.com/winfsp/winfsp) is an open-source
|
||||
Windows File System Proxy which makes it easy to write user space file
|
||||
systems for Windows. It provides a FUSE emulation layer which rclone
|
||||
uses combination with [cgofuse](https://github.com/winfsp/cgofuse).
|
||||
Both of these packages are by Bill Zissimopoulos who was very helpful
|
||||
during the implementation of rclone nfsmount for Windows.
|
||||
|
||||
### Mounting modes on windows
|
||||
|
||||
Unlike other operating systems, Microsoft Windows provides a different filesystem
|
||||
type for network and fixed drives. It optimises access on the assumption fixed
|
||||
disk drives are fast and reliable, while network drives have relatively high latency
|
||||
and less reliability. Some settings can also be differentiated between the two types,
|
||||
for example that Windows Explorer should just display icons and not create preview
|
||||
thumbnails for image and video files on network drives.
|
||||
|
||||
In most cases, rclone will mount the remote as a normal, fixed disk drive by default.
|
||||
However, you can also choose to mount it as a remote network drive, often described
|
||||
as a network share. If you mount an rclone remote using the default, fixed drive mode
|
||||
and experience unexpected program errors, freezes or other issues, consider mounting
|
||||
as a network drive instead.
|
||||
|
||||
When mounting as a fixed disk drive you can either mount to an unused drive letter,
|
||||
or to a path representing a **nonexistent** subdirectory of an **existing** parent
|
||||
directory or drive. Using the special value `*` will tell rclone to
|
||||
automatically assign the next available drive letter, starting with Z: and moving backward.
|
||||
Examples:
|
||||
|
||||
rclone nfsmount remote:path/to/files *
|
||||
rclone nfsmount remote:path/to/files X:
|
||||
rclone nfsmount remote:path/to/files C:\path\parent\mount
|
||||
rclone nfsmount remote:path/to/files X:
|
||||
|
||||
Option `--volname` can be used to set a custom volume name for the mounted
|
||||
file system. The default is to use the remote name and path.
|
||||
|
||||
To mount as network drive, you can add option `--network-mode`
|
||||
to your nfsmount command. Mounting to a directory path is not supported in
|
||||
this mode, it is a limitation Windows imposes on junctions, so the remote must always
|
||||
be mounted to a drive letter.
|
||||
|
||||
rclone nfsmount remote:path/to/files X: --network-mode
|
||||
|
||||
A volume name specified with `--volname` will be used to create the network share path.
|
||||
A complete UNC path, such as `\\cloud\remote`, optionally with path
|
||||
`\\cloud\remote\madeup\path`, will be used as is. Any other
|
||||
string will be used as the share part, after a default prefix `\\server\`.
|
||||
If no volume name is specified then `\\server\share` will be used.
|
||||
You must make sure the volume name is unique when you are mounting more than one drive,
|
||||
or else the mount command will fail. The share name will treated as the volume label for
|
||||
the mapped drive, shown in Windows Explorer etc, while the complete
|
||||
`\\server\share` will be reported as the remote UNC path by
|
||||
`net use` etc, just like a normal network drive mapping.
|
||||
|
||||
If you specify a full network share UNC path with `--volname`, this will implicitly
|
||||
set the `--network-mode` option, so the following two examples have same result:
|
||||
|
||||
rclone nfsmount remote:path/to/files X: --network-mode
|
||||
rclone nfsmount remote:path/to/files X: --volname \\server\share
|
||||
|
||||
You may also specify the network share UNC path as the mountpoint itself. Then rclone
|
||||
will automatically assign a drive letter, same as with `*` and use that as
|
||||
mountpoint, and instead use the UNC path specified as the volume name, as if it were
|
||||
specified with the `--volname` option. This will also implicitly set
|
||||
the `--network-mode` option. This means the following two examples have same result:
|
||||
|
||||
rclone nfsmount remote:path/to/files \\cloud\remote
|
||||
rclone nfsmount remote:path/to/files * --volname \\cloud\remote
|
||||
|
||||
There is yet another way to enable network mode, and to set the share path,
|
||||
and that is to pass the "native" libfuse/WinFsp option directly:
|
||||
`--fuse-flag --VolumePrefix=\server\share`. Note that the path
|
||||
must be with just a single backslash prefix in this case.
|
||||
|
||||
|
||||
*Note:* In previous versions of rclone this was the only supported method.
|
||||
|
||||
[Read more about drive mapping](https://en.wikipedia.org/wiki/Drive_mapping)
|
||||
|
||||
See also [Limitations](#limitations) section below.
|
||||
|
||||
### Windows filesystem permissions
|
||||
|
||||
The FUSE emulation layer on Windows must convert between the POSIX-based
|
||||
permission model used in FUSE, and the permission model used in Windows,
|
||||
based on access-control lists (ACL).
|
||||
|
||||
The mounted filesystem will normally get three entries in its access-control list (ACL),
|
||||
representing permissions for the POSIX permission scopes: Owner, group and others.
|
||||
By default, the owner and group will be taken from the current user, and the built-in
|
||||
group "Everyone" will be used to represent others. The user/group can be customized
|
||||
with FUSE options "UserName" and "GroupName",
|
||||
e.g. `-o UserName=user123 -o GroupName="Authenticated Users"`.
|
||||
The permissions on each entry will be set according to [options](#options)
|
||||
`--dir-perms` and `--file-perms`, which takes a value in traditional Unix
|
||||
[numeric notation](https://en.wikipedia.org/wiki/File-system_permissions#Numeric_notation).
|
||||
|
||||
The default permissions corresponds to `--file-perms 0666 --dir-perms 0777`,
|
||||
i.e. read and write permissions to everyone. This means you will not be able
|
||||
to start any programs from the mount. To be able to do that you must add
|
||||
execute permissions, e.g. `--file-perms 0777 --dir-perms 0777` to add it
|
||||
to everyone. If the program needs to write files, chances are you will
|
||||
have to enable [VFS File Caching](#vfs-file-caching) as well (see also
|
||||
[limitations](#limitations)). Note that the default write permission have
|
||||
some restrictions for accounts other than the owner, specifically it lacks
|
||||
the "write extended attributes", as explained next.
|
||||
|
||||
The mapping of permissions is not always trivial, and the result you see in
|
||||
Windows Explorer may not be exactly like you expected. For example, when setting
|
||||
a value that includes write access for the group or others scope, this will be
|
||||
mapped to individual permissions "write attributes", "write data" and
|
||||
"append data", but not "write extended attributes". Windows will then show this
|
||||
as basic permission "Special" instead of "Write", because "Write" also covers
|
||||
the "write extended attributes" permission. When setting digit 0 for group or
|
||||
others, to indicate no permissions, they will still get individual permissions
|
||||
"read attributes", "read extended attributes" and "read permissions". This is
|
||||
done for compatibility reasons, e.g. to allow users without additional
|
||||
permissions to be able to read basic metadata about files like in Unix.
|
||||
|
||||
WinFsp 2021 (version 1.9) introduced a new FUSE option "FileSecurity",
|
||||
that allows the complete specification of file security descriptors using
|
||||
[SDDL](https://docs.microsoft.com/en-us/windows/win32/secauthz/security-descriptor-string-format).
|
||||
With this you get detailed control of the resulting permissions, compared
|
||||
to use of the POSIX permissions described above, and no additional permissions
|
||||
will be added automatically for compatibility with Unix. Some example use
|
||||
cases will following.
|
||||
|
||||
If you set POSIX permissions for only allowing access to the owner,
|
||||
using `--file-perms 0600 --dir-perms 0700`, the user group and the built-in
|
||||
"Everyone" group will still be given some special permissions, as described
|
||||
above. Some programs may then (incorrectly) interpret this as the file being
|
||||
accessible by everyone, for example an SSH client may warn about "unprotected
|
||||
private key file". You can work around this by specifying
|
||||
`-o FileSecurity="D:P(A;;FA;;;OW)"`, which sets file all access (FA) to the
|
||||
owner (OW), and nothing else.
|
||||
|
||||
When setting write permissions then, except for the owner, this does not
|
||||
include the "write extended attributes" permission, as mentioned above.
|
||||
This may prevent applications from writing to files, giving permission denied
|
||||
error instead. To set working write permissions for the built-in "Everyone"
|
||||
group, similar to what it gets by default but with the addition of the
|
||||
"write extended attributes", you can specify
|
||||
`-o FileSecurity="D:P(A;;FRFW;;;WD)"`, which sets file read (FR) and file
|
||||
write (FW) to everyone (WD). If file execute (FX) is also needed, then change
|
||||
to `-o FileSecurity="D:P(A;;FRFWFX;;;WD)"`, or set file all access (FA) to
|
||||
get full access permissions, including delete, with
|
||||
`-o FileSecurity="D:P(A;;FA;;;WD)"`.
|
||||
|
||||
### Windows caveats
|
||||
|
||||
Drives created as Administrator are not visible to other accounts,
|
||||
not even an account that was elevated to Administrator with the
|
||||
User Account Control (UAC) feature. A result of this is that if you mount
|
||||
to a drive letter from a Command Prompt run as Administrator, and then try
|
||||
to access the same drive from Windows Explorer (which does not run as
|
||||
Administrator), you will not be able to see the mounted drive.
|
||||
|
||||
If you don't need to access the drive from applications running with
|
||||
administrative privileges, the easiest way around this is to always
|
||||
create the mount from a non-elevated command prompt.
|
||||
|
||||
To make mapped drives available to the user account that created them
|
||||
regardless if elevated or not, there is a special Windows setting called
|
||||
[linked connections](https://docs.microsoft.com/en-us/troubleshoot/windows-client/networking/mapped-drives-not-available-from-elevated-command#detail-to-configure-the-enablelinkedconnections-registry-entry)
|
||||
that can be enabled.
|
||||
|
||||
It is also possible to make a drive mount available to everyone on the system,
|
||||
by running the process creating it as the built-in SYSTEM account.
|
||||
There are several ways to do this: One is to use the command-line
|
||||
utility [PsExec](https://docs.microsoft.com/en-us/sysinternals/downloads/psexec),
|
||||
from Microsoft's Sysinternals suite, which has option `-s` to start
|
||||
processes as the SYSTEM account. Another alternative is to run the mount
|
||||
command from a Windows Scheduled Task, or a Windows Service, configured
|
||||
to run as the SYSTEM account. A third alternative is to use the
|
||||
[WinFsp.Launcher infrastructure](https://github.com/winfsp/winfsp/wiki/WinFsp-Service-Architecture)).
|
||||
Read more in the [install documentation](https://rclone.org/install/).
|
||||
Note that when running rclone as another user, it will not use
|
||||
the configuration file from your profile unless you tell it to
|
||||
with the [`--config`](https://rclone.org/docs/#config-config-file) option.
|
||||
Note also that it is now the SYSTEM account that will have the owner
|
||||
permissions, and other accounts will have permissions according to the
|
||||
group or others scopes. As mentioned above, these will then not get the
|
||||
"write extended attributes" permission, and this may prevent writing to
|
||||
files. You can work around this with the FileSecurity option, see
|
||||
example above.
|
||||
|
||||
Note that mapping to a directory path, instead of a drive letter,
|
||||
does not suffer from the same limitations.
|
||||
|
||||
## Mounting on macOS
|
||||
|
||||
Mounting on macOS can be done either via [built-in NFS server](/commands/rclone_serve_nfs/), [macFUSE](https://osxfuse.github.io/)
|
||||
(also known as osxfuse) or [FUSE-T](https://www.fuse-t.org/). macFUSE is a traditional
|
||||
FUSE driver utilizing a macOS kernel extension (kext). FUSE-T is an alternative FUSE system
|
||||
which "mounts" via an NFSv4 local server.
|
||||
|
||||
# NFS mount
|
||||
|
||||
This method spins up an NFS server using [serve nfs](/commands/rclone_serve_nfs/) command and mounts
|
||||
it to the specified mountpoint. If you run this in background mode using |--daemon|, you will need to
|
||||
send SIGTERM signal to the rclone process using |kill| command to stop the mount.
|
||||
|
||||
### macFUSE Notes
|
||||
|
||||
If installing macFUSE using [dmg packages](https://github.com/osxfuse/osxfuse/releases) from
|
||||
the website, rclone will locate the macFUSE libraries without any further intervention.
|
||||
If however, macFUSE is installed using the [macports](https://www.macports.org/) package manager,
|
||||
the following addition steps are required.
|
||||
|
||||
sudo mkdir /usr/local/lib
|
||||
cd /usr/local/lib
|
||||
sudo ln -s /opt/local/lib/libfuse.2.dylib
|
||||
|
||||
### FUSE-T Limitations, Caveats, and Notes
|
||||
|
||||
There are some limitations, caveats, and notes about how it works. These are current as
|
||||
of FUSE-T version 1.0.14.
|
||||
|
||||
#### ModTime update on read
|
||||
|
||||
As per the [FUSE-T wiki](https://github.com/macos-fuse-t/fuse-t/wiki#caveats):
|
||||
|
||||
> File access and modification times cannot be set separately as it seems to be an
|
||||
> issue with the NFS client which always modifies both. Can be reproduced with
|
||||
> 'touch -m' and 'touch -a' commands
|
||||
|
||||
This means that viewing files with various tools, notably macOS Finder, will cause rlcone
|
||||
to update the modification time of the file. This may make rclone upload a full new copy
|
||||
of the file.
|
||||
|
||||
#### Unicode Normalization
|
||||
|
||||
Rclone includes flags for unicode normalization with macFUSE that should be updated
|
||||
for FUSE-T. See [this forum post](https://forum.rclone.org/t/some-unicode-forms-break-mount-on-macos-with-fuse-t/36403)
|
||||
and [FUSE-T issue #16](https://github.com/macos-fuse-t/fuse-t/issues/16). The following
|
||||
flag should be added to the `rclone mount` command.
|
||||
|
||||
-o modules=iconv,from_code=UTF-8,to_code=UTF-8
|
||||
|
||||
#### Read Only mounts
|
||||
|
||||
When mounting with `--read-only`, attempts to write to files will fail *silently* as
|
||||
opposed to with a clear warning as in macFUSE.
|
||||
|
||||
## Limitations
|
||||
|
||||
Without the use of `--vfs-cache-mode` this can only write files
|
||||
sequentially, it can only seek when reading. This means that many
|
||||
applications won't work with their files on an rclone mount without
|
||||
`--vfs-cache-mode writes` or `--vfs-cache-mode full`.
|
||||
See the [VFS File Caching](#vfs-file-caching) section for more info.
|
||||
When using NFS mount on macOS, if you don't specify |--vfs-cache-mode|
|
||||
the mount point will be read-only.
|
||||
|
||||
The bucket-based remotes (e.g. Swift, S3, Google Compute Storage, B2)
|
||||
do not support the concept of empty directories, so empty
|
||||
directories will have a tendency to disappear once they fall out of
|
||||
the directory cache.
|
||||
|
||||
When `rclone mount` is invoked on Unix with `--daemon` flag, the main rclone
|
||||
program will wait for the background mount to become ready or until the timeout
|
||||
specified by the `--daemon-wait` flag. On Linux it can check mount status using
|
||||
ProcFS so the flag in fact sets **maximum** time to wait, while the real wait
|
||||
can be less. On macOS / BSD the time to wait is constant and the check is
|
||||
performed only at the end. We advise you to set wait time on macOS reasonably.
|
||||
|
||||
Only supported on Linux, FreeBSD, OS X and Windows at the moment.
|
||||
|
||||
## rclone nfsmount vs rclone sync/copy
|
||||
|
||||
File systems expect things to be 100% reliable, whereas cloud storage
|
||||
systems are a long way from 100% reliable. The rclone sync/copy
|
||||
commands cope with this with lots of retries. However rclone nfsmount
|
||||
can't use retries in the same way without making local copies of the
|
||||
uploads. Look at the [VFS File Caching](#vfs-file-caching)
|
||||
for solutions to make nfsmount more reliable.
|
||||
|
||||
## Attribute caching
|
||||
|
||||
You can use the flag `--attr-timeout` to set the time the kernel caches
|
||||
the attributes (size, modification time, etc.) for directory entries.
|
||||
|
||||
The default is `1s` which caches files just long enough to avoid
|
||||
too many callbacks to rclone from the kernel.
|
||||
|
||||
In theory 0s should be the correct value for filesystems which can
|
||||
change outside the control of the kernel. However this causes quite a
|
||||
few problems such as
|
||||
[rclone using too much memory](https://github.com/rclone/rclone/issues/2157),
|
||||
[rclone not serving files to samba](https://forum.rclone.org/t/rclone-1-39-vs-1-40-mount-issue/5112)
|
||||
and [excessive time listing directories](https://github.com/rclone/rclone/issues/2095#issuecomment-371141147).
|
||||
|
||||
The kernel can cache the info about a file for the time given by
|
||||
`--attr-timeout`. You may see corruption if the remote file changes
|
||||
length during this window. It will show up as either a truncated file
|
||||
or a file with garbage on the end. With `--attr-timeout 1s` this is
|
||||
very unlikely but not impossible. The higher you set `--attr-timeout`
|
||||
the more likely it is. The default setting of "1s" is the lowest
|
||||
setting which mitigates the problems above.
|
||||
|
||||
If you set it higher (`10s` or `1m` say) then the kernel will call
|
||||
back to rclone less often making it more efficient, however there is
|
||||
more chance of the corruption issue above.
|
||||
|
||||
If files don't change on the remote outside of the control of rclone
|
||||
then there is no chance of corruption.
|
||||
|
||||
This is the same as setting the attr_timeout option in mount.fuse.
|
||||
|
||||
## Filters
|
||||
|
||||
Note that all the rclone filters can be used to select a subset of the
|
||||
files to be visible in the mount.
|
||||
|
||||
## systemd
|
||||
|
||||
When running rclone nfsmount as a systemd service, it is possible
|
||||
to use Type=notify. In this case the service will enter the started state
|
||||
after the mountpoint has been successfully set up.
|
||||
Units having the rclone nfsmount service specified as a requirement
|
||||
will see all files and folders immediately in this mode.
|
||||
|
||||
Note that systemd runs mount units without any environment variables including
|
||||
`PATH` or `HOME`. This means that tilde (`~`) expansion will not work
|
||||
and you should provide `--config` and `--cache-dir` explicitly as absolute
|
||||
paths via rclone arguments.
|
||||
Since mounting requires the `fusermount` program, rclone will use the fallback
|
||||
PATH of `/bin:/usr/bin` in this scenario. Please ensure that `fusermount`
|
||||
is present on this PATH.
|
||||
|
||||
## Rclone as Unix mount helper
|
||||
|
||||
The core Unix program `/bin/mount` normally takes the `-t FSTYPE` argument
|
||||
then runs the `/sbin/mount.FSTYPE` helper program passing it mount options
|
||||
as `-o key=val,...` or `--opt=...`. Automount (classic or systemd) behaves
|
||||
in a similar way.
|
||||
|
||||
rclone by default expects GNU-style flags `--key val`. To run it as a mount
|
||||
helper you should symlink rclone binary to `/sbin/mount.rclone` and optionally
|
||||
`/usr/bin/rclonefs`, e.g. `ln -s /usr/bin/rclone /sbin/mount.rclone`.
|
||||
rclone will detect it and translate command-line arguments appropriately.
|
||||
|
||||
Now you can run classic mounts like this:
|
||||
```
|
||||
mount sftp1:subdir /mnt/data -t rclone -o vfs_cache_mode=writes,sftp_key_file=/path/to/pem
|
||||
```
|
||||
|
||||
or create systemd mount units:
|
||||
```
|
||||
# /etc/systemd/system/mnt-data.mount
|
||||
[Unit]
|
||||
Description=Mount for /mnt/data
|
||||
[Mount]
|
||||
Type=rclone
|
||||
What=sftp1:subdir
|
||||
Where=/mnt/data
|
||||
Options=rw,_netdev,allow_other,args2env,vfs-cache-mode=writes,config=/etc/rclone.conf,cache-dir=/var/rclone
|
||||
```
|
||||
|
||||
optionally accompanied by systemd automount unit
|
||||
```
|
||||
# /etc/systemd/system/mnt-data.automount
|
||||
[Unit]
|
||||
Description=AutoMount for /mnt/data
|
||||
[Automount]
|
||||
Where=/mnt/data
|
||||
TimeoutIdleSec=600
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
```
|
||||
|
||||
or add in `/etc/fstab` a line like
|
||||
```
|
||||
sftp1:subdir /mnt/data rclone rw,noauto,nofail,_netdev,x-systemd.automount,args2env,vfs_cache_mode=writes,config=/etc/rclone.conf,cache_dir=/var/cache/rclone 0 0
|
||||
```
|
||||
|
||||
or use classic Automountd.
|
||||
Remember to provide explicit `config=...,cache-dir=...` as a workaround for
|
||||
mount units being run without `HOME`.
|
||||
|
||||
Rclone in the mount helper mode will split `-o` argument(s) by comma, replace `_`
|
||||
by `-` and prepend `--` to get the command-line flags. Options containing commas
|
||||
or spaces can be wrapped in single or double quotes. Any inner quotes inside outer
|
||||
quotes of the same type should be doubled.
|
||||
|
||||
Mount option syntax includes a few extra options treated specially:
|
||||
|
||||
- `env.NAME=VALUE` will set an environment variable for the mount process.
|
||||
This helps with Automountd and Systemd.mount which don't allow setting
|
||||
custom environment for mount helpers.
|
||||
Typically you will use `env.HTTPS_PROXY=proxy.host:3128` or `env.HOME=/root`
|
||||
- `command=cmount` can be used to run `cmount` or any other rclone command
|
||||
rather than the default `mount`.
|
||||
- `args2env` will pass mount options to the mount helper running in background
|
||||
via environment variables instead of command line arguments. This allows to
|
||||
hide secrets from such commands as `ps` or `pgrep`.
|
||||
- `vv...` will be transformed into appropriate `--verbose=N`
|
||||
- standard mount options like `x-systemd.automount`, `_netdev`, `nosuid` and alike
|
||||
are intended only for Automountd and ignored by rclone.
|
||||
## VFS - Virtual File System
|
||||
|
||||
This command uses the VFS layer. This adapts the cloud storage objects
|
||||
that rclone uses into something which looks much more like a disk
|
||||
filing system.
|
||||
|
||||
Cloud storage objects have lots of properties which aren't like disk
|
||||
files - you can't extend them or write to the middle of them, so the
|
||||
VFS layer has to deal with that. Because there is no one right way of
|
||||
doing this there are various options explained below.
|
||||
|
||||
The VFS layer also implements a directory cache - this caches info
|
||||
about files and directories (but not the data) in memory.
|
||||
|
||||
## VFS Directory Cache
|
||||
|
||||
Using the `--dir-cache-time` flag, you can control how long a
|
||||
directory should be considered up to date and not refreshed from the
|
||||
backend. Changes made through the VFS will appear immediately or
|
||||
invalidate the cache.
|
||||
|
||||
--dir-cache-time duration Time to cache directory entries for (default 5m0s)
|
||||
--poll-interval duration Time to wait between polling for changes. Must be smaller than dir-cache-time. Only on supported remotes. Set to 0 to disable (default 1m0s)
|
||||
|
||||
However, changes made directly on the cloud storage by the web
|
||||
interface or a different copy of rclone will only be picked up once
|
||||
the directory cache expires if the backend configured does not support
|
||||
polling for changes. If the backend supports polling, changes will be
|
||||
picked up within the polling interval.
|
||||
|
||||
You can send a `SIGHUP` signal to rclone for it to flush all
|
||||
directory caches, regardless of how old they are. Assuming only one
|
||||
rclone instance is running, you can reset the cache like this:
|
||||
|
||||
kill -SIGHUP $(pidof rclone)
|
||||
|
||||
If you configure rclone with a [remote control](/rc) then you can use
|
||||
rclone rc to flush the whole directory cache:
|
||||
|
||||
rclone rc vfs/forget
|
||||
|
||||
Or individual files or directories:
|
||||
|
||||
rclone rc vfs/forget file=path/to/file dir=path/to/dir
|
||||
|
||||
## VFS File Buffering
|
||||
|
||||
The `--buffer-size` flag determines the amount of memory,
|
||||
that will be used to buffer data in advance.
|
||||
|
||||
Each open file will try to keep the specified amount of data in memory
|
||||
at all times. The buffered data is bound to one open file and won't be
|
||||
shared.
|
||||
|
||||
This flag is a upper limit for the used memory per open file. The
|
||||
buffer will only use memory for data that is downloaded but not not
|
||||
yet read. If the buffer is empty, only a small amount of memory will
|
||||
be used.
|
||||
|
||||
The maximum memory used by rclone for buffering can be up to
|
||||
`--buffer-size * open files`.
|
||||
|
||||
## VFS File Caching
|
||||
|
||||
These flags control the VFS file caching options. File caching is
|
||||
necessary to make the VFS layer appear compatible with a normal file
|
||||
system. It can be disabled at the cost of some compatibility.
|
||||
|
||||
For example you'll need to enable VFS caching if you want to read and
|
||||
write simultaneously to a file. See below for more details.
|
||||
|
||||
Note that the VFS cache is separate from the cache backend and you may
|
||||
find that you need one or the other or both.
|
||||
|
||||
--cache-dir string Directory rclone will use for caching.
|
||||
--vfs-cache-mode CacheMode Cache mode off|minimal|writes|full (default off)
|
||||
--vfs-cache-max-age duration Max time since last access of objects in the cache (default 1h0m0s)
|
||||
--vfs-cache-max-size SizeSuffix Max total size of objects in the cache (default off)
|
||||
--vfs-cache-min-free-space SizeSuffix Target minimum free space on the disk containing the cache (default off)
|
||||
--vfs-cache-poll-interval duration Interval to poll the cache for stale objects (default 1m0s)
|
||||
--vfs-write-back duration Time to writeback files after last use when using cache (default 5s)
|
||||
|
||||
If run with `-vv` rclone will print the location of the file cache. The
|
||||
files are stored in the user cache file area which is OS dependent but
|
||||
can be controlled with `--cache-dir` or setting the appropriate
|
||||
environment variable.
|
||||
|
||||
The cache has 4 different modes selected by `--vfs-cache-mode`.
|
||||
The higher the cache mode the more compatible rclone becomes at the
|
||||
cost of using disk space.
|
||||
|
||||
Note that files are written back to the remote only when they are
|
||||
closed and if they haven't been accessed for `--vfs-write-back`
|
||||
seconds. If rclone is quit or dies with files that haven't been
|
||||
uploaded, these will be uploaded next time rclone is run with the same
|
||||
flags.
|
||||
|
||||
If using `--vfs-cache-max-size` or `--vfs-cache-min-free-size` note
|
||||
that the cache may exceed these quotas for two reasons. Firstly
|
||||
because it is only checked every `--vfs-cache-poll-interval`. Secondly
|
||||
because open files cannot be evicted from the cache. When
|
||||
`--vfs-cache-max-size` or `--vfs-cache-min-free-size` is exceeded,
|
||||
rclone will attempt to evict the least accessed files from the cache
|
||||
first. rclone will start with files that haven't been accessed for the
|
||||
longest. This cache flushing strategy is efficient and more relevant
|
||||
files are likely to remain cached.
|
||||
|
||||
The `--vfs-cache-max-age` will evict files from the cache
|
||||
after the set time since last access has passed. The default value of
|
||||
1 hour will start evicting files from cache that haven't been accessed
|
||||
for 1 hour. When a cached file is accessed the 1 hour timer is reset to 0
|
||||
and will wait for 1 more hour before evicting. Specify the time with
|
||||
standard notation, s, m, h, d, w .
|
||||
|
||||
You **should not** run two copies of rclone using the same VFS cache
|
||||
with the same or overlapping remotes if using `--vfs-cache-mode > off`.
|
||||
This can potentially cause data corruption if you do. You can work
|
||||
around this by giving each rclone its own cache hierarchy with
|
||||
`--cache-dir`. You don't need to worry about this if the remotes in
|
||||
use don't overlap.
|
||||
|
||||
### --vfs-cache-mode off
|
||||
|
||||
In this mode (the default) the cache will read directly from the remote and write
|
||||
directly to the remote without caching anything on disk.
|
||||
|
||||
This will mean some operations are not possible
|
||||
|
||||
* Files can't be opened for both read AND write
|
||||
* Files opened for write can't be seeked
|
||||
* Existing files opened for write must have O_TRUNC set
|
||||
* Files open for read with O_TRUNC will be opened write only
|
||||
* Files open for write only will behave as if O_TRUNC was supplied
|
||||
* Open modes O_APPEND, O_TRUNC are ignored
|
||||
* If an upload fails it can't be retried
|
||||
|
||||
### --vfs-cache-mode minimal
|
||||
|
||||
This is very similar to "off" except that files opened for read AND
|
||||
write will be buffered to disk. This means that files opened for
|
||||
write will be a lot more compatible, but uses the minimal disk space.
|
||||
|
||||
These operations are not possible
|
||||
|
||||
* Files opened for write only can't be seeked
|
||||
* Existing files opened for write must have O_TRUNC set
|
||||
* Files opened for write only will ignore O_APPEND, O_TRUNC
|
||||
* If an upload fails it can't be retried
|
||||
|
||||
### --vfs-cache-mode writes
|
||||
|
||||
In this mode files opened for read only are still read directly from
|
||||
the remote, write only and read/write files are buffered to disk
|
||||
first.
|
||||
|
||||
This mode should support all normal file system operations.
|
||||
|
||||
If an upload fails it will be retried at exponentially increasing
|
||||
intervals up to 1 minute.
|
||||
|
||||
### --vfs-cache-mode full
|
||||
|
||||
In this mode all reads and writes are buffered to and from disk. When
|
||||
data is read from the remote this is buffered to disk as well.
|
||||
|
||||
In this mode the files in the cache will be sparse files and rclone
|
||||
will keep track of which bits of the files it has downloaded.
|
||||
|
||||
So if an application only reads the starts of each file, then rclone
|
||||
will only buffer the start of the file. These files will appear to be
|
||||
their full size in the cache, but they will be sparse files with only
|
||||
the data that has been downloaded present in them.
|
||||
|
||||
This mode should support all normal file system operations and is
|
||||
otherwise identical to `--vfs-cache-mode` writes.
|
||||
|
||||
When reading a file rclone will read `--buffer-size` plus
|
||||
`--vfs-read-ahead` bytes ahead. The `--buffer-size` is buffered in memory
|
||||
whereas the `--vfs-read-ahead` is buffered on disk.
|
||||
|
||||
When using this mode it is recommended that `--buffer-size` is not set
|
||||
too large and `--vfs-read-ahead` is set large if required.
|
||||
|
||||
**IMPORTANT** not all file systems support sparse files. In particular
|
||||
FAT/exFAT do not. Rclone will perform very badly if the cache
|
||||
directory is on a filesystem which doesn't support sparse files and it
|
||||
will log an ERROR message if one is detected.
|
||||
|
||||
### Fingerprinting
|
||||
|
||||
Various parts of the VFS use fingerprinting to see if a local file
|
||||
copy has changed relative to a remote file. Fingerprints are made
|
||||
from:
|
||||
|
||||
- size
|
||||
- modification time
|
||||
- hash
|
||||
|
||||
where available on an object.
|
||||
|
||||
On some backends some of these attributes are slow to read (they take
|
||||
an extra API call per object, or extra work per object).
|
||||
|
||||
For example `hash` is slow with the `local` and `sftp` backends as
|
||||
they have to read the entire file and hash it, and `modtime` is slow
|
||||
with the `s3`, `swift`, `ftp` and `qinqstor` backends because they
|
||||
need to do an extra API call to fetch it.
|
||||
|
||||
If you use the `--vfs-fast-fingerprint` flag then rclone will not
|
||||
include the slow operations in the fingerprint. This makes the
|
||||
fingerprinting less accurate but much faster and will improve the
|
||||
opening time of cached files.
|
||||
|
||||
If you are running a vfs cache over `local`, `s3` or `swift` backends
|
||||
then using this flag is recommended.
|
||||
|
||||
Note that if you change the value of this flag, the fingerprints of
|
||||
the files in the cache may be invalidated and the files will need to
|
||||
be downloaded again.
|
||||
|
||||
## VFS Chunked Reading
|
||||
|
||||
When rclone reads files from a remote it reads them in chunks. This
|
||||
means that rather than requesting the whole file rclone reads the
|
||||
chunk specified. This can reduce the used download quota for some
|
||||
remotes by requesting only chunks from the remote that are actually
|
||||
read, at the cost of an increased number of requests.
|
||||
|
||||
These flags control the chunking:
|
||||
|
||||
--vfs-read-chunk-size SizeSuffix Read the source objects in chunks (default 128M)
|
||||
--vfs-read-chunk-size-limit SizeSuffix Max chunk doubling size (default off)
|
||||
|
||||
Rclone will start reading a chunk of size `--vfs-read-chunk-size`,
|
||||
and then double the size for each read. When `--vfs-read-chunk-size-limit` is
|
||||
specified, and greater than `--vfs-read-chunk-size`, the chunk size for each
|
||||
open file will get doubled only until the specified value is reached. If the
|
||||
value is "off", which is the default, the limit is disabled and the chunk size
|
||||
will grow indefinitely.
|
||||
|
||||
With `--vfs-read-chunk-size 100M` and `--vfs-read-chunk-size-limit 0`
|
||||
the following parts will be downloaded: 0-100M, 100M-200M, 200M-300M, 300M-400M and so on.
|
||||
When `--vfs-read-chunk-size-limit 500M` is specified, the result would be
|
||||
0-100M, 100M-300M, 300M-700M, 700M-1200M, 1200M-1700M and so on.
|
||||
|
||||
Setting `--vfs-read-chunk-size` to `0` or "off" disables chunked reading.
|
||||
|
||||
## VFS Performance
|
||||
|
||||
These flags may be used to enable/disable features of the VFS for
|
||||
performance or other reasons. See also the [chunked reading](#vfs-chunked-reading)
|
||||
feature.
|
||||
|
||||
In particular S3 and Swift benefit hugely from the `--no-modtime` flag
|
||||
(or use `--use-server-modtime` for a slightly different effect) as each
|
||||
read of the modification time takes a transaction.
|
||||
|
||||
--no-checksum Don't compare checksums on up/download.
|
||||
--no-modtime Don't read/write the modification time (can speed things up).
|
||||
--no-seek Don't allow seeking in files.
|
||||
--read-only Only allow read-only access.
|
||||
|
||||
Sometimes rclone is delivered reads or writes out of order. Rather
|
||||
than seeking rclone will wait a short time for the in sequence read or
|
||||
write to come in. These flags only come into effect when not using an
|
||||
on disk cache file.
|
||||
|
||||
--vfs-read-wait duration Time to wait for in-sequence read before seeking (default 20ms)
|
||||
--vfs-write-wait duration Time to wait for in-sequence write before giving error (default 1s)
|
||||
|
||||
When using VFS write caching (`--vfs-cache-mode` with value writes or full),
|
||||
the global flag `--transfers` can be set to adjust the number of parallel uploads of
|
||||
modified files from the cache (the related global flag `--checkers` has no effect on the VFS).
|
||||
|
||||
--transfers int Number of file transfers to run in parallel (default 4)
|
||||
|
||||
## VFS Case Sensitivity
|
||||
|
||||
Linux file systems are case-sensitive: two files can differ only
|
||||
by case, and the exact case must be used when opening a file.
|
||||
|
||||
File systems in modern Windows are case-insensitive but case-preserving:
|
||||
although existing files can be opened using any case, the exact case used
|
||||
to create the file is preserved and available for programs to query.
|
||||
It is not allowed for two files in the same directory to differ only by case.
|
||||
|
||||
Usually file systems on macOS are case-insensitive. It is possible to make macOS
|
||||
file systems case-sensitive but that is not the default.
|
||||
|
||||
The `--vfs-case-insensitive` VFS flag controls how rclone handles these
|
||||
two cases. If its value is "false", rclone passes file names to the remote
|
||||
as-is. If the flag is "true" (or appears without a value on the
|
||||
command line), rclone may perform a "fixup" as explained below.
|
||||
|
||||
The user may specify a file name to open/delete/rename/etc with a case
|
||||
different than what is stored on the remote. If an argument refers
|
||||
to an existing file with exactly the same name, then the case of the existing
|
||||
file on the disk will be used. However, if a file name with exactly the same
|
||||
name is not found but a name differing only by case exists, rclone will
|
||||
transparently fixup the name. This fixup happens only when an existing file
|
||||
is requested. Case sensitivity of file names created anew by rclone is
|
||||
controlled by the underlying remote.
|
||||
|
||||
Note that case sensitivity of the operating system running rclone (the target)
|
||||
may differ from case sensitivity of a file system presented by rclone (the source).
|
||||
The flag controls whether "fixup" is performed to satisfy the target.
|
||||
|
||||
If the flag is not provided on the command line, then its default value depends
|
||||
on the operating system where rclone runs: "true" on Windows and macOS, "false"
|
||||
otherwise. If the flag is provided without a value, then it is "true".
|
||||
|
||||
## VFS Disk Options
|
||||
|
||||
This flag allows you to manually set the statistics about the filing system.
|
||||
It can be useful when those statistics cannot be read correctly automatically.
|
||||
|
||||
--vfs-disk-space-total-size Manually set the total disk space size (example: 256G, default: -1)
|
||||
|
||||
## Alternate report of used bytes
|
||||
|
||||
Some backends, most notably S3, do not report the amount of bytes used.
|
||||
If you need this information to be available when running `df` on the
|
||||
filesystem, then pass the flag `--vfs-used-is-size` to rclone.
|
||||
With this flag set, instead of relying on the backend to report this
|
||||
information, rclone will scan the whole remote similar to `rclone size`
|
||||
and compute the total used space itself.
|
||||
|
||||
_WARNING._ Contrary to `rclone size`, this flag ignores filters so that the
|
||||
result is accurate. However, this is very inefficient and may cost lots of API
|
||||
calls resulting in extra charges. Use it as a last resort and only with caching.
|
||||
|
||||
|
||||
```
|
||||
rclone nfsmount remote:path /path/to/mountpoint [flags]
|
||||
```
|
||||
|
||||
## Options
|
||||
|
||||
```
|
||||
--allow-non-empty Allow mounting over a non-empty directory (not supported on Windows)
|
||||
--allow-other Allow access to other users (not supported on Windows)
|
||||
--allow-root Allow access to root user (not supported on Windows)
|
||||
--async-read Use asynchronous reads (not supported on Windows) (default true)
|
||||
--attr-timeout Duration Time for which file/directory attributes are cached (default 1s)
|
||||
--daemon Run mount in background and exit parent process (as background output is suppressed, use --log-file with --log-format=pid,... to monitor) (not supported on Windows)
|
||||
--daemon-timeout Duration Time limit for rclone to respond to kernel (not supported on Windows) (default 0s)
|
||||
--daemon-wait Duration Time to wait for ready mount from daemon (maximum time on Linux, constant sleep time on OSX/BSD) (not supported on Windows) (default 1m0s)
|
||||
--debug-fuse Debug the FUSE internals - needs -v
|
||||
--default-permissions Makes kernel enforce access control based on the file mode (not supported on Windows)
|
||||
--devname string Set the device name - default is remote:path
|
||||
--dir-cache-time Duration Time to cache directory entries for (default 5m0s)
|
||||
--dir-perms FileMode Directory permissions (default 0777)
|
||||
--file-perms FileMode File permissions (default 0666)
|
||||
--fuse-flag stringArray Flags or arguments to be passed direct to libfuse/WinFsp (repeat if required)
|
||||
--gid uint32 Override the gid field set by the filesystem (not supported on Windows) (default 1000)
|
||||
-h, --help help for nfsmount
|
||||
--max-read-ahead SizeSuffix The number of bytes that can be prefetched for sequential reads (not supported on Windows) (default 128Ki)
|
||||
--mount-case-insensitive Tristate Tell the OS the mount is case insensitive (true) or sensitive (false) regardless of the backend (auto) (default unset)
|
||||
--network-mode Mount as remote network drive, instead of fixed disk drive (supported on Windows only)
|
||||
--no-checksum Don't compare checksums on up/download
|
||||
--no-modtime Don't read/write the modification time (can speed things up)
|
||||
--no-seek Don't allow seeking in files
|
||||
--noappledouble Ignore Apple Double (._) and .DS_Store files (supported on OSX only) (default true)
|
||||
--noapplexattr Ignore all "com.apple.*" extended attributes (supported on OSX only)
|
||||
-o, --option stringArray Option for libfuse/WinFsp (repeat if required)
|
||||
--poll-interval Duration Time to wait between polling for changes, must be smaller than dir-cache-time and only on supported remotes (set 0 to disable) (default 1m0s)
|
||||
--read-only Only allow read-only access
|
||||
--sudo Use sudo to run the mount command as root.
|
||||
--uid uint32 Override the uid field set by the filesystem (not supported on Windows) (default 1000)
|
||||
--umask int Override the permission bits set by the filesystem (not supported on Windows) (default 2)
|
||||
--vfs-cache-max-age Duration Max time since last access of objects in the cache (default 1h0m0s)
|
||||
--vfs-cache-max-size SizeSuffix Max total size of objects in the cache (default off)
|
||||
--vfs-cache-min-free-space SizeSuffix Target minimum free space on the disk containing the cache (default off)
|
||||
--vfs-cache-mode CacheMode Cache mode off|minimal|writes|full (default off)
|
||||
--vfs-cache-poll-interval Duration Interval to poll the cache for stale objects (default 1m0s)
|
||||
--vfs-case-insensitive If a file name not found, find a case insensitive match
|
||||
--vfs-disk-space-total-size SizeSuffix Specify the total space of disk (default off)
|
||||
--vfs-fast-fingerprint Use fast (less accurate) fingerprints for change detection
|
||||
--vfs-read-ahead SizeSuffix Extra read ahead over --buffer-size when using cache-mode full
|
||||
--vfs-read-chunk-size SizeSuffix Read the source objects in chunks (default 128Mi)
|
||||
--vfs-read-chunk-size-limit SizeSuffix If greater than --vfs-read-chunk-size, double the chunk size after each chunk read, until the limit is reached ('off' is unlimited) (default off)
|
||||
--vfs-read-wait Duration Time to wait for in-sequence read before seeking (default 20ms)
|
||||
--vfs-refresh Refreshes the directory cache recursively in the background on start
|
||||
--vfs-used-is-size rclone size Use the rclone size algorithm for Used size
|
||||
--vfs-write-back Duration Time to writeback files after last use when using cache (default 5s)
|
||||
--vfs-write-wait Duration Time to wait for in-sequence write before giving error (default 1s)
|
||||
--volname string Set the volume name (supported on Windows and OSX only)
|
||||
--write-back-cache Makes kernel buffer writes before sending them to rclone (without this, writethrough caching is used) (not supported on Windows)
|
||||
```
|
||||
|
||||
|
||||
## Filter Options
|
||||
|
||||
Flags for filtering directory listings.
|
||||
|
||||
```
|
||||
--delete-excluded Delete files on dest excluded from sync
|
||||
--exclude stringArray Exclude files matching pattern
|
||||
--exclude-from stringArray Read file exclude patterns from file (use - to read from stdin)
|
||||
--exclude-if-present stringArray Exclude directories if filename is present
|
||||
--files-from stringArray Read list of source-file names from file (use - to read from stdin)
|
||||
--files-from-raw stringArray Read list of source-file names from file without any processing of lines (use - to read from stdin)
|
||||
-f, --filter stringArray Add a file filtering rule
|
||||
--filter-from stringArray Read file filtering patterns from a file (use - to read from stdin)
|
||||
--ignore-case Ignore case in filters (case insensitive)
|
||||
--include stringArray Include files matching pattern
|
||||
--include-from stringArray Read file include patterns from file (use - to read from stdin)
|
||||
--max-age Duration Only transfer files younger than this in s or suffix ms|s|m|h|d|w|M|y (default off)
|
||||
--max-depth int If set limits the recursion depth to this (default -1)
|
||||
--max-size SizeSuffix Only transfer files smaller than this in KiB or suffix B|K|M|G|T|P (default off)
|
||||
--metadata-exclude stringArray Exclude metadatas matching pattern
|
||||
--metadata-exclude-from stringArray Read metadata exclude patterns from file (use - to read from stdin)
|
||||
--metadata-filter stringArray Add a metadata filtering rule
|
||||
--metadata-filter-from stringArray Read metadata filtering patterns from a file (use - to read from stdin)
|
||||
--metadata-include stringArray Include metadatas matching pattern
|
||||
--metadata-include-from stringArray Read metadata include patterns from file (use - to read from stdin)
|
||||
--min-age Duration Only transfer files older than this in s or suffix ms|s|m|h|d|w|M|y (default off)
|
||||
--min-size SizeSuffix Only transfer files bigger than this in KiB or suffix B|K|M|G|T|P (default off)
|
||||
```
|
||||
|
||||
See the [global flags page](/flags/) for global options not listed here.
|
||||
|
||||
# SEE ALSO
|
||||
|
||||
* [rclone](/commands/rclone/) - Show help for rclone commands, flags and backends.
|
||||
|
|
@ -404,7 +404,7 @@ rclone serve dlna remote:path [flags]
|
|||
--vfs-read-chunk-size SizeSuffix Read the source objects in chunks (default 128Mi)
|
||||
--vfs-read-chunk-size-limit SizeSuffix If greater than --vfs-read-chunk-size, double the chunk size after each chunk read, until the limit is reached ('off' is unlimited) (default off)
|
||||
--vfs-read-wait Duration Time to wait for in-sequence read before seeking (default 20ms)
|
||||
--vfs-refresh Refreshes the directory cache recursively on start
|
||||
--vfs-refresh Refreshes the directory cache recursively in the background on start
|
||||
--vfs-used-is-size rclone size Use the rclone size algorithm for Used size
|
||||
--vfs-write-back Duration Time to writeback files after last use when using cache (default 5s)
|
||||
--vfs-write-wait Duration Time to wait for in-sequence write before giving error (default 1s)
|
||||
|
|
|
@ -437,7 +437,7 @@ rclone serve docker [flags]
|
|||
--vfs-read-chunk-size SizeSuffix Read the source objects in chunks (default 128Mi)
|
||||
--vfs-read-chunk-size-limit SizeSuffix If greater than --vfs-read-chunk-size, double the chunk size after each chunk read, until the limit is reached ('off' is unlimited) (default off)
|
||||
--vfs-read-wait Duration Time to wait for in-sequence read before seeking (default 20ms)
|
||||
--vfs-refresh Refreshes the directory cache recursively on start
|
||||
--vfs-refresh Refreshes the directory cache recursively in the background on start
|
||||
--vfs-used-is-size rclone size Use the rclone size algorithm for Used size
|
||||
--vfs-write-back Duration Time to writeback files after last use when using cache (default 5s)
|
||||
--vfs-write-wait Duration Time to wait for in-sequence write before giving error (default 1s)
|
||||
|
|
|
@ -376,7 +376,7 @@ together, if `--auth-proxy` is set the authorized keys option will be
|
|||
ignored.
|
||||
|
||||
There is an example program
|
||||
[bin/test_proxy.py](https://github.com/rclone/rclone/blob/master/test_proxy.py)
|
||||
[bin/test_proxy.py](https://github.com/rclone/rclone/blob/master/bin/test_proxy.py)
|
||||
in the rclone source code.
|
||||
|
||||
The program's job is to take a `user` and `pass` on the input and turn
|
||||
|
@ -485,7 +485,7 @@ rclone serve ftp remote:path [flags]
|
|||
--vfs-read-chunk-size SizeSuffix Read the source objects in chunks (default 128Mi)
|
||||
--vfs-read-chunk-size-limit SizeSuffix If greater than --vfs-read-chunk-size, double the chunk size after each chunk read, until the limit is reached ('off' is unlimited) (default off)
|
||||
--vfs-read-wait Duration Time to wait for in-sequence read before seeking (default 20ms)
|
||||
--vfs-refresh Refreshes the directory cache recursively on start
|
||||
--vfs-refresh Refreshes the directory cache recursively in the background on start
|
||||
--vfs-used-is-size rclone size Use the rclone size algorithm for Used size
|
||||
--vfs-write-back Duration Time to writeback files after last use when using cache (default 5s)
|
||||
--vfs-write-wait Duration Time to wait for in-sequence write before giving error (default 1s)
|
||||
|
|
|
@ -477,7 +477,7 @@ together, if `--auth-proxy` is set the authorized keys option will be
|
|||
ignored.
|
||||
|
||||
There is an example program
|
||||
[bin/test_proxy.py](https://github.com/rclone/rclone/blob/master/test_proxy.py)
|
||||
[bin/test_proxy.py](https://github.com/rclone/rclone/blob/master/bin/test_proxy.py)
|
||||
in the rclone source code.
|
||||
|
||||
The program's job is to take a `user` and `pass` on the input and turn
|
||||
|
@ -595,7 +595,7 @@ rclone serve http remote:path [flags]
|
|||
--vfs-read-chunk-size SizeSuffix Read the source objects in chunks (default 128Mi)
|
||||
--vfs-read-chunk-size-limit SizeSuffix If greater than --vfs-read-chunk-size, double the chunk size after each chunk read, until the limit is reached ('off' is unlimited) (default off)
|
||||
--vfs-read-wait Duration Time to wait for in-sequence read before seeking (default 20ms)
|
||||
--vfs-refresh Refreshes the directory cache recursively on start
|
||||
--vfs-refresh Refreshes the directory cache recursively in the background on start
|
||||
--vfs-used-is-size rclone size Use the rclone size algorithm for Used size
|
||||
--vfs-write-back Duration Time to writeback files after last use when using cache (default 5s)
|
||||
--vfs-write-wait Duration Time to wait for in-sequence write before giving error (default 1s)
|
||||
|
|
|
@ -4,6 +4,7 @@ description: "Serve the remote as an NFS mount"
|
|||
slug: rclone_serve_nfs
|
||||
url: /commands/rclone_serve_nfs/
|
||||
groups: Filter
|
||||
status: Experimental
|
||||
versionIntroduced: v1.65
|
||||
# autogenerated - DO NOT EDIT, instead edit the source code in cmd/serve/nfs/ and as part of making a release run "make commanddocs"
|
||||
---
|
||||
|
@ -406,7 +407,7 @@ rclone serve nfs remote:path [flags]
|
|||
--vfs-read-chunk-size SizeSuffix Read the source objects in chunks (default 128Mi)
|
||||
--vfs-read-chunk-size-limit SizeSuffix If greater than --vfs-read-chunk-size, double the chunk size after each chunk read, until the limit is reached ('off' is unlimited) (default off)
|
||||
--vfs-read-wait Duration Time to wait for in-sequence read before seeking (default 20ms)
|
||||
--vfs-refresh Refreshes the directory cache recursively on start
|
||||
--vfs-refresh Refreshes the directory cache recursively in the background on start
|
||||
--vfs-used-is-size rclone size Use the rclone size algorithm for Used size
|
||||
--vfs-write-back Duration Time to writeback files after last use when using cache (default 5s)
|
||||
--vfs-write-wait Duration Time to wait for in-sequence write before giving error (default 1s)
|
||||
|
|
|
@ -553,7 +553,7 @@ rclone serve s3 remote:path [flags]
|
|||
--vfs-read-chunk-size SizeSuffix Read the source objects in chunks (default 128Mi)
|
||||
--vfs-read-chunk-size-limit SizeSuffix If greater than --vfs-read-chunk-size, double the chunk size after each chunk read, until the limit is reached ('off' is unlimited) (default off)
|
||||
--vfs-read-wait Duration Time to wait for in-sequence read before seeking (default 20ms)
|
||||
--vfs-refresh Refreshes the directory cache recursively on start
|
||||
--vfs-refresh Refreshes the directory cache recursively in the background on start
|
||||
--vfs-used-is-size rclone size Use the rclone size algorithm for Used size
|
||||
--vfs-write-back Duration Time to writeback files after last use when using cache (default 5s)
|
||||
--vfs-write-wait Duration Time to wait for in-sequence write before giving error (default 1s)
|
||||
|
|
|
@ -408,7 +408,7 @@ together, if `--auth-proxy` is set the authorized keys option will be
|
|||
ignored.
|
||||
|
||||
There is an example program
|
||||
[bin/test_proxy.py](https://github.com/rclone/rclone/blob/master/test_proxy.py)
|
||||
[bin/test_proxy.py](https://github.com/rclone/rclone/blob/master/bin/test_proxy.py)
|
||||
in the rclone source code.
|
||||
|
||||
The program's job is to take a `user` and `pass` on the input and turn
|
||||
|
@ -517,7 +517,7 @@ rclone serve sftp remote:path [flags]
|
|||
--vfs-read-chunk-size SizeSuffix Read the source objects in chunks (default 128Mi)
|
||||
--vfs-read-chunk-size-limit SizeSuffix If greater than --vfs-read-chunk-size, double the chunk size after each chunk read, until the limit is reached ('off' is unlimited) (default off)
|
||||
--vfs-read-wait Duration Time to wait for in-sequence read before seeking (default 20ms)
|
||||
--vfs-refresh Refreshes the directory cache recursively on start
|
||||
--vfs-refresh Refreshes the directory cache recursively in the background on start
|
||||
--vfs-used-is-size rclone size Use the rclone size algorithm for Used size
|
||||
--vfs-write-back Duration Time to writeback files after last use when using cache (default 5s)
|
||||
--vfs-write-wait Duration Time to wait for in-sequence write before giving error (default 1s)
|
||||
|
|
|
@ -506,7 +506,7 @@ together, if `--auth-proxy` is set the authorized keys option will be
|
|||
ignored.
|
||||
|
||||
There is an example program
|
||||
[bin/test_proxy.py](https://github.com/rclone/rclone/blob/master/test_proxy.py)
|
||||
[bin/test_proxy.py](https://github.com/rclone/rclone/blob/master/bin/test_proxy.py)
|
||||
in the rclone source code.
|
||||
|
||||
The program's job is to take a `user` and `pass` on the input and turn
|
||||
|
@ -626,7 +626,7 @@ rclone serve webdav remote:path [flags]
|
|||
--vfs-read-chunk-size SizeSuffix Read the source objects in chunks (default 128Mi)
|
||||
--vfs-read-chunk-size-limit SizeSuffix If greater than --vfs-read-chunk-size, double the chunk size after each chunk read, until the limit is reached ('off' is unlimited) (default off)
|
||||
--vfs-read-wait Duration Time to wait for in-sequence read before seeking (default 20ms)
|
||||
--vfs-refresh Refreshes the directory cache recursively on start
|
||||
--vfs-refresh Refreshes the directory cache recursively in the background on start
|
||||
--vfs-used-is-size rclone size Use the rclone size algorithm for Used size
|
||||
--vfs-write-back Duration Time to writeback files after last use when using cache (default 5s)
|
||||
--vfs-write-wait Duration Time to wait for in-sequence write before giving error (default 1s)
|
||||
|
|
|
@ -1614,7 +1614,7 @@ json.dump(o, sys.stdout, indent="\t")
|
|||
```
|
||||
|
||||
You can find this example (slightly expanded) in the rclone source code at
|
||||
[bin/test_metadata_mapper.py](https://github.com/rclone/rclone/blob/master/test_metadata_mapper.py).
|
||||
[bin/test_metadata_mapper.py](https://github.com/rclone/rclone/blob/master/bin/test_metadata_mapper.py).
|
||||
|
||||
If you want to see the input to the metadata mapper and the output
|
||||
returned from it in the log you can use `-vv --dump mapper`.
|
||||
|
@ -1674,7 +1674,7 @@ use multiple threads to transfer the file (default 256M).
|
|||
|
||||
Capable backends are marked in the
|
||||
[overview](/overview/#optional-features) as `MultithreadUpload`. (They
|
||||
need to implement either the `OpenWriterAt` or `OpenChunkedWriter`
|
||||
need to implement either the `OpenWriterAt` or `OpenChunkWriter`
|
||||
internal interfaces). These include include, `local`, `s3`,
|
||||
`azureblob`, `b2`, `oracleobjectstorage` and `smb` at the time of
|
||||
writing.
|
||||
|
|
|
@ -10,6 +10,17 @@ Rclone is single executable (`rclone`, or `rclone.exe` on Windows) that you can
|
|||
simply download as a zip archive and extract into a location of your choosing.
|
||||
See the [install](https://rclone.org/install/) documentation for more details.
|
||||
|
||||
## Release {{% version %}} OS requirements {#osrequirements}
|
||||
|
||||
| OS | Minimum Version |
|
||||
|:-------:|:-------:|
|
||||
| Linux | kernel 2.6.32 |
|
||||
| macOS (Intel) | 10.15 (Catalina) |
|
||||
| macOS (ARM64) | 11 (Big Sur) |
|
||||
| Windows | 10, Server 2016 |
|
||||
| FreeBSD | 12.2 |
|
||||
| OpenBSD | 6.9 |
|
||||
|
||||
## Release {{% version %}} {#release}
|
||||
|
||||
| Arch-OS | Windows | macOS | Linux | .deb | .rpm | FreeBSD | NetBSD | OpenBSD | Plan9 | Solaris |
|
||||
|
@ -101,3 +112,19 @@ script) from a URL which doesn't change then you can use these links.
|
|||
## Older Downloads
|
||||
|
||||
Older downloads can be found [here](https://downloads.rclone.org/).
|
||||
|
||||
The latest `rclone` version working for:
|
||||
| OS | Maximum rclone version |
|
||||
|:-------:|:-------:|
|
||||
| Windows 7 | v1.63.1 |
|
||||
| Windows Server 2008 | v1.63.1 |
|
||||
| Windows Server 2012 | v1.63.1 |
|
||||
| Windows XP | v1.42 |
|
||||
| Windows Vista | v1.42 |
|
||||
| macOS 10.14 (Mojave) | v1.63.1 |
|
||||
| macOS 10.13 (High Sierra) | v1.63.1 |
|
||||
| macOS 10.12 (Sierra) | v1.56.0 |
|
||||
| macOS 10.11 (El Capitan) | v1.52.0 |
|
||||
| macOS 10.10 (Yosemite) | v1.49.0 |
|
||||
| OS X 10.9 (Mavericks) | v1.42 |
|
||||
| OS X 10.8 (Mountain Lion) | v1.42 |
|
||||
|
|
|
@ -533,7 +533,7 @@ E.g. for an alternative `filter-file.txt`:
|
|||
- *
|
||||
|
||||
Files `file1.jpg`, `file3.png` and `file2.avi` are listed whilst
|
||||
`secret17.jpg` and files without the suffix .jpg` or `.png` are excluded.
|
||||
`secret17.jpg` and files without the suffix `.jpg` or `.png` are excluded.
|
||||
|
||||
E.g. for an alternative `filter-file.txt`:
|
||||
|
||||
|
|
|
@ -112,7 +112,7 @@ General networking and HTTP stuff.
|
|||
--tpslimit float Limit HTTP transactions per second to this
|
||||
--tpslimit-burst int Max burst of transactions for --tpslimit (default 1)
|
||||
--use-cookies Enable session cookiejar
|
||||
--user-agent string Set the user-agent to a specified string (default "rclone/v1.65.0")
|
||||
--user-agent string Set the user-agent to a specified string (default "rclone/v1.65.2")
|
||||
```
|
||||
|
||||
|
||||
|
|
|
@ -193,12 +193,12 @@ case "$OS" in
|
|||
exit 2
|
||||
esac
|
||||
|
||||
#cleanup
|
||||
rm -rf "$tmp_dir"
|
||||
|
||||
#update version variable post install
|
||||
version=$(rclone --version 2>>errors | head -n 1)
|
||||
|
||||
#cleanup
|
||||
rm -rf "$tmp_dir"
|
||||
|
||||
printf "\n${version} has successfully installed."
|
||||
printf '\nNow run "rclone config" for setup. Check https://rclone.org/docs/ for more details.\n\n'
|
||||
exit 0
|
||||
|
|
|
@ -485,6 +485,7 @@ upon backend-specific capabilities.
|
|||
| HDFS | Yes | No | Yes | Yes | No | No | Yes | No | No | Yes | Yes |
|
||||
| HiDrive | Yes | Yes | Yes | Yes | No | No | Yes | No | No | No | Yes |
|
||||
| HTTP | No | No | No | No | No | No | No | No | No | No | Yes |
|
||||
| ImageKit | Yes | Yes | Yes | No | No | No | No | No | No | No | Yes |
|
||||
| Internet Archive | No | Yes | No | No | Yes | Yes | No | No | Yes | Yes | No |
|
||||
| Jottacloud | Yes | Yes | Yes | Yes | Yes | Yes | No | No | Yes | Yes | Yes |
|
||||
| Koofr | Yes | Yes | Yes | Yes | No | No | Yes | No | Yes | Yes | Yes |
|
||||
|
|
|
@ -590,6 +590,7 @@ permissions are required to be available on the bucket being written to:
|
|||
* `GetObject`
|
||||
* `PutObject`
|
||||
* `PutObjectACL`
|
||||
* `CreateBucket` (unless using [s3-no-check-bucket](#s3-no-check-bucket))
|
||||
|
||||
When using the `lsd` subcommand, the `ListAllMyBuckets` permission is required.
|
||||
|
||||
|
@ -631,6 +632,7 @@ Notes on above:
|
|||
that `USER_NAME` has been created.
|
||||
2. The Resource entry must include both resource ARNs, as one implies
|
||||
the bucket and the other implies the bucket's objects.
|
||||
3. When using [s3-no-check-bucket](#s3-no-check-bucket) and the bucket already exsits, the `"arn:aws:s3:::BUCKET_NAME"` doesn't have to be included.
|
||||
|
||||
For reference, [here's an Ansible script](https://gist.github.com/ebridges/ebfc9042dd7c756cd101cfa807b7ae2b)
|
||||
that will generate one or more buckets that will work with `rclone sync`.
|
||||
|
|
|
@ -47,12 +47,14 @@
|
|||
<div class="col-md-10">
|
||||
<div class="card card-body">
|
||||
<p style="font-size: 90%;">
|
||||
© <a href="https://www.craig-wood.com/nick/">Nick Craig-Wood</a> 2014-{{ now.Format "2006" }}<br>
|
||||
{{ if .File}}{{ with $path := strings.TrimPrefix "/" .File.Path }}Source file <a href="https://github.com/rclone/rclone/blob/master/docs/content/{{ $path }}">{{ $path }}</a>{{ end }}
|
||||
© <a href="https://www.craig-wood.com/nick/" target="blank">Nick Craig-Wood</a> 2014-{{ now.Format "2006" }}<br>
|
||||
{{ if .File}}{{ with $path := strings.TrimPrefix "/" .File.Path }}Source file <a href="https://github.com/rclone/rclone/blob/master/docs/content/{{ $path }}" target="blank">{{ $path }}</a>{{ end }}
|
||||
last updated <a href="https://github.com/rclone/rclone/commit/{{ with .GitInfo }}{{ .Hash }}{{ end }}">{{ .Lastmod.Format "2006-01-02" }}</a><br>{{end}}
|
||||
Uploaded with <a href="https://rclone.org">rclone</a>.
|
||||
Built with <a href="https://github.com/spf13/hugo">Hugo</a>.
|
||||
Logo by <a href="https://twitter.com/andy23">@andy23</a>.
|
||||
Built with <a href="https://gohugo.io/" target="blank">Hugo</a>.
|
||||
Logo by <a href="https://twitter.com/andy23" target="blank">@andy23</a>.
|
||||
Served by <a href="https://caddyserver.com/" target="blank">Caddy</a>.
|
||||
Hosted at <a href="https://hetzner.cloud/?ref=62WcciVmlzHt" title="Get €20 in cloud credits" target="blank">Hetzner Cloud</a>.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -24,8 +24,8 @@
|
|||
<div class="card-header" style="padding: 5px 15px;">
|
||||
Silver Sponsor
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<a href="https://hubs.li/Q0261LHy0" target="_blank" rel="noopener" title="Visit rclone's sponsor Storj to see offer"><img src="/img/logos/storj-rclone-spot-1.png" style="max-width: 100%; height: auto;"></a><br />
|
||||
<div class="card-body" style="text-align: center">
|
||||
<a href="https://www.warp.dev/?utm_source=rclone&utm_medium=referral&utm_campaign=rclone_20231103" target="_blank" rel="noopener" title="Visit warp.dev to learn more."><img src="/img/logos/warp.svg" style=""></a><br />
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
|
|
|
@ -74,6 +74,7 @@
|
|||
<a class="dropdown-item" href="/hdfs/"><i class="fa fa-globe fa-fw"></i> HDFS (Hadoop Distributed Filesystem)</a>
|
||||
<a class="dropdown-item" href="/hidrive/"><i class="fa fa-cloud fa-fw"></i> HiDrive</a>
|
||||
<a class="dropdown-item" href="/http/"><i class="fa fa-globe fa-fw"></i> HTTP</a>
|
||||
<a class="dropdown-item" href="/imagekit/"><i class="fa fa-cloud fa-fw"></i> ImageKit</a>
|
||||
<a class="dropdown-item" href="/internetarchive/"><i class="fa fa-archive fa-fw"></i> Internet Archive</a>
|
||||
<a class="dropdown-item" href="/jottacloud/"><i class="fa fa-cloud fa-fw"></i> Jottacloud</a>
|
||||
<a class="dropdown-item" href="/koofr/"><i class="fa fa-suitcase fa-fw"></i> Koofr</a>
|
||||
|
|
|
@ -1 +1 @@
|
|||
v1.65.0
|
||||
v1.65.2
|
|
@ -60,6 +60,7 @@ type Account struct {
|
|||
closed bool // set if the file is closed
|
||||
exit chan struct{} // channel that will be closed when transfer is finished
|
||||
withBuf bool // is using a buffered in
|
||||
checking bool // set if attached transfer is checking
|
||||
|
||||
tokenBucket buckets // per file bandwidth limiter (may be nil)
|
||||
|
||||
|
@ -295,14 +296,24 @@ func (acc *Account) ServerSideTransferEnd(n int64) {
|
|||
acc.stats.Bytes(n)
|
||||
}
|
||||
|
||||
// serverSideEnd accounts for non specific server side data
|
||||
func (acc *Account) serverSideEnd(n int64) {
|
||||
// Account for bytes unless we are checking
|
||||
if !acc.checking {
|
||||
acc.stats.BytesNoNetwork(n)
|
||||
}
|
||||
}
|
||||
|
||||
// ServerSideCopyEnd accounts for a read of n bytes in a sever side copy
|
||||
func (acc *Account) ServerSideCopyEnd(n int64) {
|
||||
acc.stats.AddServerSideCopy(n)
|
||||
acc.serverSideEnd(n)
|
||||
}
|
||||
|
||||
// ServerSideMoveEnd accounts for a read of n bytes in a sever side move
|
||||
func (acc *Account) ServerSideMoveEnd(n int64) {
|
||||
acc.stats.AddServerSideMove(n)
|
||||
acc.serverSideEnd(n)
|
||||
}
|
||||
|
||||
// DryRun accounts for statistics without running the operation
|
||||
|
|
|
@ -527,6 +527,13 @@ func (s *StatsInfo) Bytes(bytes int64) {
|
|||
s.bytes += bytes
|
||||
}
|
||||
|
||||
// BytesNoNetwork updates the stats for bytes bytes but doesn't include the transfer stats
|
||||
func (s *StatsInfo) BytesNoNetwork(bytes int64) {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
s.bytes += bytes
|
||||
}
|
||||
|
||||
// GetBytes returns the number of bytes transferred so far
|
||||
func (s *StatsInfo) GetBytes() int64 {
|
||||
s.mu.RLock()
|
||||
|
|
|
@ -149,6 +149,7 @@ func (tr *Transfer) Account(ctx context.Context, in io.ReadCloser) *Account {
|
|||
} else {
|
||||
tr.acc.UpdateReader(ctx, in)
|
||||
}
|
||||
tr.acc.checking = tr.checking
|
||||
tr.mu.Unlock()
|
||||
return tr.acc
|
||||
}
|
||||
|
|
|
@ -332,9 +332,29 @@ func SameObject(src, dst fs.Object) bool {
|
|||
//
|
||||
// It returns the destination object if possible. Note that this may
|
||||
// be nil.
|
||||
//
|
||||
// This is accounted as a check.
|
||||
func Move(ctx context.Context, fdst fs.Fs, dst fs.Object, remote string, src fs.Object) (newDst fs.Object, err error) {
|
||||
return move(ctx, fdst, dst, remote, src, false)
|
||||
}
|
||||
|
||||
// MoveTransfer moves src object to dst or fdst if nil. If dst is nil
|
||||
// then it uses remote as the name of the new object.
|
||||
//
|
||||
// This is identical to Move but is accounted as a transfer.
|
||||
func MoveTransfer(ctx context.Context, fdst fs.Fs, dst fs.Object, remote string, src fs.Object) (newDst fs.Object, err error) {
|
||||
return move(ctx, fdst, dst, remote, src, true)
|
||||
}
|
||||
|
||||
// move - see Move for help
|
||||
func move(ctx context.Context, fdst fs.Fs, dst fs.Object, remote string, src fs.Object, isTransfer bool) (newDst fs.Object, err error) {
|
||||
ci := fs.GetConfig(ctx)
|
||||
tr := accounting.Stats(ctx).NewCheckingTransfer(src, "moving")
|
||||
var tr *accounting.Transfer
|
||||
if isTransfer {
|
||||
tr = accounting.Stats(ctx).NewTransfer(src)
|
||||
} else {
|
||||
tr = accounting.Stats(ctx).NewCheckingTransfer(src, "moving")
|
||||
}
|
||||
defer func() {
|
||||
if err == nil {
|
||||
accounting.Stats(ctx).Renames(1)
|
||||
|
@ -1695,7 +1715,7 @@ func moveOrCopyFile(ctx context.Context, fdst fs.Fs, fsrc fs.Fs, dstFileName str
|
|||
}
|
||||
|
||||
// Choose operations
|
||||
Op := Move
|
||||
Op := MoveTransfer
|
||||
if cp {
|
||||
Op = Copy
|
||||
}
|
||||
|
@ -1797,6 +1817,8 @@ func moveOrCopyFile(ctx context.Context, fdst fs.Fs, fsrc fs.Fs, dstFileName str
|
|||
}
|
||||
|
||||
// MoveFile moves a single file possibly to a new name
|
||||
//
|
||||
// This is treated as a transfer.
|
||||
func MoveFile(ctx context.Context, fdst fs.Fs, fsrc fs.Fs, dstFileName string, srcFileName string) (err error) {
|
||||
return moveOrCopyFile(ctx, fdst, fsrc, dstFileName, srcFileName, false)
|
||||
}
|
||||
|
|
|
@ -437,7 +437,7 @@ func (s *syncCopyMove) pairCopyOrMove(ctx context.Context, in *pipe, fdst fs.Fs,
|
|||
dst := pair.Dst
|
||||
if s.DoMove {
|
||||
if src != dst {
|
||||
_, err = operations.Move(ctx, fdst, dst, src.Remote(), src)
|
||||
_, err = operations.MoveTransfer(ctx, fdst, dst, src.Remote(), src)
|
||||
} else {
|
||||
// src == dst signals delete the src
|
||||
err = operations.DeleteFile(ctx, src)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package fs
|
||||
|
||||
// VersionTag of rclone
|
||||
var VersionTag = "v1.65.0"
|
||||
var VersionTag = "v1.65.2"
|
||||
|
|
|
@ -1675,6 +1675,24 @@ func Run(t *testing.T, opt *Opt) {
|
|||
require.NotNil(t, fileRemote)
|
||||
assert.Equal(t, fs.ErrorIsFile, err)
|
||||
|
||||
// Check Fs.Root returns the right thing
|
||||
t.Run("FsRoot", func(t *testing.T) {
|
||||
skipIfNotOk(t)
|
||||
got := fileRemote.Root()
|
||||
remoteDir := path.Dir(remoteName)
|
||||
want := remoteDir
|
||||
colon := strings.LastIndex(want, ":")
|
||||
if colon >= 0 {
|
||||
want = want[colon+1:]
|
||||
}
|
||||
if isLocalRemote {
|
||||
// only check last path element on local
|
||||
require.Equal(t, filepath.Base(remoteDir), filepath.Base(got))
|
||||
} else {
|
||||
require.Equal(t, want, got)
|
||||
}
|
||||
})
|
||||
|
||||
if strings.HasPrefix(remoteName, "TestChunker") && strings.Contains(remoteName, "Nometa") {
|
||||
// TODO fix chunker and remove this bypass
|
||||
t.Logf("Skip listing check -- chunker can't yet handle this tricky case")
|
||||
|
|
|
@ -298,10 +298,6 @@ backends:
|
|||
fastlist: false
|
||||
- backend: "ftp"
|
||||
remote: "TestFTPRclone:"
|
||||
ignore:
|
||||
- "TestMultithreadCopy/{size:131071_streams:2}"
|
||||
- "TestMultithreadCopy/{size:131072_streams:2}"
|
||||
- "TestMultithreadCopy/{size:131073_streams:2}"
|
||||
fastlist: false
|
||||
- backend: "box"
|
||||
remote: "TestBox:"
|
||||
|
|
|
@ -286,6 +286,9 @@ func (r *Run) MakeTestBinary() {
|
|||
binaryName := r.BinaryName()
|
||||
log.Printf("%s: Making test binary %q", r.Path, binaryName)
|
||||
CmdLine := []string{"go", "test", "-c"}
|
||||
if *race {
|
||||
CmdLine = append(CmdLine, "-race")
|
||||
}
|
||||
if *dryRun {
|
||||
log.Printf("Not executing: %v", CmdLine)
|
||||
return
|
||||
|
|
|
@ -35,6 +35,7 @@ var (
|
|||
clean = flag.Bool("clean", false, "Instead of testing, clean all left over test directories")
|
||||
runOnly = flag.String("run", "", "Run only those tests matching the regexp supplied")
|
||||
timeout = flag.Duration("timeout", 60*time.Minute, "Maximum time to run each test for before giving up")
|
||||
race = flag.Bool("race", false, "If set run the tests under the race detector")
|
||||
configFile = flag.String("config", "fstest/test_all/config.yaml", "Path to config file")
|
||||
outputDir = flag.String("output", path.Join(os.TempDir(), "rclone-integration-tests"), "Place to store results")
|
||||
emailReport = flag.String("email", "", "Set to email the report to the address supplied")
|
||||
|
|
14
go.mod
14
go.mod
|
@ -20,7 +20,7 @@ require (
|
|||
github.com/atotto/clipboard v0.1.4
|
||||
github.com/aws/aws-sdk-go v1.46.6
|
||||
github.com/buengese/sgzip v0.1.1
|
||||
github.com/cloudsoda/go-smb2 v0.0.0-20231106205947-b0758ecc4c67
|
||||
github.com/cloudsoda/go-smb2 v0.0.0-20231124195312-f3ec8ae2c891
|
||||
github.com/colinmarc/hdfs/v2 v2.4.0
|
||||
github.com/coreos/go-semver v0.3.1
|
||||
github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf
|
||||
|
@ -71,12 +71,12 @@ require (
|
|||
github.com/yunify/qingstor-sdk-go/v3 v3.2.0
|
||||
go.etcd.io/bbolt v1.3.8
|
||||
goftp.io/server/v2 v2.0.1
|
||||
golang.org/x/crypto v0.14.0
|
||||
golang.org/x/crypto v0.17.0
|
||||
golang.org/x/net v0.17.0
|
||||
golang.org/x/oauth2 v0.13.0
|
||||
golang.org/x/sync v0.4.0
|
||||
golang.org/x/sys v0.13.0
|
||||
golang.org/x/text v0.13.0
|
||||
golang.org/x/sys v0.15.0
|
||||
golang.org/x/text v0.14.0
|
||||
golang.org/x/time v0.3.0
|
||||
google.golang.org/api v0.148.0
|
||||
gopkg.in/validator.v2 v2.0.1
|
||||
|
@ -102,7 +102,7 @@ require (
|
|||
github.com/bradenaw/juniper v0.13.1 // indirect
|
||||
github.com/calebcase/tmpfile v1.0.3 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.2.0 // indirect
|
||||
github.com/cloudflare/circl v1.3.6 // indirect
|
||||
github.com/cloudflare/circl v1.3.7 // indirect
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.3 // indirect
|
||||
github.com/cronokirby/saferith v0.33.0 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
|
@ -114,7 +114,7 @@ require (
|
|||
github.com/gdamore/encoding v1.0.0 // indirect
|
||||
github.com/geoffgarside/ber v1.1.0 // indirect
|
||||
github.com/go-ole/go-ole v1.3.0 // indirect
|
||||
github.com/go-resty/resty/v2 v2.10.0 // indirect
|
||||
github.com/go-resty/resty/v2 v2.11.0 // indirect
|
||||
github.com/gofrs/flock v0.8.1 // indirect
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
github.com/golang-jwt/jwt/v5 v5.0.0 // indirect
|
||||
|
@ -193,5 +193,5 @@ require (
|
|||
github.com/google/go-querystring v1.1.0 // indirect
|
||||
github.com/pkg/xattr v0.4.9
|
||||
golang.org/x/mobile v0.0.0-20231006135142-2b44d11868fe
|
||||
golang.org/x/term v0.13.0
|
||||
golang.org/x/term v0.15.0
|
||||
)
|
||||
|
|
24
go.sum
24
go.sum
|
@ -131,10 +131,10 @@ github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMn
|
|||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/cloudflare/circl v1.1.0/go.mod h1:prBCrKB9DV4poKZY1l9zBXg2QJY7mvgRvtMxxK7fi4I=
|
||||
github.com/cloudflare/circl v1.3.3/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA=
|
||||
github.com/cloudflare/circl v1.3.6 h1:/xbKIqSHbZXHwkhbrhrt2YOHIwYJlXH94E3tI/gDlUg=
|
||||
github.com/cloudflare/circl v1.3.6/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA=
|
||||
github.com/cloudsoda/go-smb2 v0.0.0-20231106205947-b0758ecc4c67 h1:KzZU0EMkUm4vX/jPp5d/VttocDpocL/8QP0zyiI9Xiw=
|
||||
github.com/cloudsoda/go-smb2 v0.0.0-20231106205947-b0758ecc4c67/go.mod h1:xFxVVe3plxwhM+6BgTTPByEgG8hggo8+gtRUkbc5W8Q=
|
||||
github.com/cloudflare/circl v1.3.7 h1:qlCDlTPz2n9fu58M0Nh1J/JzcFpfgkFHHX3O35r5vcU=
|
||||
github.com/cloudflare/circl v1.3.7/go.mod h1:sRTcRWXGLrKw6yIGJ+l7amYJFfAXbZG0kBSc8r4zxgA=
|
||||
github.com/cloudsoda/go-smb2 v0.0.0-20231124195312-f3ec8ae2c891 h1:nPP4suUiNage0vvyEBgfAnhTPwwXhNqtHmSuiCIQwKU=
|
||||
github.com/cloudsoda/go-smb2 v0.0.0-20231124195312-f3ec8ae2c891/go.mod h1:xFxVVe3plxwhM+6BgTTPByEgG8hggo8+gtRUkbc5W8Q=
|
||||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||
github.com/colinmarc/hdfs/v2 v2.4.0 h1:v6R8oBx/Wu9fHpdPoJJjpGSUxo8NhHIwrwsfhFvU9W0=
|
||||
github.com/colinmarc/hdfs/v2 v2.4.0/go.mod h1:0NAO+/3knbMx6+5pCv+Hcbaz4xn/Zzbn9+WIib2rKVI=
|
||||
|
@ -201,8 +201,8 @@ github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW
|
|||
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
|
||||
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
|
||||
github.com/go-playground/validator/v10 v10.14.0 h1:vgvQWe3XCz3gIeFDm/HnTIbj6UGmg/+t63MyGU2n5js=
|
||||
github.com/go-resty/resty/v2 v2.10.0 h1:Qla4W/+TMmv0fOeeRqzEpXPLfTUnR5HZ1+lGs+CkiCo=
|
||||
github.com/go-resty/resty/v2 v2.10.0/go.mod h1:iiP/OpA0CkcL3IGt1O0+/SIItFUbkkyw5BGXiVdTu+A=
|
||||
github.com/go-resty/resty/v2 v2.11.0 h1:i7jMfNOJYMp69lq7qozJP+bjgzfAzeOhuGlyDrqxT/8=
|
||||
github.com/go-resty/resty/v2 v2.11.0/go.mod h1:iiP/OpA0CkcL3IGt1O0+/SIItFUbkkyw5BGXiVdTu+A=
|
||||
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
|
||||
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
|
||||
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||
|
@ -592,8 +592,9 @@ golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw
|
|||
golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
|
||||
golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58=
|
||||
golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
|
||||
golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc=
|
||||
golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
|
||||
golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k=
|
||||
golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||
|
@ -752,8 +753,9 @@ golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|||
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
|
||||
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc=
|
||||
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
|
@ -762,8 +764,9 @@ golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
|||
golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U=
|
||||
golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY=
|
||||
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
|
||||
golang.org/x/term v0.13.0 h1:bb+I9cTfFazGW51MZqBVmZy7+JEJMouUHTUSKVQLBek=
|
||||
golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U=
|
||||
golang.org/x/term v0.15.0 h1:y/Oo/a/q3IXu26lQgl04j/gjuBDOBlx7X6Om1j2CPW4=
|
||||
golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0=
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
|
@ -777,8 +780,9 @@ golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
|||
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||
golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
|
||||
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
|
||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
|
|
|
@ -216,7 +216,7 @@ func (db *DB) loop() {
|
|||
|
||||
// Do a key-value operation and return error when done
|
||||
func (db *DB) Do(write bool, op Op) error {
|
||||
if db.queue == nil {
|
||||
if db == nil || db.queue == nil {
|
||||
return ErrInactive
|
||||
}
|
||||
r := &request{
|
||||
|
|
|
@ -292,7 +292,7 @@ func (ts *TokenSource) Token() (*oauth2.Token, error) {
|
|||
if err != nil {
|
||||
return nil, fmt.Errorf("couldn't fetch token: %w", err)
|
||||
}
|
||||
changed = changed || (*token != *ts.token)
|
||||
changed = changed || token.AccessToken != ts.token.AccessToken || token.RefreshToken != ts.token.RefreshToken || token.Expiry != ts.token.Expiry
|
||||
ts.token = token
|
||||
if changed {
|
||||
// Bump on the expiry timer if it is set
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
package readers
|
||||
|
||||
import "io"
|
||||
import (
|
||||
"io"
|
||||
|
||||
"github.com/rclone/rclone/fs"
|
||||
)
|
||||
|
||||
// LimitedReadCloser adds io.Closer to io.LimitedReader. Create one with NewLimitedReadCloser
|
||||
type LimitedReadCloser struct {
|
||||
|
@ -8,6 +12,16 @@ type LimitedReadCloser struct {
|
|||
io.Closer
|
||||
}
|
||||
|
||||
// Close closes the underlying io.Closer. The error, if any, will be ignored if data is read completely
|
||||
func (lrc *LimitedReadCloser) Close() error {
|
||||
err := lrc.Closer.Close()
|
||||
if err != nil && lrc.N == 0 {
|
||||
fs.Debugf(nil, "ignoring close error because we already got all the data")
|
||||
err = nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// NewLimitedReadCloser returns a LimitedReadCloser wrapping rc to
|
||||
// limit it to reading limit bytes. If limit < 0 then it does not
|
||||
// wrap rc, it just returns it.
|
||||
|
|
|
@ -12,16 +12,17 @@ notice will be removed.
|
|||
The shims are a thin wrapper over the rclone RPC.
|
||||
|
||||
The implementation is based on cgo; to build it you need Go and a GCC compatible
|
||||
C compiler (GCC or Clang). On Windows you can use the MinGW port of GCC,
|
||||
e.g. by installing it in a [MSYS2](https://www.msys2.org) distribution
|
||||
(make sure you install GCC in the classic mingw64 subsystem, the ucrt64 version
|
||||
is not compatible with cgo).
|
||||
C compiler (GCC or Clang). On Windows you can use the MinGW ports, e.g. by installing
|
||||
in a [MSYS2](https://www.msys2.org) distribution (you may now install GCC in the newer
|
||||
and recommended UCRT64 subsystem, however there were compatibility issues with previous
|
||||
versions of cgo where, if not force rebuild with go build option `-a` helped, you had
|
||||
to resort to the classic MINGW64 subsystem).
|
||||
|
||||
Build a shared library like this:
|
||||
Build a shared library like this (change from .so to .dll on Windows):
|
||||
|
||||
go build --buildmode=c-shared -o librclone.so github.com/rclone/rclone/librclone
|
||||
|
||||
Build a static library like this:
|
||||
Build a static library like this (change from .a to .lib on Windows):
|
||||
|
||||
go build --buildmode=c-archive -o librclone.a github.com/rclone/rclone/librclone
|
||||
|
||||
|
|
|
@ -714,3 +714,47 @@ func TestRWCacheRename(t *testing.T) {
|
|||
assert.False(t, vfs.cache.Exists("rename_me"))
|
||||
assert.True(t, vfs.cache.Exists("i_was_renamed"))
|
||||
}
|
||||
|
||||
// Test the cache reading a file that is updated externally
|
||||
//
|
||||
// See: https://github.com/rclone/rclone/issues/6053
|
||||
func TestRWCacheUpdate(t *testing.T) {
|
||||
opt := vfscommon.DefaultOpt
|
||||
opt.CacheMode = vfscommon.CacheModeFull
|
||||
opt.WriteBack = writeBackDelay
|
||||
opt.DirCacheTime = 100 * time.Millisecond
|
||||
r, vfs := newTestVFSOpt(t, &opt)
|
||||
|
||||
if r.Fremote.Precision() == fs.ModTimeNotSupported {
|
||||
t.Skip("skip as modtime not supported")
|
||||
}
|
||||
|
||||
const filename = "TestRWCacheUpdate"
|
||||
|
||||
modTime := time.Now().Add(-time.Hour)
|
||||
for i := 0; i < 10; i++ {
|
||||
modTime = modTime.Add(time.Minute)
|
||||
// Refresh test file
|
||||
contents := fmt.Sprintf("TestRWCacheUpdate%03d", i)
|
||||
// Increase the size for second half of test
|
||||
for j := 5; j < i; j++ {
|
||||
contents += "*"
|
||||
}
|
||||
file1 := r.WriteObject(context.Background(), filename, contents, modTime)
|
||||
r.CheckRemoteItems(t, file1)
|
||||
|
||||
// Wait for directory cache to expire
|
||||
time.Sleep(2 * opt.DirCacheTime)
|
||||
|
||||
// Check the file is OK via the VFS
|
||||
data, err := vfs.ReadFile(filename)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, contents, string(data))
|
||||
|
||||
// Check Stat
|
||||
fi, err := vfs.Stat(filename)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, int64(len(contents)), fi.Size())
|
||||
fstest.AssertTimeEqualWithPrecision(t, filename, modTime, fi.ModTime(), r.Fremote.Precision())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -810,6 +810,7 @@ func (item *Item) _checkObject(o fs.Object) error {
|
|||
if !item.info.Dirty {
|
||||
fs.Debugf(item.name, "vfs cache: removing cached entry as stale (remote fingerprint %q != cached fingerprint %q)", remoteFingerprint, item.info.Fingerprint)
|
||||
item._remove("stale (remote is different)")
|
||||
item.info.Fingerprint = remoteFingerprint
|
||||
} else {
|
||||
fs.Debugf(item.name, "vfs cache: remote object has changed but local object modified - keeping it (remote fingerprint %q != cached fingerprint %q)", remoteFingerprint, item.info.Fingerprint)
|
||||
}
|
||||
|
|
|
@ -409,8 +409,14 @@ func TestItemReloadCacheStale(t *testing.T) {
|
|||
assert.NotEqual(t, contents, contents2)
|
||||
|
||||
// Re-open with updated object
|
||||
oldFingerprint := item.info.Fingerprint
|
||||
assert.NotEqual(t, "", oldFingerprint)
|
||||
require.NoError(t, item.Open(obj))
|
||||
|
||||
// Make sure fingerprint was updated
|
||||
assert.NotEqual(t, oldFingerprint, item.info.Fingerprint)
|
||||
assert.NotEqual(t, "", item.info.Fingerprint)
|
||||
|
||||
// Check size is now 110
|
||||
size, err = item.GetSize()
|
||||
require.NoError(t, err)
|
||||
|
|
|
@ -22,7 +22,7 @@ func AddFlags(flagSet *pflag.FlagSet) {
|
|||
flags.BoolVarP(flagSet, &Opt.NoChecksum, "no-checksum", "", Opt.NoChecksum, "Don't compare checksums on up/download", "VFS")
|
||||
flags.BoolVarP(flagSet, &Opt.NoSeek, "no-seek", "", Opt.NoSeek, "Don't allow seeking in files", "VFS")
|
||||
flags.DurationVarP(flagSet, &Opt.DirCacheTime, "dir-cache-time", "", Opt.DirCacheTime, "Time to cache directory entries for", "VFS")
|
||||
flags.BoolVarP(flagSet, &Opt.Refresh, "vfs-refresh", "", Opt.Refresh, "Refreshes the directory cache recursively on start", "VFS")
|
||||
flags.BoolVarP(flagSet, &Opt.Refresh, "vfs-refresh", "", Opt.Refresh, "Refreshes the directory cache recursively in the background on start", "VFS")
|
||||
flags.DurationVarP(flagSet, &Opt.PollInterval, "poll-interval", "", Opt.PollInterval, "Time to wait between polling for changes, must be smaller than dir-cache-time and only on supported remotes (set 0 to disable)", "VFS")
|
||||
flags.BoolVarP(flagSet, &Opt.ReadOnly, "read-only", "", Opt.ReadOnly, "Only allow read-only access", "VFS")
|
||||
flags.FVarP(flagSet, &Opt.CacheMode, "vfs-cache-mode", "", "Cache mode off|minimal|writes|full", "VFS")
|
||||
|
|
Loading…
Reference in New Issue