mirror of
https://github.com/rclone/rclone.git
synced 2026-01-28 15:23:26 +00:00
Compare commits
67 Commits
fix-1727-o
...
tiers
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
db0560e295 | ||
|
|
e75dbd6e91 | ||
|
|
8679bbce90 | ||
|
|
c65d2383b2 | ||
|
|
d9c1a96071 | ||
|
|
824257583c | ||
|
|
cd857754c7 | ||
|
|
017d930dfc | ||
|
|
6ed68883fe | ||
|
|
2a5e0b28c9 | ||
|
|
264e75d892 | ||
|
|
4553c3de7b | ||
|
|
2e9e4a47a2 | ||
|
|
e44829a448 | ||
|
|
6b9f77459a | ||
|
|
4b2c39c585 | ||
|
|
dbf2499d85 | ||
|
|
760a134c95 | ||
|
|
63cfe260a2 | ||
|
|
3550275cd3 | ||
|
|
b728929f44 | ||
|
|
9ec918f137 | ||
|
|
3a9c7ceeb1 | ||
|
|
5502c0f8ae | ||
|
|
d707ae7cf4 | ||
|
|
9bef7f0dbf | ||
|
|
933bbf3ac8 | ||
|
|
ecc5972d6f | ||
|
|
07805796ab | ||
|
|
189e6dbf6a | ||
|
|
d47e289165 | ||
|
|
e51a0599a0 | ||
|
|
530a901de3 | ||
|
|
a64a8aad0e | ||
|
|
6529d2cd8f | ||
|
|
d9895fef9d | ||
|
|
8c7b7ac891 | ||
|
|
f814498561 | ||
|
|
5f4e4b1a20 | ||
|
|
28c187b9b4 | ||
|
|
e07afc4645 | ||
|
|
08932ab92a | ||
|
|
356ee57edb | ||
|
|
7c1660214d | ||
|
|
51b197c86f | ||
|
|
029ffd2761 | ||
|
|
f81cd7d279 | ||
|
|
1a0a4628d7 | ||
|
|
c10a4d465c | ||
|
|
3a6e07a613 | ||
|
|
c36f99d343 | ||
|
|
3e21a7261b | ||
|
|
fd439fab62 | ||
|
|
976aa6b416 | ||
|
|
b3a0383ca3 | ||
|
|
c13f129339 | ||
|
|
748d8c8957 | ||
|
|
4d379efcbb | ||
|
|
e5e6a4b5ae | ||
|
|
df18e8c55b | ||
|
|
f4e17d8b0b | ||
|
|
e5c69511bc | ||
|
|
175d4bc553 | ||
|
|
4851f1796c | ||
|
|
4ff8899b2c | ||
|
|
8f29a0b0a1 | ||
|
|
8b0e76e53b |
2
.github/workflows/build.yml
vendored
2
.github/workflows/build.yml
vendored
@@ -229,7 +229,7 @@ jobs:
|
||||
cache: false
|
||||
|
||||
- name: Cache
|
||||
uses: actions/cache@v4
|
||||
uses: actions/cache@v5
|
||||
with:
|
||||
path: |
|
||||
~/go/pkg/mod
|
||||
|
||||
@@ -129,7 +129,7 @@ jobs:
|
||||
|
||||
- name: Load Go Build Cache for Docker
|
||||
id: go-cache
|
||||
uses: actions/cache@v4
|
||||
uses: actions/cache@v5
|
||||
with:
|
||||
key: ${{ runner.os }}-${{ steps.imageos.outputs.result }}-go-${{ env.CACHE_NAME }}-${{ env.PLATFORM }}-${{ hashFiles('**/go.mod') }}-${{ hashFiles('**/go.sum') }}
|
||||
restore-keys: |
|
||||
@@ -183,7 +183,7 @@ jobs:
|
||||
touch "/tmp/digests/${digest#sha256:}"
|
||||
|
||||
- name: Upload Image Digest
|
||||
uses: actions/upload-artifact@v5
|
||||
uses: actions/upload-artifact@v6
|
||||
with:
|
||||
name: digests-${{ env.PLATFORM }}
|
||||
path: /tmp/digests/*
|
||||
@@ -198,7 +198,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Download Image Digests
|
||||
uses: actions/download-artifact@v6
|
||||
uses: actions/download-artifact@v7
|
||||
with:
|
||||
path: /tmp/digests
|
||||
pattern: digests-*
|
||||
|
||||
@@ -632,14 +632,22 @@ Add your backend to the docs - you'll need to pick an icon for it from
|
||||
alphabetical order of full name of remote (e.g. `drive` is ordered as
|
||||
`Google Drive`) but with the local file system last.
|
||||
|
||||
First add a data file about your backend in
|
||||
`docs/data/backends/remote.yaml` - this is used to build the overview
|
||||
tables and the tiering info.
|
||||
|
||||
- Create it with: `bin/manage_backends.py create docs/data/backends/remote.yaml`
|
||||
- Edit it to fill in the blanks. Look at the [tiers docs](https://rclone.org/tiers/).
|
||||
- Run this command to fill in the features: `bin/manage_backends.py features docs/data/backends/remote.yaml`
|
||||
|
||||
Next edit these files:
|
||||
|
||||
- `README.md` - main GitHub page
|
||||
- `docs/content/remote.md` - main docs page (note the backend options are
|
||||
automatically added to this file with `make backenddocs`)
|
||||
- make sure this has the `autogenerated options` comments in (see your
|
||||
reference backend docs)
|
||||
- update them in your backend with `bin/make_backend_docs.py remote`
|
||||
- `docs/content/overview.md` - overview docs - add an entry into the Features
|
||||
table and the Optional Features table.
|
||||
- `docs/content/docs.md` - list of remotes in config section
|
||||
- `docs/content/_index.md` - front page of rclone.org
|
||||
- `docs/layouts/chrome/navbar.html` - add it to the website navigation
|
||||
|
||||
@@ -28,21 +28,25 @@ directories to and from different cloud storage providers.
|
||||
- Alibaba Cloud (Aliyun) Object Storage System (OSS) [:page_facing_up:](https://rclone.org/s3/#alibaba-oss)
|
||||
- Amazon S3 [:page_facing_up:](https://rclone.org/s3/)
|
||||
- ArvanCloud Object Storage (AOS) [:page_facing_up:](https://rclone.org/s3/#arvan-cloud-object-storage-aos)
|
||||
- Bizfly Cloud Simple Storage [:page_facing_up:](https://rclone.org/s3/#bizflycloud)
|
||||
- Backblaze B2 [:page_facing_up:](https://rclone.org/b2/)
|
||||
- Box [:page_facing_up:](https://rclone.org/box/)
|
||||
- Ceph [:page_facing_up:](https://rclone.org/s3/#ceph)
|
||||
- China Mobile Ecloud Elastic Object Storage (EOS) [:page_facing_up:](https://rclone.org/s3/#china-mobile-ecloud-eos)
|
||||
- Cloudflare R2 [:page_facing_up:](https://rclone.org/s3/#cloudflare-r2)
|
||||
- Citrix ShareFile [:page_facing_up:](https://rclone.org/sharefile/)
|
||||
- Cloudflare R2 [:page_facing_up:](https://rclone.org/s3/#cloudflare-r2)
|
||||
- Cloudinary [:page_facing_up:](https://rclone.org/cloudinary/)
|
||||
- Cubbit DS3 [:page_facing_up:](https://rclone.org/s3/#Cubbit)
|
||||
- DigitalOcean Spaces [:page_facing_up:](https://rclone.org/s3/#digitalocean-spaces)
|
||||
- Digi Storage [:page_facing_up:](https://rclone.org/koofr/#digi-storage)
|
||||
- Dreamhost [:page_facing_up:](https://rclone.org/s3/#dreamhost)
|
||||
- Drime [:page_facing_up:](https://rclone.org/s3/#drime)
|
||||
- Dropbox [:page_facing_up:](https://rclone.org/dropbox/)
|
||||
- Enterprise File Fabric [:page_facing_up:](https://rclone.org/filefabric/)
|
||||
- Exaba [:page_facing_up:](https://rclone.org/s3/#exaba)
|
||||
- Fastmail Files [:page_facing_up:](https://rclone.org/webdav/#fastmail-files)
|
||||
- FileLu [:page_facing_up:](https://rclone.org/filelu/)
|
||||
- Filen [:page_facing_up:](https://rclone.org/filen/)
|
||||
- Files.com [:page_facing_up:](https://rclone.org/filescom/)
|
||||
- FlashBlade [:page_facing_up:](https://rclone.org/s3/#pure-storage-flashblade)
|
||||
- FTP [:page_facing_up:](https://rclone.org/ftp/)
|
||||
@@ -109,6 +113,7 @@ directories to and from different cloud storage providers.
|
||||
- Selectel Object Storage [:page_facing_up:](https://rclone.org/s3/#selectel)
|
||||
- Servercore Object Storage [:page_facing_up:](https://rclone.org/s3/#servercore)
|
||||
- SFTP [:page_facing_up:](https://rclone.org/sftp/)
|
||||
- Shade [:page_facing_up:](https://rclone.org/shade/)
|
||||
- SMB / CIFS [:page_facing_up:](https://rclone.org/smb/)
|
||||
- Spectra Logic [:page_facing_up:](https://rclone.org/s3/#spectralogic)
|
||||
- StackPath [:page_facing_up:](https://rclone.org/s3/#stackpath)
|
||||
|
||||
@@ -16,11 +16,13 @@ import (
|
||||
_ "github.com/rclone/rclone/backend/compress"
|
||||
_ "github.com/rclone/rclone/backend/crypt"
|
||||
_ "github.com/rclone/rclone/backend/doi"
|
||||
_ "github.com/rclone/rclone/backend/drime"
|
||||
_ "github.com/rclone/rclone/backend/drive"
|
||||
_ "github.com/rclone/rclone/backend/dropbox"
|
||||
_ "github.com/rclone/rclone/backend/fichier"
|
||||
_ "github.com/rclone/rclone/backend/filefabric"
|
||||
_ "github.com/rclone/rclone/backend/filelu"
|
||||
_ "github.com/rclone/rclone/backend/filen"
|
||||
_ "github.com/rclone/rclone/backend/filescom"
|
||||
_ "github.com/rclone/rclone/backend/ftp"
|
||||
_ "github.com/rclone/rclone/backend/gofile"
|
||||
@@ -55,6 +57,7 @@ import (
|
||||
_ "github.com/rclone/rclone/backend/s3"
|
||||
_ "github.com/rclone/rclone/backend/seafile"
|
||||
_ "github.com/rclone/rclone/backend/sftp"
|
||||
_ "github.com/rclone/rclone/backend/shade"
|
||||
_ "github.com/rclone/rclone/backend/sharefile"
|
||||
_ "github.com/rclone/rclone/backend/sia"
|
||||
_ "github.com/rclone/rclone/backend/smb"
|
||||
@@ -63,7 +66,6 @@ import (
|
||||
_ "github.com/rclone/rclone/backend/swift"
|
||||
_ "github.com/rclone/rclone/backend/ulozto"
|
||||
_ "github.com/rclone/rclone/backend/union"
|
||||
_ "github.com/rclone/rclone/backend/uptobox"
|
||||
_ "github.com/rclone/rclone/backend/webdav"
|
||||
_ "github.com/rclone/rclone/backend/yandex"
|
||||
_ "github.com/rclone/rclone/backend/zoho"
|
||||
|
||||
@@ -77,7 +77,7 @@ The DOI provider can be set when rclone does not automatically recognize a suppo
|
||||
Name: "doi_resolver_api_url",
|
||||
Help: `The URL of the DOI resolver API to use.
|
||||
|
||||
The DOI resolver can be set for testing or for cases when the the canonical DOI resolver API cannot be used.
|
||||
The DOI resolver can be set for testing or for cases when the canonical DOI resolver API cannot be used.
|
||||
|
||||
Defaults to "https://doi.org/api".`,
|
||||
Required: false,
|
||||
|
||||
237
backend/drime/api/types.go
Normal file
237
backend/drime/api/types.go
Normal file
@@ -0,0 +1,237 @@
|
||||
// Package api has type definitions for drime
|
||||
//
|
||||
// Converted from the API docs with help from https://mholt.github.io/json-to-go/
|
||||
package api
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Types of things in Item
|
||||
const (
|
||||
ItemTypeFolder = "folder"
|
||||
)
|
||||
|
||||
// User information
|
||||
type User struct {
|
||||
Email string `json:"email"`
|
||||
ID json.Number `json:"id"`
|
||||
Avatar string `json:"avatar"`
|
||||
ModelType string `json:"model_type"`
|
||||
OwnsEntry bool `json:"owns_entry"`
|
||||
EntryPermissions []any `json:"entry_permissions"`
|
||||
DisplayName string `json:"display_name"`
|
||||
}
|
||||
|
||||
// Permissions for a file
|
||||
type Permissions struct {
|
||||
FilesUpdate bool `json:"files.update"`
|
||||
FilesCreate bool `json:"files.create"`
|
||||
FilesDownload bool `json:"files.download"`
|
||||
FilesDelete bool `json:"files.delete"`
|
||||
}
|
||||
|
||||
// Item describes a folder or a file as returned by /drive/file-entries
|
||||
type Item struct {
|
||||
ID json.Number `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Description any `json:"description"`
|
||||
FileName string `json:"file_name"`
|
||||
Mime string `json:"mime"`
|
||||
Color any `json:"color"`
|
||||
Backup bool `json:"backup"`
|
||||
Tracked int `json:"tracked"`
|
||||
FileSize int64 `json:"file_size"`
|
||||
UserID json.Number `json:"user_id"`
|
||||
ParentID json.Number `json:"parent_id"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
DeletedAt any `json:"deleted_at"`
|
||||
IsDeleted int `json:"is_deleted"`
|
||||
Path string `json:"path"`
|
||||
DiskPrefix any `json:"disk_prefix"`
|
||||
Type string `json:"type"`
|
||||
Extension any `json:"extension"`
|
||||
FileHash any `json:"file_hash"`
|
||||
Public bool `json:"public"`
|
||||
Thumbnail bool `json:"thumbnail"`
|
||||
MuxStatus any `json:"mux_status"`
|
||||
ThumbnailURL any `json:"thumbnail_url"`
|
||||
WorkspaceID int `json:"workspace_id"`
|
||||
IsEncrypted int `json:"is_encrypted"`
|
||||
Iv any `json:"iv"`
|
||||
VaultID any `json:"vault_id"`
|
||||
OwnerID int `json:"owner_id"`
|
||||
Hash string `json:"hash"`
|
||||
URL string `json:"url"`
|
||||
Users []User `json:"users"`
|
||||
Tags []any `json:"tags"`
|
||||
Permissions Permissions `json:"permissions"`
|
||||
}
|
||||
|
||||
// Listing response
|
||||
type Listing struct {
|
||||
CurrentPage int `json:"current_page"`
|
||||
Data []Item `json:"data"`
|
||||
From int `json:"from"`
|
||||
LastPage int `json:"last_page"`
|
||||
NextPage int `json:"next_page"`
|
||||
PerPage int `json:"per_page"`
|
||||
PrevPage int `json:"prev_page"`
|
||||
To int `json:"to"`
|
||||
Total int `json:"total"`
|
||||
}
|
||||
|
||||
// UploadResponse for a file
|
||||
type UploadResponse struct {
|
||||
Status string `json:"status"`
|
||||
FileEntry Item `json:"fileEntry"`
|
||||
}
|
||||
|
||||
// CreateFolderRequest for a folder
|
||||
type CreateFolderRequest struct {
|
||||
Name string `json:"name"`
|
||||
ParentID json.Number `json:"parentId,omitempty"`
|
||||
}
|
||||
|
||||
// CreateFolderResponse for a folder
|
||||
type CreateFolderResponse struct {
|
||||
Status string `json:"status"`
|
||||
Folder Item `json:"folder"`
|
||||
}
|
||||
|
||||
// Error is returned from drime when things go wrong
|
||||
type Error struct {
|
||||
Message string `json:"message"`
|
||||
}
|
||||
|
||||
// Error returns a string for the error and satisfies the error interface
|
||||
func (e Error) Error() string {
|
||||
out := fmt.Sprintf("Error %q", e.Message)
|
||||
return out
|
||||
}
|
||||
|
||||
// Check Error satisfies the error interface
|
||||
var _ error = (*Error)(nil)
|
||||
|
||||
// DeleteRequest is the input to DELETE /file-entries
|
||||
type DeleteRequest struct {
|
||||
EntryIDs []string `json:"entryIds"`
|
||||
DeleteForever bool `json:"deleteForever"`
|
||||
}
|
||||
|
||||
// DeleteResponse is the input to DELETE /file-entries
|
||||
type DeleteResponse struct {
|
||||
Status string `json:"status"`
|
||||
Message string `json:"message"`
|
||||
Errors map[string]string `json:"errors"`
|
||||
}
|
||||
|
||||
// UpdateItemRequest describes the updates to be done to an item for PUT /file-entries/{id}/
|
||||
type UpdateItemRequest struct {
|
||||
Name string `json:"name,omitempty"`
|
||||
Description string `json:"description,omitempty"`
|
||||
}
|
||||
|
||||
// UpdateItemResponse is returned by PUT /file-entries/{id}/
|
||||
type UpdateItemResponse struct {
|
||||
Status string `json:"status"`
|
||||
FileEntry Item `json:"fileEntry"`
|
||||
}
|
||||
|
||||
// MoveRequest is the input to /file-entries/move
|
||||
type MoveRequest struct {
|
||||
EntryIDs []string `json:"entryIds"`
|
||||
DestinationID string `json:"destinationId"`
|
||||
}
|
||||
|
||||
// MoveResponse is returned by POST /file-entries/move
|
||||
type MoveResponse struct {
|
||||
Status string `json:"status"`
|
||||
Entries []Item `json:"entries"`
|
||||
}
|
||||
|
||||
// CopyRequest is the input to /file-entries/duplicate
|
||||
type CopyRequest struct {
|
||||
EntryIDs []string `json:"entryIds"`
|
||||
DestinationID string `json:"destinationId"`
|
||||
}
|
||||
|
||||
// CopyResponse is returned by POST /file-entries/duplicate
|
||||
type CopyResponse struct {
|
||||
Status string `json:"status"`
|
||||
Entries []Item `json:"entries"`
|
||||
}
|
||||
|
||||
// MultiPartCreateRequest is the input of POST /s3/multipart/create
|
||||
type MultiPartCreateRequest struct {
|
||||
Filename string `json:"filename"`
|
||||
Mime string `json:"mime"`
|
||||
Size int64 `json:"size"`
|
||||
Extension string `json:"extension"`
|
||||
ParentID json.Number `json:"parent_id"`
|
||||
RelativePath string `json:"relativePath"`
|
||||
}
|
||||
|
||||
// MultiPartCreateResponse is returned by POST /s3/multipart/create
|
||||
type MultiPartCreateResponse struct {
|
||||
UploadID string `json:"uploadId"`
|
||||
Key string `json:"key"`
|
||||
}
|
||||
|
||||
// CompletedPart Type for completed parts when making a multipart upload.
|
||||
type CompletedPart struct {
|
||||
ETag string `json:"ETag"`
|
||||
PartNumber int32 `json:"PartNumber"`
|
||||
}
|
||||
|
||||
// MultiPartGetURLsRequest is the input of POST /s3/multipart/batch-sign-part-urls
|
||||
type MultiPartGetURLsRequest struct {
|
||||
UploadID string `json:"uploadId"`
|
||||
Key string `json:"key"`
|
||||
PartNumbers []int `json:"partNumbers"`
|
||||
}
|
||||
|
||||
// MultiPartGetURLsResponse is the result of POST /s3/multipart/batch-sign-part-urls
|
||||
type MultiPartGetURLsResponse struct {
|
||||
URLs []struct {
|
||||
URL string `json:"url"`
|
||||
PartNumber int32 `json:"partNumber"`
|
||||
} `json:"urls"`
|
||||
}
|
||||
|
||||
// MultiPartCompleteRequest is the input to POST /s3/multipart/complete
|
||||
type MultiPartCompleteRequest struct {
|
||||
UploadID string `json:"uploadId"`
|
||||
Key string `json:"key"`
|
||||
Parts []CompletedPart `json:"parts"`
|
||||
}
|
||||
|
||||
// MultiPartCompleteResponse is the result of POST /s3/multipart/complete
|
||||
type MultiPartCompleteResponse struct {
|
||||
Location string `json:"location"`
|
||||
}
|
||||
|
||||
// MultiPartEntriesRequest is the input to POST /s3/entries
|
||||
type MultiPartEntriesRequest struct {
|
||||
ClientMime string `json:"clientMime"`
|
||||
ClientName string `json:"clientName"`
|
||||
Filename string `json:"filename"`
|
||||
Size int64 `json:"size"`
|
||||
ClientExtension string `json:"clientExtension"`
|
||||
ParentID json.Number `json:"parent_id"`
|
||||
RelativePath string `json:"relativePath"`
|
||||
}
|
||||
|
||||
// MultiPartEntriesResponse is the result of POST /s3/entries
|
||||
type MultiPartEntriesResponse struct {
|
||||
FileEntry Item `json:"fileEntry"`
|
||||
}
|
||||
|
||||
// MultiPartAbort is the input of POST /s3/multipart/abort
|
||||
type MultiPartAbort struct {
|
||||
UploadID string `json:"uploadId"`
|
||||
Key string `json:"key"`
|
||||
}
|
||||
1563
backend/drime/drime.go
Normal file
1563
backend/drime/drime.go
Normal file
File diff suppressed because it is too large
Load Diff
33
backend/drime/drime_test.go
Normal file
33
backend/drime/drime_test.go
Normal file
@@ -0,0 +1,33 @@
|
||||
// Drime filesystem interface
|
||||
package drime
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/rclone/rclone/fs"
|
||||
"github.com/rclone/rclone/fstest/fstests"
|
||||
)
|
||||
|
||||
// TestIntegration runs integration tests against the remote
|
||||
func TestIntegration(t *testing.T) {
|
||||
fstests.Run(t, &fstests.Opt{
|
||||
RemoteName: "TestDrime:",
|
||||
NilObject: (*Object)(nil),
|
||||
ChunkedUpload: fstests.ChunkedUploadConfig{
|
||||
MinChunkSize: minChunkSize,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func (f *Fs) SetUploadChunkSize(cs fs.SizeSuffix) (fs.SizeSuffix, error) {
|
||||
return f.setUploadChunkSize(cs)
|
||||
}
|
||||
|
||||
func (f *Fs) SetUploadCutoff(cs fs.SizeSuffix) (fs.SizeSuffix, error) {
|
||||
return f.setUploadCutoff(cs)
|
||||
}
|
||||
|
||||
var (
|
||||
_ fstests.SetUploadChunkSizer = (*Fs)(nil)
|
||||
_ fstests.SetUploadCutoffer = (*Fs)(nil)
|
||||
)
|
||||
1178
backend/filen/filen.go
Normal file
1178
backend/filen/filen.go
Normal file
File diff suppressed because it is too large
Load Diff
14
backend/filen/filen_test.go
Normal file
14
backend/filen/filen_test.go
Normal file
@@ -0,0 +1,14 @@
|
||||
package filen
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/rclone/rclone/fstest/fstests"
|
||||
)
|
||||
|
||||
func TestIntegration(t *testing.T) {
|
||||
fstests.Run(t, &fstests.Opt{
|
||||
RemoteName: "TestFilen:",
|
||||
NilObject: (*Object)(nil),
|
||||
})
|
||||
}
|
||||
@@ -204,6 +204,12 @@ Example:
|
||||
Help: `URL for HTTP CONNECT proxy
|
||||
|
||||
Set this to a URL for an HTTP proxy which supports the HTTP CONNECT verb.
|
||||
|
||||
Supports the format http://user:pass@host:port, http://host:port, http://host.
|
||||
|
||||
Example:
|
||||
|
||||
http://myUser:myPass@proxyhostname.example.com:8000
|
||||
`,
|
||||
Advanced: true,
|
||||
}, {
|
||||
@@ -892,7 +898,7 @@ func (f *Fs) List(ctx context.Context, dir string) (entries fs.DirEntries, err e
|
||||
|
||||
resultchan := make(chan []*ftp.Entry, 1)
|
||||
errchan := make(chan error, 1)
|
||||
go func() {
|
||||
go func(c *ftp.ServerConn) {
|
||||
result, err := c.List(f.dirFromStandardPath(path.Join(f.root, dir)))
|
||||
f.putFtpConnection(&c, err)
|
||||
if err != nil {
|
||||
@@ -900,7 +906,7 @@ func (f *Fs) List(ctx context.Context, dir string) (entries fs.DirEntries, err e
|
||||
return
|
||||
}
|
||||
resultchan <- result
|
||||
}()
|
||||
}(c)
|
||||
|
||||
// Wait for List for up to Timeout seconds
|
||||
timer := time.NewTimer(f.ci.TimeoutOrInfinite())
|
||||
|
||||
@@ -72,7 +72,7 @@ func (ik *ImageKit) Upload(ctx context.Context, file io.Reader, param UploadPara
|
||||
|
||||
response := &UploadResult{}
|
||||
|
||||
formReader, contentType, _, err := rest.MultipartUpload(ctx, file, formParams, "file", param.FileName)
|
||||
formReader, contentType, _, err := rest.MultipartUpload(ctx, file, formParams, "file", param.FileName, "application/octet-stream")
|
||||
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("failed to make multipart upload: %w", err)
|
||||
|
||||
@@ -17,12 +17,10 @@ Improvements:
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"path"
|
||||
"slices"
|
||||
"strings"
|
||||
@@ -256,25 +254,7 @@ func NewFs(ctx context.Context, name, root string, m configmap.Mapper) (fs.Fs, e
|
||||
defer megaCacheMu.Unlock()
|
||||
srv := megaCache[opt.User]
|
||||
if srv == nil {
|
||||
// srv = mega.New().SetClient(fshttp.NewClient(ctx))
|
||||
|
||||
// Workaround for Mega's use of insecure cipher suites which are no longer supported by default since Go 1.22.
|
||||
// Relevant issues:
|
||||
// https://github.com/rclone/rclone/issues/8565
|
||||
// https://github.com/meganz/webclient/issues/103
|
||||
clt := fshttp.NewClient(ctx)
|
||||
clt.Transport = fshttp.NewTransportCustom(ctx, func(t *http.Transport) {
|
||||
var ids []uint16
|
||||
// Read default ciphers
|
||||
for _, cs := range tls.CipherSuites() {
|
||||
ids = append(ids, cs.ID)
|
||||
}
|
||||
// Insecure but Mega uses TLS_RSA_WITH_AES_128_GCM_SHA256 for storage endpoints
|
||||
// (e.g. https://gfs302n114.userstorage.mega.co.nz) as of June 18, 2025.
|
||||
t.TLSClientConfig.CipherSuites = append(ids, tls.TLS_RSA_WITH_AES_128_GCM_SHA256)
|
||||
})
|
||||
srv = mega.New().SetClient(clt)
|
||||
|
||||
srv = mega.New().SetClient(fshttp.NewClient(ctx))
|
||||
srv.SetRetries(ci.LowLevelRetries) // let mega do the low level retries
|
||||
srv.SetHTTPS(opt.UseHTTPS)
|
||||
srv.SetLogger(func(format string, v ...any) {
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"context"
|
||||
"crypto/md5"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"path"
|
||||
@@ -24,7 +25,8 @@ import (
|
||||
var (
|
||||
hashType = hash.MD5
|
||||
// the object storage is persistent
|
||||
buckets = newBucketsInfo()
|
||||
buckets = newBucketsInfo()
|
||||
errWriteOnly = errors.New("can't read when using --memory-discard")
|
||||
)
|
||||
|
||||
// Register with Fs
|
||||
@@ -33,12 +35,32 @@ func init() {
|
||||
Name: "memory",
|
||||
Description: "In memory object storage system.",
|
||||
NewFs: NewFs,
|
||||
Options: []fs.Option{},
|
||||
Options: []fs.Option{{
|
||||
Name: "discard",
|
||||
Default: false,
|
||||
Advanced: true,
|
||||
Help: `If set all writes will be discarded and reads will return an error
|
||||
|
||||
If set then when files are uploaded the contents not be saved. The
|
||||
files will appear to have been uploaded but will give an error on
|
||||
read. Files will have their MD5 sum calculated on upload which takes
|
||||
very little CPU time and allows the transfers to be checked.
|
||||
|
||||
This can be useful for testing performance.
|
||||
|
||||
Probably most easily used by using the connection string syntax:
|
||||
|
||||
:memory,discard:bucket
|
||||
|
||||
`,
|
||||
}},
|
||||
})
|
||||
}
|
||||
|
||||
// Options defines the configuration for this backend
|
||||
type Options struct{}
|
||||
type Options struct {
|
||||
Discard bool `config:"discard"`
|
||||
}
|
||||
|
||||
// Fs represents a remote memory server
|
||||
type Fs struct {
|
||||
@@ -164,6 +186,7 @@ type objectData struct {
|
||||
hash string
|
||||
mimeType string
|
||||
data []byte
|
||||
size int64
|
||||
}
|
||||
|
||||
// Object describes a memory object
|
||||
@@ -558,7 +581,7 @@ func (o *Object) Hash(ctx context.Context, t hash.Type) (string, error) {
|
||||
if t != hashType {
|
||||
return "", hash.ErrUnsupported
|
||||
}
|
||||
if o.od.hash == "" {
|
||||
if o.od.hash == "" && !o.fs.opt.Discard {
|
||||
sum := md5.Sum(o.od.data)
|
||||
o.od.hash = hex.EncodeToString(sum[:])
|
||||
}
|
||||
@@ -567,7 +590,7 @@ func (o *Object) Hash(ctx context.Context, t hash.Type) (string, error) {
|
||||
|
||||
// Size returns the size of an object in bytes
|
||||
func (o *Object) Size() int64 {
|
||||
return int64(len(o.od.data))
|
||||
return o.od.size
|
||||
}
|
||||
|
||||
// ModTime returns the modification time of the object
|
||||
@@ -593,6 +616,9 @@ func (o *Object) Storable() bool {
|
||||
|
||||
// Open an object for read
|
||||
func (o *Object) Open(ctx context.Context, options ...fs.OpenOption) (in io.ReadCloser, err error) {
|
||||
if o.fs.opt.Discard {
|
||||
return nil, errWriteOnly
|
||||
}
|
||||
var offset, limit int64 = 0, -1
|
||||
for _, option := range options {
|
||||
switch x := option.(type) {
|
||||
@@ -624,13 +650,24 @@ func (o *Object) Open(ctx context.Context, options ...fs.OpenOption) (in io.Read
|
||||
// The new object may have been created if an error is returned
|
||||
func (o *Object) Update(ctx context.Context, in io.Reader, src fs.ObjectInfo, options ...fs.OpenOption) (err error) {
|
||||
bucket, bucketPath := o.split()
|
||||
data, err := io.ReadAll(in)
|
||||
var data []byte
|
||||
var size int64
|
||||
var hash string
|
||||
if o.fs.opt.Discard {
|
||||
h := md5.New()
|
||||
size, err = io.Copy(h, in)
|
||||
hash = hex.EncodeToString(h.Sum(nil))
|
||||
} else {
|
||||
data, err = io.ReadAll(in)
|
||||
size = int64(len(data))
|
||||
}
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to update memory object: %w", err)
|
||||
}
|
||||
o.od = &objectData{
|
||||
data: data,
|
||||
hash: "",
|
||||
size: size,
|
||||
hash: hash,
|
||||
modTime: src.ModTime(ctx),
|
||||
mimeType: fs.MimeType(ctx, src),
|
||||
}
|
||||
|
||||
@@ -403,7 +403,7 @@ This is why this flag is not set as the default.
|
||||
|
||||
As a rule of thumb if nearly all of your data is under rclone's root
|
||||
directory (the |root/directory| in |onedrive:root/directory|) then
|
||||
using this flag will be be a big performance win. If your data is
|
||||
using this flag will be a big performance win. If your data is
|
||||
mostly not under the root then using this flag will be a big
|
||||
performance loss.
|
||||
|
||||
|
||||
@@ -60,9 +60,6 @@ type StateChangeConf struct {
|
||||
func (conf *StateChangeConf) WaitForStateContext(ctx context.Context, entityType string) (any, error) {
|
||||
// fs.Debugf(entityType, "Waiting for state to become: %s", conf.Target)
|
||||
|
||||
notfoundTick := 0
|
||||
targetOccurrence := 0
|
||||
|
||||
// Set a default for times to check for not found
|
||||
if conf.NotFoundChecks == 0 {
|
||||
conf.NotFoundChecks = 20
|
||||
@@ -84,9 +81,11 @@ func (conf *StateChangeConf) WaitForStateContext(ctx context.Context, entityType
|
||||
// cancellation channel for the refresh loop
|
||||
cancelCh := make(chan struct{})
|
||||
|
||||
result := Result{}
|
||||
|
||||
go func() {
|
||||
notfoundTick := 0
|
||||
targetOccurrence := 0
|
||||
result := Result{}
|
||||
|
||||
defer close(resCh)
|
||||
|
||||
select {
|
||||
|
||||
@@ -222,3 +222,11 @@ type UserInfo struct {
|
||||
} `json:"steps"`
|
||||
} `json:"journey"`
|
||||
}
|
||||
|
||||
// DiffResult is the response from /diff
|
||||
type DiffResult struct {
|
||||
Result int `json:"result"`
|
||||
DiffID int64 `json:"diffid"`
|
||||
Entries []map[string]any `json:"entries"`
|
||||
Error string `json:"error"`
|
||||
}
|
||||
|
||||
@@ -171,6 +171,7 @@ type Fs struct {
|
||||
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
|
||||
lastDiffID int64 // change tracking state for diff long-polling
|
||||
}
|
||||
|
||||
// Object describes a pcloud object
|
||||
@@ -1033,6 +1034,137 @@ func (f *Fs) Shutdown(ctx context.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// ChangeNotify implements fs.Features.ChangeNotify
|
||||
func (f *Fs) ChangeNotify(ctx context.Context, notify func(string, fs.EntryType), ch <-chan time.Duration) {
|
||||
// Start long-poll loop in background
|
||||
go f.changeNotifyLoop(ctx, notify, ch)
|
||||
}
|
||||
|
||||
// changeNotifyLoop contains the blocking long-poll logic.
|
||||
func (f *Fs) changeNotifyLoop(ctx context.Context, notify func(string, fs.EntryType), ch <-chan time.Duration) {
|
||||
// Standard polling interval
|
||||
interval := 30 * time.Second
|
||||
|
||||
// Start with diffID = 0 to get the current state
|
||||
var diffID int64
|
||||
|
||||
// Helper to process changes from the diff API
|
||||
handleChanges := func(entries []map[string]any) {
|
||||
notifiedPaths := make(map[string]bool)
|
||||
|
||||
for _, entry := range entries {
|
||||
meta, ok := entry["metadata"].(map[string]any)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
// Robust extraction of ParentFolderID
|
||||
var pid int64
|
||||
if val, ok := meta["parentfolderid"]; ok {
|
||||
switch v := val.(type) {
|
||||
case float64:
|
||||
pid = int64(v)
|
||||
case int64:
|
||||
pid = v
|
||||
case int:
|
||||
pid = int64(v)
|
||||
}
|
||||
}
|
||||
|
||||
// Resolve the path using dirCache.GetInv
|
||||
// pCloud uses "d" prefix for directory IDs in cache, but API returns numbers
|
||||
dirID := fmt.Sprintf("d%d", pid)
|
||||
parentPath, ok := f.dirCache.GetInv(dirID)
|
||||
|
||||
if !ok {
|
||||
// Parent not in cache, so we can ignore this change as it is outside
|
||||
// of what the mount has seen or cares about.
|
||||
continue
|
||||
}
|
||||
|
||||
name, _ := meta["name"].(string)
|
||||
fullPath := path.Join(parentPath, name)
|
||||
|
||||
// Determine EntryType (File or Directory)
|
||||
entryType := fs.EntryObject
|
||||
if isFolder, ok := meta["isfolder"].(bool); ok && isFolder {
|
||||
entryType = fs.EntryDirectory
|
||||
}
|
||||
|
||||
// Deduplicate notifications for this batch
|
||||
if !notifiedPaths[fullPath] {
|
||||
fs.Debugf(f, "ChangeNotify: detected change in %q (type: %v)", fullPath, entryType)
|
||||
notify(fullPath, entryType)
|
||||
notifiedPaths[fullPath] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for {
|
||||
// Check context and channel
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return
|
||||
case newInterval, ok := <-ch:
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
interval = newInterval
|
||||
default:
|
||||
}
|
||||
|
||||
// Setup /diff Request
|
||||
opts := rest.Opts{
|
||||
Method: "GET",
|
||||
Path: "/diff",
|
||||
Parameters: url.Values{},
|
||||
}
|
||||
|
||||
if diffID != 0 {
|
||||
opts.Parameters.Set("diffid", strconv.FormatInt(diffID, 10))
|
||||
opts.Parameters.Set("block", "1")
|
||||
} else {
|
||||
opts.Parameters.Set("last", "0")
|
||||
}
|
||||
|
||||
// Perform Long-Poll
|
||||
// Timeout set to 90s (server usually blocks for 60s max)
|
||||
reqCtx, cancel := context.WithTimeout(ctx, 90*time.Second)
|
||||
var result api.DiffResult
|
||||
|
||||
_, err := f.srv.CallJSON(reqCtx, &opts, nil, &result)
|
||||
cancel()
|
||||
|
||||
if err != nil {
|
||||
if errors.Is(err, context.Canceled) {
|
||||
return
|
||||
}
|
||||
// Ignore timeout errors as they are normal for long-polling
|
||||
if !errors.Is(err, context.DeadlineExceeded) {
|
||||
fs.Infof(f, "ChangeNotify: polling error: %v. Waiting %v.", err, interval)
|
||||
time.Sleep(interval)
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
// If result is not 0, reset DiffID to resync
|
||||
if result.Result != 0 {
|
||||
diffID = 0
|
||||
time.Sleep(2 * time.Second)
|
||||
continue
|
||||
}
|
||||
|
||||
if result.DiffID != 0 {
|
||||
diffID = result.DiffID
|
||||
f.lastDiffID = diffID
|
||||
}
|
||||
|
||||
if len(result.Entries) > 0 {
|
||||
handleChanges(result.Entries)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Hashes returns the supported hash sets.
|
||||
func (f *Fs) Hashes() hash.Set {
|
||||
// EU region supports SHA1 and SHA256 (but rclone doesn't
|
||||
@@ -1327,7 +1459,7 @@ func (o *Object) Update(ctx context.Context, in io.Reader, src fs.ObjectInfo, op
|
||||
// opts.Body=0), so upload it as a multipart form POST with
|
||||
// Content-Length set.
|
||||
if size == 0 {
|
||||
formReader, contentType, overhead, err := rest.MultipartUpload(ctx, in, opts.Parameters, "content", leaf)
|
||||
formReader, contentType, overhead, err := rest.MultipartUpload(ctx, in, opts.Parameters, "content", leaf, opts.ContentType)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to make multipart upload for 0 length file: %w", err)
|
||||
}
|
||||
@@ -1401,6 +1533,7 @@ var (
|
||||
_ fs.ListPer = (*Fs)(nil)
|
||||
_ fs.Abouter = (*Fs)(nil)
|
||||
_ fs.Shutdowner = (*Fs)(nil)
|
||||
_ fs.ChangeNotifier = (*Fs)(nil)
|
||||
_ fs.Object = (*Object)(nil)
|
||||
_ fs.IDer = (*Object)(nil)
|
||||
)
|
||||
|
||||
@@ -1384,7 +1384,7 @@ func (f *Fs) uploadByForm(ctx context.Context, in io.Reader, name string, size i
|
||||
for i := range iVal.NumField() {
|
||||
params.Set(iTyp.Field(i).Tag.Get("json"), iVal.Field(i).String())
|
||||
}
|
||||
formReader, contentType, overhead, err := rest.MultipartUpload(ctx, in, params, "file", name)
|
||||
formReader, contentType, overhead, err := rest.MultipartUpload(ctx, in, params, "file", name, "application/octet-stream")
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to make multipart upload: %w", err)
|
||||
}
|
||||
|
||||
@@ -10,8 +10,8 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
protonDriveAPI "github.com/henrybear327/Proton-API-Bridge"
|
||||
"github.com/henrybear327/go-proton-api"
|
||||
protonDriveAPI "github.com/rclone/Proton-API-Bridge"
|
||||
"github.com/rclone/go-proton-api"
|
||||
|
||||
"github.com/pquerna/otp/totp"
|
||||
|
||||
|
||||
15
backend/s3/provider/BizflyCloud.yaml
Normal file
15
backend/s3/provider/BizflyCloud.yaml
Normal file
@@ -0,0 +1,15 @@
|
||||
name: BizflyCloud
|
||||
description: Bizfly Cloud Simple Storage
|
||||
region:
|
||||
hn: Ha Noi
|
||||
hcm: Ho Chi Minh
|
||||
endpoint:
|
||||
hn.ss.bfcplatform.vn: Hanoi endpoint
|
||||
hcm.ss.bfcplatform.vn: Ho Chi Minh endpoint
|
||||
acl: {}
|
||||
bucket_acl: true
|
||||
quirks:
|
||||
force_path_style: true
|
||||
list_url_encode: false
|
||||
use_multipart_etag: false
|
||||
use_already_exists: false
|
||||
@@ -1,26 +1,26 @@
|
||||
name: Linode
|
||||
description: Linode Object Storage
|
||||
endpoint:
|
||||
nl-ams-1.linodeobjects.com: Amsterdam (Netherlands), nl-ams-1
|
||||
us-southeast-1.linodeobjects.com: Atlanta, GA (USA), us-southeast-1
|
||||
in-maa-1.linodeobjects.com: Chennai (India), in-maa-1
|
||||
us-ord-1.linodeobjects.com: Chicago, IL (USA), us-ord-1
|
||||
eu-central-1.linodeobjects.com: Frankfurt (Germany), eu-central-1
|
||||
id-cgk-1.linodeobjects.com: Jakarta (Indonesia), id-cgk-1
|
||||
gb-lon-1.linodeobjects.com: London 2 (Great Britain), gb-lon-1
|
||||
us-lax-1.linodeobjects.com: Los Angeles, CA (USA), us-lax-1
|
||||
es-mad-1.linodeobjects.com: Madrid (Spain), es-mad-1
|
||||
au-mel-1.linodeobjects.com: Melbourne (Australia), au-mel-1
|
||||
us-mia-1.linodeobjects.com: Miami, FL (USA), us-mia-1
|
||||
it-mil-1.linodeobjects.com: Milan (Italy), it-mil-1
|
||||
us-east-1.linodeobjects.com: Newark, NJ (USA), us-east-1
|
||||
jp-osa-1.linodeobjects.com: Osaka (Japan), jp-osa-1
|
||||
fr-par-1.linodeobjects.com: Paris (France), fr-par-1
|
||||
br-gru-1.linodeobjects.com: São Paulo (Brazil), br-gru-1
|
||||
us-sea-1.linodeobjects.com: Seattle, WA (USA), us-sea-1
|
||||
ap-south-1.linodeobjects.com: Singapore, ap-south-1
|
||||
sg-sin-1.linodeobjects.com: Singapore 2, sg-sin-1
|
||||
se-sto-1.linodeobjects.com: Stockholm (Sweden), se-sto-1
|
||||
us-iad-1.linodeobjects.com: Washington, DC, (USA), us-iad-1
|
||||
nl-ams-1.linodeobjects.com: Amsterdam, NL (nl-ams-1)
|
||||
us-southeast-1.linodeobjects.com: Atlanta, GA, US (us-southeast-1)
|
||||
in-maa-1.linodeobjects.com: Chennai, IN (in-maa-1)
|
||||
us-ord-1.linodeobjects.com: Chicago, IL, US (us-ord-1)
|
||||
eu-central-1.linodeobjects.com: Frankfurt, DE (eu-central-1)
|
||||
id-cgk-1.linodeobjects.com: Jakarta, ID (id-cgk-1)
|
||||
gb-lon-1.linodeobjects.com: London 2, UK (gb-lon-1)
|
||||
us-lax-1.linodeobjects.com: Los Angeles, CA, US (us-lax-1)
|
||||
es-mad-1.linodeobjects.com: Madrid, ES (es-mad-1)
|
||||
us-mia-1.linodeobjects.com: Miami, FL, US (us-mia-1)
|
||||
it-mil-1.linodeobjects.com: Milan, IT (it-mil-1)
|
||||
us-east-1.linodeobjects.com: Newark, NJ, US (us-east-1)
|
||||
jp-osa-1.linodeobjects.com: Osaka, JP (jp-osa-1)
|
||||
fr-par-1.linodeobjects.com: Paris, FR (fr-par-1)
|
||||
br-gru-1.linodeobjects.com: Sao Paulo, BR (br-gru-1)
|
||||
us-sea-1.linodeobjects.com: Seattle, WA, US (us-sea-1)
|
||||
ap-south-1.linodeobjects.com: Singapore, SG (ap-south-1)
|
||||
sg-sin-1.linodeobjects.com: Singapore 2, SG (sg-sin-1)
|
||||
se-sto-1.linodeobjects.com: Stockholm, SE (se-sto-1)
|
||||
jp-tyo-1.linodeobjects.com: Tokyo 3, JP (jp-tyo-1)
|
||||
us-iad-10.linodeobjects.com: Washington, DC, US (us-iad-10)
|
||||
acl: {}
|
||||
bucket_acl: true
|
||||
|
||||
@@ -2,7 +2,17 @@ name: Selectel
|
||||
description: Selectel Object Storage
|
||||
region:
|
||||
ru-1: St. Petersburg
|
||||
ru-3: St. Petersburg
|
||||
ru-7: Moscow
|
||||
gis-1: Moscow
|
||||
kz-1: Kazakhstan
|
||||
uz-2: Uzbekistan
|
||||
endpoint:
|
||||
s3.ru-1.storage.selcloud.ru: Saint Petersburg
|
||||
s3.ru-1.storage.selcloud.ru: St. Petersburg
|
||||
s3.ru-3.storage.selcloud.ru: St. Petersburg
|
||||
s3.ru-7.storage.selcloud.ru: Moscow
|
||||
s3.gis-1.storage.selcloud.ru: Moscow
|
||||
s3.kz-1.storage.selcloud.ru: Kazakhstan
|
||||
s3.uz-2.storage.selcloud.ru: Uzbekistan
|
||||
quirks:
|
||||
list_url_encode: false
|
||||
|
||||
@@ -2928,7 +2928,9 @@ func (f *Fs) Copy(ctx context.Context, src fs.Object, remote string) (fs.Object,
|
||||
req := s3.CopyObjectInput{
|
||||
MetadataDirective: types.MetadataDirectiveCopy,
|
||||
}
|
||||
|
||||
if srcObj.storageClass != nil {
|
||||
req.StorageClass = types.StorageClass(*srcObj.storageClass)
|
||||
}
|
||||
// Build upload options including headers and metadata
|
||||
ci := fs.GetConfig(ctx)
|
||||
uploadOptions := fs.MetadataAsOpenOptions(ctx)
|
||||
@@ -4501,7 +4503,12 @@ func (o *Object) prepareUpload(ctx context.Context, src fs.ObjectInfo, options [
|
||||
ACL: types.ObjectCannedACL(o.fs.opt.ACL),
|
||||
Key: &bucketPath,
|
||||
}
|
||||
|
||||
if tierObj, ok := src.(fs.GetTierer); ok {
|
||||
tier := tierObj.GetTier()
|
||||
if tier != "" {
|
||||
ui.req.StorageClass = types.StorageClass(strings.ToUpper(tier))
|
||||
}
|
||||
}
|
||||
// Fetch metadata if --metadata is in use
|
||||
meta, err := fs.GetMetadataOptions(ctx, o.fs, src, options)
|
||||
if err != nil {
|
||||
|
||||
@@ -688,7 +688,7 @@ func (f *Fs) upload(ctx context.Context, in io.Reader, uploadLink, filePath stri
|
||||
"need_idx_progress": {"true"},
|
||||
"replace": {"1"},
|
||||
}
|
||||
formReader, contentType, _, err := rest.MultipartUpload(ctx, in, parameters, "file", f.opt.Enc.FromStandardName(filename))
|
||||
formReader, contentType, _, err := rest.MultipartUpload(ctx, in, parameters, "file", f.opt.Enc.FromStandardName(filename), "application/octet-stream")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to make multipart upload: %w", err)
|
||||
}
|
||||
|
||||
@@ -519,6 +519,12 @@ Example:
|
||||
Help: `URL for HTTP CONNECT proxy
|
||||
|
||||
Set this to a URL for an HTTP proxy which supports the HTTP CONNECT verb.
|
||||
|
||||
Supports the format http://user:pass@host:port, http://host:port, http://host.
|
||||
|
||||
Example:
|
||||
|
||||
http://myUser:myPass@proxyhostname.example.com:8000
|
||||
`,
|
||||
Advanced: true,
|
||||
}, {
|
||||
@@ -919,15 +925,8 @@ func NewFs(ctx context.Context, name, root string, m configmap.Mapper) (fs.Fs, e
|
||||
opt.Port = "22"
|
||||
}
|
||||
|
||||
// get proxy URL if set
|
||||
if opt.HTTPProxy != "" {
|
||||
proxyURL, err := url.Parse(opt.HTTPProxy)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to parse HTTP Proxy URL: %w", err)
|
||||
}
|
||||
f.proxyURL = proxyURL
|
||||
}
|
||||
|
||||
// Set up sshConfig here from opt
|
||||
// **NB** everything else should be setup in NewFsWithConnection
|
||||
sshConfig := &ssh.ClientConfig{
|
||||
User: opt.User,
|
||||
Auth: []ssh.AuthMethod{},
|
||||
@@ -1175,11 +1174,21 @@ func NewFsWithConnection(ctx context.Context, f *Fs, name string, root string, m
|
||||
f.mkdirLock = newStringLock()
|
||||
f.pacer = fs.NewPacer(ctx, pacer.NewDefault(pacer.MinSleep(minSleep), pacer.MaxSleep(maxSleep), pacer.DecayConstant(decayConstant)))
|
||||
f.savedpswd = ""
|
||||
|
||||
// set the pool drainer timer going
|
||||
if f.opt.IdleTimeout > 0 {
|
||||
f.drain = time.AfterFunc(time.Duration(f.opt.IdleTimeout), func() { _ = f.drainPool(ctx) })
|
||||
}
|
||||
|
||||
// get proxy URL if set
|
||||
if opt.HTTPProxy != "" {
|
||||
proxyURL, err := url.Parse(opt.HTTPProxy)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to parse HTTP Proxy URL: %w", err)
|
||||
}
|
||||
f.proxyURL = proxyURL
|
||||
}
|
||||
|
||||
f.features = (&fs.Features{
|
||||
CanHaveEmptyDirectories: true,
|
||||
SlowHash: true,
|
||||
@@ -1249,7 +1258,7 @@ func NewFsWithConnection(ctx context.Context, f *Fs, name string, root string, m
|
||||
fs.Debugf(f, "Failed to resolve path using RealPath: %v", err)
|
||||
cwd, err := c.sftpClient.Getwd()
|
||||
if err != nil {
|
||||
fs.Debugf(f, "Failed to to read current directory - using relative paths: %v", err)
|
||||
fs.Debugf(f, "Failed to read current directory - using relative paths: %v", err)
|
||||
} else {
|
||||
f.absRoot = path.Join(cwd, f.root)
|
||||
fs.Debugf(f, "Relative path joined with current directory to get absolute path %q", f.absRoot)
|
||||
|
||||
27
backend/shade/api/types.go
Normal file
27
backend/shade/api/types.go
Normal file
@@ -0,0 +1,27 @@
|
||||
// Package api has type definitions for shade
|
||||
package api
|
||||
|
||||
// ListDirResponse -------------------------------------------------
|
||||
// Format from shade api
|
||||
type ListDirResponse struct {
|
||||
Type string `json:"type"` // "file" or "tree"
|
||||
Path string `json:"path"` // Full path including root
|
||||
Ino int `json:"ino"` // inode number
|
||||
Mtime int64 `json:"mtime"` // Modified time in milliseconds
|
||||
Ctime int64 `json:"ctime"` // Created time in milliseconds
|
||||
Size int64 `json:"size"` // Size in bytes
|
||||
Hash string `json:"hash"` // MD5 hash
|
||||
Draft bool `json:"draft"` // Whether this is a draft file
|
||||
}
|
||||
|
||||
// PartURL Type for multipart upload/download
|
||||
type PartURL struct {
|
||||
URL string `json:"url"`
|
||||
Headers map[string]string `json:"headers,omitempty"`
|
||||
}
|
||||
|
||||
// CompletedPart Type for completed parts when making a multipart upload.
|
||||
type CompletedPart struct {
|
||||
ETag string
|
||||
PartNumber int32
|
||||
}
|
||||
1039
backend/shade/shade.go
Normal file
1039
backend/shade/shade.go
Normal file
File diff suppressed because it is too large
Load Diff
21
backend/shade/shade_test.go
Normal file
21
backend/shade/shade_test.go
Normal file
@@ -0,0 +1,21 @@
|
||||
package shade_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/rclone/rclone/backend/shade"
|
||||
"github.com/rclone/rclone/fstest/fstests"
|
||||
)
|
||||
|
||||
// TestIntegration runs integration tests against the remote
|
||||
func TestIntegration(t *testing.T) {
|
||||
name := "TestShade"
|
||||
fstests.Run(t, &fstests.Opt{
|
||||
RemoteName: name + ":",
|
||||
NilObject: (*shade.Object)(nil),
|
||||
SkipInvalidUTF8: true,
|
||||
ExtraConfig: []fstests.ExtraConfigItem{
|
||||
{Name: name, Key: "eventually_consistent_delay", Value: "7"},
|
||||
},
|
||||
})
|
||||
}
|
||||
336
backend/shade/upload.go
Normal file
336
backend/shade/upload.go
Normal file
@@ -0,0 +1,336 @@
|
||||
//multipart upload for shade
|
||||
|
||||
package shade
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"path"
|
||||
"sort"
|
||||
"sync"
|
||||
|
||||
"github.com/rclone/rclone/backend/shade/api"
|
||||
"github.com/rclone/rclone/fs"
|
||||
"github.com/rclone/rclone/fs/chunksize"
|
||||
"github.com/rclone/rclone/lib/multipart"
|
||||
"github.com/rclone/rclone/lib/rest"
|
||||
)
|
||||
|
||||
var warnStreamUpload sync.Once
|
||||
|
||||
type shadeChunkWriter struct {
|
||||
initToken string
|
||||
chunkSize int64
|
||||
size int64
|
||||
f *Fs
|
||||
o *Object
|
||||
completedParts []api.CompletedPart
|
||||
completedPartsMu sync.Mutex
|
||||
}
|
||||
|
||||
// uploadMultipart handles multipart upload for larger files
|
||||
func (o *Object) uploadMultipart(ctx context.Context, src fs.ObjectInfo, in io.Reader, options ...fs.OpenOption) error {
|
||||
|
||||
chunkWriter, err := multipart.UploadMultipart(ctx, src, in, multipart.UploadMultipartOptions{
|
||||
Open: o.fs,
|
||||
OpenOptions: options,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var shadeWriter = chunkWriter.(*shadeChunkWriter)
|
||||
o.size = shadeWriter.size
|
||||
return nil
|
||||
}
|
||||
|
||||
// OpenChunkWriter returns the chunk size and a ChunkWriter
|
||||
//
|
||||
// Pass in the remote and the src object
|
||||
// You can also use options to hint at the desired chunk size
|
||||
func (f *Fs) OpenChunkWriter(ctx context.Context, remote string, src fs.ObjectInfo, options ...fs.OpenOption) (info fs.ChunkWriterInfo, writer fs.ChunkWriter, err error) {
|
||||
// Temporary Object under construction
|
||||
o := &Object{
|
||||
fs: f,
|
||||
remote: remote,
|
||||
}
|
||||
|
||||
uploadParts := f.opt.MaxUploadParts
|
||||
if uploadParts < 1 {
|
||||
uploadParts = 1
|
||||
} else if uploadParts > maxUploadParts {
|
||||
uploadParts = maxUploadParts
|
||||
}
|
||||
size := src.Size()
|
||||
fs.FixRangeOption(options, size)
|
||||
|
||||
// calculate size of parts
|
||||
chunkSize := f.opt.ChunkSize
|
||||
|
||||
// size can be -1 here meaning we don't know the size of the incoming file. We use ChunkSize
|
||||
// buffers here (default 64 MB). With a maximum number of parts (10,000) this will be a file of
|
||||
// 640 GB.
|
||||
if size == -1 {
|
||||
warnStreamUpload.Do(func() {
|
||||
fs.Logf(f, "Streaming uploads using chunk size %v will have maximum file size of %v",
|
||||
chunkSize, fs.SizeSuffix(int64(chunkSize)*int64(uploadParts)))
|
||||
})
|
||||
} else {
|
||||
chunkSize = chunksize.Calculator(src, size, uploadParts, chunkSize)
|
||||
}
|
||||
|
||||
token, err := o.fs.refreshJWTToken(ctx)
|
||||
if err != nil {
|
||||
return info, nil, fmt.Errorf("failed to get token: %w", err)
|
||||
}
|
||||
|
||||
err = f.ensureParentDirectories(ctx, remote)
|
||||
if err != nil {
|
||||
return info, nil, fmt.Errorf("failed to ensure parent directories: %w", err)
|
||||
}
|
||||
|
||||
fullPath := remote
|
||||
if f.root != "" {
|
||||
fullPath = path.Join(f.root, remote)
|
||||
}
|
||||
|
||||
// Initiate multipart upload
|
||||
type initRequest struct {
|
||||
Path string `json:"path"`
|
||||
PartSize int64 `json:"partSize"`
|
||||
}
|
||||
reqBody := initRequest{
|
||||
Path: fullPath,
|
||||
PartSize: int64(chunkSize),
|
||||
}
|
||||
|
||||
var initResp struct {
|
||||
Token string `json:"token"`
|
||||
}
|
||||
|
||||
opts := rest.Opts{
|
||||
Method: "POST",
|
||||
Path: fmt.Sprintf("/%s/upload/multipart", o.fs.drive),
|
||||
RootURL: o.fs.endpoint,
|
||||
ExtraHeaders: map[string]string{
|
||||
"Authorization": "Bearer " + token,
|
||||
},
|
||||
Options: options,
|
||||
}
|
||||
|
||||
err = o.fs.pacer.Call(func() (bool, error) {
|
||||
res, err := o.fs.srv.CallJSON(ctx, &opts, reqBody, &initResp)
|
||||
if err != nil {
|
||||
return res != nil && res.StatusCode == http.StatusTooManyRequests, err
|
||||
}
|
||||
return false, nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return info, nil, fmt.Errorf("failed to initiate multipart upload: %w", err)
|
||||
}
|
||||
|
||||
chunkWriter := &shadeChunkWriter{
|
||||
initToken: initResp.Token,
|
||||
chunkSize: int64(chunkSize),
|
||||
size: size,
|
||||
f: f,
|
||||
o: o,
|
||||
}
|
||||
info = fs.ChunkWriterInfo{
|
||||
ChunkSize: int64(chunkSize),
|
||||
Concurrency: f.opt.Concurrency,
|
||||
LeavePartsOnError: false,
|
||||
}
|
||||
return info, chunkWriter, err
|
||||
}
|
||||
|
||||
// WriteChunk will write chunk number with reader bytes, where chunk number >= 0
|
||||
func (s *shadeChunkWriter) WriteChunk(ctx context.Context, chunkNumber int, reader io.ReadSeeker) (bytesWritten int64, err error) {
|
||||
|
||||
token, err := s.f.refreshJWTToken(ctx)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
// Read chunk
|
||||
var chunk bytes.Buffer
|
||||
n, err := io.Copy(&chunk, reader)
|
||||
|
||||
if n == 0 {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("failed to read chunk: %w", err)
|
||||
}
|
||||
// Get presigned URL for this part
|
||||
var partURL api.PartURL
|
||||
|
||||
partOpts := rest.Opts{
|
||||
Method: "POST",
|
||||
Path: fmt.Sprintf("/%s/upload/multipart/part/%d?token=%s", s.f.drive, chunkNumber+1, url.QueryEscape(s.initToken)),
|
||||
RootURL: s.f.endpoint,
|
||||
ExtraHeaders: map[string]string{
|
||||
"Authorization": "Bearer " + token,
|
||||
},
|
||||
}
|
||||
|
||||
err = s.f.pacer.Call(func() (bool, error) {
|
||||
res, err := s.f.srv.CallJSON(ctx, &partOpts, nil, &partURL)
|
||||
if err != nil {
|
||||
return res != nil && res.StatusCode == http.StatusTooManyRequests, err
|
||||
}
|
||||
return false, nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("failed to get part URL: %w", err)
|
||||
}
|
||||
opts := rest.Opts{
|
||||
Method: "PUT",
|
||||
RootURL: partURL.URL,
|
||||
Body: &chunk,
|
||||
ContentType: "",
|
||||
ContentLength: &n,
|
||||
}
|
||||
|
||||
// Add headers
|
||||
var uploadRes *http.Response
|
||||
if len(partURL.Headers) > 0 {
|
||||
opts.ExtraHeaders = make(map[string]string)
|
||||
for k, v := range partURL.Headers {
|
||||
opts.ExtraHeaders[k] = v
|
||||
}
|
||||
}
|
||||
|
||||
err = s.f.pacer.Call(func() (bool, error) {
|
||||
uploadRes, err = s.f.srv.Call(ctx, &opts)
|
||||
if err != nil {
|
||||
return uploadRes != nil && uploadRes.StatusCode == http.StatusTooManyRequests, err
|
||||
}
|
||||
return false, nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("failed to upload part %d: %w", chunk, err)
|
||||
}
|
||||
|
||||
if uploadRes.StatusCode != http.StatusOK && uploadRes.StatusCode != http.StatusCreated {
|
||||
body, _ := io.ReadAll(uploadRes.Body)
|
||||
fs.CheckClose(uploadRes.Body, &err)
|
||||
return 0, fmt.Errorf("part upload failed with status %d: %s", uploadRes.StatusCode, string(body))
|
||||
}
|
||||
|
||||
// Get ETag from response
|
||||
etag := uploadRes.Header.Get("ETag")
|
||||
fs.CheckClose(uploadRes.Body, &err)
|
||||
|
||||
s.completedPartsMu.Lock()
|
||||
defer s.completedPartsMu.Unlock()
|
||||
s.completedParts = append(s.completedParts, api.CompletedPart{
|
||||
PartNumber: int32(chunkNumber + 1),
|
||||
ETag: etag,
|
||||
})
|
||||
return n, nil
|
||||
}
|
||||
|
||||
// Close complete chunked writer finalising the file.
|
||||
func (s *shadeChunkWriter) Close(ctx context.Context) error {
|
||||
|
||||
// Complete multipart upload
|
||||
sort.Slice(s.completedParts, func(i, j int) bool {
|
||||
return s.completedParts[i].PartNumber < s.completedParts[j].PartNumber
|
||||
})
|
||||
|
||||
type completeRequest struct {
|
||||
Parts []api.CompletedPart `json:"parts"`
|
||||
}
|
||||
var completeBody completeRequest
|
||||
|
||||
if s.completedParts == nil {
|
||||
completeBody = completeRequest{Parts: []api.CompletedPart{}}
|
||||
} else {
|
||||
completeBody = completeRequest{Parts: s.completedParts}
|
||||
}
|
||||
|
||||
token, err := s.f.refreshJWTToken(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
completeOpts := rest.Opts{
|
||||
Method: "POST",
|
||||
Path: fmt.Sprintf("/%s/upload/multipart/complete?token=%s", s.f.drive, url.QueryEscape(s.initToken)),
|
||||
RootURL: s.f.endpoint,
|
||||
ExtraHeaders: map[string]string{
|
||||
"Authorization": "Bearer " + token,
|
||||
},
|
||||
}
|
||||
|
||||
var response http.Response
|
||||
|
||||
err = s.f.pacer.Call(func() (bool, error) {
|
||||
res, err := s.f.srv.CallJSON(ctx, &completeOpts, completeBody, &response)
|
||||
|
||||
if err != nil && res == nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
if res.StatusCode == http.StatusTooManyRequests {
|
||||
return true, err // Retry on 429
|
||||
}
|
||||
|
||||
if res.StatusCode != http.StatusOK && res.StatusCode != http.StatusCreated {
|
||||
body, _ := io.ReadAll(res.Body)
|
||||
return false, fmt.Errorf("complete multipart failed with status %d: %s", res.StatusCode, string(body))
|
||||
}
|
||||
|
||||
return false, nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to complete multipart upload: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Abort chunk write
|
||||
//
|
||||
// You can and should call Abort without calling Close.
|
||||
func (s *shadeChunkWriter) Abort(ctx context.Context) error {
|
||||
token, err := s.f.refreshJWTToken(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
opts := rest.Opts{
|
||||
Method: "POST",
|
||||
Path: fmt.Sprintf("/%s/upload/abort/multipart?token=%s", s.f.drive, url.QueryEscape(s.initToken)),
|
||||
RootURL: s.f.endpoint,
|
||||
ExtraHeaders: map[string]string{
|
||||
"Authorization": "Bearer " + token,
|
||||
},
|
||||
}
|
||||
|
||||
err = s.f.pacer.Call(func() (bool, error) {
|
||||
res, err := s.f.srv.Call(ctx, &opts)
|
||||
if err != nil {
|
||||
fs.Debugf(s.f, "Failed to abort multipart upload: %v", err)
|
||||
return false, nil // Don't retry abort
|
||||
}
|
||||
if res.StatusCode != http.StatusOK && res.StatusCode != http.StatusCreated {
|
||||
fs.Debugf(s.f, "Abort returned status %d", res.StatusCode)
|
||||
}
|
||||
return false, nil
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to abort multipart upload: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -54,7 +54,7 @@ var SharedOptions = []fs.Option{{
|
||||
Name: "chunk_size",
|
||||
Help: strings.ReplaceAll(`Above this size files will be chunked.
|
||||
|
||||
Above this size files will be chunked into a a |`+segmentsContainerSuffix+`| container
|
||||
Above this size files will be chunked into a |`+segmentsContainerSuffix+`| container
|
||||
or a |`+segmentsDirectory+`| directory. (See the |use_segments_container| option
|
||||
for more info). Default for this is 5 GiB which is its maximum value, which
|
||||
means only files above this size will be chunked.
|
||||
|
||||
@@ -1,171 +0,0 @@
|
||||
// Package api provides types used by the Uptobox API.
|
||||
package api
|
||||
|
||||
import "fmt"
|
||||
|
||||
// Error contains the error code and message returned by the API
|
||||
type Error struct {
|
||||
Success bool `json:"success,omitempty"`
|
||||
StatusCode int `json:"statusCode,omitempty"`
|
||||
Message string `json:"message,omitempty"`
|
||||
Data string `json:"data,omitempty"`
|
||||
}
|
||||
|
||||
// Error returns a string for the error and satisfies the error interface
|
||||
func (e Error) Error() string {
|
||||
out := fmt.Sprintf("api error %d", e.StatusCode)
|
||||
if e.Message != "" {
|
||||
out += ": " + e.Message
|
||||
}
|
||||
if e.Data != "" {
|
||||
out += ": " + e.Data
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// FolderEntry represents a Uptobox subfolder when listing folder contents
|
||||
type FolderEntry struct {
|
||||
FolderID uint64 `json:"fld_id"`
|
||||
Description string `json:"fld_descr"`
|
||||
Password string `json:"fld_password"`
|
||||
FullPath string `json:"fullPath"`
|
||||
Path string `json:"fld_name"`
|
||||
Name string `json:"name"`
|
||||
Hash string `json:"hash"`
|
||||
}
|
||||
|
||||
// FolderInfo represents the current folder when listing folder contents
|
||||
type FolderInfo struct {
|
||||
FolderID uint64 `json:"fld_id"`
|
||||
Hash string `json:"hash"`
|
||||
FileCount uint64 `json:"fileCount"`
|
||||
TotalFileSize int64 `json:"totalFileSize"`
|
||||
}
|
||||
|
||||
// FileInfo represents a file when listing folder contents
|
||||
type FileInfo struct {
|
||||
Name string `json:"file_name"`
|
||||
Description string `json:"file_descr"`
|
||||
Created string `json:"file_created"`
|
||||
Size int64 `json:"file_size"`
|
||||
Downloads uint64 `json:"file_downloads"`
|
||||
Code string `json:"file_code"`
|
||||
Password string `json:"file_password"`
|
||||
Public int `json:"file_public"`
|
||||
LastDownload string `json:"file_last_download"`
|
||||
ID uint64 `json:"id"`
|
||||
}
|
||||
|
||||
// ReadMetadataResponse is the response when listing folder contents
|
||||
type ReadMetadataResponse struct {
|
||||
StatusCode int `json:"statusCode"`
|
||||
Message string `json:"message"`
|
||||
Data struct {
|
||||
CurrentFolder FolderInfo `json:"currentFolder"`
|
||||
Folders []FolderEntry `json:"folders"`
|
||||
Files []FileInfo `json:"files"`
|
||||
PageCount int `json:"pageCount"`
|
||||
TotalFileCount int `json:"totalFileCount"`
|
||||
TotalFileSize int64 `json:"totalFileSize"`
|
||||
} `json:"data"`
|
||||
}
|
||||
|
||||
// UploadInfo is the response when initiating an upload
|
||||
type UploadInfo struct {
|
||||
StatusCode int `json:"statusCode"`
|
||||
Message string `json:"message"`
|
||||
Data struct {
|
||||
UploadLink string `json:"uploadLink"`
|
||||
MaxUpload string `json:"maxUpload"`
|
||||
} `json:"data"`
|
||||
}
|
||||
|
||||
// UploadResponse is the response to a successful upload
|
||||
type UploadResponse struct {
|
||||
Files []struct {
|
||||
Name string `json:"name"`
|
||||
Size int64 `json:"size"`
|
||||
URL string `json:"url"`
|
||||
DeleteURL string `json:"deleteUrl"`
|
||||
} `json:"files"`
|
||||
}
|
||||
|
||||
// UpdateResponse is a generic response to various action on files (rename/copy/move)
|
||||
type UpdateResponse struct {
|
||||
Message string `json:"message"`
|
||||
StatusCode int `json:"statusCode"`
|
||||
}
|
||||
|
||||
// Download is the response when requesting a download link
|
||||
type Download struct {
|
||||
StatusCode int `json:"statusCode"`
|
||||
Message string `json:"message"`
|
||||
Data struct {
|
||||
DownloadLink string `json:"dlLink"`
|
||||
} `json:"data"`
|
||||
}
|
||||
|
||||
// MetadataRequestOptions represents all the options when listing folder contents
|
||||
type MetadataRequestOptions struct {
|
||||
Limit uint64
|
||||
Offset uint64
|
||||
SearchField string
|
||||
Search string
|
||||
}
|
||||
|
||||
// CreateFolderRequest is used for creating a folder
|
||||
type CreateFolderRequest struct {
|
||||
Token string `json:"token"`
|
||||
Path string `json:"path"`
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
// DeleteFolderRequest is used for deleting a folder
|
||||
type DeleteFolderRequest struct {
|
||||
Token string `json:"token"`
|
||||
FolderID uint64 `json:"fld_id"`
|
||||
}
|
||||
|
||||
// CopyMoveFileRequest is used for moving/copying a file
|
||||
type CopyMoveFileRequest struct {
|
||||
Token string `json:"token"`
|
||||
FileCodes string `json:"file_codes"`
|
||||
DestinationFolderID uint64 `json:"destination_fld_id"`
|
||||
Action string `json:"action"`
|
||||
}
|
||||
|
||||
// MoveFolderRequest is used for moving a folder
|
||||
type MoveFolderRequest struct {
|
||||
Token string `json:"token"`
|
||||
FolderID uint64 `json:"fld_id"`
|
||||
DestinationFolderID uint64 `json:"destination_fld_id"`
|
||||
Action string `json:"action"`
|
||||
}
|
||||
|
||||
// RenameFolderRequest is used for renaming a folder
|
||||
type RenameFolderRequest struct {
|
||||
Token string `json:"token"`
|
||||
FolderID uint64 `json:"fld_id"`
|
||||
NewName string `json:"new_name"`
|
||||
}
|
||||
|
||||
// UpdateFileInformation is used for renaming a file
|
||||
type UpdateFileInformation struct {
|
||||
Token string `json:"token"`
|
||||
FileCode string `json:"file_code"`
|
||||
NewName string `json:"new_name,omitempty"`
|
||||
Description string `json:"description,omitempty"`
|
||||
Password string `json:"password,omitempty"`
|
||||
Public string `json:"public,omitempty"`
|
||||
}
|
||||
|
||||
// RemoveFileRequest is used for deleting a file
|
||||
type RemoveFileRequest struct {
|
||||
Token string `json:"token"`
|
||||
FileCodes string `json:"file_codes"`
|
||||
}
|
||||
|
||||
// Token represents the authentication token
|
||||
type Token struct {
|
||||
Token string `json:"token"`
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,21 +0,0 @@
|
||||
// Test Uptobox filesystem interface
|
||||
package uptobox_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/rclone/rclone/backend/uptobox"
|
||||
"github.com/rclone/rclone/fstest"
|
||||
"github.com/rclone/rclone/fstest/fstests"
|
||||
)
|
||||
|
||||
// TestIntegration runs integration tests against the remote
|
||||
func TestIntegration(t *testing.T) {
|
||||
if *fstest.RemoteName == "" {
|
||||
*fstest.RemoteName = "TestUptobox:"
|
||||
}
|
||||
fstests.Run(t, &fstests.Opt{
|
||||
RemoteName: *fstest.RemoteName,
|
||||
NilObject: (*uptobox.Object)(nil),
|
||||
})
|
||||
}
|
||||
@@ -817,7 +817,7 @@ func (f *Fs) upload(ctx context.Context, name string, parent string, size int64,
|
||||
params.Set("filename", url.QueryEscape(name))
|
||||
params.Set("parent_id", parent)
|
||||
params.Set("override-name-exist", strconv.FormatBool(true))
|
||||
formReader, contentType, overhead, err := rest.MultipartUpload(ctx, in, nil, "content", name)
|
||||
formReader, contentType, overhead, err := rest.MultipartUpload(ctx, in, nil, "content", name, "application/octet-stream")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to make multipart upload: %w", err)
|
||||
}
|
||||
|
||||
@@ -43,9 +43,11 @@ docs = [
|
||||
"compress.md",
|
||||
"combine.md",
|
||||
"doi.md",
|
||||
"drime.md"
|
||||
"dropbox.md",
|
||||
"filefabric.md",
|
||||
"filelu.md",
|
||||
"filen.md",
|
||||
"filescom.md",
|
||||
"ftp.md",
|
||||
"gofile.md",
|
||||
@@ -84,11 +86,11 @@ docs = [
|
||||
"protondrive.md",
|
||||
"seafile.md",
|
||||
"sftp.md",
|
||||
"shade.md",
|
||||
"smb.md",
|
||||
"storj.md",
|
||||
"sugarsync.md",
|
||||
"ulozto.md",
|
||||
"uptobox.md",
|
||||
"union.md",
|
||||
"webdav.md",
|
||||
"yandex.md",
|
||||
|
||||
300
bin/manage_backends.py
Executable file
300
bin/manage_backends.py
Executable file
@@ -0,0 +1,300 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Manage the backend yaml files in docs/data/backends
|
||||
|
||||
usage: manage_backends.py [-h] {create,features,update,help} [files ...]
|
||||
|
||||
Manage rclone backend YAML files.
|
||||
|
||||
positional arguments:
|
||||
{create,features,update,help}
|
||||
Action to perform
|
||||
files List of YAML files to operate on
|
||||
|
||||
options:
|
||||
-h, --help show this help message and exit
|
||||
"""
|
||||
import argparse
|
||||
import sys
|
||||
import os
|
||||
import yaml
|
||||
import json
|
||||
import subprocess
|
||||
import time
|
||||
import socket
|
||||
from contextlib import contextmanager
|
||||
from pprint import pprint
|
||||
|
||||
# --- Configuration ---
|
||||
|
||||
# The order in which keys should appear in the YAML file
|
||||
CANONICAL_ORDER = [
|
||||
"backend",
|
||||
"name",
|
||||
"tier",
|
||||
"maintainers",
|
||||
"features_score",
|
||||
"integration_tests",
|
||||
"data_integrity",
|
||||
"performance",
|
||||
"adoption",
|
||||
"docs",
|
||||
"security",
|
||||
"virtual",
|
||||
"remote",
|
||||
"features",
|
||||
"hashes",
|
||||
"precision"
|
||||
]
|
||||
|
||||
# Default values for fields when creating/updating
|
||||
DEFAULTS = {
|
||||
"tier": None,
|
||||
"maintainers": None,
|
||||
"features_score": None,
|
||||
"integration_tests": None,
|
||||
"data_integrity": None,
|
||||
"performance": None,
|
||||
"adoption": None,
|
||||
"docs": None,
|
||||
"security": None,
|
||||
"virtual": False,
|
||||
"remote": None,
|
||||
"features": [],
|
||||
"hashes": [],
|
||||
"precision": None
|
||||
}
|
||||
|
||||
# --- Test server management ---
|
||||
|
||||
def wait_for_tcp(address_str, delay=1, timeout=2, tries=60):
|
||||
"""
|
||||
Blocks until the specified TCP address (e.g., '172.17.0.3:21') is reachable.
|
||||
"""
|
||||
host, port = address_str.split(":")
|
||||
port = int(port)
|
||||
print(f"Waiting for {host}:{port}...")
|
||||
for tri in range(tries):
|
||||
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
|
||||
sock.settimeout(timeout)
|
||||
result = sock.connect_ex((host, port))
|
||||
if result == 0:
|
||||
print(f"Connected to {host}:{port} successfully!")
|
||||
break
|
||||
else:
|
||||
print(f"Failed to connect to {host}:{port} try {tri} !")
|
||||
time.sleep(delay)
|
||||
|
||||
def parse_init_output(binary_input):
|
||||
"""
|
||||
Parse the output of the init script
|
||||
"""
|
||||
decoded_str = binary_input.decode('utf-8')
|
||||
result = {}
|
||||
for line in decoded_str.splitlines():
|
||||
if '=' in line:
|
||||
key, value = line.split('=', 1)
|
||||
result[key.strip()] = value.strip()
|
||||
return result
|
||||
|
||||
@contextmanager
|
||||
def test_server(remote):
|
||||
"""Start the test server for remote if needed"""
|
||||
remote_name = remote.split(":",1)[0]
|
||||
init_script = "fstest/testserver/init.d/" + remote_name
|
||||
if not os.path.isfile(init_script):
|
||||
yield
|
||||
return
|
||||
print(f"--- Starting {init_script} ---")
|
||||
out = subprocess.check_output([init_script, "start"])
|
||||
out = parse_init_output(out)
|
||||
pprint(out)
|
||||
# Configure the server with environment variables
|
||||
env_keys = []
|
||||
for key, value in out.items():
|
||||
env_key = f"RCLONE_CONFIG_{remote_name.upper()}_{key.upper()}"
|
||||
env_keys.append(env_key)
|
||||
os.environ[env_key] = value
|
||||
for key,var in os.environ.items():
|
||||
if key.startswith("RCLON"):
|
||||
print(key, var)
|
||||
if "_connect" in out:
|
||||
wait_for_tcp(out["_connect"])
|
||||
try:
|
||||
yield
|
||||
finally:
|
||||
print(f"--- Stopping {init_script} ---")
|
||||
subprocess.run([init_script, "stop"], check=True)
|
||||
# Remove the env vars
|
||||
for env_key in env_keys:
|
||||
del os.environ[env_key]
|
||||
|
||||
# --- Helper Functions ---
|
||||
|
||||
def load_yaml(filepath):
|
||||
if not os.path.exists(filepath):
|
||||
return {}
|
||||
with open(filepath, 'r', encoding='utf-8') as f:
|
||||
return yaml.safe_load(f) or {}
|
||||
|
||||
def save_yaml(filepath, data):
|
||||
# Reconstruct dictionary in canonical order
|
||||
ordered_data = {}
|
||||
|
||||
# Add known keys in order
|
||||
for key in CANONICAL_ORDER:
|
||||
if key in data:
|
||||
ordered_data[key] = data[key]
|
||||
|
||||
# Add any other keys that might exist (custom fields)
|
||||
for key in data:
|
||||
if key not in CANONICAL_ORDER:
|
||||
ordered_data[key] = data[key]
|
||||
|
||||
# Ensure features are a sorted list (if present)
|
||||
if 'features' in ordered_data and isinstance(ordered_data['features'], list):
|
||||
ordered_data['features'].sort()
|
||||
|
||||
with open(filepath, 'w', encoding='utf-8') as f:
|
||||
yaml.dump(ordered_data, f, default_flow_style=False, sort_keys=False, allow_unicode=True)
|
||||
print(f"Saved {filepath}")
|
||||
|
||||
def get_backend_name_from_file(filepath):
|
||||
"""
|
||||
s3.yaml -> S3
|
||||
azureblob.yaml -> Azureblob
|
||||
"""
|
||||
basename = os.path.basename(filepath)
|
||||
name, _ = os.path.splitext(basename)
|
||||
return name.title()
|
||||
|
||||
def fetch_rclone_features(remote_str):
|
||||
"""
|
||||
Runs `rclone backend features remote:` and returns the JSON object.
|
||||
"""
|
||||
cmd = ["rclone", "backend", "features", remote_str]
|
||||
try:
|
||||
with test_server(remote_str):
|
||||
result = subprocess.run(cmd, capture_output=True, text=True, check=True)
|
||||
return json.loads(result.stdout)
|
||||
except subprocess.CalledProcessError as e:
|
||||
print(f"Error running rclone: {e.stderr}")
|
||||
return None
|
||||
except FileNotFoundError:
|
||||
print("Error: 'rclone' command not found in PATH.")
|
||||
sys.exit(1)
|
||||
|
||||
# --- Verbs ---
|
||||
|
||||
def do_create(files):
|
||||
for filepath in files:
|
||||
if os.path.exists(filepath):
|
||||
print(f"Skipping {filepath} (already exists)")
|
||||
continue
|
||||
|
||||
data = DEFAULTS.copy()
|
||||
# Set a default name based on filename
|
||||
data['name'] = get_backend_name_from_file(filepath)
|
||||
save_yaml(filepath, data)
|
||||
|
||||
def do_update(files):
|
||||
for filepath in files:
|
||||
if not os.path.exists(filepath):
|
||||
print(f"Warning: {filepath} does not exist. Use 'create' first.")
|
||||
continue
|
||||
|
||||
data = load_yaml(filepath)
|
||||
modified = False
|
||||
|
||||
# Inject the filename as the 'backend'
|
||||
file_backend = os.path.splitext(os.path.basename(filepath))[0]
|
||||
|
||||
if data.get('backend') != file_backend:
|
||||
data['backend'] = file_backend
|
||||
modified = True
|
||||
print(f"[{filepath}] Updated backend to: {file_backend}")
|
||||
|
||||
# Add missing default fields
|
||||
for key, default_val in DEFAULTS.items():
|
||||
if key not in data:
|
||||
data[key] = default_val
|
||||
modified = True
|
||||
print(f"[{filepath}] Added missing field: {key}")
|
||||
|
||||
# Special handling for 'name' if it was just added as None or didn't exist
|
||||
if data.get('name') is None:
|
||||
data['name'] = get_backend_name_from_file(filepath)
|
||||
modified = True
|
||||
print(f"[{filepath}] Set default name: {data['name']}")
|
||||
|
||||
if modified:
|
||||
save_yaml(filepath, data)
|
||||
else:
|
||||
# We save anyway to enforce canonical order if the file was messy
|
||||
save_yaml(filepath, data)
|
||||
|
||||
def do_features(files):
|
||||
for filepath in files:
|
||||
if not os.path.exists(filepath):
|
||||
print(f"Error: {filepath} not found.")
|
||||
continue
|
||||
|
||||
data = load_yaml(filepath)
|
||||
remote = data.get('remote')
|
||||
|
||||
if not remote:
|
||||
print(f"Error: [{filepath}] 'remote' field is missing or empty. Cannot fetch features.")
|
||||
continue
|
||||
|
||||
print(f"[{filepath}] Fetching features for remote: '{remote}'...")
|
||||
rclone_data = fetch_rclone_features(remote)
|
||||
|
||||
if not rclone_data:
|
||||
print(f"Failed to fetch data for {filepath}")
|
||||
continue
|
||||
|
||||
# Process Features (Dict -> Sorted List of True keys)
|
||||
features_dict = rclone_data.get('Features', {})
|
||||
# Filter only true values and sort keys
|
||||
feature_list = sorted([k for k, v in features_dict.items() if v])
|
||||
|
||||
# Process Hashes
|
||||
hashes_list = rclone_data.get('Hashes', [])
|
||||
|
||||
# Process Precision
|
||||
precision = rclone_data.get('Precision')
|
||||
|
||||
# Update data
|
||||
data['features'] = feature_list
|
||||
data['hashes'] = hashes_list
|
||||
data['precision'] = precision
|
||||
|
||||
save_yaml(filepath, data)
|
||||
|
||||
# --- Main CLI ---
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description="Manage rclone backend YAML files.")
|
||||
parser.add_argument("verb", choices=["create", "features", "update", "help"], help="Action to perform")
|
||||
parser.add_argument("files", nargs="*", help="List of YAML files to operate on")
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
if args.verb == "help":
|
||||
parser.print_help()
|
||||
sys.exit(0)
|
||||
|
||||
if not args.files:
|
||||
print("Error: No files specified.")
|
||||
parser.print_help()
|
||||
sys.exit(1)
|
||||
|
||||
if args.verb == "create":
|
||||
do_create(args.files)
|
||||
elif args.verb == "update":
|
||||
do_update(args.files)
|
||||
elif args.verb == "features":
|
||||
do_features(args.files)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -1,4 +1,4 @@
|
||||
//go:build cmount && ((linux && cgo) || (darwin && cgo) || (freebsd && cgo) || (openbsd && cgo) || windows)
|
||||
//go:build cmount && ((linux && cgo) || (darwin && cgo) || (freebsd && cgo) || windows)
|
||||
|
||||
package cmount
|
||||
|
||||
@@ -6,7 +6,6 @@ import (
|
||||
"io"
|
||||
"os"
|
||||
"path"
|
||||
"runtime"
|
||||
"strings"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
@@ -211,12 +210,6 @@ func (fsys *FS) Readdir(dirPath string,
|
||||
// We can't seek in directories and FUSE should know that so
|
||||
// return an error if ofst is ever set.
|
||||
if ofst > 0 {
|
||||
// However openbsd doesn't seem to know this - perhaps a bug in its
|
||||
// FUSE implementation or a bug in cgofuse?
|
||||
// See: https://github.com/billziss-gh/cgofuse/issues/49
|
||||
if runtime.GOOS == "openbsd" {
|
||||
return 0
|
||||
}
|
||||
return -fuse.ESPIPE
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//go:build cmount && ((linux && cgo) || (darwin && cgo) || (freebsd && cgo) || (openbsd && cgo) || windows)
|
||||
//go:build cmount && ((linux && cgo) || (darwin && cgo) || (freebsd && cgo) || windows)
|
||||
|
||||
// Package cmount implements a FUSE mounting system for rclone remotes.
|
||||
//
|
||||
@@ -8,9 +8,9 @@ package cmount
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
"os"
|
||||
"runtime"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/rclone/rclone/cmd/mountlib"
|
||||
@@ -59,14 +59,12 @@ func mountOptions(VFS *vfs.VFS, device string, mountpoint string, opt *mountlib.
|
||||
} else {
|
||||
options = append(options, "-o", "fsname="+device)
|
||||
options = append(options, "-o", "subtype=rclone")
|
||||
if runtime.GOOS != "openbsd" {
|
||||
options = append(options, "-o", fmt.Sprintf("max_readahead=%d", opt.MaxReadAhead))
|
||||
// This causes FUSE to supply O_TRUNC with the Open
|
||||
// call which is more efficient for cmount. However
|
||||
// it does not work with cgofuse on Windows with
|
||||
// WinFSP so cmount must work with or without it.
|
||||
options = append(options, "-o", "atomic_o_trunc")
|
||||
}
|
||||
options = append(options, "-o", fmt.Sprintf("max_readahead=%d", opt.MaxReadAhead))
|
||||
// This causes FUSE to supply O_TRUNC with the Open
|
||||
// call which is more efficient for cmount. However
|
||||
// it does not work with cgofuse on Windows with
|
||||
// WinFSP so cmount must work with or without it.
|
||||
options = append(options, "-o", "atomic_o_trunc")
|
||||
if opt.DaemonTimeout != 0 {
|
||||
options = append(options, "-o", fmt.Sprintf("daemon_timeout=%d", int(time.Duration(opt.DaemonTimeout).Seconds())))
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//go:build cmount && ((linux && cgo) || (darwin && cgo) || (freebsd && cgo) || (openbsd && cgo) || windows) && (!race || !windows)
|
||||
//go:build cmount && ((linux && cgo) || (darwin && cgo) || (freebsd && cgo) || windows) && (!race || !windows)
|
||||
|
||||
// Package cmount implements a FUSE mounting system for rclone remotes.
|
||||
//
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//go:build !((linux && cgo && cmount) || (darwin && cgo && cmount) || (freebsd && cgo && cmount) || (openbsd && cgo && cmount) || (windows && cmount))
|
||||
//go:build !((linux && cgo && cmount) || (darwin && cgo && cmount) || (freebsd && cgo && cmount) || (windows && cmount))
|
||||
|
||||
// Package cmount implements a FUSE mounting system for rclone remotes.
|
||||
//
|
||||
|
||||
@@ -341,7 +341,7 @@ func (h *testState) preconfigureServer() {
|
||||
// The `\\?\` prefix tells Windows APIs to pass strings unmodified to the
|
||||
// filesystem without additional parsing [1]. Our workaround is roughly to add
|
||||
// the prefix to whichever parameter doesn't have it (when the OS is Windows).
|
||||
// I'm not sure this generalizes, but it works for the the kinds of inputs we're
|
||||
// I'm not sure this generalizes, but it works for the kinds of inputs we're
|
||||
// throwing at it.
|
||||
//
|
||||
// [1]: https://learn.microsoft.com/en-us/windows/win32/fileio/naming-a-file?redirectedfrom=MSDN#win32-file-namespaces
|
||||
|
||||
@@ -26,6 +26,10 @@ Note that |ls| and |lsl| recurse by default - use |--max-depth 1| to stop the re
|
||||
The other list commands |lsd|,|lsf|,|lsjson| do not recurse by default -
|
||||
use |-R| to make them recurse.
|
||||
|
||||
List commands prefer a recursive method that uses more memory but fewer
|
||||
transactions by default. Use |--disable ListR| to suppress the behavior.
|
||||
See [|--fast-list|](/docs/#fast-list) for more details.
|
||||
|
||||
Listing a nonexistent directory will produce an error except for
|
||||
remotes which can't have empty directories (e.g. s3, swift, or gcs -
|
||||
the bucket-based remotes).`, "|", "`")
|
||||
|
||||
@@ -97,7 +97,7 @@ with the following options:
|
||||
- If ` + "`--files-only`" + ` is specified then files will be returned only,
|
||||
no directories.
|
||||
|
||||
If ` + "`--stat`" + ` is set then the the output is not an array of items,
|
||||
If ` + "`--stat`" + ` is set then the output is not an array of items,
|
||||
but instead a single JSON blob will be returned about the item pointed to.
|
||||
This will return an error if the item isn't found, however on bucket based
|
||||
backends (like s3, gcs, b2, azureblob etc) if the item isn't found it will
|
||||
|
||||
@@ -71,7 +71,7 @@ rclone rc mount/mount fs=mydrive: mountPoint=/home/<user>/mountPoint mountType=m
|
||||
rclone rc mount/mount fs=TestDrive: mountPoint=/mnt/tmp vfsOpt='{"CacheMode": 2}' mountOpt='{"AllowOther": true}'
|
||||
` + "```" + `
|
||||
|
||||
The vfsOpt are as described in options/get and can be seen in the the
|
||||
The vfsOpt are as described in options/get and can be seen in the
|
||||
"vfs" section when running and the mountOpt can be seen in the "mount" section:
|
||||
|
||||
` + "```console" + `
|
||||
|
||||
@@ -34,7 +34,7 @@ argument by passing a hyphen as an argument. This will use the first
|
||||
line of STDIN as the password not including the trailing newline.
|
||||
|
||||
` + "```console" + `
|
||||
echo "secretpassword" | rclone obscure -
|
||||
echo 'secretpassword' | rclone obscure -
|
||||
` + "```" + `
|
||||
|
||||
If there is no data on STDIN to read, rclone obscure will default to
|
||||
|
||||
@@ -13,6 +13,26 @@ docs](https://docs.aws.amazon.com/general/latest/gr/signature-version-4.html)).
|
||||
`--auth-key` is not provided then `serve s3` will allow anonymous
|
||||
access.
|
||||
|
||||
Like all rclone flags `--auth-key` can be set via environment
|
||||
variables, in this case `RCLONE_AUTH_KEY`. Since this flag can be
|
||||
repeated, the input to `RCLONE_AUTH_KEY` is CSV encoded. Because the
|
||||
`accessKey,secretKey` has a comma in, this means it needs to be in
|
||||
quotes.
|
||||
|
||||
```console
|
||||
export RCLONE_AUTH_KEY='"user,pass"'
|
||||
rclone serve s3 ...
|
||||
```
|
||||
|
||||
Or to supply multiple identities:
|
||||
|
||||
```console
|
||||
export RCLONE_AUTH_KEY='"user1,pass1","user2,pass2"'
|
||||
rclone serve s3 ...
|
||||
```
|
||||
|
||||
Setting this variable without quotes will produce an error.
|
||||
|
||||
Please note that some clients may require HTTPS endpoints. See [the
|
||||
SSL docs](#tls-ssl) for more information.
|
||||
|
||||
|
||||
@@ -70,6 +70,11 @@ func newServer(ctx context.Context, f fs.Fs, opt *Options, vfsOpt *vfscommon.Opt
|
||||
w.s3Secret = getAuthSecret(opt.AuthKey)
|
||||
}
|
||||
|
||||
authList, err := authlistResolver(opt.AuthKey)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("parsing auth list failed: %q", err)
|
||||
}
|
||||
|
||||
var newLogger logger
|
||||
w.faker = gofakes3.New(
|
||||
newBackend(w),
|
||||
@@ -77,7 +82,7 @@ func newServer(ctx context.Context, f fs.Fs, opt *Options, vfsOpt *vfscommon.Opt
|
||||
gofakes3.WithLogger(newLogger),
|
||||
gofakes3.WithRequestID(rand.Uint64()),
|
||||
gofakes3.WithoutVersioning(),
|
||||
gofakes3.WithV4Auth(authlistResolver(opt.AuthKey)),
|
||||
gofakes3.WithV4Auth(authList),
|
||||
gofakes3.WithIntegrityCheck(true), // Check Content-MD5 if supplied
|
||||
)
|
||||
|
||||
@@ -92,7 +97,7 @@ func newServer(ctx context.Context, f fs.Fs, opt *Options, vfsOpt *vfscommon.Opt
|
||||
w._vfs = vfs.New(f, vfsOpt)
|
||||
|
||||
if len(opt.AuthKey) > 0 {
|
||||
w.faker.AddAuthKeys(authlistResolver(opt.AuthKey))
|
||||
w.faker.AddAuthKeys(authList)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ package s3
|
||||
import (
|
||||
"context"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"io"
|
||||
"os"
|
||||
"path"
|
||||
@@ -125,15 +126,14 @@ func rmdirRecursive(p string, VFS *vfs.VFS) {
|
||||
}
|
||||
}
|
||||
|
||||
func authlistResolver(list []string) map[string]string {
|
||||
func authlistResolver(list []string) (map[string]string, error) {
|
||||
authList := make(map[string]string)
|
||||
for _, v := range list {
|
||||
parts := strings.Split(v, ",")
|
||||
if len(parts) != 2 {
|
||||
fs.Infof(nil, "Ignored: invalid auth pair %s", v)
|
||||
continue
|
||||
return nil, errors.New("invalid auth pair: expecting a single comma")
|
||||
}
|
||||
authList[parts[0]] = parts[1]
|
||||
}
|
||||
return authList
|
||||
return authList, nil
|
||||
}
|
||||
|
||||
@@ -291,7 +291,7 @@ func (c *conn) handleChannel(newChannel ssh.NewChannel) {
|
||||
}
|
||||
}
|
||||
fs.Debugf(c.what, " - accepted: %v\n", ok)
|
||||
err = req.Reply(ok, reply)
|
||||
err := req.Reply(ok, reply)
|
||||
if err != nil {
|
||||
fs.Errorf(c.what, "Failed to Reply to request: %v", err)
|
||||
return
|
||||
|
||||
@@ -116,6 +116,7 @@ WebDAV or S3, that work out of the box.)
|
||||
{{< provider name="Akamai Netstorage" home="https://www.akamai.com/us/en/products/media-delivery/netstorage.jsp" config="/netstorage/" >}}
|
||||
{{< provider name="Alibaba Cloud (Aliyun) Object Storage System (OSS)" home="https://www.alibabacloud.com/product/oss/" config="/s3/#alibaba-oss" >}}
|
||||
{{< provider name="Amazon S3" home="https://aws.amazon.com/s3/" config="/s3/" >}}
|
||||
{{< provider name="Bizfly Cloud Simple Storage" home="https://bizflycloud.vn/" config="/s3/#bizflycloud" >}}
|
||||
{{< provider name="Backblaze B2" home="https://www.backblaze.com/cloud-storage" config="/b2/" >}}
|
||||
{{< provider name="Box" home="https://www.box.com/" config="/box/" >}}
|
||||
{{< provider name="Ceph" home="http://ceph.com/" config="/s3/#ceph" >}}
|
||||
@@ -128,12 +129,14 @@ WebDAV or S3, that work out of the box.)
|
||||
{{< provider name="DigitalOcean Spaces" home="https://www.digitalocean.com/products/object-storage/" config="/s3/#digitalocean-spaces" >}}
|
||||
{{< provider name="Digi Storage" home="https://storage.rcs-rds.ro/" config="/koofr/#digi-storage" >}}
|
||||
{{< provider name="Dreamhost" home="https://www.dreamhost.com/cloud/storage/" config="/s3/#dreamhost" >}}
|
||||
{{< provider name="Drime" home="https://www.drime.cloud/" config="/drime/" >}}
|
||||
{{< provider name="Dropbox" home="https://www.dropbox.com/" config="/dropbox/" >}}
|
||||
{{< provider name="Enterprise File Fabric" home="https://storagemadeeasy.com/about/" config="/filefabric/" >}}
|
||||
{{< provider name="Exaba" home="https://exaba.com/" config="/s3/#exaba" >}}
|
||||
{{< provider name="Fastmail Files" home="https://www.fastmail.com/" config="/webdav/#fastmail-files" >}}
|
||||
{{< provider name="FileLu Cloud Storage" home="https://filelu.com/" config="/filelu/" >}}
|
||||
{{< provider name="FileLu S5 (S3-Compatible Object Storage)" home="https://s5lu.com/" config="/s3/#filelu-s5" >}}
|
||||
{{< provider name="Filen" home="https://www.filen.io/" config="/filen/" >}}
|
||||
{{< provider name="Files.com" home="https://www.files.com/" config="/filescom/" >}}
|
||||
{{< provider name="FlashBlade" home="https://www.purestorage.com/products/unstructured-data-storage.html" config="/s3/#pure-storage-flashblade" >}}
|
||||
{{< provider name="FTP" home="https://en.wikipedia.org/wiki/File_Transfer_Protocol" config="/ftp/" >}}
|
||||
@@ -202,6 +205,7 @@ WebDAV or S3, that work out of the box.)
|
||||
{{< provider name="Selectel" home="https://selectel.ru/services/cloud/storage/" config="/s3/#selectel" >}}
|
||||
{{< provider name="Servercore Object Storage" home="https://servercore.com/services/object-storage/" config="/s3/#servercore" >}}
|
||||
{{< provider name="SFTP" home="https://en.wikipedia.org/wiki/SSH_File_Transfer_Protocol" config="/sftp/" >}}
|
||||
{{< provider name="Shade" home="https://shade.inc" config="/shade/" >}}
|
||||
{{< provider name="Sia" home="https://sia.tech/" config="/sia/" >}}
|
||||
{{< provider name="SMB / CIFS" home="https://en.wikipedia.org/wiki/Server_Message_Block" config="/smb/" >}}
|
||||
{{< provider name="Spectra Logic" home="https://spectralogic.com/blackpearl-nearline-object-gateway/" config="/s3/#spectralogic" >}}
|
||||
@@ -211,7 +215,6 @@ WebDAV or S3, that work out of the box.)
|
||||
{{< provider name="SugarSync" home="https://sugarsync.com/" config="/sugarsync/" >}}
|
||||
{{< provider name="Tencent Cloud Object Storage (COS)" home="https://intl.cloud.tencent.com/product/cos" config="/s3/#tencent-cos" >}}
|
||||
{{< provider name="Uloz.to" home="https://uloz.to" config="/ulozto/" >}}
|
||||
{{< provider name="Uptobox" home="https://uptobox.com" config="/uptobox/" >}}
|
||||
{{< provider name="Wasabi" home="https://wasabi.com/" config="/s3/#wasabi" >}}
|
||||
{{< provider name="WebDAV" home="https://en.wikipedia.org/wiki/WebDAV" config="/webdav/" >}}
|
||||
{{< provider name="Yandex Disk" home="https://disk.yandex.com/" config="/yandex/" >}}
|
||||
|
||||
@@ -1055,3 +1055,18 @@ put them back in again. -->
|
||||
- Vladislav Tropnikov <vtr.name@gmail.com>
|
||||
- Leo <i@hardrain980.com>
|
||||
- Johannes Rothe <mail@johannes-rothe.de>
|
||||
- Tingsong Xu <tingsong.xu@rightcapital.com>
|
||||
- Jonas Tingeborn <134889+jojje@users.noreply.github.com>
|
||||
- jhasse-shade <jacob@shade.inc>
|
||||
- vyv03354 <VYV03354@nifty.ne.jp>
|
||||
- masrlinu <masrlinu@users.noreply.github.com> <5259918+masrlinu@users.noreply.github.com>
|
||||
- vupn0712 <126212736+vupn0712@users.noreply.github.com>
|
||||
- darkdragon-001 <darkdragon-001@users.noreply.github.com>
|
||||
- sys6101 <csvmen@gmail.com>
|
||||
- Nicolas Dessart <nds@outsight.tech>
|
||||
- Qingwei Li <332664203@qq.com>
|
||||
- yy <yhymmt37@gmail.com>
|
||||
- Marc-Philip <marc-philip.werner@sap.com>
|
||||
- Mikel Olasagasti Uranga <mikel@olasagasti.info>
|
||||
- Nick Owens <mischief@offblast.org>
|
||||
- hyusap <paulayush@gmail.com>
|
||||
|
||||
@@ -6,6 +6,22 @@ description: "Rclone Changelog"
|
||||
|
||||
# Changelog
|
||||
|
||||
## v1.72.1 - 2025-12-10
|
||||
|
||||
[See commits](https://github.com/rclone/rclone/compare/v1.72.0...v1.72.1)
|
||||
|
||||
- Bug Fixes
|
||||
- build: update to go1.25.5 to fix [CVE-2025-61729](https://pkg.go.dev/vuln/GO-2025-4155)
|
||||
- doc fixes (Duncan Smart, Nick Craig-Wood)
|
||||
- configfile: Fix piped config support (Jonas Tingeborn)
|
||||
- log
|
||||
- Fix PID not included in JSON log output (Tingsong Xu)
|
||||
- Fix backtrace not going to the --log-file (Nick Craig-Wood)
|
||||
- Google Cloud Storage
|
||||
- Improve endpoint parameter docs (Johannes Rothe)
|
||||
- S3
|
||||
- Add missing regions for Selectel provider (Nick Craig-Wood)
|
||||
|
||||
## v1.72.0 - 2025-11-21
|
||||
|
||||
[See commits](https://github.com/rclone/rclone/compare/v1.71.0...v1.72.0)
|
||||
|
||||
@@ -1015,10 +1015,6 @@ rclone [flags]
|
||||
--union-search-policy string Policy to choose upstream on SEARCH category (default "ff")
|
||||
--union-upstreams string List of space separated upstreams
|
||||
-u, --update Skip files that are newer on the destination
|
||||
--uptobox-access-token string Your access token
|
||||
--uptobox-description string Description of the remote
|
||||
--uptobox-encoding Encoding The encoding for the backend (default Slash,LtGt,DoubleQuote,BackQuote,Del,Ctl,LeftSpace,InvalidUtf8,Dot)
|
||||
--uptobox-private Set to make uploaded files private
|
||||
--use-cookies Enable session cookiejar
|
||||
--use-json-log Use json log format
|
||||
--use-mmap Use mmap allocator (see docs)
|
||||
|
||||
@@ -336,7 +336,7 @@ full new copy of the file.
|
||||
When mounting with `--read-only`, attempts to write to files will fail *silently*
|
||||
as opposed to with a clear warning as in macFUSE.
|
||||
|
||||
# Mounting on Linux
|
||||
## Mounting on Linux
|
||||
|
||||
On newer versions of Ubuntu, you may encounter the following error when running
|
||||
`rclone mount`:
|
||||
|
||||
@@ -43,9 +43,11 @@ See the following for detailed instructions for
|
||||
- [Crypt](/crypt/) - to encrypt other remotes
|
||||
- [DigitalOcean Spaces](/s3/#digitalocean-spaces)
|
||||
- [Digi Storage](/koofr/#digi-storage)
|
||||
- [Drime](/drime/)
|
||||
- [Dropbox](/dropbox/)
|
||||
- [Enterprise File Fabric](/filefabric/)
|
||||
- [FileLu Cloud Storage](/filelu/)
|
||||
- [Filen](/filen/)
|
||||
- [Files.com](/filescom/)
|
||||
- [FTP](/ftp/)
|
||||
- [Gofile](/gofile/)
|
||||
@@ -82,13 +84,13 @@ See the following for detailed instructions for
|
||||
- [rsync.net](/sftp/#rsync-net)
|
||||
- [Seafile](/seafile/)
|
||||
- [SFTP](/sftp/)
|
||||
- [Shade](/shade/)
|
||||
- [Sia](/sia/)
|
||||
- [SMB](/smb/)
|
||||
- [Storj](/storj/)
|
||||
- [SugarSync](/sugarsync/)
|
||||
- [Union](/union/)
|
||||
- [Uloz.to](/ulozto/)
|
||||
- [Uptobox](/uptobox/)
|
||||
- [WebDAV](/webdav/)
|
||||
- [Yandex Disk](/yandex/)
|
||||
- [Zoho WorkDrive](/zoho/)
|
||||
|
||||
244
docs/content/drime.md
Normal file
244
docs/content/drime.md
Normal file
@@ -0,0 +1,244 @@
|
||||
---
|
||||
title: "Drime"
|
||||
description: "Rclone docs for Drime"
|
||||
versionIntroduced: "v1.73"
|
||||
---
|
||||
|
||||
# {{< icon "fa fa-cloud" >}} Drime
|
||||
|
||||
[Drime](https://drime.cloud/) is a cloud storage and transfer service focused
|
||||
on fast, resilient file delivery. It offers both free and paid tiers with
|
||||
emphasis on high-speed uploads and link sharing.
|
||||
|
||||
To setup Drime you need to log in, navigate to Settings, Developer, and create a
|
||||
token to use as an API access key. Give it a sensible name and copy the token
|
||||
for use in the config.
|
||||
|
||||
## Configuration
|
||||
|
||||
Here is a run through of `rclone config` to make a remote called `remote`.
|
||||
|
||||
Firstly run:
|
||||
|
||||
|
||||
```console
|
||||
rclone config
|
||||
```
|
||||
|
||||
Then follow through the interactive setup:
|
||||
|
||||
|
||||
```text
|
||||
No remotes found, make a new one?
|
||||
n) New remote
|
||||
s) Set configuration password
|
||||
q) Quit config
|
||||
n/s/q> n
|
||||
|
||||
Enter name for new remote.
|
||||
name> remote
|
||||
|
||||
Option Storage.
|
||||
Type of storage to configure.
|
||||
Choose a number from below, or type in your own value.
|
||||
XX / Drime
|
||||
\ (drime)
|
||||
Storage> drime
|
||||
|
||||
Option access_token.
|
||||
API Access token
|
||||
You can get this from the web control panel.
|
||||
Enter a value. Press Enter to leave empty.
|
||||
access_token> YOUR_API_ACCESS_TOKEN
|
||||
|
||||
Edit advanced config?
|
||||
y) Yes
|
||||
n) No (default)
|
||||
y/n> n
|
||||
|
||||
Configuration complete.
|
||||
Options:
|
||||
- type: drime
|
||||
- access_token: YOUR_API_ACCESS_TOKEN
|
||||
Keep this "remote" remote?
|
||||
y) Yes this is OK (default)
|
||||
e) Edit this remote
|
||||
d) Delete this remote
|
||||
y/e/d> y
|
||||
```
|
||||
|
||||
Once configured you can then use `rclone` like this (replace `remote` with the
|
||||
name you gave your remote):
|
||||
|
||||
List directories and files in the top level of your Drime
|
||||
|
||||
```console
|
||||
rclone lsf remote:
|
||||
```
|
||||
|
||||
To copy a local directory to a Drime directory called backup
|
||||
|
||||
```console
|
||||
rclone copy /home/source remote:backup
|
||||
```
|
||||
|
||||
|
||||
### Modification times and hashes
|
||||
|
||||
Drime does not support modification times or hashes.
|
||||
|
||||
This means that by default syncs will only use the size of the file to determine
|
||||
if it needs updating.
|
||||
|
||||
You can use the `--update` flag which will use the time the object was uploaded.
|
||||
For many operations this is sufficient to determine if it has changed. However
|
||||
files created with timestamps in the past will be missed by the sync if using
|
||||
`--update`.
|
||||
|
||||
|
||||
### Restricted filename characters
|
||||
|
||||
In addition to the [default restricted characters set](/overview/#restricted-characters)
|
||||
the following characters are also replaced:
|
||||
|
||||
| Character | Value | Replacement |
|
||||
| --------- |:-----:|:-----------:|
|
||||
| \ | 0x5C | \ |
|
||||
|
||||
File names can also not start or end with the following characters. These only
|
||||
get replaced if they are the first or last character in the name:
|
||||
|
||||
| Character | Value | Replacement |
|
||||
| --------- |:-----:|:-----------:|
|
||||
| SP | 0x20 | ␠ |
|
||||
|
||||
Invalid UTF-8 bytes will also be [replaced](/overview/#invalid-utf8),
|
||||
as they can't be used in JSON strings.
|
||||
|
||||
### Root folder ID
|
||||
|
||||
You can set the `root_folder_id` for rclone. This is the directory
|
||||
(identified by its `Folder ID`) that rclone considers to be the root
|
||||
of your Drime drive.
|
||||
|
||||
Normally you will leave this blank and rclone will determine the
|
||||
correct root to use itself and fill in the value in the config file.
|
||||
|
||||
However you can set this to restrict rclone to a specific folder
|
||||
hierarchy.
|
||||
|
||||
In order to do this you will have to find the `Folder ID` of the
|
||||
directory you wish rclone to display.
|
||||
|
||||
You can do this with rclone
|
||||
|
||||
```console
|
||||
$ rclone lsf -Fip --dirs-only remote:
|
||||
d6341f53-ee65-4f29-9f59-d11e8070b2a0;Files/
|
||||
f4f5c9b8-6ece-478b-b03e-4538edfe5a1c;Photos/
|
||||
d50e356c-29ca-4b27-a3a7-494d91026e04;Videos/
|
||||
```
|
||||
|
||||
The ID to use is the part before the `;` so you could set
|
||||
|
||||
```text
|
||||
root_folder_id = d6341f53-ee65-4f29-9f59-d11e8070b2a0
|
||||
```
|
||||
|
||||
To restrict rclone to the `Files` directory.
|
||||
|
||||
<!-- autogenerated options start - DO NOT EDIT - instead edit fs.RegInfo in backend/drime/drime.go and run make backenddocs to verify --> <!-- markdownlint-disable-line line-length -->
|
||||
### Standard options
|
||||
|
||||
Here are the Standard options specific to drime (Drime).
|
||||
|
||||
#### --drime-access-token
|
||||
|
||||
API Access token
|
||||
|
||||
You can get this from the web control panel.
|
||||
|
||||
Properties:
|
||||
|
||||
- Config: access_token
|
||||
- Env Var: RCLONE_DRIME_ACCESS_TOKEN
|
||||
- Type: string
|
||||
- Required: false
|
||||
|
||||
### Advanced options
|
||||
|
||||
Here are the Advanced options specific to drime (Drime).
|
||||
|
||||
#### --drime-root-folder-id
|
||||
|
||||
ID of the root folder
|
||||
|
||||
Leave this blank normally, rclone will fill it in automatically.
|
||||
|
||||
If you want rclone to be restricted to a particular folder you can
|
||||
fill it in - see the docs for more info.
|
||||
|
||||
|
||||
Properties:
|
||||
|
||||
- Config: root_folder_id
|
||||
- Env Var: RCLONE_DRIME_ROOT_FOLDER_ID
|
||||
- Type: string
|
||||
- Required: false
|
||||
|
||||
#### --drime-workspace-id
|
||||
|
||||
Account ID
|
||||
|
||||
Leave this blank normally, rclone will fill it in automatically.
|
||||
|
||||
|
||||
Properties:
|
||||
|
||||
- Config: workspace_id
|
||||
- Env Var: RCLONE_DRIME_WORKSPACE_ID
|
||||
- Type: string
|
||||
- Required: false
|
||||
|
||||
#### --drime-list-chunk
|
||||
|
||||
Number of items to list in each call
|
||||
|
||||
Properties:
|
||||
|
||||
- Config: list_chunk
|
||||
- Env Var: RCLONE_DRIME_LIST_CHUNK
|
||||
- Type: int
|
||||
- Default: 1000
|
||||
|
||||
#### --drime-encoding
|
||||
|
||||
The encoding for the backend.
|
||||
|
||||
See the [encoding section in the overview](/overview/#encoding) for more info.
|
||||
|
||||
Properties:
|
||||
|
||||
- Config: encoding
|
||||
- Env Var: RCLONE_DRIME_ENCODING
|
||||
- Type: Encoding
|
||||
- Default: Slash,BackSlash,Del,Ctl,LeftSpace,RightSpace,InvalidUtf8,Dot
|
||||
|
||||
#### --drime-description
|
||||
|
||||
Description of the remote.
|
||||
|
||||
Properties:
|
||||
|
||||
- Config: description
|
||||
- Env Var: RCLONE_DRIME_DESCRIPTION
|
||||
- Type: string
|
||||
- Required: false
|
||||
|
||||
<!-- autogenerated options stop -->
|
||||
|
||||
## Limitations
|
||||
|
||||
Drime only supports filenames up to 255 bytes in length, where filenames are
|
||||
encoded in UTF8.
|
||||
|
||||
@@ -316,3 +316,47 @@ back again when transferring to a different storage system where the
|
||||
original characters are supported. When the same Unicode characters
|
||||
are intentionally used in file names, this replacement strategy leads
|
||||
to unwanted renames. Read more under section [caveats](/overview/#restricted-filenames-caveats).
|
||||
|
||||
### Why does rclone fail to connect over TLS but another client works?
|
||||
|
||||
If you see TLS handshake failures (or packet captures show the server
|
||||
rejecting all offered ciphers), the server/proxy may only support
|
||||
legacy TLS cipher suites (for example RSA key-exchange ciphers
|
||||
such as `RSA_WITH_AES_256_CBC_SHA256`, or old 3DES ciphers). Recent Go
|
||||
versions (which rclone is built with) have **removed insecure ciphers
|
||||
from the default list**, so rclone may refuse to negotiate them even
|
||||
if other tools still do.
|
||||
|
||||
If you can't update/reconfigure the server/proxy to support modern TLS
|
||||
(TLS 1.2/1.3) and ECDHE-based cipher suites you can re-enable legacy
|
||||
ciphers via `GODEBUG`:
|
||||
|
||||
- Windows (cmd.exe):
|
||||
|
||||
```bat
|
||||
set GODEBUG=tlsrsakex=1
|
||||
rclone copy ...
|
||||
```
|
||||
|
||||
- Windows (PowerShell):
|
||||
|
||||
```powershell
|
||||
$env:GODEBUG="tlsrsakex=1"
|
||||
rclone copy ...
|
||||
```
|
||||
|
||||
- Linux/macOS:
|
||||
|
||||
```sh
|
||||
GODEBUG=tlsrsakex=1 rclone copy ...
|
||||
```
|
||||
|
||||
If the server only supports 3DES, try:
|
||||
|
||||
```sh
|
||||
GODEBUG=tls3des=1 rclone ...
|
||||
```
|
||||
|
||||
This applies to **any rclone feature using TLS** (HTTPS, FTPS, WebDAV
|
||||
over TLS, proxies with TLS interception, etc.). Use these workarounds
|
||||
only long enough to get the server/proxy updated.
|
||||
|
||||
244
docs/content/filen.md
Normal file
244
docs/content/filen.md
Normal file
@@ -0,0 +1,244 @@
|
||||
---
|
||||
title: "Filen"
|
||||
description: "Rclone docs for Filen"
|
||||
versionIntroduced: "1.73"
|
||||
---
|
||||
|
||||
# {{< icon "fa fa-solid fa-f" >}} Filen
|
||||
## Configuration
|
||||
The initial setup for Filen requires that you get an API key for your account,
|
||||
currently this is only possible using the [Filen CLI](https://github.com/FilenCloudDienste/filen-cli).
|
||||
This means you must first download the CLI, login, and then run the `export-api-key` command.
|
||||
|
||||
Here is an example of how to make a remote called `FilenRemote`. First run:
|
||||
|
||||
rclone config
|
||||
|
||||
This will guide you through an interactive setup process:
|
||||
```
|
||||
No remotes found, make a new one?
|
||||
n) New remote
|
||||
s) Set configuration password
|
||||
q) Quit config
|
||||
n/s/q> n
|
||||
|
||||
name> FilenRemote
|
||||
Option Storage.
|
||||
|
||||
Type of storage to configure.
|
||||
Choose a number from below, or type in your own value.
|
||||
[snip]
|
||||
XX / Filen
|
||||
\ "filen"
|
||||
[snip]
|
||||
Storage> filen
|
||||
|
||||
Option Email.
|
||||
The email of your Filen account
|
||||
Enter a value.
|
||||
Email> youremail@provider.com
|
||||
|
||||
Option Password.
|
||||
The password of your Filen account
|
||||
Choose an alternative below.
|
||||
y) Yes, type in my own password
|
||||
g) Generate random password
|
||||
y/g> y
|
||||
Enter the password:
|
||||
password:
|
||||
Confirm the password:
|
||||
password:
|
||||
|
||||
Option API Key.
|
||||
An API Key for your Filen account
|
||||
Get this using the Filen CLI export-api-key command
|
||||
You can download the Filen CLI from https://github.com/FilenCloudDienste/filen-cli
|
||||
Choose an alternative below.
|
||||
y) Yes, type in my own password
|
||||
g) Generate random password
|
||||
y/g> y
|
||||
Enter the password:
|
||||
password:
|
||||
Confirm the password:
|
||||
password:
|
||||
|
||||
Edit advanced config?
|
||||
y) Yes
|
||||
n) No (default)
|
||||
y/n> n
|
||||
|
||||
Configuration complete.
|
||||
Options:
|
||||
- type: filen
|
||||
- Email: youremail@provider.com
|
||||
- Password: *** ENCRYPTED ***
|
||||
- API Key: *** ENCRYPTED ***
|
||||
Keep this "FilenRemote" remote?
|
||||
y) Yes this is OK (default)
|
||||
e) Edit this remote
|
||||
d) Delete this remote
|
||||
y/e/d> y
|
||||
```
|
||||
|
||||
### Modification times and hashes
|
||||
Modification times are fully supported for files, for directories, only the creation time matters.
|
||||
|
||||
Filen supports Blake3 hashes.
|
||||
|
||||
### Restricted filename characters
|
||||
Invalid UTF-8 bytes will be [replaced](/overview/#invalid-utf8)
|
||||
|
||||
|
||||
### API Key
|
||||
|
||||
<!-- autogenerated options start - DO NOT EDIT - instead edit fs.RegInfo in backend/filen/filen.go and run make backenddocs to verify --> <!-- markdownlint-disable-line line-length -->
|
||||
### Standard options
|
||||
|
||||
Here are the Standard options specific to filen (Filen).
|
||||
|
||||
#### --filen-email
|
||||
|
||||
Email of your Filen account
|
||||
|
||||
Properties:
|
||||
|
||||
- Config: email
|
||||
- Env Var: RCLONE_FILEN_EMAIL
|
||||
- Type: string
|
||||
- Required: true
|
||||
|
||||
#### --filen-password
|
||||
|
||||
Password of your Filen account
|
||||
|
||||
**NB** Input to this must be obscured - see [rclone obscure](/commands/rclone_obscure/).
|
||||
|
||||
Properties:
|
||||
|
||||
- Config: password
|
||||
- Env Var: RCLONE_FILEN_PASSWORD
|
||||
- Type: string
|
||||
- Required: true
|
||||
|
||||
#### --filen-api-key
|
||||
|
||||
API Key for your Filen account
|
||||
|
||||
Get this using the Filen CLI export-api-key command
|
||||
You can download the Filen CLI from https://github.com/FilenCloudDienste/filen-cli
|
||||
|
||||
**NB** Input to this must be obscured - see [rclone obscure](/commands/rclone_obscure/).
|
||||
|
||||
Properties:
|
||||
|
||||
- Config: api_key
|
||||
- Env Var: RCLONE_FILEN_API_KEY
|
||||
- Type: string
|
||||
- Required: true
|
||||
|
||||
### Advanced options
|
||||
|
||||
Here are the Advanced options specific to filen (Filen).
|
||||
|
||||
#### --filen-encoding
|
||||
|
||||
The encoding for the backend.
|
||||
|
||||
See the [encoding section in the overview](/overview/#encoding) for more info.
|
||||
|
||||
Properties:
|
||||
|
||||
- Config: encoding
|
||||
- Env Var: RCLONE_FILEN_ENCODING
|
||||
- Type: Encoding
|
||||
- Default: Slash,Del,Ctl,InvalidUtf8,Dot
|
||||
|
||||
#### --filen-upload-concurrency
|
||||
|
||||
Concurrency for multipart uploads.
|
||||
|
||||
This is the number of chunks of the same file that are uploaded
|
||||
concurrently for multipart uploads.
|
||||
|
||||
Note that chunks are stored in memory and there may be up to
|
||||
"--transfers" * "--filen-upload-concurrency" chunks stored at once
|
||||
in memory.
|
||||
|
||||
If you are uploading small numbers of large files over high-speed links
|
||||
and these uploads do not fully utilize your bandwidth, then increasing
|
||||
this may help to speed up the transfers.
|
||||
|
||||
Properties:
|
||||
|
||||
- Config: upload_concurrency
|
||||
- Env Var: RCLONE_FILEN_UPLOAD_CONCURRENCY
|
||||
- Type: int
|
||||
- Default: 16
|
||||
|
||||
#### --filen-master-keys
|
||||
|
||||
Master Keys (internal use only)
|
||||
|
||||
Properties:
|
||||
|
||||
- Config: master_keys
|
||||
- Env Var: RCLONE_FILEN_MASTER_KEYS
|
||||
- Type: string
|
||||
- Required: false
|
||||
|
||||
#### --filen-private-key
|
||||
|
||||
Private RSA Key (internal use only)
|
||||
|
||||
Properties:
|
||||
|
||||
- Config: private_key
|
||||
- Env Var: RCLONE_FILEN_PRIVATE_KEY
|
||||
- Type: string
|
||||
- Required: false
|
||||
|
||||
#### --filen-public-key
|
||||
|
||||
Public RSA Key (internal use only)
|
||||
|
||||
Properties:
|
||||
|
||||
- Config: public_key
|
||||
- Env Var: RCLONE_FILEN_PUBLIC_KEY
|
||||
- Type: string
|
||||
- Required: false
|
||||
|
||||
#### --filen-auth-version
|
||||
|
||||
Authentication Version (internal use only)
|
||||
|
||||
Properties:
|
||||
|
||||
- Config: auth_version
|
||||
- Env Var: RCLONE_FILEN_AUTH_VERSION
|
||||
- Type: string
|
||||
- Required: false
|
||||
|
||||
#### --filen-base-folder-uuid
|
||||
|
||||
UUID of Account Root Directory (internal use only)
|
||||
|
||||
Properties:
|
||||
|
||||
- Config: base_folder_uuid
|
||||
- Env Var: RCLONE_FILEN_BASE_FOLDER_UUID
|
||||
- Type: string
|
||||
- Required: false
|
||||
|
||||
#### --filen-description
|
||||
|
||||
Description of the remote.
|
||||
|
||||
Properties:
|
||||
|
||||
- Config: description
|
||||
- Env Var: RCLONE_FILEN_DESCRIPTION
|
||||
- Type: string
|
||||
- Required: false
|
||||
|
||||
<!-- autogenerated options stop -->
|
||||
@@ -1138,10 +1138,6 @@ Backend-only flags (these can be set in the config file also).
|
||||
--union-min-free-space SizeSuffix Minimum viable free space for lfs/eplfs policies (default 1Gi)
|
||||
--union-search-policy string Policy to choose upstream on SEARCH category (default "ff")
|
||||
--union-upstreams string List of space separated upstreams
|
||||
--uptobox-access-token string Your access token
|
||||
--uptobox-description string Description of the remote
|
||||
--uptobox-encoding Encoding The encoding for the backend (default Slash,LtGt,DoubleQuote,BackQuote,Del,Ctl,LeftSpace,InvalidUtf8,Dot)
|
||||
--uptobox-private Set to make uploaded files private
|
||||
--webdav-auth-redirect Preserve authentication on redirect
|
||||
--webdav-bearer-token string Bearer token instead of user/pass (e.g. a Macaroon)
|
||||
--webdav-bearer-token-command string Command to run to get a bearer token
|
||||
|
||||
@@ -498,6 +498,12 @@ URL for HTTP CONNECT proxy
|
||||
|
||||
Set this to a URL for an HTTP proxy which supports the HTTP CONNECT verb.
|
||||
|
||||
Supports the format http://user:pass@host:port, http://host:port, http://host.
|
||||
|
||||
Example:
|
||||
|
||||
http://myUser:myPass@proxyhostname.example.com:8000
|
||||
|
||||
|
||||
Properties:
|
||||
|
||||
|
||||
@@ -659,8 +659,14 @@ second that each client_id can do set by Google.
|
||||
If there is a problem with this client_id (eg quota too low or the
|
||||
client_id stops working) then you can make your own.
|
||||
|
||||
Please follow the steps in [the google drive docs](https://rclone.org/drive/#making-your-own-client-id).
|
||||
You will need these scopes instead of the drive ones detailed:
|
||||
Please follow the steps in [the google drive docs](https://rclone.org/drive/#making-your-own-client-id)
|
||||
with the following differences:
|
||||
|
||||
- At step 3, instead of enabling the "Google Drive API", search for and
|
||||
enable the "Photos Library API".
|
||||
|
||||
- At step 5, you will need to add different scopes. Use these scopes
|
||||
instead of the drive ones:
|
||||
|
||||
```text
|
||||
https://www.googleapis.com/auth/photoslibrary.appendonly
|
||||
|
||||
@@ -14,103 +14,7 @@ show through.
|
||||
|
||||
Here is an overview of the major features of each cloud storage system.
|
||||
|
||||
| Name | Hash | ModTime | Case Insensitive | Duplicate Files | MIME Type | Metadata |
|
||||
| ---------------------------- |:-----------------:|:-------:|:----------------:|:---------------:|:---------:|:--------:|
|
||||
| 1Fichier | Whirlpool | - | No | Yes | R | - |
|
||||
| Akamai Netstorage | MD5, SHA256 | R/W | No | No | R | - |
|
||||
| Amazon S3 (or S3 compatible) | MD5 | R/W | No | No | R/W | RWU |
|
||||
| Backblaze B2 | SHA1 | R/W | No | No | R/W | - |
|
||||
| Box | SHA1 | R/W | Yes | No | - | - |
|
||||
| Citrix ShareFile | MD5 | R/W | Yes | No | - | - |
|
||||
| Cloudinary | MD5 | R | No | Yes | - | - |
|
||||
| Dropbox | DBHASH ¹ | R | Yes | No | - | - |
|
||||
| Enterprise File Fabric | - | R/W | Yes | No | R/W | - |
|
||||
| FileLu Cloud Storage | MD5 | R/W | No | Yes | R | - |
|
||||
| Files.com | MD5, CRC32 | DR/W | Yes | No | R | - |
|
||||
| FTP | - | R/W ¹⁰ | No | No | - | - |
|
||||
| Gofile | MD5 | DR/W | No | Yes | R | - |
|
||||
| Google Cloud Storage | MD5 | R/W | No | No | R/W | - |
|
||||
| Google Drive | MD5, SHA1, SHA256 | DR/W | No | Yes | R/W | DRWU |
|
||||
| Google Photos | - | - | No | Yes | R | - |
|
||||
| HDFS | - | R/W | No | No | - | - |
|
||||
| HiDrive | HiDrive ¹² | R/W | No | No | - | - |
|
||||
| HTTP | - | R | No | No | R | R |
|
||||
| iCloud Drive | - | R | No | No | - | - |
|
||||
| Internet Archive | MD5, SHA1, CRC32 | R/W ¹¹ | No | No | - | RWU |
|
||||
| Jottacloud | MD5 | R/W | Yes | No | R | RW |
|
||||
| Koofr | MD5 | - | Yes | No | - | - |
|
||||
| Linkbox | - | R | No | No | - | - |
|
||||
| Mail.ru Cloud | Mailru ⁶ | R/W | Yes | No | - | - |
|
||||
| Mega | - | - | No | Yes | - | - |
|
||||
| Memory | MD5 | R/W | No | No | - | - |
|
||||
| Microsoft Azure Blob Storage | MD5 | R/W | No | No | R/W | - |
|
||||
| Microsoft Azure Files Storage | MD5 | R/W | Yes | No | R/W | - |
|
||||
| Microsoft OneDrive | QuickXorHash ⁵ | DR/W | Yes | No | R | DRW |
|
||||
| OpenDrive | MD5 | R/W | Yes | Partial ⁸ | - | - |
|
||||
| OpenStack Swift | MD5 | R/W | No | No | R/W | - |
|
||||
| Oracle Object Storage | MD5 | R/W | No | No | R/W | RU |
|
||||
| pCloud | MD5, SHA1 ⁷ | R/W | No | No | W | - |
|
||||
| PikPak | MD5 | R | No | No | R | - |
|
||||
| Pixeldrain | SHA256 | R/W | No | No | R | RW |
|
||||
| premiumize.me | - | - | Yes | No | R | - |
|
||||
| put.io | CRC-32 | R/W | No | Yes | R | - |
|
||||
| Proton Drive | SHA1 | R/W | No | No | R | - |
|
||||
| QingStor | MD5 | - ⁹ | No | No | R/W | - |
|
||||
| Quatrix by Maytech | - | R/W | No | No | - | - |
|
||||
| Seafile | - | - | No | No | - | - |
|
||||
| SFTP | MD5, SHA1 ² | DR/W | Depends | No | - | - |
|
||||
| Sia | - | - | No | No | - | - |
|
||||
| SMB | - | R/W | Yes | No | - | - |
|
||||
| SugarSync | - | - | No | No | - | - |
|
||||
| Storj | - | R | No | No | - | - |
|
||||
| Uloz.to | MD5, SHA256 ¹³ | - | No | Yes | - | - |
|
||||
| Uptobox | - | - | No | Yes | - | - |
|
||||
| WebDAV | MD5, SHA1 ³ | R ⁴ | Depends | No | - | - |
|
||||
| Yandex Disk | MD5 | R/W | No | No | R | - |
|
||||
| Zoho WorkDrive | - | - | No | No | - | - |
|
||||
| The local filesystem | All | DR/W | Depends | No | - | DRWU |
|
||||
|
||||
¹ Dropbox supports [its own custom
|
||||
hash](https://www.dropbox.com/developers/reference/content-hash).
|
||||
This is an SHA256 sum of all the 4 MiB block SHA256s.
|
||||
|
||||
² SFTP supports checksums if the same login has shell access and
|
||||
`md5sum` or `sha1sum` as well as `echo` are in the remote's PATH.
|
||||
|
||||
³ WebDAV supports hashes when used with Fastmail Files, Owncloud and Nextcloud only.
|
||||
|
||||
⁴ WebDAV supports modtimes when used with Fastmail Files, Owncloud and Nextcloud
|
||||
only.
|
||||
|
||||
⁵ [QuickXorHash](https://docs.microsoft.com/en-us/onedrive/developer/code-snippets/quickxorhash)
|
||||
is Microsoft's own hash.
|
||||
|
||||
⁶ Mail.ru uses its own modified SHA1 hash
|
||||
|
||||
⁷ pCloud only supports SHA1 (not MD5) in its EU region
|
||||
|
||||
⁸ Opendrive does not support creation of duplicate files using
|
||||
their web client interface or other stock clients, but the underlying
|
||||
storage platform has been determined to allow duplicate files, and it
|
||||
is possible to create them with `rclone`. It may be that this is a
|
||||
mistake or an unsupported feature.
|
||||
|
||||
⁹ QingStor does not support SetModTime for objects bigger than 5 GiB.
|
||||
|
||||
¹⁰ FTP supports modtimes for the major FTP servers, and also others
|
||||
if they advertised required protocol extensions. See [this](/ftp/#modification-times)
|
||||
for more details.
|
||||
|
||||
¹¹ Internet Archive requires option `wait_archive` to be set to a non-zero value
|
||||
for full modtime support.
|
||||
|
||||
¹² HiDrive supports [its own custom
|
||||
hash](https://static.hidrive.com/dev/0001).
|
||||
It combines SHA1 sums for each 4 KiB block hierarchically to a single
|
||||
top-level sum.
|
||||
|
||||
¹³ Uloz.to provides server-calculated MD5 hash upon file upload. MD5 and SHA256
|
||||
hashes are client-calculated and stored as metadata fields.
|
||||
{{< features-table >}}
|
||||
|
||||
### Hash
|
||||
|
||||
@@ -506,73 +410,7 @@ See [the metadata docs](/docs/#metadata) for more info.
|
||||
All rclone remotes support a base command set. Other features depend
|
||||
upon backend-specific capabilities.
|
||||
|
||||
| Name | Purge | Copy | Move | DirMove | CleanUp | ListR | StreamUpload | MultithreadUpload | LinkSharing | About | EmptyDir |
|
||||
| ---------------------------- |:-----:|:----:|:----:|:-------:|:-------:|:-----:|:------------:|:------------------|:------------:|:-----:|:--------:|
|
||||
| 1Fichier | No | Yes | Yes | No | No | No | No | No | Yes | No | Yes |
|
||||
| Akamai Netstorage | Yes | No | No | No | No | Yes | Yes | No | No | No | Yes |
|
||||
| Amazon S3 (or S3 compatible) | No | Yes | No | No | Yes | Yes | Yes | Yes | Yes | No | No |
|
||||
| Backblaze B2 | No | Yes | No | No | Yes | Yes | Yes | Yes | Yes | No | No |
|
||||
| Box | Yes | Yes | Yes | Yes | Yes | No | Yes | No | Yes | Yes | Yes |
|
||||
| Citrix ShareFile | Yes | Yes | Yes | Yes | No | No | No | No | No | No | Yes |
|
||||
| Dropbox | Yes | Yes | Yes | Yes | No | No | Yes | No | Yes | Yes | Yes |
|
||||
| Cloudinary | No | No | No | No | No | No | Yes | No | No | No | No |
|
||||
| Enterprise File Fabric | Yes | Yes | Yes | Yes | Yes | No | No | No | No | No | Yes |
|
||||
| Files.com | Yes | Yes | Yes | Yes | No | No | Yes | No | Yes | No | Yes |
|
||||
| FTP | No | No | Yes | Yes | No | No | Yes | No | No | No | Yes |
|
||||
| Gofile | Yes | Yes | Yes | Yes | No | No | Yes | No | Yes | Yes | Yes |
|
||||
| Google Cloud Storage | Yes | Yes | No | No | No | No | Yes | No | No | No | No |
|
||||
| Google Drive | Yes | Yes | Yes | Yes | Yes | Yes | Yes | No | Yes | Yes | Yes |
|
||||
| Google Photos | No | No | No | No | No | No | No | No | No | No | No |
|
||||
| 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 |
|
||||
| iCloud Drive | Yes | Yes | Yes | Yes | No | No | No | No | No | No | Yes |
|
||||
| ImageKit | Yes | No | 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 |
|
||||
| Mail.ru Cloud | Yes | Yes | Yes | Yes | Yes | No | No | No | Yes | Yes | Yes |
|
||||
| Mega | Yes | No | Yes | Yes | Yes | No | No | No | Yes | Yes | Yes |
|
||||
| Memory | No | Yes | No | No | No | Yes | Yes | No | No | No | No |
|
||||
| Microsoft Azure Blob Storage | Yes | Yes | No | No | No | Yes | Yes | Yes | No | No | No |
|
||||
| Microsoft Azure Files Storage | No | Yes | Yes | Yes | No | No | Yes | Yes | No | Yes | Yes |
|
||||
| Microsoft OneDrive | Yes | Yes | Yes | Yes | Yes | Yes ⁵ | No | No | Yes | Yes | Yes |
|
||||
| OpenDrive | Yes | Yes | Yes | Yes | No | No | No | No | No | Yes | Yes |
|
||||
| OpenStack Swift | Yes ¹ | Yes | No | No | No | Yes | Yes | No | No | Yes | No |
|
||||
| Oracle Object Storage | No | Yes | No | No | Yes | Yes | Yes | Yes | No | No | No |
|
||||
| pCloud | Yes | Yes | Yes | Yes | Yes | No | No | No | Yes | Yes | Yes |
|
||||
| PikPak | Yes | Yes | Yes | Yes | Yes | No | No | No | Yes | Yes | Yes |
|
||||
| Pixeldrain | Yes | No | Yes | Yes | No | No | Yes | No | Yes | Yes | Yes |
|
||||
| premiumize.me | Yes | No | Yes | Yes | No | No | No | No | Yes | Yes | Yes |
|
||||
| put.io | Yes | No | Yes | Yes | Yes | No | Yes | No | No | Yes | Yes |
|
||||
| Proton Drive | Yes | No | Yes | Yes | Yes | No | No | No | No | Yes | Yes |
|
||||
| QingStor | No | Yes | No | No | Yes | Yes | No | No | No | No | No |
|
||||
| Quatrix by Maytech | Yes | Yes | Yes | Yes | No | No | No | No | No | Yes | Yes |
|
||||
| Seafile | Yes | Yes | Yes | Yes | Yes | Yes | Yes | No | Yes | Yes | Yes |
|
||||
| SFTP | No | Yes ⁴| Yes | Yes | No | No | Yes | No | No | Yes | Yes |
|
||||
| Sia | No | No | No | No | No | No | Yes | No | No | No | Yes |
|
||||
| SMB | No | No | Yes | Yes | No | No | Yes | Yes | No | No | Yes |
|
||||
| SugarSync | Yes | Yes | Yes | Yes | No | No | Yes | No | Yes | No | Yes |
|
||||
| Storj | Yes ² | Yes | Yes | No | No | Yes | Yes | No | Yes | No | No |
|
||||
| Uloz.to | No | No | Yes | Yes | No | No | No | No | No | No | Yes |
|
||||
| Uptobox | No | Yes | Yes | Yes | No | No | No | No | No | No | No |
|
||||
| WebDAV | Yes | Yes | Yes | Yes | No | No | Yes ³ | No | No | Yes | Yes |
|
||||
| Yandex Disk | Yes | Yes | Yes | Yes | Yes | No | Yes | No | Yes | Yes | Yes |
|
||||
| Zoho WorkDrive | Yes | Yes | Yes | Yes | No | No | No | No | No | Yes | Yes |
|
||||
| The local filesystem | No | No | Yes | Yes | No | No | Yes | Yes | No | Yes | Yes |
|
||||
|
||||
¹ Note Swift implements this in order to delete directory markers but
|
||||
it doesn't actually have a quicker way of deleting files other than
|
||||
deleting them individually.
|
||||
|
||||
² Storj implements this efficiently only for entire buckets. If
|
||||
purging a directory inside a bucket, files are deleted individually.
|
||||
|
||||
³ StreamUpload is not supported with Nextcloud
|
||||
|
||||
⁴ Use the `--sftp-copy-is-hardlink` flag to enable.
|
||||
|
||||
⁵ Use the `--onedrive-delta` flag to enable.
|
||||
{{< optional-features-table >}}
|
||||
|
||||
### Purge
|
||||
|
||||
|
||||
@@ -173,6 +173,31 @@ So if the folder you want rclone to use your is "My Music/", then use the return
|
||||
id from ```rclone lsf``` command (ex. `dxxxxxxxx2`) as the `root_folder_id` variable
|
||||
value in the config file.
|
||||
|
||||
### Change notifications and mounts
|
||||
|
||||
The pCloud backend supports real‑time updates for rclone mounts via change
|
||||
notifications. rclone uses pCloud’s diff long‑polling API to detect changes and
|
||||
will automatically refresh directory listings in the mounted filesystem when
|
||||
changes occur.
|
||||
|
||||
Notes and behavior:
|
||||
|
||||
- Works automatically when using `rclone mount` and requires no additional
|
||||
configuration.
|
||||
- Notifications are directory‑scoped: when rclone detects a change, it refreshes
|
||||
the affected directory so new/removed/renamed files become visible promptly.
|
||||
- Updates are near real‑time. The backend uses a long‑poll with short fallback
|
||||
polling intervals, so you should see changes appear quickly without manual
|
||||
refreshes.
|
||||
|
||||
If you want to debug or verify notifications, you can use the helper command:
|
||||
|
||||
```bash
|
||||
rclone test changenotify remote:
|
||||
```
|
||||
|
||||
This will log incoming change notifications for the given remote.
|
||||
|
||||
<!-- autogenerated options start - DO NOT EDIT - instead edit fs.RegInfo in backend/pcloud/pcloud.go and run make backenddocs to verify --> <!-- markdownlint-disable-line line-length -->
|
||||
### Standard options
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@ The S3 backend can be used with a number of different providers:
|
||||
{{< provider name="China Mobile Ecloud Elastic Object Storage (EOS)" home="https://ecloud.10086.cn/home/product-introduction/eos/" config="/s3/#china-mobile-ecloud-eos" >}}
|
||||
{{< provider name="Cloudflare R2" home="https://blog.cloudflare.com/r2-open-beta/" config="/s3/#cloudflare-r2" >}}
|
||||
{{< provider name="Arvan Cloud Object Storage (AOS)" home="https://www.arvancloud.com/en/products/cloud-storage" config="/s3/#arvan-cloud" >}}
|
||||
{{< provider name="Bizfly Cloud Simple Storage" home="https://bizflycloud.vn/" config="/s3/#bizflycloud" >}}
|
||||
{{< provider name="Cubbit DS3" home="https://cubbit.io/ds3-cloud" config="/s3/#Cubbit" >}}
|
||||
{{< provider name="DigitalOcean Spaces" home="https://www.digitalocean.com/products/object-storage/" config="/s3/#digitalocean-spaces" >}}
|
||||
{{< provider name="Dreamhost" home="https://www.dreamhost.com/cloud/storage/" config="/s3/#dreamhost" >}}
|
||||
@@ -4536,6 +4537,36 @@ server_side_encryption =
|
||||
storage_class =
|
||||
```
|
||||
|
||||
### BizflyCloud {#bizflycloud}
|
||||
|
||||
[Bizfly Cloud Simple Storage](https://bizflycloud.vn/simple-storage) is an
|
||||
S3-compatible service with regions in Hanoi (HN) and Ho Chi Minh City (HCM).
|
||||
|
||||
Use the endpoint for your region:
|
||||
|
||||
- HN: `hn.ss.bfcplatform.vn`
|
||||
- HCM: `hcm.ss.bfcplatform.vn`
|
||||
|
||||
A minimal configuration looks like this.
|
||||
|
||||
```ini
|
||||
[bizfly]
|
||||
type = s3
|
||||
provider = BizflyCloud
|
||||
env_auth = false
|
||||
access_key_id = YOUR_ACCESS_KEY
|
||||
secret_access_key = YOUR_SECRET_KEY
|
||||
region = HN
|
||||
endpoint = hn.ss.bfcplatform.vn
|
||||
location_constraint =
|
||||
acl =
|
||||
server_side_encryption =
|
||||
storage_class =
|
||||
```
|
||||
|
||||
Switch `region` and `endpoint` to `HCM` and `hcm.ss.bfcplatform.vn` for Ho Chi
|
||||
Minh City.
|
||||
|
||||
### Ceph
|
||||
|
||||
[Ceph](https://ceph.com/) is an open-source, unified, distributed
|
||||
|
||||
@@ -1186,6 +1186,12 @@ URL for HTTP CONNECT proxy
|
||||
|
||||
Set this to a URL for an HTTP proxy which supports the HTTP CONNECT verb.
|
||||
|
||||
Supports the format http://user:pass@host:port, http://host:port, http://host.
|
||||
|
||||
Example:
|
||||
|
||||
http://myUser:myPass@proxyhostname.example.com:8000
|
||||
|
||||
|
||||
Properties:
|
||||
|
||||
|
||||
218
docs/content/shade.md
Normal file
218
docs/content/shade.md
Normal file
@@ -0,0 +1,218 @@
|
||||
# {{< icon "fa fa-moon" >}} Shade
|
||||
|
||||
This is a backend for the [Shade](https://shade.inc/) platform
|
||||
|
||||
## About Shade
|
||||
|
||||
[Shade](https://shade.inc/) is an AI-powered cloud NAS that makes your cloud files behave like a local drive, optimized for media and creative workflows. It provides fast, secure access with natural-language search, easy sharing, and scalable cloud storage.
|
||||
|
||||
|
||||
## Accounts & Pricing
|
||||
|
||||
To use this backend, you need to [create a free account](https://app.shade.inc/) on Shade. You can start with a free account and get 20GB of storage for free.
|
||||
|
||||
|
||||
## Usage
|
||||
|
||||
Paths are specified as `remote:path`
|
||||
|
||||
Paths may be as deep as required, e.g. `remote:directory/subdirectory`.
|
||||
|
||||
|
||||
## Configuration
|
||||
|
||||
Here is an example of making a Shade configuration.
|
||||
|
||||
First, create a [create a free account](https://app.shade.inc/) account and choose a plan.
|
||||
|
||||
You will need to log in and get the `API Key` and `Drive ID` for your account from the settings section of your account and created drive respectively.
|
||||
|
||||
Now run
|
||||
|
||||
`rclone config`
|
||||
|
||||
Follow this interactive process:
|
||||
|
||||
```sh
|
||||
$ rclone config
|
||||
e) Edit existing remote
|
||||
n) New remote
|
||||
d) Delete remote
|
||||
r) Rename remote
|
||||
c) Copy remote
|
||||
s) Set configuration password
|
||||
q) Quit config
|
||||
e/n/d/r/c/s/q> n
|
||||
|
||||
Enter name for new remote.
|
||||
name> Shade
|
||||
|
||||
Option Storage.
|
||||
Type of storage to configure.
|
||||
Choose a number from below, or type in your own value.
|
||||
[OTHER OPTIONS]
|
||||
xx / Shade FS
|
||||
\ (shade)
|
||||
[OTHER OPTIONS]
|
||||
Storage> xx
|
||||
|
||||
Option drive_id.
|
||||
The ID of your drive, see this in the drive settings. Individual rclone configs must be made per drive.
|
||||
Enter a value.
|
||||
drive_id> [YOUR_ID]
|
||||
|
||||
Option api_key.
|
||||
An API key for your account.
|
||||
Enter a value.
|
||||
api_key> [YOUR_API_KEY]
|
||||
|
||||
Edit advanced config?
|
||||
y) Yes
|
||||
n) No (default)
|
||||
y/n> n
|
||||
|
||||
Configuration complete.
|
||||
Options:
|
||||
- type: shade
|
||||
- drive_id: [YOUR_ID]
|
||||
- api_key: [YOUR_API_KEY]
|
||||
Keep this "Shade" remote?
|
||||
y) Yes this is OK (default)
|
||||
e) Edit this remote
|
||||
d) Delete this remote
|
||||
y/e/d> y
|
||||
```
|
||||
|
||||
### Modification times and hashes
|
||||
|
||||
Shade does not support hashes and writing mod times.
|
||||
|
||||
|
||||
### Transfers
|
||||
|
||||
Shade uses multipart uploads by default. This means that files will be chunked and sent up to Shade concurrently. In order to configure how many simultaneous uploads you want to use, upload the 'concurrency' option in the advanced config section. Note that this uses more memory and initiates more http requests.
|
||||
|
||||
### Deleting files
|
||||
|
||||
Please note that when deleting files in Shade via rclone it will delete the file instantly, instead of sending it to the trash. This means that it will not be recoverable.
|
||||
|
||||
|
||||
<!-- autogenerated options start - DO NOT EDIT - instead edit fs.RegInfo in backend/shade/shade.go and run make backenddocs to verify --> <!-- markdownlint-disable-line line-length -->
|
||||
### Standard options
|
||||
|
||||
Here are the Standard options specific to shade (Shade FS).
|
||||
|
||||
#### --shade-drive-id
|
||||
|
||||
The ID of your drive, see this in the drive settings. Individual rclone configs must be made per drive.
|
||||
|
||||
Properties:
|
||||
|
||||
- Config: drive_id
|
||||
- Env Var: RCLONE_SHADE_DRIVE_ID
|
||||
- Type: string
|
||||
- Required: true
|
||||
|
||||
#### --shade-api-key
|
||||
|
||||
An API key for your account. You can find this under Settings > API Keys
|
||||
|
||||
Properties:
|
||||
|
||||
- Config: api_key
|
||||
- Env Var: RCLONE_SHADE_API_KEY
|
||||
- Type: string
|
||||
- Required: true
|
||||
|
||||
### Advanced options
|
||||
|
||||
Here are the Advanced options specific to shade (Shade FS).
|
||||
|
||||
#### --shade-endpoint
|
||||
|
||||
Endpoint for the service.
|
||||
|
||||
Leave blank normally.
|
||||
|
||||
Properties:
|
||||
|
||||
- Config: endpoint
|
||||
- Env Var: RCLONE_SHADE_ENDPOINT
|
||||
- Type: string
|
||||
- Required: false
|
||||
|
||||
#### --shade-chunk-size
|
||||
|
||||
Chunk size to use for uploading.
|
||||
|
||||
Any files larger than this will be uploaded in chunks of this size.
|
||||
|
||||
Note that this is stored in memory per transfer, so increasing it will
|
||||
increase memory usage.
|
||||
|
||||
Minimum is 5MB, maximum is 5GB.
|
||||
|
||||
Properties:
|
||||
|
||||
- Config: chunk_size
|
||||
- Env Var: RCLONE_SHADE_CHUNK_SIZE
|
||||
- Type: SizeSuffix
|
||||
- Default: 64Mi
|
||||
|
||||
#### --shade-encoding
|
||||
|
||||
The encoding for the backend.
|
||||
|
||||
See the [encoding section in the overview](/overview/#encoding) for more info.
|
||||
|
||||
Properties:
|
||||
|
||||
- Config: encoding
|
||||
- Env Var: RCLONE_SHADE_ENCODING
|
||||
- Type: Encoding
|
||||
- Default: Slash,BackSlash,Del,Ctl,InvalidUtf8,Dot
|
||||
|
||||
#### --shade-description
|
||||
|
||||
Description of the remote.
|
||||
|
||||
Properties:
|
||||
|
||||
- Config: description
|
||||
- Env Var: RCLONE_SHADE_DESCRIPTION
|
||||
- Type: string
|
||||
- Required: false
|
||||
|
||||
<!-- autogenerated options stop -->
|
||||
|
||||
## Limitations
|
||||
|
||||
Note that Shade is case insensitive so you can't have a file called
|
||||
"Hello.doc" and one called "hello.doc".
|
||||
|
||||
Shade only supports filenames up to 255 characters in length.
|
||||
|
||||
`rclone about` is not supported by the Shade backend. Backends without
|
||||
this capability cannot determine free space for an rclone mount or
|
||||
use policy `mfs` (most free space) as a member of an rclone union
|
||||
remote.
|
||||
|
||||
See [List of backends that do not support rclone about](https://rclone.org/overview/#optional-features) and [rclone about](https://rclone.org/commands/rclone_about/)
|
||||
|
||||
## Backend commands
|
||||
|
||||
Here are the commands specific to the shade backend.
|
||||
|
||||
Run them with
|
||||
|
||||
rclone backend COMMAND remote:
|
||||
|
||||
The help below will explain what arguments each command takes.
|
||||
|
||||
See the [backend](/commands/rclone_backend/) command for more
|
||||
info on how to pass options and arguments.
|
||||
|
||||
These can be run on a running backend using the rc command
|
||||
[backend/command](/rc/#backend-command).
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ Thank you to our sponsors:
|
||||
<!-- markdownlint-capture -->
|
||||
<!-- markdownlint-disable line-length no-bare-urls -->
|
||||
|
||||
{{< sponsor src="/img/logos/rabata/txt_1_300x114.png" width="300" height="200" title="Visit our sponsor Rabata.io" link="https://rabata.io/?utm_source=banner&utm_medium=rclone&utm_content=general">}}
|
||||
{{< sponsor src="/img/logos/rabata.svg" width="300" height="200" title="Visit our sponsor Rabata.io" link="https://rabata.io/?utm_source=banner&utm_medium=rclone&utm_content=general">}}
|
||||
{{< sponsor src="/img/logos/idrive_e2.svg" width="300" height="200" title="Visit our sponsor IDrive e2" link="https://www.idrive.com/e2/?refer=rclone">}}
|
||||
{{< sponsor src="/img/logos/filescom-enterprise-grade-workflows.png" width="300" height="200" title="Start Your Free Trial Today" link="https://files.com/?utm_source=rclone&utm_medium=referral&utm_campaign=banner&utm_term=rclone">}}
|
||||
{{< sponsor src="/img/logos/mega-s4.svg" width="300" height="200" title="MEGA S4: New S3 compatible object storage. High scale. Low cost. Free egress." link="https://mega.io/objectstorage?utm_source=rclone&utm_medium=referral&utm_campaign=rclone-mega-s4&mct=rclonepromo">}}
|
||||
|
||||
58
docs/content/tiers.md
Normal file
58
docs/content/tiers.md
Normal file
@@ -0,0 +1,58 @@
|
||||
---
|
||||
title: "Backend Support Tiers"
|
||||
description: "A complete list of supported backends and their stability tiers."
|
||||
---
|
||||
|
||||
# Tiers
|
||||
|
||||
Rclone backends are divided into tiers to give users an idea of the stability of each backend.
|
||||
|
||||
| Tier | Label | Intended meaning |
|
||||
|--------|---------------|------------------|
|
||||
| Tier 1 | Core | Production-grade, first-class |
|
||||
| Tier 2 | Stable | Well-supported, minor gaps |
|
||||
| Tier 3 | Supported | Works for many uses; known caveats |
|
||||
| Tier 4 | Experimental | Use with care; expect gaps/changes |
|
||||
| Tier 5 | Deprecated | No longer maintained or supported |
|
||||
|
||||
## Overview
|
||||
|
||||
Here is a summary of all backends:
|
||||
|
||||
{{< tiers-table >}}
|
||||
|
||||
## Scoring
|
||||
|
||||
Here is how the backends are scored.
|
||||
|
||||
### Features
|
||||
|
||||
These are useful optional features a backend should have in rough
|
||||
order of importance. Each one of these scores a point for the Features
|
||||
column.
|
||||
|
||||
- F1: Hash(es)
|
||||
- F2: Modtime
|
||||
- F3: Stream upload
|
||||
- F4: Copy/Move
|
||||
- F5: DirMove
|
||||
- F6: Metadata
|
||||
- F7: MultipartUpload
|
||||
|
||||
|
||||
### Tier
|
||||
|
||||
The tier is decided after determining these attributes. Some discretion is allowed in tiering as some of these attributes are more important than others.
|
||||
|
||||
| Attr | T1: Core | T2: Stable | T3: Supported | T4: Experimental | T5: Incubator |
|
||||
|------|----------|------------|---------------|------------------|---------------|
|
||||
| Maintainers | >=2 | >=1 | >=1 | >=0 | >=0 |
|
||||
| API source | Official | Official | Either | Either | Either |
|
||||
| Features (F1-F7) | >=5/7 | >=4/7 | >=3/7 | >=2/7 | N/A |
|
||||
| Integration tests | All Green | All green | Nearly all green | Some Flaky | N/A |
|
||||
| Error handling | Pacer | Pacer | Retries | Retries | N/A |
|
||||
| Data integrity | Hashes, alt, modtime | Hashes or alt | Hash OR modtime | Best-effort | N/A |
|
||||
| Perf baseline | Bench within 2x S3 | Bench doc | Anecdotal OK | Optional | N/A |
|
||||
| Adoption | widely used | often used | some use | N/A | N/A |
|
||||
| Docs completeness | Full | Full | Basic | Minimal | Minimal |
|
||||
| Security | Principle-of-least-privilege | Reasonable scopes | Basic auth | Works | Works |
|
||||
@@ -1,179 +0,0 @@
|
||||
---
|
||||
title: "Uptobox"
|
||||
description: "Rclone docs for Uptobox"
|
||||
versionIntroduced: "v1.56"
|
||||
---
|
||||
|
||||
# {{< icon "fa fa-archive" >}} Uptobox
|
||||
|
||||
This is a Backend for Uptobox file storage service. Uptobox is closer to a
|
||||
one-click hoster than a traditional cloud storage provider and therefore not
|
||||
suitable for long term storage.
|
||||
|
||||
Paths are specified as `remote:path`
|
||||
|
||||
Paths may be as deep as required, e.g. `remote:directory/subdirectory`.
|
||||
|
||||
## Configuration
|
||||
|
||||
To configure an Uptobox backend you'll need your personal api token. You'll find
|
||||
it in your [account settings](https://uptobox.com/my_account).
|
||||
|
||||
Here is an example of how to make a remote called `remote` with the default setup.
|
||||
First run:
|
||||
|
||||
```console
|
||||
rclone config
|
||||
```
|
||||
|
||||
This will guide you through an interactive setup process:
|
||||
|
||||
```text
|
||||
Current remotes:
|
||||
|
||||
Name Type
|
||||
==== ====
|
||||
TestUptobox uptobox
|
||||
|
||||
e) Edit existing remote
|
||||
n) New remote
|
||||
d) Delete remote
|
||||
r) Rename remote
|
||||
c) Copy remote
|
||||
s) Set configuration password
|
||||
q) Quit config
|
||||
e/n/d/r/c/s/q> n
|
||||
name> uptobox
|
||||
Type of storage to configure.
|
||||
Enter a string value. Press Enter for the default ("").
|
||||
Choose a number from below, or type in your own value
|
||||
[...]
|
||||
37 / Uptobox
|
||||
\ "uptobox"
|
||||
[...]
|
||||
Storage> uptobox
|
||||
** See help for uptobox backend at: https://rclone.org/uptobox/ **
|
||||
|
||||
Your API Key, get it from https://uptobox.com/my_account
|
||||
Enter a string value. Press Enter for the default ("").
|
||||
api_key> xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
Edit advanced config? (y/n)
|
||||
y) Yes
|
||||
n) No (default)
|
||||
y/n> n
|
||||
Remote config
|
||||
--------------------
|
||||
[uptobox]
|
||||
type = uptobox
|
||||
api_key = xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
--------------------
|
||||
y) Yes this is OK (default)
|
||||
e) Edit this remote
|
||||
d) Delete this remote
|
||||
y/e/d>
|
||||
```
|
||||
|
||||
Once configured you can then use `rclone` like this (replace `remote` with the
|
||||
name you gave your remote):
|
||||
|
||||
List directories in top level of your Uptobox
|
||||
|
||||
```console
|
||||
rclone lsd remote:
|
||||
```
|
||||
|
||||
List all the files in your Uptobox
|
||||
|
||||
```console
|
||||
rclone ls remote:
|
||||
```
|
||||
|
||||
To copy a local directory to an Uptobox directory called backup
|
||||
|
||||
```console
|
||||
rclone copy /home/source remote:backup
|
||||
```
|
||||
|
||||
### Modification times and hashes
|
||||
|
||||
Uptobox supports neither modified times nor checksums. All timestamps
|
||||
will read as that set by `--default-time`.
|
||||
|
||||
### Restricted filename characters
|
||||
|
||||
In addition to the [default restricted characters set](/overview/#restricted-characters)
|
||||
the following characters are also replaced:
|
||||
|
||||
| Character | Value | Replacement |
|
||||
| --------- |:-----:|:-----------:|
|
||||
| " | 0x22 | " |
|
||||
| ` | 0x41 | ` |
|
||||
|
||||
Invalid UTF-8 bytes will also be [replaced](/overview/#invalid-utf8),
|
||||
as they can't be used in XML strings.
|
||||
|
||||
<!-- autogenerated options start - DO NOT EDIT - instead edit fs.RegInfo in backend/uptobox/uptobox.go and run make backenddocs to verify --> <!-- markdownlint-disable-line line-length -->
|
||||
### Standard options
|
||||
|
||||
Here are the Standard options specific to uptobox (Uptobox).
|
||||
|
||||
#### --uptobox-access-token
|
||||
|
||||
Your access token.
|
||||
|
||||
Get it from https://uptobox.com/my_account.
|
||||
|
||||
Properties:
|
||||
|
||||
- Config: access_token
|
||||
- Env Var: RCLONE_UPTOBOX_ACCESS_TOKEN
|
||||
- Type: string
|
||||
- Required: false
|
||||
|
||||
### Advanced options
|
||||
|
||||
Here are the Advanced options specific to uptobox (Uptobox).
|
||||
|
||||
#### --uptobox-private
|
||||
|
||||
Set to make uploaded files private
|
||||
|
||||
Properties:
|
||||
|
||||
- Config: private
|
||||
- Env Var: RCLONE_UPTOBOX_PRIVATE
|
||||
- Type: bool
|
||||
- Default: false
|
||||
|
||||
#### --uptobox-encoding
|
||||
|
||||
The encoding for the backend.
|
||||
|
||||
See the [encoding section in the overview](/overview/#encoding) for more info.
|
||||
|
||||
Properties:
|
||||
|
||||
- Config: encoding
|
||||
- Env Var: RCLONE_UPTOBOX_ENCODING
|
||||
- Type: Encoding
|
||||
- Default: Slash,LtGt,DoubleQuote,BackQuote,Del,Ctl,LeftSpace,InvalidUtf8,Dot
|
||||
|
||||
#### --uptobox-description
|
||||
|
||||
Description of the remote.
|
||||
|
||||
Properties:
|
||||
|
||||
- Config: description
|
||||
- Env Var: RCLONE_UPTOBOX_DESCRIPTION
|
||||
- Type: string
|
||||
- Required: false
|
||||
|
||||
<!-- autogenerated options stop -->
|
||||
|
||||
## Limitations
|
||||
|
||||
Uptobox will delete inactive files that have not been accessed in 60 days.
|
||||
|
||||
`rclone about` is not supported by this backend an overview of used space can however
|
||||
been seen in the uptobox web interface.
|
||||
16
docs/data/backends/alias.yaml
Normal file
16
docs/data/backends/alias.yaml
Normal file
@@ -0,0 +1,16 @@
|
||||
backend: alias
|
||||
name: Alias
|
||||
tier: Tier 1
|
||||
maintainers: Core
|
||||
features_score: 7
|
||||
integration_tests: Passing
|
||||
data_integrity: Hash
|
||||
performance: High
|
||||
adoption: Widely used
|
||||
docs: Full
|
||||
security: High
|
||||
virtual: true
|
||||
remote: null
|
||||
features: null
|
||||
hashes: null
|
||||
precision: null
|
||||
43
docs/data/backends/archive.yaml
Normal file
43
docs/data/backends/archive.yaml
Normal file
@@ -0,0 +1,43 @@
|
||||
backend: archive
|
||||
name: Archive
|
||||
tier: Tier 3
|
||||
maintainers: Core
|
||||
features_score: 3
|
||||
integration_tests: Passing
|
||||
data_integrity: Hash
|
||||
performance: High
|
||||
adoption: Some use
|
||||
docs: Full
|
||||
security: High
|
||||
virtual: true
|
||||
remote: 'TestArchive:'
|
||||
features:
|
||||
- About
|
||||
- CanHaveEmptyDirectories
|
||||
- DirMove
|
||||
- Move
|
||||
- OpenWriterAt
|
||||
- Overlay
|
||||
- PartialUploads
|
||||
- PutStream
|
||||
- ReadMetadata
|
||||
- SetWrapper
|
||||
- UnWrap
|
||||
- UserMetadata
|
||||
- WrapFs
|
||||
- WriteMetadata
|
||||
hashes:
|
||||
- md5
|
||||
- sha1
|
||||
- whirlpool
|
||||
- crc32
|
||||
- sha256
|
||||
- sha512
|
||||
- blake3
|
||||
- xxh3
|
||||
- xxh128
|
||||
- dropbox
|
||||
- hidrive
|
||||
- mailru
|
||||
- quickxor
|
||||
precision: 1000000000
|
||||
34
docs/data/backends/azureblob.yaml
Normal file
34
docs/data/backends/azureblob.yaml
Normal file
@@ -0,0 +1,34 @@
|
||||
backend: azureblob
|
||||
name: Azure Blob
|
||||
tier: Tier 1
|
||||
maintainers: Core
|
||||
features_score: 7
|
||||
integration_tests: Passing
|
||||
data_integrity: Hash
|
||||
performance: High
|
||||
adoption: Widely used
|
||||
docs: Full
|
||||
security: High
|
||||
virtual: false
|
||||
remote: 'TestAzureBlob:'
|
||||
features:
|
||||
- BucketBased
|
||||
- BucketBasedRootOK
|
||||
- Copy
|
||||
- DoubleSlash
|
||||
- GetTier
|
||||
- ListP
|
||||
- ListR
|
||||
- OpenChunkWriter
|
||||
- Purge
|
||||
- PutStream
|
||||
- ReadMetadata
|
||||
- ReadMimeType
|
||||
- ServerSideAcrossConfigs
|
||||
- SetTier
|
||||
- UserMetadata
|
||||
- WriteMetadata
|
||||
- WriteMimeType
|
||||
hashes:
|
||||
- md5
|
||||
precision: 1
|
||||
30
docs/data/backends/azurefiles.yaml
Normal file
30
docs/data/backends/azurefiles.yaml
Normal file
@@ -0,0 +1,30 @@
|
||||
backend: azurefiles
|
||||
name: Azure Files
|
||||
tier: Tier 2
|
||||
maintainers: Core
|
||||
features_score: 6
|
||||
integration_tests: Passing
|
||||
data_integrity: Hash
|
||||
performance: High
|
||||
adoption: Widely used
|
||||
docs: Full
|
||||
security: High
|
||||
virtual: false
|
||||
remote: 'TestAzureFiles:'
|
||||
features:
|
||||
- About
|
||||
- CanHaveEmptyDirectories
|
||||
- CaseInsensitive
|
||||
- Copy
|
||||
- DirMove
|
||||
- ListP
|
||||
- Move
|
||||
- OpenWriterAt
|
||||
- PartialUploads
|
||||
- PutStream
|
||||
- ReadMimeType
|
||||
- SlowHash
|
||||
- WriteMimeType
|
||||
hashes:
|
||||
- md5
|
||||
precision: 1000000000
|
||||
31
docs/data/backends/b2.yaml
Normal file
31
docs/data/backends/b2.yaml
Normal file
@@ -0,0 +1,31 @@
|
||||
backend: b2
|
||||
name: B2
|
||||
tier: Tier 1
|
||||
maintainers: Core
|
||||
features_score: 6
|
||||
integration_tests: Passing
|
||||
data_integrity: Hash
|
||||
performance: High
|
||||
adoption: Widely used
|
||||
docs: Full
|
||||
security: High
|
||||
virtual: false
|
||||
remote: 'TestB2:'
|
||||
features:
|
||||
- BucketBased
|
||||
- BucketBasedRootOK
|
||||
- ChunkWriterDoesntSeek
|
||||
- CleanUp
|
||||
- Command
|
||||
- Copy
|
||||
- ListP
|
||||
- ListR
|
||||
- OpenChunkWriter
|
||||
- PublicLink
|
||||
- Purge
|
||||
- PutStream
|
||||
- ReadMimeType
|
||||
- WriteMimeType
|
||||
hashes:
|
||||
- sha1
|
||||
precision: 1000000
|
||||
32
docs/data/backends/box.yaml
Normal file
32
docs/data/backends/box.yaml
Normal file
@@ -0,0 +1,32 @@
|
||||
backend: box
|
||||
name: Box
|
||||
tier: Tier 1
|
||||
maintainers: Core
|
||||
features_score: 6
|
||||
integration_tests: Passing
|
||||
data_integrity: Hash
|
||||
performance: High
|
||||
adoption: Widely used
|
||||
docs: Full
|
||||
security: High
|
||||
virtual: false
|
||||
remote: 'TestBox:'
|
||||
features:
|
||||
- About
|
||||
- CanHaveEmptyDirectories
|
||||
- CaseInsensitive
|
||||
- ChangeNotify
|
||||
- CleanUp
|
||||
- Copy
|
||||
- DirCacheFlush
|
||||
- DirMove
|
||||
- ListP
|
||||
- Move
|
||||
- PublicLink
|
||||
- Purge
|
||||
- PutStream
|
||||
- PutUnchecked
|
||||
- Shutdown
|
||||
hashes:
|
||||
- sha1
|
||||
precision: 1000000000
|
||||
40
docs/data/backends/cache.yaml
Normal file
40
docs/data/backends/cache.yaml
Normal file
@@ -0,0 +1,40 @@
|
||||
backend: cache
|
||||
name: Cache
|
||||
tier: Tier 5
|
||||
maintainers: None
|
||||
features_score: 7
|
||||
integration_tests: Passing
|
||||
data_integrity: Full
|
||||
performance: High
|
||||
adoption: Some use
|
||||
docs: Full
|
||||
security: High
|
||||
virtual: true
|
||||
remote: 'TestCache:'
|
||||
features:
|
||||
- About
|
||||
- CanHaveEmptyDirectories
|
||||
- Command
|
||||
- DirCacheFlush
|
||||
- DirMove
|
||||
- Move
|
||||
- Overlay
|
||||
- PutStream
|
||||
- SetWrapper
|
||||
- UnWrap
|
||||
- WrapFs
|
||||
hashes:
|
||||
- md5
|
||||
- sha1
|
||||
- whirlpool
|
||||
- crc32
|
||||
- sha256
|
||||
- sha512
|
||||
- blake3
|
||||
- xxh3
|
||||
- xxh128
|
||||
- dropbox
|
||||
- hidrive
|
||||
- mailru
|
||||
- quickxor
|
||||
precision: 1
|
||||
16
docs/data/backends/chunker.yaml
Normal file
16
docs/data/backends/chunker.yaml
Normal file
@@ -0,0 +1,16 @@
|
||||
backend: chunker
|
||||
name: Chunker
|
||||
tier: Tier 4
|
||||
maintainers: None
|
||||
features_score: 7
|
||||
integration_tests: Passing
|
||||
data_integrity: Full
|
||||
performance: High
|
||||
adoption: null
|
||||
docs: null
|
||||
security: null
|
||||
virtual: true
|
||||
remote: 'TestChunkerLocal:'
|
||||
features: null
|
||||
hashes: null
|
||||
precision: null
|
||||
18
docs/data/backends/cloudinary.yaml
Normal file
18
docs/data/backends/cloudinary.yaml
Normal file
@@ -0,0 +1,18 @@
|
||||
backend: cloudinary
|
||||
name: Cloudinary
|
||||
tier: Tier 3
|
||||
maintainers: Core
|
||||
features_score: 3
|
||||
integration_tests: Failing
|
||||
data_integrity: Hash
|
||||
performance: High
|
||||
adoption: Often used
|
||||
docs: Full
|
||||
security: High
|
||||
virtual: false
|
||||
remote: 'TestCloudinary:'
|
||||
features:
|
||||
- CanHaveEmptyDirectories
|
||||
hashes:
|
||||
- md5
|
||||
precision: 3153600000000000000
|
||||
49
docs/data/backends/combine.yaml
Normal file
49
docs/data/backends/combine.yaml
Normal file
@@ -0,0 +1,49 @@
|
||||
backend: combine
|
||||
name: Combine
|
||||
tier: Tier 1
|
||||
maintainers: Core
|
||||
features_score: 7
|
||||
integration_tests: Passing
|
||||
data_integrity: Hash
|
||||
performance: High
|
||||
adoption: Often used
|
||||
docs: Full
|
||||
security: High
|
||||
virtual: true
|
||||
remote: TestCombine:dir1
|
||||
features:
|
||||
- About
|
||||
- CanHaveEmptyDirectories
|
||||
- DirModTimeUpdatesOnWrite
|
||||
- DirMove
|
||||
- DirSetModTime
|
||||
- ListP
|
||||
- MkdirMetadata
|
||||
- Move
|
||||
- OpenWriterAt
|
||||
- Overlay
|
||||
- PartialUploads
|
||||
- PutStream
|
||||
- ReadDirMetadata
|
||||
- ReadMetadata
|
||||
- SlowHash
|
||||
- UserDirMetadata
|
||||
- UserMetadata
|
||||
- WriteDirMetadata
|
||||
- WriteDirSetModTime
|
||||
- WriteMetadata
|
||||
hashes:
|
||||
- md5
|
||||
- sha1
|
||||
- whirlpool
|
||||
- crc32
|
||||
- sha256
|
||||
- sha512
|
||||
- blake3
|
||||
- xxh3
|
||||
- xxh128
|
||||
- dropbox
|
||||
- hidrive
|
||||
- mailru
|
||||
- quickxor
|
||||
precision: 1
|
||||
39
docs/data/backends/compress.yaml
Normal file
39
docs/data/backends/compress.yaml
Normal file
@@ -0,0 +1,39 @@
|
||||
backend: compress
|
||||
name: Compress
|
||||
tier: Tier 4
|
||||
maintainers: Core
|
||||
features_score: null
|
||||
integration_tests: Failing
|
||||
data_integrity: High
|
||||
performance: null
|
||||
adoption: null
|
||||
docs: null
|
||||
security: null
|
||||
virtual: true
|
||||
remote: 'TestCompress:'
|
||||
features:
|
||||
- About
|
||||
- CanHaveEmptyDirectories
|
||||
- DirModTimeUpdatesOnWrite
|
||||
- DirMove
|
||||
- DirSetModTime
|
||||
- ListP
|
||||
- MkdirMetadata
|
||||
- Move
|
||||
- Overlay
|
||||
- PartialUploads
|
||||
- PutStream
|
||||
- ReadDirMetadata
|
||||
- ReadMetadata
|
||||
- ReadMimeType
|
||||
- SetWrapper
|
||||
- UnWrap
|
||||
- UserDirMetadata
|
||||
- UserMetadata
|
||||
- WrapFs
|
||||
- WriteDirMetadata
|
||||
- WriteDirSetModTime
|
||||
- WriteMetadata
|
||||
hashes:
|
||||
- md5
|
||||
precision: 1
|
||||
16
docs/data/backends/crypt.yaml
Normal file
16
docs/data/backends/crypt.yaml
Normal file
@@ -0,0 +1,16 @@
|
||||
backend: crypt
|
||||
name: Crypt
|
||||
tier: Tier 1
|
||||
maintainers: Core
|
||||
features_score: 7
|
||||
integration_tests: Passing
|
||||
data_integrity: High
|
||||
performance: High
|
||||
adoption: Widely used
|
||||
docs: Full
|
||||
security: High
|
||||
virtual: true
|
||||
remote: 'TestCryptLocal:'
|
||||
features: null
|
||||
hashes: null
|
||||
precision: null
|
||||
16
docs/data/backends/doi.yaml
Normal file
16
docs/data/backends/doi.yaml
Normal file
@@ -0,0 +1,16 @@
|
||||
backend: doi
|
||||
name: Doi
|
||||
tier: Tier 2
|
||||
maintainers: External
|
||||
features_score: null
|
||||
integration_tests: null
|
||||
data_integrity: High
|
||||
performance: null
|
||||
adoption: null
|
||||
docs: null
|
||||
security: null
|
||||
virtual: false
|
||||
remote: null
|
||||
features: null
|
||||
hashes: null
|
||||
precision: null
|
||||
27
docs/data/backends/drime.yaml
Normal file
27
docs/data/backends/drime.yaml
Normal file
@@ -0,0 +1,27 @@
|
||||
backend: drime
|
||||
name: Drime
|
||||
tier: Tier 1
|
||||
maintainers: Core
|
||||
features_score: null
|
||||
integration_tests: Passing
|
||||
data_integrity: High
|
||||
performance: null
|
||||
adoption: null
|
||||
docs: null
|
||||
security: null
|
||||
virtual: false
|
||||
remote: 'TestDrime:'
|
||||
features:
|
||||
- CanHaveEmptyDirectories
|
||||
- Copy
|
||||
- DirCacheFlush
|
||||
- DirMove
|
||||
- Move
|
||||
- OpenChunkWriter
|
||||
- Purge
|
||||
- PutStream
|
||||
- PutUnchecked
|
||||
- ReadMimeType
|
||||
- WriteMimeType
|
||||
hashes: []
|
||||
precision: 3153600000000000000
|
||||
48
docs/data/backends/drive.yaml
Normal file
48
docs/data/backends/drive.yaml
Normal file
@@ -0,0 +1,48 @@
|
||||
backend: drive
|
||||
name: Drive
|
||||
tier: Tier 1
|
||||
maintainers: Core
|
||||
features_score: 7
|
||||
integration_tests: Passing
|
||||
data_integrity: Hash
|
||||
performance: High
|
||||
adoption: Widely used
|
||||
docs: Full
|
||||
security: High
|
||||
virtual: false
|
||||
remote: 'TestDrive:'
|
||||
features:
|
||||
- About
|
||||
- CanHaveEmptyDirectories
|
||||
- ChangeNotify
|
||||
- CleanUp
|
||||
- Command
|
||||
- Copy
|
||||
- DirCacheFlush
|
||||
- DirMove
|
||||
- DirSetModTime
|
||||
- DuplicateFiles
|
||||
- FilterAware
|
||||
- ListP
|
||||
- ListR
|
||||
- MergeDirs
|
||||
- MkdirMetadata
|
||||
- Move
|
||||
- PublicLink
|
||||
- Purge
|
||||
- PutStream
|
||||
- PutUnchecked
|
||||
- ReadDirMetadata
|
||||
- ReadMetadata
|
||||
- ReadMimeType
|
||||
- UserDirMetadata
|
||||
- UserMetadata
|
||||
- WriteDirMetadata
|
||||
- WriteDirSetModTime
|
||||
- WriteMetadata
|
||||
- WriteMimeType
|
||||
hashes:
|
||||
- md5
|
||||
- sha1
|
||||
- sha256
|
||||
precision: 1000000
|
||||
29
docs/data/backends/dropbox.yaml
Normal file
29
docs/data/backends/dropbox.yaml
Normal file
@@ -0,0 +1,29 @@
|
||||
backend: dropbox
|
||||
name: Dropbox
|
||||
tier: Tier 1
|
||||
maintainers: Core
|
||||
features_score: 6
|
||||
integration_tests: Passing
|
||||
data_integrity: Hash
|
||||
performance: High
|
||||
adoption: Widely used
|
||||
docs: Full
|
||||
security: High
|
||||
virtual: false
|
||||
remote: 'TestDropbox:'
|
||||
features:
|
||||
- About
|
||||
- CanHaveEmptyDirectories
|
||||
- CaseInsensitive
|
||||
- ChangeNotify
|
||||
- Copy
|
||||
- DirMove
|
||||
- ListP
|
||||
- Move
|
||||
- PublicLink
|
||||
- Purge
|
||||
- PutStream
|
||||
- Shutdown
|
||||
hashes:
|
||||
- dropbox
|
||||
precision: 1000000000
|
||||
26
docs/data/backends/fichier.yaml
Normal file
26
docs/data/backends/fichier.yaml
Normal file
@@ -0,0 +1,26 @@
|
||||
backend: fichier
|
||||
name: Fichier
|
||||
tier: Tier 3
|
||||
maintainers: Core
|
||||
features_score: 2
|
||||
integration_tests: Passing
|
||||
data_integrity: Hash
|
||||
performance: Medium
|
||||
adoption: Some use
|
||||
docs: Full
|
||||
security: High
|
||||
virtual: false
|
||||
remote: 'TestFichier:'
|
||||
features:
|
||||
- About
|
||||
- CanHaveEmptyDirectories
|
||||
- Copy
|
||||
- DirMove
|
||||
- DuplicateFiles
|
||||
- Move
|
||||
- PublicLink
|
||||
- PutUnchecked
|
||||
- ReadMimeType
|
||||
hashes:
|
||||
- whirlpool
|
||||
precision: 3153600000000000000
|
||||
26
docs/data/backends/filefabric.yaml
Normal file
26
docs/data/backends/filefabric.yaml
Normal file
@@ -0,0 +1,26 @@
|
||||
backend: filefabric
|
||||
name: Filefabric
|
||||
tier: Tier 4
|
||||
maintainers: Core
|
||||
features_score: 3
|
||||
integration_tests: Failing
|
||||
data_integrity: Modtime
|
||||
performance: Medium
|
||||
adoption: Some use
|
||||
docs: Full
|
||||
security: High
|
||||
virtual: false
|
||||
remote: 'TestFileFabric:'
|
||||
features:
|
||||
- CanHaveEmptyDirectories
|
||||
- CaseInsensitive
|
||||
- CleanUp
|
||||
- Copy
|
||||
- DirCacheFlush
|
||||
- DirMove
|
||||
- Move
|
||||
- Purge
|
||||
- ReadMimeType
|
||||
- WriteMimeType
|
||||
hashes: []
|
||||
precision: 1000000000
|
||||
21
docs/data/backends/filelu.yaml
Normal file
21
docs/data/backends/filelu.yaml
Normal file
@@ -0,0 +1,21 @@
|
||||
backend: filelu
|
||||
name: Filelu
|
||||
tier: Tier 1
|
||||
maintainers: Core
|
||||
features_score: null
|
||||
integration_tests: Passing
|
||||
data_integrity: Hash
|
||||
performance: High
|
||||
adoption: Widely used
|
||||
docs: Full
|
||||
security: High
|
||||
virtual: false
|
||||
remote: 'TestFileLu:'
|
||||
features:
|
||||
- About
|
||||
- CanHaveEmptyDirectories
|
||||
- Move
|
||||
- Purge
|
||||
- SlowHash
|
||||
hashes: []
|
||||
precision: 3153600000000000000
|
||||
29
docs/data/backends/filen.yaml
Normal file
29
docs/data/backends/filen.yaml
Normal file
@@ -0,0 +1,29 @@
|
||||
backend: filen
|
||||
name: Filen
|
||||
tier: Tier 1
|
||||
maintainers: External
|
||||
features_score: 6
|
||||
integration_tests: Passing
|
||||
data_integrity: Hash
|
||||
performance: High
|
||||
adoption: Some use
|
||||
docs: Full
|
||||
security: High
|
||||
virtual: false
|
||||
remote: 'TestFilen:'
|
||||
features:
|
||||
- About
|
||||
- CanHaveEmptyDirectories
|
||||
- ChunkWriterDoesntSeek
|
||||
- CleanUp
|
||||
- DirMove
|
||||
- ListR
|
||||
- Move
|
||||
- OpenChunkWriter
|
||||
- Purge
|
||||
- PutStream
|
||||
- ReadMimeType
|
||||
- WriteMimeType
|
||||
hashes:
|
||||
- blake3
|
||||
precision: 1000000
|
||||
29
docs/data/backends/filescom.yaml
Normal file
29
docs/data/backends/filescom.yaml
Normal file
@@ -0,0 +1,29 @@
|
||||
backend: filescom
|
||||
name: Filescom
|
||||
tier: Tier 1
|
||||
maintainers: Core
|
||||
features_score: 5
|
||||
integration_tests: Passing
|
||||
data_integrity: Hash
|
||||
performance: High
|
||||
adoption: Widely used
|
||||
docs: Full
|
||||
security: High
|
||||
virtual: false
|
||||
remote: 'TestFilesCom:'
|
||||
features:
|
||||
- CanHaveEmptyDirectories
|
||||
- CaseInsensitive
|
||||
- Copy
|
||||
- DirModTimeUpdatesOnWrite
|
||||
- DirMove
|
||||
- DirSetModTime
|
||||
- Move
|
||||
- PublicLink
|
||||
- Purge
|
||||
- PutStream
|
||||
- ReadMimeType
|
||||
hashes:
|
||||
- md5
|
||||
- crc32
|
||||
precision: 1000000000
|
||||
22
docs/data/backends/ftp.yaml
Normal file
22
docs/data/backends/ftp.yaml
Normal file
@@ -0,0 +1,22 @@
|
||||
backend: ftp
|
||||
name: FTP
|
||||
tier: Tier 1
|
||||
maintainers: Core
|
||||
features_score: 4
|
||||
integration_tests: Passing
|
||||
data_integrity: Modtime
|
||||
performance: High
|
||||
adoption: Widely used
|
||||
docs: Full
|
||||
security: High
|
||||
virtual: false
|
||||
remote: 'TestFTPProftpd:'
|
||||
features:
|
||||
- CanHaveEmptyDirectories
|
||||
- DirMove
|
||||
- Move
|
||||
- PartialUploads
|
||||
- PutStream
|
||||
- Shutdown
|
||||
hashes: []
|
||||
precision: 1000000000
|
||||
34
docs/data/backends/gofile.yaml
Normal file
34
docs/data/backends/gofile.yaml
Normal file
@@ -0,0 +1,34 @@
|
||||
backend: gofile
|
||||
name: Gofile
|
||||
tier: Tier 1
|
||||
maintainers: Core
|
||||
features_score: 5
|
||||
integration_tests: Passing
|
||||
data_integrity: Hash
|
||||
performance: High
|
||||
adoption: Often used
|
||||
docs: Full
|
||||
security: High
|
||||
virtual: false
|
||||
remote: 'TestGoFile:'
|
||||
features:
|
||||
- About
|
||||
- CanHaveEmptyDirectories
|
||||
- Copy
|
||||
- DirCacheFlush
|
||||
- DirModTimeUpdatesOnWrite
|
||||
- DirMove
|
||||
- DirSetModTime
|
||||
- DuplicateFiles
|
||||
- ListR
|
||||
- MergeDirs
|
||||
- Move
|
||||
- PublicLink
|
||||
- Purge
|
||||
- PutStream
|
||||
- PutUnchecked
|
||||
- ReadMimeType
|
||||
- WriteDirSetModTime
|
||||
hashes:
|
||||
- md5
|
||||
precision: 1000000000
|
||||
26
docs/data/backends/googlecloudstorage.yaml
Normal file
26
docs/data/backends/googlecloudstorage.yaml
Normal file
@@ -0,0 +1,26 @@
|
||||
backend: googlecloudstorage
|
||||
name: Google Cloud Storage
|
||||
tier: Tier 1
|
||||
maintainers: Core
|
||||
features_score: 6
|
||||
integration_tests: Passing
|
||||
data_integrity: Hash
|
||||
performance: High
|
||||
adoption: Widely used
|
||||
docs: Full
|
||||
security: High
|
||||
virtual: false
|
||||
remote: 'TestGoogleCloudStorage:'
|
||||
features:
|
||||
- BucketBased
|
||||
- BucketBasedRootOK
|
||||
- CanHaveEmptyDirectories
|
||||
- Copy
|
||||
- ListP
|
||||
- ListR
|
||||
- PutStream
|
||||
- ReadMimeType
|
||||
- WriteMimeType
|
||||
hashes:
|
||||
- md5
|
||||
precision: 1
|
||||
20
docs/data/backends/googlephotos.yaml
Normal file
20
docs/data/backends/googlephotos.yaml
Normal file
@@ -0,0 +1,20 @@
|
||||
backend: googlephotos
|
||||
name: Google Photos
|
||||
tier: Tier 5
|
||||
maintainers: None
|
||||
features_score: 0
|
||||
integration_tests: Failing
|
||||
data_integrity: Other
|
||||
performance: Low
|
||||
adoption: Some use
|
||||
docs: Full
|
||||
security: High
|
||||
virtual: false
|
||||
remote: 'TestGooglePhotos:'
|
||||
features:
|
||||
- Disconnect
|
||||
- ReadMimeType
|
||||
- Shutdown
|
||||
- UserInfo
|
||||
hashes: []
|
||||
precision: 3153600000000000000
|
||||
16
docs/data/backends/hasher.yaml
Normal file
16
docs/data/backends/hasher.yaml
Normal file
@@ -0,0 +1,16 @@
|
||||
backend: hasher
|
||||
name: Hasher
|
||||
tier: Tier 4
|
||||
maintainers: Core
|
||||
features_score: null
|
||||
integration_tests: Passing
|
||||
data_integrity: Full
|
||||
performance: High
|
||||
adoption: null
|
||||
docs: null
|
||||
security: null
|
||||
virtual: true
|
||||
remote: null
|
||||
features: null
|
||||
hashes: null
|
||||
precision: null
|
||||
22
docs/data/backends/hdfs.yaml
Normal file
22
docs/data/backends/hdfs.yaml
Normal file
@@ -0,0 +1,22 @@
|
||||
backend: hdfs
|
||||
name: Hdfs
|
||||
tier: Tier 2
|
||||
maintainers: Core
|
||||
features_score: 4
|
||||
integration_tests: Passing
|
||||
data_integrity: Modtime
|
||||
performance: Medium
|
||||
adoption: Some use
|
||||
docs: Full
|
||||
security: High
|
||||
virtual: false
|
||||
remote: 'TestHdfs:'
|
||||
features:
|
||||
- About
|
||||
- CanHaveEmptyDirectories
|
||||
- DirMove
|
||||
- Move
|
||||
- Purge
|
||||
- PutStream
|
||||
hashes: []
|
||||
precision: 1000000000
|
||||
25
docs/data/backends/hidrive.yaml
Normal file
25
docs/data/backends/hidrive.yaml
Normal file
@@ -0,0 +1,25 @@
|
||||
backend: hidrive
|
||||
name: Hidrive
|
||||
tier: Tier 1
|
||||
maintainers: Core
|
||||
features_score: 5
|
||||
integration_tests: Passing
|
||||
data_integrity: Hash
|
||||
performance: Medium
|
||||
adoption: Often used
|
||||
docs: Full
|
||||
security: High
|
||||
virtual: false
|
||||
remote: 'TestHiDrive:'
|
||||
features:
|
||||
- CanHaveEmptyDirectories
|
||||
- Copy
|
||||
- DirMove
|
||||
- Move
|
||||
- Purge
|
||||
- PutStream
|
||||
- PutUnchecked
|
||||
- Shutdown
|
||||
hashes:
|
||||
- hidrive
|
||||
precision: 1000000000
|
||||
20
docs/data/backends/http.yaml
Normal file
20
docs/data/backends/http.yaml
Normal file
@@ -0,0 +1,20 @@
|
||||
backend: http
|
||||
name: Http
|
||||
tier: Tier 3
|
||||
maintainers: Core
|
||||
features_score: null
|
||||
integration_tests: Disabled
|
||||
data_integrity: High
|
||||
performance: null
|
||||
adoption: null
|
||||
docs: null
|
||||
security: null
|
||||
virtual: false
|
||||
remote: ':http,url=''http://downloads.rclone.org'':'
|
||||
features:
|
||||
- CanHaveEmptyDirectories
|
||||
- Command
|
||||
- PutStream
|
||||
- ReadMetadata
|
||||
hashes: []
|
||||
precision: 1000000000
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user