mirror of
https://github.com/rclone/rclone.git
synced 2025-12-21 02:33:49 +00:00
Compare commits
11 Commits
dependabot
...
fix-9031-b
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b5bf9b629f | ||
|
|
6f81885ebf | ||
|
|
976aa6b416 | ||
|
|
b3a0383ca3 | ||
|
|
c13f129339 | ||
|
|
748d8c8957 | ||
|
|
4d379efcbb | ||
|
|
e5e6a4b5ae | ||
|
|
df18e8c55b | ||
|
|
f4e17d8b0b | ||
|
|
e5c69511bc |
2
.github/workflows/build.yml
vendored
2
.github/workflows/build.yml
vendored
@@ -229,7 +229,7 @@ jobs:
|
|||||||
cache: false
|
cache: false
|
||||||
|
|
||||||
- name: Cache
|
- name: Cache
|
||||||
uses: actions/cache@v4
|
uses: actions/cache@v5
|
||||||
with:
|
with:
|
||||||
path: |
|
path: |
|
||||||
~/go/pkg/mod
|
~/go/pkg/mod
|
||||||
|
|||||||
@@ -129,7 +129,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Load Go Build Cache for Docker
|
- name: Load Go Build Cache for Docker
|
||||||
id: go-cache
|
id: go-cache
|
||||||
uses: actions/cache@v4
|
uses: actions/cache@v5
|
||||||
with:
|
with:
|
||||||
key: ${{ runner.os }}-${{ steps.imageos.outputs.result }}-go-${{ env.CACHE_NAME }}-${{ env.PLATFORM }}-${{ hashFiles('**/go.mod') }}-${{ hashFiles('**/go.sum') }}
|
key: ${{ runner.os }}-${{ steps.imageos.outputs.result }}-go-${{ env.CACHE_NAME }}-${{ env.PLATFORM }}-${{ hashFiles('**/go.mod') }}-${{ hashFiles('**/go.sum') }}
|
||||||
restore-keys: |
|
restore-keys: |
|
||||||
@@ -183,7 +183,7 @@ jobs:
|
|||||||
touch "/tmp/digests/${digest#sha256:}"
|
touch "/tmp/digests/${digest#sha256:}"
|
||||||
|
|
||||||
- name: Upload Image Digest
|
- name: Upload Image Digest
|
||||||
uses: actions/upload-artifact@v5
|
uses: actions/upload-artifact@v6
|
||||||
with:
|
with:
|
||||||
name: digests-${{ env.PLATFORM }}
|
name: digests-${{ env.PLATFORM }}
|
||||||
path: /tmp/digests/*
|
path: /tmp/digests/*
|
||||||
@@ -198,7 +198,7 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Download Image Digests
|
- name: Download Image Digests
|
||||||
uses: actions/download-artifact@v6
|
uses: actions/download-artifact@v7
|
||||||
with:
|
with:
|
||||||
path: /tmp/digests
|
path: /tmp/digests
|
||||||
pattern: digests-*
|
pattern: digests-*
|
||||||
|
|||||||
@@ -133,32 +133,23 @@ type File struct {
|
|||||||
Info map[string]string `json:"fileInfo"` // The custom information that was uploaded with the file. This is a JSON object, holding the name/value pairs that were uploaded with the file.
|
Info map[string]string `json:"fileInfo"` // The custom information that was uploaded with the file. This is a JSON object, holding the name/value pairs that were uploaded with the file.
|
||||||
}
|
}
|
||||||
|
|
||||||
// StorageAPI is as returned from the b2_authorize_account call
|
// AuthorizeAccountResponse is as returned from the b2_authorize_account call
|
||||||
type StorageAPI struct {
|
type AuthorizeAccountResponse struct {
|
||||||
AbsoluteMinimumPartSize int `json:"absoluteMinimumPartSize"` // The smallest possible size of a part of a large file.
|
AbsoluteMinimumPartSize int `json:"absoluteMinimumPartSize"` // The smallest possible size of a part of a large file.
|
||||||
|
AccountID string `json:"accountId"` // The identifier for the account.
|
||||||
Allowed struct { // An object (see below) containing the capabilities of this auth token, and any restrictions on using it.
|
Allowed struct { // An object (see below) containing the capabilities of this auth token, and any restrictions on using it.
|
||||||
Buckets []struct { // When present, access is restricted to one or more buckets.
|
BucketID string `json:"bucketId"` // When present, access is restricted to one bucket.
|
||||||
ID string `json:"id"` // ID of bucket
|
BucketName string `json:"bucketName"` // When present, name of bucket - may be empty
|
||||||
Name string `json:"name"` // When present, name of bucket - may be empty
|
Capabilities []string `json:"capabilities"` // A list of strings, each one naming a capability the key has.
|
||||||
} `json:"buckets"`
|
|
||||||
Capabilities []string `json:"capabilities"` // A list of strings, each one naming a capability the key has for every bucket.
|
|
||||||
NamePrefix any `json:"namePrefix"` // When present, access is restricted to files whose names start with the prefix
|
NamePrefix any `json:"namePrefix"` // When present, access is restricted to files whose names start with the prefix
|
||||||
} `json:"allowed"`
|
} `json:"allowed"`
|
||||||
APIURL string `json:"apiUrl"` // The base URL to use for all API calls except for uploading and downloading files.
|
APIURL string `json:"apiUrl"` // The base URL to use for all API calls except for uploading and downloading files.
|
||||||
|
AuthorizationToken string `json:"authorizationToken"` // An authorization token to use with all calls, other than b2_authorize_account, that need an Authorization header.
|
||||||
DownloadURL string `json:"downloadUrl"` // The base URL to use for downloading files.
|
DownloadURL string `json:"downloadUrl"` // The base URL to use for downloading files.
|
||||||
MinimumPartSize int `json:"minimumPartSize"` // DEPRECATED: This field will always have the same value as recommendedPartSize. Use recommendedPartSize instead.
|
MinimumPartSize int `json:"minimumPartSize"` // DEPRECATED: This field will always have the same value as recommendedPartSize. Use recommendedPartSize instead.
|
||||||
RecommendedPartSize int `json:"recommendedPartSize"` // The recommended size for each part of a large file. We recommend using this part size for optimal upload performance.
|
RecommendedPartSize int `json:"recommendedPartSize"` // The recommended size for each part of a large file. We recommend using this part size for optimal upload performance.
|
||||||
}
|
}
|
||||||
|
|
||||||
// AuthorizeAccountResponse is as returned from the b2_authorize_account call
|
|
||||||
type AuthorizeAccountResponse struct {
|
|
||||||
AccountID string `json:"accountId"` // The identifier for the account.
|
|
||||||
AuthorizationToken string `json:"authorizationToken"` // An authorization token to use with all calls, other than b2_authorize_account, that need an Authorization header.
|
|
||||||
APIs struct { // Supported APIs for this account / key. These are API-dependent JSON objects.
|
|
||||||
Storage StorageAPI `json:"storageApi"`
|
|
||||||
} `json:"apiInfo"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// ListBucketsRequest is parameters for b2_list_buckets call
|
// ListBucketsRequest is parameters for b2_list_buckets call
|
||||||
type ListBucketsRequest struct {
|
type ListBucketsRequest struct {
|
||||||
AccountID string `json:"accountId"` // The identifier for the account.
|
AccountID string `json:"accountId"` // The identifier for the account.
|
||||||
|
|||||||
@@ -607,29 +607,17 @@ func NewFs(ctx context.Context, name, root string, m configmap.Mapper) (fs.Fs, e
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to authorize account: %w", err)
|
return nil, fmt.Errorf("failed to authorize account: %w", err)
|
||||||
}
|
}
|
||||||
// If this is a key limited to one or more buckets, one of them must exist
|
// If this is a key limited to a single bucket, it must exist already
|
||||||
// and be ours.
|
if f.rootBucket != "" && f.info.Allowed.BucketID != "" {
|
||||||
if f.rootBucket != "" && len(f.info.APIs.Storage.Allowed.Buckets) != 0 {
|
allowedBucket := f.opt.Enc.ToStandardName(f.info.Allowed.BucketName)
|
||||||
buckets := f.info.APIs.Storage.Allowed.Buckets
|
|
||||||
var rootFound = false
|
|
||||||
var rootID string
|
|
||||||
for _, b := range buckets {
|
|
||||||
allowedBucket := f.opt.Enc.ToStandardName(b.Name)
|
|
||||||
if allowedBucket == "" {
|
if allowedBucket == "" {
|
||||||
fs.Debugf(f, "bucket %q that application key is restricted to no longer exists", b.ID)
|
return nil, errors.New("bucket that application key is restricted to no longer exists")
|
||||||
continue
|
|
||||||
}
|
}
|
||||||
|
if allowedBucket != f.rootBucket {
|
||||||
if allowedBucket == f.rootBucket {
|
return nil, fmt.Errorf("you must use bucket %q with this application key", allowedBucket)
|
||||||
rootFound = true
|
|
||||||
rootID = b.ID
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !rootFound {
|
|
||||||
return nil, fmt.Errorf("you must use bucket(s) %q with this application key", buckets)
|
|
||||||
}
|
}
|
||||||
f.cache.MarkOK(f.rootBucket)
|
f.cache.MarkOK(f.rootBucket)
|
||||||
f.setBucketID(f.rootBucket, rootID)
|
f.setBucketID(f.rootBucket, f.info.Allowed.BucketID)
|
||||||
}
|
}
|
||||||
if f.rootBucket != "" && f.rootDirectory != "" {
|
if f.rootBucket != "" && f.rootDirectory != "" {
|
||||||
// Check to see if the (bucket,directory) is actually an existing file
|
// Check to see if the (bucket,directory) is actually an existing file
|
||||||
@@ -655,7 +643,7 @@ func (f *Fs) authorizeAccount(ctx context.Context) error {
|
|||||||
defer f.authMu.Unlock()
|
defer f.authMu.Unlock()
|
||||||
opts := rest.Opts{
|
opts := rest.Opts{
|
||||||
Method: "GET",
|
Method: "GET",
|
||||||
Path: "/b2api/v4/b2_authorize_account",
|
Path: "/b2api/v1/b2_authorize_account",
|
||||||
RootURL: f.opt.Endpoint,
|
RootURL: f.opt.Endpoint,
|
||||||
UserName: f.opt.Account,
|
UserName: f.opt.Account,
|
||||||
Password: f.opt.Key,
|
Password: f.opt.Key,
|
||||||
@@ -668,13 +656,13 @@ func (f *Fs) authorizeAccount(ctx context.Context) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to authenticate: %w", err)
|
return fmt.Errorf("failed to authenticate: %w", err)
|
||||||
}
|
}
|
||||||
f.srv.SetRoot(f.info.APIs.Storage.APIURL+"/b2api/v1").SetHeader("Authorization", f.info.AuthorizationToken)
|
f.srv.SetRoot(f.info.APIURL+"/b2api/v1").SetHeader("Authorization", f.info.AuthorizationToken)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// hasPermission returns if the current AuthorizationToken has the selected permission
|
// hasPermission returns if the current AuthorizationToken has the selected permission
|
||||||
func (f *Fs) hasPermission(permission string) bool {
|
func (f *Fs) hasPermission(permission string) bool {
|
||||||
return slices.Contains(f.info.APIs.Storage.Allowed.Capabilities, permission)
|
return slices.Contains(f.info.Allowed.Capabilities, permission)
|
||||||
}
|
}
|
||||||
|
|
||||||
// getUploadURL returns the upload info with the UploadURL and the AuthorizationToken
|
// getUploadURL returns the upload info with the UploadURL and the AuthorizationToken
|
||||||
@@ -1079,12 +1067,9 @@ type listBucketFn func(*api.Bucket) error
|
|||||||
|
|
||||||
// listBucketsToFn lists the buckets to the function supplied
|
// listBucketsToFn lists the buckets to the function supplied
|
||||||
func (f *Fs) listBucketsToFn(ctx context.Context, bucketName string, fn listBucketFn) error {
|
func (f *Fs) listBucketsToFn(ctx context.Context, bucketName string, fn listBucketFn) error {
|
||||||
responses := make([]api.ListBucketsResponse, len(f.info.APIs.Storage.Allowed.Buckets))[:0]
|
|
||||||
|
|
||||||
call := func(id string) error {
|
|
||||||
var account = api.ListBucketsRequest{
|
var account = api.ListBucketsRequest{
|
||||||
AccountID: f.info.AccountID,
|
AccountID: f.info.AccountID,
|
||||||
BucketID: id,
|
BucketID: f.info.Allowed.BucketID,
|
||||||
}
|
}
|
||||||
if bucketName != "" && account.BucketID == "" {
|
if bucketName != "" && account.BucketID == "" {
|
||||||
account.BucketName = f.opt.Enc.FromStandardName(bucketName)
|
account.BucketName = f.opt.Enc.FromStandardName(bucketName)
|
||||||
@@ -1102,42 +1087,10 @@ func (f *Fs) listBucketsToFn(ctx context.Context, bucketName string, fn listBuck
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
responses = append(responses, response)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
for i := range f.info.APIs.Storage.Allowed.Buckets {
|
|
||||||
b := &f.info.APIs.Storage.Allowed.Buckets[i]
|
|
||||||
// Empty names indicate a bucket that no longer exists, this is non-fatal
|
|
||||||
// for multi-bucket API keys.
|
|
||||||
if b.Name == "" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
// When requesting a specific bucket skip over non-matching names
|
|
||||||
if bucketName != "" && b.Name != bucketName {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
err := call(b.ID)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(f.info.APIs.Storage.Allowed.Buckets) == 0 {
|
|
||||||
err := call("")
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
f.bucketIDMutex.Lock()
|
f.bucketIDMutex.Lock()
|
||||||
f.bucketTypeMutex.Lock()
|
f.bucketTypeMutex.Lock()
|
||||||
f._bucketID = make(map[string]string, 1)
|
f._bucketID = make(map[string]string, 1)
|
||||||
f._bucketType = make(map[string]string, 1)
|
f._bucketType = make(map[string]string, 1)
|
||||||
|
|
||||||
for ri := range responses {
|
|
||||||
response := &responses[ri]
|
|
||||||
for i := range response.Buckets {
|
for i := range response.Buckets {
|
||||||
bucket := &response.Buckets[i]
|
bucket := &response.Buckets[i]
|
||||||
bucket.Name = f.opt.Enc.ToStandardName(bucket.Name)
|
bucket.Name = f.opt.Enc.ToStandardName(bucket.Name)
|
||||||
@@ -1145,19 +1098,15 @@ func (f *Fs) listBucketsToFn(ctx context.Context, bucketName string, fn listBuck
|
|||||||
f._bucketID[bucket.Name] = bucket.ID
|
f._bucketID[bucket.Name] = bucket.ID
|
||||||
f._bucketType[bucket.Name] = bucket.Type
|
f._bucketType[bucket.Name] = bucket.Type
|
||||||
}
|
}
|
||||||
}
|
|
||||||
f.bucketTypeMutex.Unlock()
|
f.bucketTypeMutex.Unlock()
|
||||||
f.bucketIDMutex.Unlock()
|
f.bucketIDMutex.Unlock()
|
||||||
for ri := range responses {
|
|
||||||
response := &responses[ri]
|
|
||||||
for i := range response.Buckets {
|
for i := range response.Buckets {
|
||||||
bucket := &response.Buckets[i]
|
bucket := &response.Buckets[i]
|
||||||
err := fn(bucket)
|
err = fn(bucket)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1657,7 +1606,7 @@ func (f *Fs) PublicLink(ctx context.Context, remote string, expire fs.Duration,
|
|||||||
bucket, bucketPath := f.split(remote)
|
bucket, bucketPath := f.split(remote)
|
||||||
var RootURL string
|
var RootURL string
|
||||||
if f.opt.DownloadURL == "" {
|
if f.opt.DownloadURL == "" {
|
||||||
RootURL = f.info.APIs.Storage.DownloadURL
|
RootURL = f.info.DownloadURL
|
||||||
} else {
|
} else {
|
||||||
RootURL = f.opt.DownloadURL
|
RootURL = f.opt.DownloadURL
|
||||||
}
|
}
|
||||||
@@ -2008,7 +1957,7 @@ func (o *Object) getOrHead(ctx context.Context, method string, options []fs.Open
|
|||||||
// Use downloadUrl from backblaze if downloadUrl is not set
|
// Use downloadUrl from backblaze if downloadUrl is not set
|
||||||
// otherwise use the custom downloadUrl
|
// otherwise use the custom downloadUrl
|
||||||
if o.fs.opt.DownloadURL == "" {
|
if o.fs.opt.DownloadURL == "" {
|
||||||
opts.RootURL = o.fs.info.APIs.Storage.DownloadURL
|
opts.RootURL = o.fs.info.DownloadURL
|
||||||
} else {
|
} else {
|
||||||
opts.RootURL = o.fs.opt.DownloadURL
|
opts.RootURL = o.fs.opt.DownloadURL
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,26 +1,26 @@
|
|||||||
name: Linode
|
name: Linode
|
||||||
description: Linode Object Storage
|
description: Linode Object Storage
|
||||||
endpoint:
|
endpoint:
|
||||||
nl-ams-1.linodeobjects.com: Amsterdam (Netherlands), nl-ams-1
|
nl-ams-1.linodeobjects.com: Amsterdam, NL (nl-ams-1)
|
||||||
us-southeast-1.linodeobjects.com: Atlanta, GA (USA), us-southeast-1
|
us-southeast-1.linodeobjects.com: Atlanta, GA, US (us-southeast-1)
|
||||||
in-maa-1.linodeobjects.com: Chennai (India), in-maa-1
|
in-maa-1.linodeobjects.com: Chennai, IN (in-maa-1)
|
||||||
us-ord-1.linodeobjects.com: Chicago, IL (USA), us-ord-1
|
us-ord-1.linodeobjects.com: Chicago, IL, US (us-ord-1)
|
||||||
eu-central-1.linodeobjects.com: Frankfurt (Germany), eu-central-1
|
eu-central-1.linodeobjects.com: Frankfurt, DE (eu-central-1)
|
||||||
id-cgk-1.linodeobjects.com: Jakarta (Indonesia), id-cgk-1
|
id-cgk-1.linodeobjects.com: Jakarta, ID (id-cgk-1)
|
||||||
gb-lon-1.linodeobjects.com: London 2 (Great Britain), gb-lon-1
|
gb-lon-1.linodeobjects.com: London 2, UK (gb-lon-1)
|
||||||
us-lax-1.linodeobjects.com: Los Angeles, CA (USA), us-lax-1
|
us-lax-1.linodeobjects.com: Los Angeles, CA, US (us-lax-1)
|
||||||
es-mad-1.linodeobjects.com: Madrid (Spain), es-mad-1
|
es-mad-1.linodeobjects.com: Madrid, ES (es-mad-1)
|
||||||
au-mel-1.linodeobjects.com: Melbourne (Australia), au-mel-1
|
us-mia-1.linodeobjects.com: Miami, FL, US (us-mia-1)
|
||||||
us-mia-1.linodeobjects.com: Miami, FL (USA), us-mia-1
|
it-mil-1.linodeobjects.com: Milan, IT (it-mil-1)
|
||||||
it-mil-1.linodeobjects.com: Milan (Italy), it-mil-1
|
us-east-1.linodeobjects.com: Newark, NJ, US (us-east-1)
|
||||||
us-east-1.linodeobjects.com: Newark, NJ (USA), us-east-1
|
jp-osa-1.linodeobjects.com: Osaka, JP (jp-osa-1)
|
||||||
jp-osa-1.linodeobjects.com: Osaka (Japan), jp-osa-1
|
fr-par-1.linodeobjects.com: Paris, FR (fr-par-1)
|
||||||
fr-par-1.linodeobjects.com: Paris (France), fr-par-1
|
br-gru-1.linodeobjects.com: Sao Paulo, BR (br-gru-1)
|
||||||
br-gru-1.linodeobjects.com: São Paulo (Brazil), br-gru-1
|
us-sea-1.linodeobjects.com: Seattle, WA, US (us-sea-1)
|
||||||
us-sea-1.linodeobjects.com: Seattle, WA (USA), us-sea-1
|
ap-south-1.linodeobjects.com: Singapore, SG (ap-south-1)
|
||||||
ap-south-1.linodeobjects.com: Singapore, ap-south-1
|
sg-sin-1.linodeobjects.com: Singapore 2, SG (sg-sin-1)
|
||||||
sg-sin-1.linodeobjects.com: Singapore 2, sg-sin-1
|
se-sto-1.linodeobjects.com: Stockholm, SE (se-sto-1)
|
||||||
se-sto-1.linodeobjects.com: Stockholm (Sweden), se-sto-1
|
jp-tyo-1.linodeobjects.com: Tokyo 3, JP (jp-tyo-1)
|
||||||
us-iad-1.linodeobjects.com: Washington, DC, (USA), us-iad-1
|
us-iad-10.linodeobjects.com: Washington, DC, US (us-iad-10)
|
||||||
acl: {}
|
acl: {}
|
||||||
bucket_acl: true
|
bucket_acl: true
|
||||||
|
|||||||
@@ -2,7 +2,17 @@ name: Selectel
|
|||||||
description: Selectel Object Storage
|
description: Selectel Object Storage
|
||||||
region:
|
region:
|
||||||
ru-1: St. Petersburg
|
ru-1: St. Petersburg
|
||||||
|
ru-3: St. Petersburg
|
||||||
|
ru-7: Moscow
|
||||||
|
gis-1: Moscow
|
||||||
|
kz-1: Kazakhstan
|
||||||
|
uz-2: Uzbekistan
|
||||||
endpoint:
|
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:
|
quirks:
|
||||||
list_url_encode: false
|
list_url_encode: false
|
||||||
|
|||||||
@@ -1057,3 +1057,4 @@ put them back in again. -->
|
|||||||
- Johannes Rothe <mail@johannes-rothe.de>
|
- Johannes Rothe <mail@johannes-rothe.de>
|
||||||
- Tingsong Xu <tingsong.xu@rightcapital.com>
|
- Tingsong Xu <tingsong.xu@rightcapital.com>
|
||||||
- Jonas Tingeborn <134889+jojje@users.noreply.github.com>
|
- Jonas Tingeborn <134889+jojje@users.noreply.github.com>
|
||||||
|
- jhasse-shade <jacob@shade.inc>
|
||||||
|
|||||||
@@ -283,7 +283,7 @@ It is useful to know how many requests are sent to the server in different scena
|
|||||||
All copy commands send the following 4 requests:
|
All copy commands send the following 4 requests:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
/b2api/v4/b2_authorize_account
|
/b2api/v1/b2_authorize_account
|
||||||
/b2api/v1/b2_create_bucket
|
/b2api/v1/b2_create_bucket
|
||||||
/b2api/v1/b2_list_buckets
|
/b2api/v1/b2_list_buckets
|
||||||
/b2api/v1/b2_list_file_names
|
/b2api/v1/b2_list_file_names
|
||||||
|
|||||||
@@ -6,6 +6,22 @@ description: "Rclone Changelog"
|
|||||||
|
|
||||||
# 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
|
## v1.72.0 - 2025-11-21
|
||||||
|
|
||||||
[See commits](https://github.com/rclone/rclone/compare/v1.71.0...v1.72.0)
|
[See commits](https://github.com/rclone/rclone/compare/v1.71.0...v1.72.0)
|
||||||
|
|||||||
@@ -541,7 +541,7 @@ upon backend-specific capabilities.
|
|||||||
| OpenDrive | Yes | Yes | Yes | Yes | No | No | No | No | No | 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 |
|
| 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 |
|
| 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 |
|
| pCloud | Yes | Yes | Yes | Yes | Yes | Yes | No | No | Yes | Yes | Yes |
|
||||||
| PikPak | 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 |
|
| 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 |
|
| premiumize.me | Yes | No | Yes | Yes | No | No | No | No | Yes | Yes | Yes |
|
||||||
|
|||||||
@@ -1301,6 +1301,7 @@ func TestSyncAfterRemovingAFileAndAddingAFileSubDirWithErrors(t *testing.T) {
|
|||||||
err := Sync(ctx, r.Fremote, r.Flocal, false)
|
err := Sync(ctx, r.Fremote, r.Flocal, false)
|
||||||
assert.Equal(t, fs.ErrorNotDeleting, err)
|
assert.Equal(t, fs.ErrorNotDeleting, err)
|
||||||
testLoggerVsLsf(ctx, r.Fremote, r.Flocal, operations.GetLoggerOpt(ctx).JSON, t)
|
testLoggerVsLsf(ctx, r.Fremote, r.Flocal, operations.GetLoggerOpt(ctx).JSON, t)
|
||||||
|
accounting.GlobalStats().ResetCounters()
|
||||||
|
|
||||||
r.CheckLocalListing(
|
r.CheckLocalListing(
|
||||||
t,
|
t,
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import (
|
|||||||
|
|
||||||
_ "github.com/rclone/rclone/backend/all"
|
_ "github.com/rclone/rclone/backend/all"
|
||||||
"github.com/rclone/rclone/fs"
|
"github.com/rclone/rclone/fs"
|
||||||
|
"github.com/rclone/rclone/fs/accounting"
|
||||||
"github.com/rclone/rclone/fs/filter"
|
"github.com/rclone/rclone/fs/filter"
|
||||||
"github.com/rclone/rclone/fs/operations"
|
"github.com/rclone/rclone/fs/operations"
|
||||||
"github.com/rclone/rclone/fs/walk"
|
"github.com/rclone/rclone/fs/walk"
|
||||||
@@ -507,6 +508,7 @@ func TestError(t *testing.T) {
|
|||||||
err = Sync(ctx, r.Fremote, r.Flocal, true)
|
err = Sync(ctx, r.Fremote, r.Flocal, true)
|
||||||
// testLoggerVsLsf(ctx, r.Fremote, r.Flocal, operations.GetLoggerOpt(ctx).JSON, t)
|
// testLoggerVsLsf(ctx, r.Fremote, r.Flocal, operations.GetLoggerOpt(ctx).JSON, t)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
|
accounting.GlobalStats().ResetCounters()
|
||||||
|
|
||||||
r.CheckLocalListing(t, []fstest.Item{file1}, []string{"toe", "toe/toe"})
|
r.CheckLocalListing(t, []fstest.Item{file1}, []string{"toe", "toe/toe"})
|
||||||
r.CheckRemoteListing(t, []fstest.Item{file1}, []string{"toe", "toe/toe"})
|
r.CheckRemoteListing(t, []fstest.Item{file1}, []string{"toe", "toe/toe"})
|
||||||
|
|||||||
Reference in New Issue
Block a user