From 8ca7b2af072e5b8dbafbf28ad00685225d6c9f5d Mon Sep 17 00:00:00 2001 From: tgfisher Date: Mon, 21 Oct 2024 00:10:09 -0700 Subject: [PATCH 01/39] docs: mention that inline comments are not supported in a filter-file --- docs/content/filtering.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/content/filtering.md b/docs/content/filtering.md index ffc898c25..c73e41f7b 100644 --- a/docs/content/filtering.md +++ b/docs/content/filtering.md @@ -505,6 +505,8 @@ processed in. Arrange the order of filter rules with the most restrictive first and work down. +Lines starting with # or ; are ignored, and can be used to write comments. Inline comments are not supported. _Use `-vv --dump filters` to see how they appear in the final regexp._ + E.g. for `filter-file.txt`: # a sample filter rule file @@ -512,6 +514,7 @@ E.g. for `filter-file.txt`: + *.jpg + *.png + file2.avi + - /dir/tmp/** # WARNING! This text will be treated as part of the path. - /dir/Trash/** + /dir/** # exclude everything else From 11a90917ec013ddd0bf4fc35d57ad2ecfe0ce100 Mon Sep 17 00:00:00 2001 From: Nick Craig-Wood Date: Mon, 21 Oct 2024 10:14:41 +0100 Subject: [PATCH 02/39] Add Simon Bos to contributors --- docs/content/authors.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/content/authors.md b/docs/content/authors.md index beac7491e..876a7f0d9 100644 --- a/docs/content/authors.md +++ b/docs/content/authors.md @@ -900,3 +900,4 @@ put them back in again.` >}} * lostb1t * Matthias Gatto * André Tran + * Simon Bos From 9f2c590e13e974e7a04d34483fccd8d855ac66ef Mon Sep 17 00:00:00 2001 From: Nick Craig-Wood Date: Mon, 21 Oct 2024 10:14:41 +0100 Subject: [PATCH 03/39] Add Alexandre Hamez to contributors --- docs/content/authors.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/content/authors.md b/docs/content/authors.md index 876a7f0d9..89a752cbe 100644 --- a/docs/content/authors.md +++ b/docs/content/authors.md @@ -901,3 +901,4 @@ put them back in again.` >}} * Matthias Gatto * André Tran * Simon Bos + * Alexandre Hamez <199517+ahamez@users.noreply.github.com> From 82a510e79346c69f6b2b9a9f5604afd4343ad848 Mon Sep 17 00:00:00 2001 From: Nick Craig-Wood Date: Mon, 21 Oct 2024 10:14:41 +0100 Subject: [PATCH 04/39] Add Randy Bush to contributors --- docs/content/authors.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/content/authors.md b/docs/content/authors.md index 89a752cbe..07bbc47ae 100644 --- a/docs/content/authors.md +++ b/docs/content/authors.md @@ -902,3 +902,4 @@ put them back in again.` >}} * André Tran * Simon Bos * Alexandre Hamez <199517+ahamez@users.noreply.github.com> + * Randy Bush From d97492cbc329c773047feb5dc991fef33f752c51 Mon Sep 17 00:00:00 2001 From: Nick Craig-Wood Date: Mon, 21 Oct 2024 10:14:41 +0100 Subject: [PATCH 05/39] Add Diego Monti to contributors --- docs/content/authors.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/content/authors.md b/docs/content/authors.md index 07bbc47ae..a7f7a6d85 100644 --- a/docs/content/authors.md +++ b/docs/content/authors.md @@ -903,3 +903,4 @@ put them back in again.` >}} * Simon Bos * Alexandre Hamez <199517+ahamez@users.noreply.github.com> * Randy Bush + * Diego Monti From 1b10cd3732e790d4d1820db1faa854a74613f17c Mon Sep 17 00:00:00 2001 From: Nick Craig-Wood Date: Mon, 21 Oct 2024 10:14:41 +0100 Subject: [PATCH 06/39] Add tgfisher to contributors --- docs/content/authors.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/content/authors.md b/docs/content/authors.md index a7f7a6d85..e2a6f847c 100644 --- a/docs/content/authors.md +++ b/docs/content/authors.md @@ -904,3 +904,4 @@ put them back in again.` >}} * Alexandre Hamez <199517+ahamez@users.noreply.github.com> * Randy Bush * Diego Monti + * tgfisher From 264c9fb2c00d85cc9cf294797d72e4f2af5c931d Mon Sep 17 00:00:00 2001 From: Nick Craig-Wood Date: Thu, 18 Jul 2024 16:40:48 +0100 Subject: [PATCH 07/39] drive: implement rclone backend rescue to rescue orphaned files Fixes #4166 --- backend/drive/drive.go | 103 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 97 insertions(+), 6 deletions(-) diff --git a/backend/drive/drive.go b/backend/drive/drive.go index f39800af0..f49603437 100644 --- a/backend/drive/drive.go +++ b/backend/drive/drive.go @@ -3559,7 +3559,8 @@ func (f *Fs) copyID(ctx context.Context, id, dest string) (err error) { return nil } -func (f *Fs) query(ctx context.Context, query string) (entries []*drive.File, err error) { +// Run the drive query calling fn on each entry found +func (f *Fs) queryFn(ctx context.Context, query string, fn func(*drive.File)) (err error) { list := f.svc.Files.List() if query != "" { list.Q(query) @@ -3578,10 +3579,7 @@ func (f *Fs) query(ctx context.Context, query string) (entries []*drive.File, er if f.rootFolderID == "appDataFolder" { list.Spaces("appDataFolder") } - fields := fmt.Sprintf("files(%s),nextPageToken,incompleteSearch", f.getFileFields(ctx)) - - var results []*drive.File for { var files *drive.FileList err = f.pacer.Call(func() (bool, error) { @@ -3589,20 +3587,66 @@ func (f *Fs) query(ctx context.Context, query string) (entries []*drive.File, er return f.shouldRetry(ctx, err) }) if err != nil { - return nil, fmt.Errorf("failed to execute query: %w", err) + return fmt.Errorf("failed to execute query: %w", err) } if files.IncompleteSearch { fs.Errorf(f, "search result INCOMPLETE") } - results = append(results, files.Files...) + for _, item := range files.Files { + fn(item) + } if files.NextPageToken == "" { break } list.PageToken(files.NextPageToken) } + return nil +} + +// Run the drive query returning the entries found +func (f *Fs) query(ctx context.Context, query string) (entries []*drive.File, err error) { + var results []*drive.File + err = f.queryFn(ctx, query, func(item *drive.File) { + results = append(results, item) + }) + if err != nil { + return nil, err + } return results, nil } +// Rescue, list or delete orphaned files +func (f *Fs) rescue(ctx context.Context, dirID string, delete bool) (err error) { + return f.queryFn(ctx, "'me' in owners and trashed=false", func(item *drive.File) { + if len(item.Parents) != 0 { + return + } + // Have found an orphaned entry + if delete { + fs.Infof(item.Name, "Deleting orphan %q into trash", item.Id) + err = f.delete(ctx, item.Id, true) + if err != nil { + fs.Errorf(item.Name, "Failed to delete orphan %q: %v", item.Id, err) + } + } else if dirID == "" { + operations.SyncPrintf("%q, %q\n", item.Name, item.Id) + } else { + fs.Infof(item.Name, "Rescuing orphan %q", item.Id) + err = f.pacer.Call(func() (bool, error) { + _, err = f.svc.Files.Update(item.Id, nil). + AddParents(dirID). + Fields(f.getFileFields(ctx)). + SupportsAllDrives(true). + Context(ctx).Do() + return f.shouldRetry(ctx, err) + }) + if err != nil { + fs.Errorf(item.Name, "Failed to rescue orphan %q: %v", item.Id, err) + } + } + }) +} + var commandHelp = []fs.CommandHelp{{ Name: "get", Short: "Get command for fetching the drive config parameters", @@ -3794,6 +3838,37 @@ The result is a JSON array of matches, for example: "webViewLink": "https://drive.google.com/file/d/0AxBe_CDEF4zkGHI4d0FjYko2QkD/view?usp=drivesdk\u0026resourcekey=0-ABCDEFGHIXJQpIGqBJq3MC" } ]`, +}, { + Name: "rescue", + Short: "Rescue or delete any orphaned files", + Long: `This command rescues or deletes any orphaned files or directories. + +Sometimes files can get orphaned in Google Drive. This means that they +are no longer in any folder in Google Drive. + +This command finds those files and either rescues them to a directory +you specify or deletes them. + +Usage: + +This can be used in 3 ways. + +First, list all orphaned files + + rclone backend rescue drive: + +Second rescue all orphaned files to the directory indicated + + rclone backend rescue drive: "relative/path/to/rescue/directory" + +e.g. To rescue all orphans to a directory called "Orphans" in the top level + + rclone backend rescue drive: Orphans + +Third delete all orphaned files to the trash + + rclone backend rescue drive: -o delete +`, }} // Command the backend to run a named command @@ -3922,6 +3997,22 @@ func (f *Fs) Command(ctx context.Context, name string, arg []string, opt map[str } else { return nil, errors.New("need a query argument") } + case "rescue": + dirID := "" + _, delete := opt["delete"] + if len(arg) == 0 { + // no arguments - list only + } else if !delete && len(arg) == 1 { + dir := arg[0] + dirID, err = f.dirCache.FindDir(ctx, dir, true) + if err != nil { + return nil, fmt.Errorf("failed to find or create rescue directory %q: %w", dir, err) + } + fs.Infof(f, "Rescuing orphans into %q", dir) + } else { + return nil, errors.New("syntax error: need 0 or 1 args or -o delete") + } + return nil, f.rescue(ctx, dirID, delete) default: return nil, fs.ErrorCommandNotFound } From 8b4b59412df4c7052c4402284daf9d998d636b4e Mon Sep 17 00:00:00 2001 From: Nick Craig-Wood Date: Tue, 8 Oct 2024 10:35:29 +0100 Subject: [PATCH 08/39] fs: fix Don't know how to set key "chunkSize" on upload errors in tests Before this testing any backend which implemented the OpenChunkWriter gave this error: ERROR : writer-at-subdir/writer-at-file: Don't know how to set key "chunkSize" on upload This was due to the ChunkOption incorrectly rendering into HTTP headers which weren't understood by the backend. --- fs/open_options.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/open_options.go b/fs/open_options.go index cbcd98cb7..cb48a930e 100644 --- a/fs/open_options.go +++ b/fs/open_options.go @@ -293,7 +293,7 @@ type ChunkOption struct { // Header formats the option as an http header func (o *ChunkOption) Header() (key string, value string) { - return "chunkSize", fmt.Sprintf("%v", o.ChunkSize) + return "", "" } // Mandatory returns whether the option must be parsed or can be ignored From 53ff3b3b32cb904e3a45226921c8bbdfcec2e014 Mon Sep 17 00:00:00 2001 From: Nick Craig-Wood Date: Wed, 9 Oct 2024 10:08:08 +0100 Subject: [PATCH 09/39] s3: add Selectel as a provider --- README.md | 1 + backend/s3/s3.go | 31 +++++++++-- docs/content/_index.md | 1 + docs/content/s3.md | 120 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 149 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index d1e859244..1f47ee914 100644 --- a/README.md +++ b/README.md @@ -111,6 +111,7 @@ Rclone *("rsync for cloud storage")* is a command-line program to sync files and * Scaleway [:page_facing_up:](https://rclone.org/s3/#scaleway) * Seafile [:page_facing_up:](https://rclone.org/seafile/) * SeaweedFS [:page_facing_up:](https://rclone.org/s3/#seaweedfs) + * Selectel Object Storage [:page_facing_up:](https://rclone.org/s3/#selectel) * SFTP [:page_facing_up:](https://rclone.org/sftp/) * SMB / CIFS [:page_facing_up:](https://rclone.org/smb/) * StackPath [:page_facing_up:](https://rclone.org/s3/#stackpath) diff --git a/backend/s3/s3.go b/backend/s3/s3.go index ccec63e89..eda36a259 100644 --- a/backend/s3/s3.go +++ b/backend/s3/s3.go @@ -154,6 +154,9 @@ var providerOption = fs.Option{ }, { Value: "SeaweedFS", Help: "SeaweedFS S3", + }, { + Value: "Selectel", + Help: "Selectel Object Storage", }, { Value: "StackPath", Help: "StackPath Object Storage", @@ -551,10 +554,19 @@ func init() { Value: "tw-001", Help: "Asia (Taiwan)", }}, + }, { + // See endpoints for object storage regions: https://docs.selectel.ru/en/cloud/object-storage/manage/domains/#s3-api-domains + Name: "region", + Help: "Region where your data stored.\n", + Provider: "Selectel", + Examples: []fs.OptionExample{{ + Value: "ru-1", + Help: "St. Petersburg", + }}, }, { Name: "region", Help: "Region to connect to.\n\nLeave blank if you are using an S3 clone and you don't have a region.", - Provider: "!AWS,Alibaba,ArvanCloud,ChinaMobile,Cloudflare,IONOS,Petabox,Liara,Linode,Magalu,Qiniu,RackCorp,Scaleway,Storj,Synology,TencentCOS,HuaweiOBS,IDrive", + Provider: "!AWS,Alibaba,ArvanCloud,ChinaMobile,Cloudflare,IONOS,Petabox,Liara,Linode,Magalu,Qiniu,RackCorp,Scaleway,Selectel,Storj,Synology,TencentCOS,HuaweiOBS,IDrive", Examples: []fs.OptionExample{{ Value: "", Help: "Use this if unsure.\nWill use v4 signatures and an empty region.", @@ -1319,10 +1331,19 @@ func init() { Value: "s3-ap-northeast-1.qiniucs.com", Help: "Northeast Asia Endpoint 1", }}, + }, { + // Selectel endpoints: https://docs.selectel.ru/en/cloud/object-storage/manage/domains/#s3-api-domains + Name: "endpoint", + Help: "Endpoint for Selectel Object Storage.", + Provider: "Selectel", + Examples: []fs.OptionExample{{ + Value: "s3.ru-1.storage.selcloud.ru", + Help: "Saint Petersburg", + }}, }, { Name: "endpoint", Help: "Endpoint for S3 API.\n\nRequired when using an S3 clone.", - Provider: "!AWS,ArvanCloud,IBMCOS,IDrive,IONOS,TencentCOS,HuaweiOBS,Alibaba,ChinaMobile,GCS,Liara,Linode,MagaluCloud,Scaleway,StackPath,Storj,Synology,RackCorp,Qiniu,Petabox", + Provider: "!AWS,ArvanCloud,IBMCOS,IDrive,IONOS,TencentCOS,HuaweiOBS,Alibaba,ChinaMobile,GCS,Liara,Linode,MagaluCloud,Scaleway,Selectel,StackPath,Storj,Synology,RackCorp,Qiniu,Petabox", Examples: []fs.OptionExample{{ Value: "objects-us-east-1.dream.io", Help: "Dream Objects endpoint", @@ -1845,7 +1866,7 @@ func init() { }, { Name: "location_constraint", Help: "Location constraint - must be set to match the Region.\n\nLeave blank if not sure. Used when creating buckets only.", - Provider: "!AWS,Alibaba,ArvanCloud,HuaweiOBS,ChinaMobile,Cloudflare,IBMCOS,IDrive,IONOS,Leviia,Liara,Linode,Magalu,Outscale,Qiniu,RackCorp,Scaleway,StackPath,Storj,TencentCOS,Petabox", + Provider: "!AWS,Alibaba,ArvanCloud,HuaweiOBS,ChinaMobile,Cloudflare,IBMCOS,IDrive,IONOS,Leviia,Liara,Linode,Magalu,Outscale,Qiniu,RackCorp,Scaleway,Selectel,StackPath,Storj,TencentCOS,Petabox", }, { Name: "acl", Help: `Canned ACL used when creating buckets and storing or copying objects. @@ -1860,7 +1881,7 @@ doesn't copy the ACL from the source but rather writes a fresh one. If the acl is an empty string then no X-Amz-Acl: header is added and the default (private) will be used. `, - Provider: "!Storj,Synology,Cloudflare", + Provider: "!Storj,Selectel,Synology,Cloudflare", Examples: []fs.OptionExample{{ Value: "default", Help: "Owner gets Full_CONTROL.\nNo one else has access rights (default).", @@ -3430,6 +3451,8 @@ func setQuirks(opt *Options) { } urlEncodeListings = true useAlreadyExists = true + case "Selectel": + urlEncodeListings = false case "SeaweedFS": listObjectsV2 = false // untested virtualHostStyle = false diff --git a/docs/content/_index.md b/docs/content/_index.md index 45abcfef0..711b55041 100644 --- a/docs/content/_index.md +++ b/docs/content/_index.md @@ -178,6 +178,7 @@ WebDAV or S3, that work out of the box.) {{< provider name="Seafile" home="https://www.seafile.com/" config="/seafile/" >}} {{< provider name="Seagate Lyve Cloud" home="https://www.seagate.com/gb/en/services/cloud/storage/" config="/s3/#lyve" >}} {{< provider name="SeaweedFS" home="https://github.com/chrislusf/seaweedfs/" config="/s3/#seaweedfs" >}} +{{< provider name="Selectel" home="https://selectel.ru/services/cloud/storage/" config="/s3/#selectel" >}} {{< provider name="SFTP" home="https://en.wikipedia.org/wiki/SSH_File_Transfer_Protocol" config="/sftp/" >}} {{< provider name="Sia" home="https://sia.tech/" config="/sia/" >}} {{< provider name="SMB / CIFS" home="https://en.wikipedia.org/wiki/Server_Message_Block" config="/smb/" >}} diff --git a/docs/content/s3.md b/docs/content/s3.md index 0a0f553f1..58b16b79a 100644 --- a/docs/content/s3.md +++ b/docs/content/s3.md @@ -35,6 +35,7 @@ The S3 backend can be used with a number of different providers: {{< provider name="Scaleway" home="https://www.scaleway.com/en/object-storage/" config="/s3/#scaleway" >}} {{< provider name="Seagate Lyve Cloud" home="https://www.seagate.com/gb/en/services/cloud/storage/" config="/s3/#lyve" >}} {{< provider name="SeaweedFS" home="https://github.com/chrislusf/seaweedfs/" config="/s3/#seaweedfs" >}} +{{< provider name="Selectel" home="https://selectel.ru/services/cloud/storage/" config="/s3/#selectel" >}} {{< provider name="StackPath" home="https://www.stackpath.com/products/object-storage/" config="/s3/#stackpath" >}} {{< provider name="Storj" home="https://storj.io/" config="/s3/#storj" >}} {{< provider name="Synology C2 Object Storage" home="https://c2.synology.com/en-global/object-storage/overview" config="/s3/#synology-c2" >}} @@ -3850,6 +3851,125 @@ So once set up, for example to copy files into a bucket rclone copy /path/to/files seaweedfs_s3:foo ``` +### Selectel + +[Selectel Cloud Storage](https://selectel.ru/services/cloud/storage/) +is an S3 compatible storage system which features triple redundancy +storage, automatic scaling, high availability and a comprehensive IAM +system. + +Selectel have a section on their website for [configuring +rclone](https://docs.selectel.ru/en/cloud/object-storage/tools/rclone/) +which shows how to make the right API keys. + +From rclone v1.69 Selectel is a supported operator - please choose the +`Selectel` provider type. + +Note that you should use "vHosted" access for the buckets (which is +the recommended default), not "path style". + +You can use `rclone config` to make a new provider like this + +``` +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> selectel + +Option Storage. +Type of storage to configure. +Choose a number from below, or type in your own value. +[snip] +XX / Amazon S3 Compliant Storage Providers including ..., Selectel, ... + \ (s3) +[snip] +Storage> s3 + +Option provider. +Choose your S3 provider. +Choose a number from below, or type in your own value. +Press Enter to leave empty. +[snip] +XX / Selectel Object Storage + \ (Selectel) +[snip] +provider> Selectel + +Option env_auth. +Get AWS credentials from runtime (environment variables or EC2/ECS meta data if no env vars). +Only applies if access_key_id and secret_access_key is blank. +Choose a number from below, or type in your own boolean value (true or false). +Press Enter for the default (false). + 1 / Enter AWS credentials in the next step. + \ (false) + 2 / Get AWS credentials from the environment (env vars or IAM). + \ (true) +env_auth> 1 + +Option access_key_id. +AWS Access Key ID. +Leave blank for anonymous access or runtime credentials. +Enter a value. Press Enter to leave empty. +access_key_id> ACCESS_KEY + +Option secret_access_key. +AWS Secret Access Key (password). +Leave blank for anonymous access or runtime credentials. +Enter a value. Press Enter to leave empty. +secret_access_key> SECRET_ACCESS_KEY + +Option region. +Region where your data stored. +Choose a number from below, or type in your own value. +Press Enter to leave empty. + 1 / St. Petersburg + \ (ru-1) +region> 1 + +Option endpoint. +Endpoint for Selectel Object Storage. +Choose a number from below, or type in your own value. +Press Enter to leave empty. + 1 / Saint Petersburg + \ (s3.ru-1.storage.selcloud.ru) +endpoint> 1 + +Edit advanced config? +y) Yes +n) No (default) +y/n> n + +Configuration complete. +Options: +- type: s3 +- provider: Selectel +- access_key_id: ACCESS_KEY +- secret_access_key: SECRET_ACCESS_KEY +- region: ru-1 +- endpoint: s3.ru-1.storage.selcloud.ru +Keep this "selectel" remote? +y) Yes this is OK (default) +e) Edit this remote +d) Delete this remote +y/e/d> y +``` + +And your config should end up looking like this: + +``` +[selectel] +type = s3 +provider = Selectel +access_key_id = ACCESS_KEY +secret_access_key = SECRET_ACCESS_KEY +region = ru-1 +endpoint = s3.ru-1.storage.selcloud.ru +``` + ### Wasabi [Wasabi](https://wasabi.com) is a cloud-based object storage service for a From 75257fc9cdcaba71aba29e733c75c253fcf1540d Mon Sep 17 00:00:00 2001 From: Kaloyan Raev Date: Wed, 16 Oct 2024 17:33:01 +0300 Subject: [PATCH 10/39] s3: Storj provider: fix server-side copy of files bigger than 5GB Like some other S3-compatible providers, Storj does not currently implements UploadPartCopy and returns NotImplemented errors for multi-part server side copies. This patch works around the problem by raising --s3-copy-cutoff for Storj to the maximum. This means that rclone will never use multi-part copies for files in Storj. This includes files larger than 5GB which (according to AWS documentation) must be copied with multi-part copy. This works fine for Storj. See https://github.com/storj/roadmap/issues/40 --- backend/s3/s3.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/backend/s3/s3.go b/backend/s3/s3.go index eda36a259..3c62dd3c5 100644 --- a/backend/s3/s3.go +++ b/backend/s3/s3.go @@ -3470,6 +3470,10 @@ func setQuirks(opt *Options) { opt.ChunkSize = 64 * fs.Mebi } useAlreadyExists = false // returns BucketAlreadyExists + // Storj doesn't support multi-part server side copy: + // https://github.com/storj/roadmap/issues/40 + // So make cutoff very large which it does support + opt.CopyCutoff = math.MaxInt64 case "Synology": useMultipartEtag = false useAlreadyExists = false // untested From 175aa07cddff5352857f54ea0fea92dc940afde7 Mon Sep 17 00:00:00 2001 From: Nick Craig-Wood Date: Thu, 3 Oct 2024 10:29:07 +0100 Subject: [PATCH 11/39] onedrive: fix Retry-After handling to look at 503 errors also According to the Microsoft docs a Retry-After header can be returned on 429 errors and 503 errors, but before this change we were only checking for it on 429 errors. See: https://forum.rclone.org/t/onedrive-503-response-retry-after-not-used/48045 --- backend/onedrive/onedrive.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/onedrive/onedrive.go b/backend/onedrive/onedrive.go index 3ceac3f55..f7555017e 100644 --- a/backend/onedrive/onedrive.go +++ b/backend/onedrive/onedrive.go @@ -827,7 +827,7 @@ func shouldRetry(ctx context.Context, resp *http.Response, err error) (bool, err retry = true fs.Debugf(nil, "HTTP 401: Unable to initialize RPS. Trying again.") } - case 429: // Too Many Requests. + case 429, 503: // Too Many Requests, Server Too Busy // see https://docs.microsoft.com/en-us/sharepoint/dev/general-development/how-to-avoid-getting-throttled-or-blocked-in-sharepoint-online if values := resp.Header["Retry-After"]; len(values) == 1 && values[0] != "" { retryAfter, parseErr := strconv.Atoi(values[0]) From 29fd89418965d375322886f7f198f689931e9cac Mon Sep 17 00:00:00 2001 From: Moises Lima Date: Thu, 10 Oct 2024 14:42:42 -0300 Subject: [PATCH 12/39] lib/http: disable automatic authentication skipping for unix sockets Disabling the authentication for unix sockets makes it impossible to use `rclone serve` behind a proxy that that communicates with rclone via a unix socket. Re-enabling the authentication should not have any effect on most users of unix sockets as they do not set authentication up with a unix socket anyway. --- lib/http/context.go | 6 --- lib/http/middleware.go | 15 ------ lib/http/server.go | 3 +- lib/http/server_test.go | 107 +++++++++++++++++++++++++++++----------- 4 files changed, 80 insertions(+), 51 deletions(-) diff --git a/lib/http/context.go b/lib/http/context.go index 239572c75..cbb551568 100644 --- a/lib/http/context.go +++ b/lib/http/context.go @@ -36,12 +36,6 @@ func IsAuthenticated(r *http.Request) bool { return false } -// IsUnixSocket checks if the request was received on a unix socket, used to skip auth & CORS -func IsUnixSocket(r *http.Request) bool { - v, _ := r.Context().Value(ctxKeyUnixSock).(bool) - return v -} - // PublicURL returns the URL defined in NewBaseContext, used for logging & CORS func PublicURL(r *http.Request) string { v, _ := r.Context().Value(ctxKeyPublicURL).(string) diff --git a/lib/http/middleware.go b/lib/http/middleware.go index 06b82278b..8030ec4f1 100644 --- a/lib/http/middleware.go +++ b/lib/http/middleware.go @@ -57,11 +57,6 @@ func NewLoggedBasicAuthenticator(realm string, secrets goauth.SecretProvider) *L func basicAuth(authenticator *LoggedBasicAuth) func(next http.Handler) http.Handler { return func(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - // skip auth for unix socket - if IsUnixSocket(r) { - next.ServeHTTP(w, r) - return - } // skip auth for CORS preflight if r.Method == "OPTIONS" { next.ServeHTTP(w, r) @@ -123,11 +118,6 @@ func MiddlewareAuthBasic(user, pass, realm, salt string) Middleware { func MiddlewareAuthCustom(fn CustomAuthFn, realm string, userFromContext bool) Middleware { return func(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - // skip auth for unix socket - if IsUnixSocket(r) { - next.ServeHTTP(w, r) - return - } // skip auth for CORS preflight if r.Method == "OPTIONS" { next.ServeHTTP(w, r) @@ -175,11 +165,6 @@ func MiddlewareCORS(allowOrigin string) Middleware { return func(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - // skip cors for unix sockets - if IsUnixSocket(r) { - next.ServeHTTP(w, r) - return - } if allowOrigin != "" { w.Header().Add("Access-Control-Allow-Origin", allowOrigin) diff --git a/lib/http/server.go b/lib/http/server.go index acc07c4b2..9964c297e 100644 --- a/lib/http/server.go +++ b/lib/http/server.go @@ -39,8 +39,7 @@ If you set ` + "`--{{ .Prefix }}addr`" + ` to listen on a public or LAN accessib then using Authentication is advised - see the next section for info. You can use a unix socket by setting the url to ` + "`unix:///path/to/socket`" + ` -or just by using an absolute path name. Note that unix sockets bypass the -authentication - this is expected to be done with file system permissions. +or just by using an absolute path name. ` + "`--{{ .Prefix }}addr`" + ` may be repeated to listen on multiple IPs/ports/sockets. Socket activation, described further below, can also be used to accomplish the same. diff --git a/lib/http/server_test.go b/lib/http/server_test.go index 0c636d274..22e49580b 100644 --- a/lib/http/server_test.go +++ b/lib/http/server_test.go @@ -3,6 +3,7 @@ package http import ( "context" "crypto/tls" + "fmt" "io" "net" "net/http" @@ -63,46 +64,96 @@ func testReadTestdataFile(t *testing.T, path string) []byte { } func TestNewServerUnix(t *testing.T) { - ctx := context.Background() - tempDir := t.TempDir() path := filepath.Join(tempDir, "rclone.sock") - cfg := DefaultCfg() - cfg.ListenAddr = []string{path} - - auth := AuthConfig{ - BasicUser: "test", - BasicPass: "test", + servers := []struct { + name string + status int + result string + cfg Config + auth AuthConfig + user string + pass string + }{ + { + name: "ServerWithoutAuth/NoCreds", + status: http.StatusOK, + result: "hello world", + cfg: Config{ + ListenAddr: []string{path}, + }, + }, { + name: "ServerWithAuth/NoCreds", + status: http.StatusUnauthorized, + cfg: Config{ + ListenAddr: []string{path}, + }, + auth: AuthConfig{ + BasicUser: "test", + BasicPass: "test", + }, + }, { + name: "ServerWithAuth/GoodCreds", + status: http.StatusOK, + result: "hello world", + cfg: Config{ + ListenAddr: []string{path}, + }, + auth: AuthConfig{ + BasicUser: "test", + BasicPass: "test", + }, + user: "test", + pass: "test", + }, { + name: "ServerWithAuth/BadCreds", + status: http.StatusUnauthorized, + cfg: Config{ + ListenAddr: []string{path}, + }, + auth: AuthConfig{ + BasicUser: "test", + BasicPass: "test", + }, + user: "testBAD", + pass: "testBAD", + }, } - s, err := NewServer(ctx, WithConfig(cfg), WithAuth(auth)) - require.NoError(t, err) - defer func() { - require.NoError(t, s.Shutdown()) - _, err := os.Stat(path) - require.ErrorIs(t, err, os.ErrNotExist, "shutdown should remove socket") - }() + for _, ss := range servers { + t.Run(ss.name, func(t *testing.T) { + s, err := NewServer(context.Background(), WithConfig(ss.cfg), WithAuth(ss.auth)) + require.NoError(t, err) + defer func() { + require.NoError(t, s.Shutdown()) + _, err := os.Stat(path) + require.ErrorIs(t, err, os.ErrNotExist, "shutdown should remove socket") + }() - require.Empty(t, s.URLs(), "unix socket should not appear in URLs") + require.Empty(t, s.URLs(), "unix socket should not appear in URLs") - expected := []byte("hello world") - s.Router().Mount("/", testEchoHandler(expected)) - s.Serve() + s.Router().Mount("/", testEchoHandler([]byte(ss.result))) + s.Serve() - client := testNewHTTPClientUnix(path) - req, err := http.NewRequest("GET", "http://unix", nil) - require.NoError(t, err) + client := testNewHTTPClientUnix(path) + req, err := http.NewRequest("GET", "http://unix", nil) + require.NoError(t, err) - resp, err := client.Do(req) - require.NoError(t, err) + req.SetBasicAuth(ss.user, ss.pass) - testExpectRespBody(t, resp, expected) + resp, err := client.Do(req) + require.NoError(t, err) + defer func() { + _ = resp.Body.Close() + }() - require.Equal(t, http.StatusOK, resp.StatusCode, "unix sockets should ignore auth") + require.Equal(t, ss.status, resp.StatusCode, fmt.Sprintf("should return status %d", ss.status)) - for _, key := range _testCORSHeaderKeys { - require.NotContains(t, resp.Header, key, "unix sockets should not be sent CORS headers") + if ss.result != "" { + testExpectRespBody(t, resp, []byte(ss.result)) + } + }) } } From c527dd8c9c92d5046c2b692f7b3e8dda8a667bab Mon Sep 17 00:00:00 2001 From: Nick Craig-Wood Date: Thu, 24 Oct 2024 17:56:42 +0100 Subject: [PATCH 13/39] Add Moises Lima to contributors --- docs/content/authors.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/content/authors.md b/docs/content/authors.md index e2a6f847c..a8cf95206 100644 --- a/docs/content/authors.md +++ b/docs/content/authors.md @@ -905,3 +905,4 @@ put them back in again.` >}} * Randy Bush * Diego Monti * tgfisher + * Moises Lima From 72f06bcc4b513858d3dfa1cee65e82f97cd6ab24 Mon Sep 17 00:00:00 2001 From: Nick Craig-Wood Date: Thu, 24 Oct 2024 13:12:11 +0100 Subject: [PATCH 14/39] lib/oauthutil: allow the browser opening function to be overridden --- lib/oauthutil/oauthutil.go | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/lib/oauthutil/oauthutil.go b/lib/oauthutil/oauthutil.go index 2f3d5278f..dae98a3f2 100644 --- a/lib/oauthutil/oauthutil.go +++ b/lib/oauthutil/oauthutil.go @@ -80,6 +80,11 @@ All done. Please go back to rclone. ` ) +// OpenURL is used when rclone wants to open a browser window +// for user authentication. It defaults to something which +// should work for most uses, but may be overridden. +var OpenURL = open.Start + // SharedOptions are shared between backends the utilize an OAuth flow var SharedOptions = []fs.Option{{ Name: config.ConfigClientID, @@ -716,8 +721,12 @@ func configSetup(ctx context.Context, id, name string, m configmap.Mapper, oauth if !authorizeNoAutoBrowser { // Open the URL for the user to visit - _ = open.Start(authURL) - fs.Logf(nil, "If your browser doesn't open automatically go to the following link: %s\n", authURL) + err := OpenURL(authURL) + if err != nil { + fs.Errorf(nil, "Failed to open browser automatically (%v) - please go to the following link: %s\n", err, authURL) + } else { + fs.Logf(nil, "If your browser doesn't open automatically go to the following link: %s\n", authURL) + } } else { fs.Logf(nil, "Please go to the following link: %s\n", authURL) } From 16baa24964e1b937381195c055b598744e285b51 Mon Sep 17 00:00:00 2001 From: Nick Craig-Wood Date: Thu, 24 Oct 2024 11:20:37 +0100 Subject: [PATCH 15/39] serve s3: fix excess locking which was making serve s3 single threaded The fix for this was in the upstream library to narrow the locking window. See: https://forum.rclone.org/t/can-rclone-serve-s3-handle-more-than-one-client/48329/ --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 954905cd1..fd6c96bc8 100644 --- a/go.mod +++ b/go.mod @@ -59,7 +59,7 @@ require ( github.com/prometheus/client_golang v1.19.1 github.com/putdotio/go-putio/putio v0.0.0-20200123120452-16d982cac2b8 github.com/quasilyte/go-ruleguard/dsl v0.3.22 - github.com/rclone/gofakes3 v0.0.3-0.20240807151802-e80146f8de87 + github.com/rclone/gofakes3 v0.0.3 github.com/rfjakob/eme v1.1.2 github.com/rivo/uniseg v0.4.7 github.com/rogpeppe/go-internal v1.12.0 diff --git a/go.sum b/go.sum index 81ff97f66..e1dff78eb 100644 --- a/go.sum +++ b/go.sum @@ -519,8 +519,8 @@ github.com/quic-go/quic-go v0.40.1 h1:X3AGzUNFs0jVuO3esAGnTfvdgvL4fq655WaOi1snv1 github.com/quic-go/quic-go v0.40.1/go.mod h1:PeN7kuVJ4xZbxSv/4OX6S1USOX8MJvydwpTx31vx60c= github.com/rasky/go-xdr v0.0.0-20170124162913-1a41d1a06c93 h1:UVArwN/wkKjMVhh2EQGC0tEc1+FqiLlvYXY5mQ2f8Wg= github.com/rasky/go-xdr v0.0.0-20170124162913-1a41d1a06c93/go.mod h1:Nfe4efndBz4TibWycNE+lqyJZiMX4ycx+QKV8Ta0f/o= -github.com/rclone/gofakes3 v0.0.3-0.20240807151802-e80146f8de87 h1:0YRo2aYhE+SCZsjWYMFe8zLD18xieXy7wQ8M9Ywcr/g= -github.com/rclone/gofakes3 v0.0.3-0.20240807151802-e80146f8de87/go.mod h1:z7+o2VUwitO0WuVHReQlOW9jZ03LpeJ0PUFSULyTIds= +github.com/rclone/gofakes3 v0.0.3 h1:0sKCxJ8TUUAG5KXGuc/fcDKGnzB/j6IjNQui9ntIZPo= +github.com/rclone/gofakes3 v0.0.3/go.mod h1:z7+o2VUwitO0WuVHReQlOW9jZ03LpeJ0PUFSULyTIds= github.com/relvacode/iso8601 v1.3.0 h1:HguUjsGpIMh/zsTczGN3DVJFxTU/GX+MMmzcKoMO7ko= github.com/relvacode/iso8601 v1.3.0/go.mod h1:FlNp+jz+TXpyRqgmM7tnzHHzBnz776kmAH2h3sZCn0I= github.com/rfjakob/eme v1.1.2 h1:SxziR8msSOElPayZNFfQw4Tjx/Sbaeeh3eRvrHVMUs4= From 40159e7a1615b4c48ed66a8e4fd1346aaf1c7138 Mon Sep 17 00:00:00 2001 From: Dimitar Ivanov Date: Fri, 25 Oct 2024 12:40:57 +0300 Subject: [PATCH 16/39] sftp: allow inline ssh public certificate for sftp Currently rclone allows us to specify the path to a public ssh certificate file. That works great for cases where we can specify key path, like local envs. If users are using rclone with [volsync](https://github.com/backube/volsync/tree/main/docs/usage/rclone) there currently is a limitation that users can specify only the rclone config file. With this change users can pass the public certificate in the same fashion as they can with `key_file`. --- backend/sftp/sftp.go | 26 ++++++++++++++++++++------ docs/content/sftp.md | 15 ++++++++++++++- 2 files changed, 34 insertions(+), 7 deletions(-) diff --git a/backend/sftp/sftp.go b/backend/sftp/sftp.go index e47e47db2..c3c60aade 100644 --- a/backend/sftp/sftp.go +++ b/backend/sftp/sftp.go @@ -99,6 +99,11 @@ Only PEM encrypted key files (old OpenSSH format) are supported. Encrypted keys in the new OpenSSH format can't be used.`, IsPassword: true, Sensitive: true, + }, { + Name: "pubkey", + Help: `SSH public certificate for public certificate based authentication. +Set this if you have a signed certificate you want to use for authentication. +If specified will override pubkey_file.`, }, { Name: "pubkey_file", Help: `Optional path to public key file. @@ -511,6 +516,7 @@ type Options struct { KeyPem string `config:"key_pem"` KeyFile string `config:"key_file"` KeyFilePass string `config:"key_file_pass"` + PubKey string `config:"pubkey"` PubKeyFile string `config:"pubkey_file"` KnownHostsFile string `config:"known_hosts_file"` KeyUseAgent bool `config:"key_use_agent"` @@ -997,13 +1003,21 @@ func NewFs(ctx context.Context, name, root string, m configmap.Mapper) (fs.Fs, e } // If a public key has been specified then use that - if pubkeyFile != "" { - certfile, err := os.ReadFile(pubkeyFile) - if err != nil { - return nil, fmt.Errorf("unable to read cert file: %w", err) + if pubkeyFile != "" || opt.PubKey != "" { + pubKeyRaw := []byte(opt.PubKey) + // Use this error if public key is provided inline and is not a certificate + // if public key file is provided instead, use the err in the if block + notACertError := errors.New("public key provided is not a certificate: " + opt.PubKey) + if opt.PubKey == "" { + notACertError = errors.New("public key file is not a certificate file: " + pubkeyFile) + err := error(nil) + pubKeyRaw, err = os.ReadFile(pubkeyFile) + if err != nil { + return nil, fmt.Errorf("unable to read cert file: %w", err) + } } - pk, _, _, _, err := ssh.ParseAuthorizedKey(certfile) + pk, _, _, _, err := ssh.ParseAuthorizedKey(pubKeyRaw) if err != nil { return nil, fmt.Errorf("unable to parse cert file: %w", err) } @@ -1017,7 +1031,7 @@ func NewFs(ctx context.Context, name, root string, m configmap.Mapper) (fs.Fs, e // knows everything it needs. cert, ok := pk.(*ssh.Certificate) if !ok { - return nil, errors.New("public key file is not a certificate file: " + pubkeyFile) + return nil, notACertError } pubsigner, err := ssh.NewCertSigner(cert, signer) if err != nil { diff --git a/docs/content/sftp.md b/docs/content/sftp.md index 2ba4a48a7..56f4d98dc 100644 --- a/docs/content/sftp.md +++ b/docs/content/sftp.md @@ -156,7 +156,7 @@ and the public key built into it will be used during the authentication process. If you have a certificate you may use it to sign your public key, creating a separate SSH user certificate that should be used instead of the plain public key extracted from the private key. Then you must provide the path to the -user certificate public key file in `pubkey_file`. +user certificate public key file in `pubkey_file` or the content of the file in `pubkey`. Note: This is not the traditional public key paired with your private key, typically saved as `/home/$USER/.ssh/id_rsa.pub`. Setting this path in @@ -494,6 +494,19 @@ Properties: - Type: string - Required: false +#### --sftp-pubkey + +SSH public certificate for public certificate based authentication. +Set this if you have a signed certificate you want to use for authentication. +If specified will override pubkey_file. + +Properties: + +- Config: pubkey +- Env Var: RCLONE_SFTP_PUBKEY +- Type: string +- Required: false + #### --sftp-pubkey-file Optional path to public key file. From b9207e57274cd6e7c488c5bd751a058ba0f8b3b9 Mon Sep 17 00:00:00 2001 From: shenpengfeng Date: Tue, 29 Oct 2024 16:26:37 +0800 Subject: [PATCH 17/39] docs: fix function name in comment --- cmdtest/environment_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmdtest/environment_test.go b/cmdtest/environment_test.go index 2c161bf49..47410c687 100644 --- a/cmdtest/environment_test.go +++ b/cmdtest/environment_test.go @@ -15,7 +15,7 @@ import ( "github.com/stretchr/testify/require" ) -// TestCmdTest demonstrates and verifies the test functions for end-to-end testing of rclone +// TestEnvironmentVariables demonstrates and verifies the test functions for end-to-end testing of rclone func TestEnvironmentVariables(t *testing.T) { createTestEnvironment(t) From e3053350f3916998d99a91cb73522362723c4288 Mon Sep 17 00:00:00 2001 From: Nick Craig-Wood Date: Fri, 8 Nov 2024 10:02:31 +0000 Subject: [PATCH 18/39] Add Dimitar Ivanov to contributors --- docs/content/authors.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/content/authors.md b/docs/content/authors.md index a8cf95206..85a7458ff 100644 --- a/docs/content/authors.md +++ b/docs/content/authors.md @@ -906,3 +906,4 @@ put them back in again.` >}} * Diego Monti * tgfisher * Moises Lima + * Dimitar Ivanov From 0ad925278d7d65904319fe55829c14261d8172b5 Mon Sep 17 00:00:00 2001 From: Nick Craig-Wood Date: Fri, 8 Nov 2024 10:02:31 +0000 Subject: [PATCH 19/39] Add shenpengfeng to contributors --- docs/content/authors.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/content/authors.md b/docs/content/authors.md index 85a7458ff..ddc85ad0c 100644 --- a/docs/content/authors.md +++ b/docs/content/authors.md @@ -907,3 +907,4 @@ put them back in again.` >}} * tgfisher * Moises Lima * Dimitar Ivanov + * shenpengfeng From 2f7a30cf61526869324ef714a696601cd61cb1b3 Mon Sep 17 00:00:00 2001 From: Nick Craig-Wood Date: Fri, 8 Nov 2024 10:00:47 +0000 Subject: [PATCH 20/39] test_all: try to fix mailru rate limits in integration tests The Mailru backend integration tests have been failing due to new rate limits on the backend. This patch - Removes Mailru from the chunker tests - Adds the flag so we only run one Mailru test at once --- fstest/test_all/config.yaml | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/fstest/test_all/config.yaml b/fstest/test_all/config.yaml index 3aa68afab..1565c7e8e 100644 --- a/fstest/test_all/config.yaml +++ b/fstest/test_all/config.yaml @@ -55,17 +55,17 @@ backends: remote: "TestChunkerChunk3bNoRenameLocal:" fastlist: true maxfile: 6k - - backend: "chunker" - remote: "TestChunkerMailru:" - fastlist: true - ignore: - - TestApplyTransforms - - backend: "chunker" - remote: "TestChunkerChunk50bMailru:" - fastlist: true - maxfile: 10k - ignore: - - TestApplyTransforms + # - backend: "chunker" + # remote: "TestChunkerMailru:" + # fastlist: true + # ignore: + # - TestApplyTransforms + # - backend: "chunker" + # remote: "TestChunkerChunk50bMailru:" + # fastlist: true + # maxfile: 10k + # ignore: + # - TestApplyTransforms - backend: "chunker" remote: "TestChunkerChunk50bYandex:" fastlist: true @@ -449,6 +449,7 @@ backends: remote: "TestMailru:" subdir: false fastlist: false + oneonly: true ignore: - TestApplyTransforms - backend: "seafile" From 3e14ba54b8093e2ee9afc5298333309903a7d48b Mon Sep 17 00:00:00 2001 From: Nick Craig-Wood Date: Fri, 8 Nov 2024 14:01:51 +0000 Subject: [PATCH 21/39] gofile: fix server side copying over existing object This was creating a duplicate. --- backend/gofile/gofile.go | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/backend/gofile/gofile.go b/backend/gofile/gofile.go index 8f7b98b89..ca4091046 100644 --- a/backend/gofile/gofile.go +++ b/backend/gofile/gofile.go @@ -1214,7 +1214,7 @@ func (f *Fs) copyTo(ctx context.Context, srcID, srcLeaf, dstLeaf, dstDirectoryID // Will only be called if src.Fs().Name() == f.Name() // // If it isn't possible then return fs.ErrorCantCopy -func (f *Fs) Copy(ctx context.Context, src fs.Object, remote string) (fs.Object, error) { +func (f *Fs) Copy(ctx context.Context, src fs.Object, remote string) (dst fs.Object, err error) { srcObj, ok := src.(*Object) if !ok { fs.Debugf(src, "Can't copy - not same remote type") @@ -1228,6 +1228,19 @@ func (f *Fs) Copy(ctx context.Context, src fs.Object, remote string) (fs.Object, return nil, fmt.Errorf("can't copy %q -> %q as are same name", srcPath, dstPath) } + // Find existing object + existingObj, err := f.NewObject(ctx, remote) + if err == nil { + defer func() { + // Don't remove existing object if returning an error + if err != nil { + return + } + fs.Debugf(existingObj, "Server side copy: removing existing object after successful copy") + err = existingObj.Remove(ctx) + }() + } + // Create temporary object dstObj, dstLeaf, dstDirectoryID, err := f.createObject(ctx, remote, srcObj.modTime, srcObj.size) if err != nil { From 2bafbf3c04108bab8358428fa9f34d40e5ce057c Mon Sep 17 00:00:00 2001 From: Nick Craig-Wood Date: Fri, 8 Nov 2024 16:44:04 +0000 Subject: [PATCH 22/39] operations: add RemoveExisting to safely remove an existing file This renames the file first and if the operation is successful then it deletes the renamed file. --- fs/operations/operations.go | 51 ++++++++++++++++++++++ fs/operations/operations_test.go | 73 ++++++++++++++++++++++++++++++++ 2 files changed, 124 insertions(+) diff --git a/fs/operations/operations.go b/fs/operations/operations.go index 53d846525..eeba711fb 100644 --- a/fs/operations/operations.go +++ b/fs/operations/operations.go @@ -1188,6 +1188,57 @@ func Delete(ctx context.Context, f fs.Fs) error { return err } +// RemoveExisting removes an existing file in a safe way so that it +// can be restored if the operation fails. +// +// This first detects if there is an existing file and renames it to a +// temporary name if there is. +// +// The returned cleanup function should be called on a defer statement +// with a pointer to the error returned. It will revert the changes if +// there is an error or delete the existing file if not. +func RemoveExisting(ctx context.Context, f fs.Fs, remote string, operation string) (cleanup func(*error), err error) { + existingObj, err := f.NewObject(ctx, remote) + if err != nil { + return func(*error) {}, nil + } + doMove := f.Features().Move + if doMove == nil { + return nil, fmt.Errorf("%s: destination file exists already and can't rename", operation) + } + + // Avoid making the leaf name longer if it's already lengthy to avoid + // trouble with file name length limits. + suffix := "." + random.String(8) + var remoteSaved string + if len(path.Base(remote)) > 100 { + remoteSaved = TruncateString(remote, len(remote)-len(suffix)) + suffix + } else { + remoteSaved = remote + suffix + } + + fs.Debugf(existingObj, "%s: renaming existing object to %q before starting", operation, remoteSaved) + existingObj, err = doMove(ctx, existingObj, remoteSaved) + if err != nil { + return nil, fmt.Errorf("%s: failed to rename existing file: %w", operation, err) + } + return func(perr *error) { + if *perr == nil { + fs.Debugf(existingObj, "%s: removing renamed existing file after operation", operation) + err := existingObj.Remove(ctx) + if err != nil { + *perr = fmt.Errorf("%s: failed to remove renamed existing file: %w", operation, err) + } + } else { + fs.Debugf(existingObj, "%s: renaming existing back after failed operation", operation) + _, renameErr := doMove(ctx, existingObj, remote) + if renameErr != nil { + fs.Errorf(existingObj, "%s: failed to restore existing file after failed operation: %v", operation, renameErr) + } + } + }, nil +} + // listToChan will transfer all objects in the listing to the output // // If an error occurs, the error will be logged, and it will close the diff --git a/fs/operations/operations_test.go b/fs/operations/operations_test.go index 96ce5704a..2a5c3cb6c 100644 --- a/fs/operations/operations_test.go +++ b/fs/operations/operations_test.go @@ -1884,3 +1884,76 @@ func TestDirsEqual(t *testing.T) { equal = operations.DirsEqual(ctx, src, dst, opt) assert.True(t, equal) } + +func TestRemoveExisting(t *testing.T) { + ctx := context.Background() + r := fstest.NewRun(t) + if r.Fremote.Features().Move == nil { + t.Skip("Skipping as remote can't Move") + } + + file1 := r.WriteObject(ctx, "sub dir/test remove existing", "hello world", t1) + file2 := r.WriteObject(ctx, "sub dir/test remove existing with long name 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890", "hello long name world", t1) + + r.CheckRemoteItems(t, file1, file2) + + var returnedError error + + // Check not found first + cleanup, err := operations.RemoveExisting(ctx, r.Fremote, "not found", "TEST") + assert.Equal(t, err, nil) + r.CheckRemoteItems(t, file1, file2) + cleanup(&returnedError) + r.CheckRemoteItems(t, file1, file2) + + // Remove file1 + cleanup, err = operations.RemoveExisting(ctx, r.Fremote, file1.Path, "TEST") + assert.Equal(t, err, nil) + //r.CheckRemoteItems(t, file1, file2) + + // Check file1 with temporary name exists + var buf bytes.Buffer + err = operations.List(ctx, r.Fremote, &buf) + require.NoError(t, err) + res := buf.String() + assert.NotContains(t, res, " 11 "+file1.Path+"\n") + assert.Contains(t, res, " 11 "+file1.Path+".") + assert.Contains(t, res, " 21 "+file2.Path+"\n") + + cleanup(&returnedError) + r.CheckRemoteItems(t, file2) + + // Remove file2 with an error + cleanup, err = operations.RemoveExisting(ctx, r.Fremote, file2.Path, "TEST") + assert.Equal(t, err, nil) + + // Check file2 with truncated temporary name exists + buf.Reset() + err = operations.List(ctx, r.Fremote, &buf) + require.NoError(t, err) + res = buf.String() + assert.NotContains(t, res, " 21 "+file2.Path+"\n") + assert.NotContains(t, res, " 21 "+file2.Path+".") + assert.Contains(t, res, " 21 "+file2.Path[:100]) + + returnedError = errors.New("BOOM") + cleanup(&returnedError) + r.CheckRemoteItems(t, file2) + + // Remove file2 + cleanup, err = operations.RemoveExisting(ctx, r.Fremote, file2.Path, "TEST") + assert.Equal(t, err, nil) + + // Check file2 with truncated temporary name exists + buf.Reset() + err = operations.List(ctx, r.Fremote, &buf) + require.NoError(t, err) + res = buf.String() + assert.NotContains(t, res, " 21 "+file2.Path+"\n") + assert.NotContains(t, res, " 21 "+file2.Path+".") + assert.Contains(t, res, " 21 "+file2.Path[:100]) + + returnedError = nil + cleanup(&returnedError) + r.CheckRemoteItems(t) +} From ceea6753eeaaed7cceb08041c4741b0784b8a0ac Mon Sep 17 00:00:00 2001 From: Nick Craig-Wood Date: Fri, 8 Nov 2024 14:01:51 +0000 Subject: [PATCH 23/39] dropbox: fix server side copying over existing object This was causing a conflict error. This was fixed by renaming the existing file first and if the copy was successful deleting it, or renaming it back. --- backend/dropbox/dropbox.go | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/backend/dropbox/dropbox.go b/backend/dropbox/dropbox.go index f2f1fc852..520c5dbc2 100644 --- a/backend/dropbox/dropbox.go +++ b/backend/dropbox/dropbox.go @@ -47,6 +47,7 @@ import ( "github.com/rclone/rclone/fs/config/obscure" "github.com/rclone/rclone/fs/fserrors" "github.com/rclone/rclone/fs/hash" + "github.com/rclone/rclone/fs/operations" "github.com/rclone/rclone/lib/batcher" "github.com/rclone/rclone/lib/encoder" "github.com/rclone/rclone/lib/oauthutil" @@ -1020,13 +1021,20 @@ func (f *Fs) Precision() time.Duration { // Will only be called if src.Fs().Name() == f.Name() // // If it isn't possible then return fs.ErrorCantCopy -func (f *Fs) Copy(ctx context.Context, src fs.Object, remote string) (fs.Object, error) { +func (f *Fs) Copy(ctx context.Context, src fs.Object, remote string) (dst fs.Object, err error) { srcObj, ok := src.(*Object) if !ok { fs.Debugf(src, "Can't copy - not same remote type") return nil, fs.ErrorCantCopy } + // Find and remove existing object + cleanup, err := operations.RemoveExisting(ctx, f, remote, "server side copy") + if err != nil { + return nil, err + } + defer cleanup(&err) + // Temporary Object under construction dstObj := &Object{ fs: f, @@ -1040,7 +1048,6 @@ func (f *Fs) Copy(ctx context.Context, src fs.Object, remote string) (fs.Object, ToPath: f.opt.Enc.FromStandardPath(dstObj.remotePath()), }, } - var err error var result *files.RelocationResult err = f.pacer.Call(func() (bool, error) { result, err = f.srv.CopyV2(&arg) From f307d929a82ab3c05ffb232299d732b0d29bd5fe Mon Sep 17 00:00:00 2001 From: Nick Craig-Wood Date: Fri, 8 Nov 2024 14:01:51 +0000 Subject: [PATCH 24/39] onedrive: fix server side copying over existing object This was causing a conflict error. This was fixed by renaming the existing file first and if the copy was successful deleting it, or renaming it back. --- backend/onedrive/onedrive.go | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/backend/onedrive/onedrive.go b/backend/onedrive/onedrive.go index f7555017e..97dc8245f 100644 --- a/backend/onedrive/onedrive.go +++ b/backend/onedrive/onedrive.go @@ -1609,7 +1609,7 @@ func (f *Fs) waitForJob(ctx context.Context, location string, o *Object) error { // Will only be called if src.Fs().Name() == f.Name() // // If it isn't possible then return fs.ErrorCantCopy -func (f *Fs) Copy(ctx context.Context, src fs.Object, remote string) (fs.Object, error) { +func (f *Fs) Copy(ctx context.Context, src fs.Object, remote string) (dst fs.Object, err error) { srcObj, ok := src.(*Object) if !ok { fs.Debugf(src, "Can't copy - not same remote type") @@ -1624,11 +1624,18 @@ func (f *Fs) Copy(ctx context.Context, src fs.Object, remote string) (fs.Object, return nil, fs.ErrorCantCopy } - err := srcObj.readMetaData(ctx) + err = srcObj.readMetaData(ctx) if err != nil { return nil, err } + // Find and remove existing object + cleanup, err := operations.RemoveExisting(ctx, f, remote, "server side copy") + if err != nil { + return nil, err + } + defer cleanup(&err) + // Check we aren't overwriting a file on the same remote if srcObj.fs == f { srcPath := srcObj.rootPath() From 740f6b318c430147cc1d561049b7b70884cdef5c Mon Sep 17 00:00:00 2001 From: Nick Craig-Wood Date: Fri, 8 Nov 2024 14:01:51 +0000 Subject: [PATCH 25/39] putio: fix server side copying over existing object This was causing a conflict error. This was fixed by checking for the existing object and deleting it after the file was server side copied. --- backend/putio/fs.go | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/backend/putio/fs.go b/backend/putio/fs.go index cc21cac00..cdd89ceba 100644 --- a/backend/putio/fs.go +++ b/backend/putio/fs.go @@ -572,6 +572,17 @@ func (f *Fs) Copy(ctx context.Context, src fs.Object, remote string) (o fs.Objec if err != nil { return nil, err } + + // We have successfully copied the file to random name + // Check to see if file already exists first and delete it if so + existingObj, err := f.NewObject(ctx, remote) + if err == nil { + err = existingObj.Remove(ctx) + if err != nil { + return nil, fmt.Errorf("server side copy: failed to remove existing file: %w", err) + } + } + err = f.pacer.Call(func() (bool, error) { params := url.Values{} params.Set("file_id", strconv.FormatInt(resp.File.ID, 10)) From ca2b27422f895510c3828c9546b064f9757626a6 Mon Sep 17 00:00:00 2001 From: Nick Craig-Wood Date: Fri, 8 Nov 2024 14:01:51 +0000 Subject: [PATCH 26/39] sugarsync: fix server side copying over existing object This was causing a conflict error. This was fixed by renaming the existing file first and if the copy was successful deleting it, or renaming it back. --- backend/sugarsync/sugarsync.go | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/backend/sugarsync/sugarsync.go b/backend/sugarsync/sugarsync.go index da5143643..880776698 100644 --- a/backend/sugarsync/sugarsync.go +++ b/backend/sugarsync/sugarsync.go @@ -35,6 +35,7 @@ import ( "github.com/rclone/rclone/fs/fserrors" "github.com/rclone/rclone/fs/fshttp" "github.com/rclone/rclone/fs/hash" + "github.com/rclone/rclone/fs/operations" "github.com/rclone/rclone/lib/dircache" "github.com/rclone/rclone/lib/encoder" "github.com/rclone/rclone/lib/pacer" @@ -867,13 +868,13 @@ func (f *Fs) Precision() time.Duration { // Will only be called if src.Fs().Name() == f.Name() // // If it isn't possible then return fs.ErrorCantCopy -func (f *Fs) Copy(ctx context.Context, src fs.Object, remote string) (fs.Object, error) { +func (f *Fs) Copy(ctx context.Context, src fs.Object, remote string) (dst fs.Object, err error) { srcObj, ok := src.(*Object) if !ok { fs.Debugf(src, "Can't copy - not same remote type") return nil, fs.ErrorCantCopy } - err := srcObj.readMetaData(ctx) + err = srcObj.readMetaData(ctx) if err != nil { return nil, err } @@ -890,6 +891,13 @@ func (f *Fs) Copy(ctx context.Context, src fs.Object, remote string) (fs.Object, return nil, err } + // Find and remove existing object + cleanup, err := operations.RemoveExisting(ctx, f, remote, "server side copy") + if err != nil { + return nil, err + } + defer cleanup(&err) + // Copy the object opts := rest.Opts{ Method: "POST", From abb4f7756898818c0d8c6ce2445f55df9514ad51 Mon Sep 17 00:00:00 2001 From: Nick Craig-Wood Date: Fri, 8 Nov 2024 14:01:51 +0000 Subject: [PATCH 27/39] yandex: fix server side copying over existing object This was causing a conflict error. This was fixed by renaming the existing file first and if the copy was successful deleting it, or renaming it back. --- backend/yandex/yandex.go | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/backend/yandex/yandex.go b/backend/yandex/yandex.go index 7171491ea..0d5f18e18 100644 --- a/backend/yandex/yandex.go +++ b/backend/yandex/yandex.go @@ -22,6 +22,7 @@ import ( "github.com/rclone/rclone/fs/config/obscure" "github.com/rclone/rclone/fs/fserrors" "github.com/rclone/rclone/fs/hash" + "github.com/rclone/rclone/fs/operations" "github.com/rclone/rclone/lib/encoder" "github.com/rclone/rclone/lib/oauthutil" "github.com/rclone/rclone/lib/pacer" @@ -713,7 +714,7 @@ func (f *Fs) copyOrMove(ctx context.Context, method, src, dst string, overwrite // Will only be called if src.Fs().Name() == f.Name() // // If it isn't possible then return fs.ErrorCantCopy -func (f *Fs) Copy(ctx context.Context, src fs.Object, remote string) (fs.Object, error) { +func (f *Fs) Copy(ctx context.Context, src fs.Object, remote string) (dst fs.Object, err error) { srcObj, ok := src.(*Object) if !ok { fs.Debugf(src, "Can't copy - not same remote type") @@ -721,12 +722,21 @@ func (f *Fs) Copy(ctx context.Context, src fs.Object, remote string) (fs.Object, } dstPath := f.filePath(remote) - err := f.mkParentDirs(ctx, dstPath) + err = f.mkParentDirs(ctx, dstPath) if err != nil { return nil, err } - err = f.copyOrMove(ctx, "copy", srcObj.filePath(), dstPath, false) + // Find and remove existing object + // + // Note that the overwrite flag doesn't seem to work for server side copy + cleanup, err := operations.RemoveExisting(ctx, f, remote, "server side copy") + if err != nil { + return nil, err + } + defer cleanup(&err) + + err = f.copyOrMove(ctx, "copy", srcObj.filePath(), dstPath, false) if err != nil { return nil, fmt.Errorf("couldn't copy file: %w", err) } From ee72554fb944ebfaaa50804e7cfcce5db1ec2783 Mon Sep 17 00:00:00 2001 From: Nick Craig-Wood Date: Fri, 8 Nov 2024 17:39:36 +0000 Subject: [PATCH 28/39] pikpak: fix fatal crash on startup with token that can't be refreshed --- backend/pikpak/pikpak.go | 1 + 1 file changed, 1 insertion(+) diff --git a/backend/pikpak/pikpak.go b/backend/pikpak/pikpak.go index b70ecf92a..f2a1390f1 100644 --- a/backend/pikpak/pikpak.go +++ b/backend/pikpak/pikpak.go @@ -561,6 +561,7 @@ func newFs(ctx context.Context, name, path string, m configmap.Mapper) (*Fs, err if strings.Contains(err.Error(), "invalid_grant") { return f, f.reAuthorize(ctx) } + return nil, err } return f, nil From df19c6f7bf6ac55fe0ba85b91b4528b7c6867485 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 4 Nov 2024 23:43:08 +0000 Subject: [PATCH 29/39] build(deps): bump github.com/golang-jwt/jwt/v4 from 4.5.0 to 4.5.1 Bumps [github.com/golang-jwt/jwt/v4](https://github.com/golang-jwt/jwt) from 4.5.0 to 4.5.1. - [Release notes](https://github.com/golang-jwt/jwt/releases) - [Changelog](https://github.com/golang-jwt/jwt/blob/main/VERSION_HISTORY.md) - [Commits](https://github.com/golang-jwt/jwt/compare/v4.5.0...v4.5.1) --- updated-dependencies: - dependency-name: github.com/golang-jwt/jwt/v4 dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index fd6c96bc8..b435593c8 100644 --- a/go.mod +++ b/go.mod @@ -223,7 +223,7 @@ require ( require ( github.com/Microsoft/go-winio v0.6.1 // indirect github.com/ProtonMail/go-crypto v1.0.0 - github.com/golang-jwt/jwt/v4 v4.5.0 + github.com/golang-jwt/jwt/v4 v4.5.1 github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/pkg/xattr v0.4.9 golang.org/x/mobile v0.0.0-20240716161057-1ad2df20a8b6 diff --git a/go.sum b/go.sum index e1dff78eb..d1ba61b34 100644 --- a/go.sum +++ b/go.sum @@ -275,8 +275,8 @@ github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw= github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= -github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg= -github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= +github.com/golang-jwt/jwt/v4 v4.5.1 h1:JdqV9zKUdtaa9gdPlywC3aeoEsR681PlKC+4F5gQgeo= +github.com/golang-jwt/jwt/v4 v4.5.1/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk= github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= From 1072173d5802bc9a12d0bc56379f588eedb59060 Mon Sep 17 00:00:00 2001 From: Nick Craig-Wood Date: Fri, 8 Nov 2024 19:44:48 +0000 Subject: [PATCH 30/39] build: update all dependencies --- go.mod | 130 +++++++++++++------------- go.sum | 281 +++++++++++++++++++++++++++++---------------------------- 2 files changed, 209 insertions(+), 202 deletions(-) diff --git a/go.mod b/go.mod index b435593c8..eada8a54a 100644 --- a/go.mod +++ b/go.mod @@ -4,25 +4,25 @@ go 1.21 require ( bazil.org/fuse v0.0.0-20230120002735-62a210ff1fd5 - github.com/Azure/azure-sdk-for-go/sdk/azcore v1.13.0 - github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.7.0 - github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.3.2 - github.com/Azure/azure-sdk-for-go/sdk/storage/azfile v1.2.2 + github.com/Azure/azure-sdk-for-go/sdk/azcore v1.16.0 + github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.0 + github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.4.1 + github.com/Azure/azure-sdk-for-go/sdk/storage/azfile v1.3.1 github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 - github.com/Files-com/files-sdk-go/v3 v3.2.34 + github.com/Files-com/files-sdk-go/v3 v3.2.78 github.com/Max-Sum/base32768 v0.0.0-20230304063302-18e6ce5945fd github.com/a8m/tree v0.0.0-20240104212747-2c8764a5f17e github.com/aalpar/deheap v0.0.0-20210914013432-0cc84d79dec3 github.com/abbot/go-http-auth v0.4.0 github.com/anacrolix/dms v1.7.1 - github.com/anacrolix/log v0.15.2 + github.com/anacrolix/log v0.16.0 github.com/atotto/clipboard v0.1.4 - github.com/aws/aws-sdk-go-v2 v1.30.3 - github.com/aws/aws-sdk-go-v2/config v1.27.27 - github.com/aws/aws-sdk-go-v2/credentials v1.17.27 - github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.10 - github.com/aws/aws-sdk-go-v2/service/s3 v1.58.3 - github.com/aws/smithy-go v1.20.3 + github.com/aws/aws-sdk-go-v2 v1.32.4 + github.com/aws/aws-sdk-go-v2/config v1.28.3 + github.com/aws/aws-sdk-go-v2/credentials v1.17.44 + github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.37 + github.com/aws/aws-sdk-go-v2/service/s3 v1.66.3 + github.com/aws/smithy-go v1.22.0 github.com/buengese/sgzip v0.1.1 github.com/cloudsoda/go-smb2 v0.0.0-20231124195312-f3ec8ae2c891 github.com/colinmarc/hdfs/v2 v2.4.0 @@ -30,33 +30,33 @@ require ( github.com/coreos/go-systemd/v22 v22.5.0 github.com/dop251/scsu v0.0.0-20220106150536-84ac88021d00 github.com/dropbox/dropbox-sdk-go-unofficial/v6 v6.0.5 - github.com/gabriel-vasile/mimetype v1.4.4 + github.com/gabriel-vasile/mimetype v1.4.6 github.com/gdamore/tcell/v2 v2.7.4 github.com/go-chi/chi/v5 v5.1.0 github.com/go-darwin/apfs v0.0.0-20211011131704-f84b94dbf348 - github.com/go-git/go-billy/v5 v5.5.0 + github.com/go-git/go-billy/v5 v5.6.0 github.com/google/uuid v1.6.0 - github.com/hanwen/go-fuse/v2 v2.5.1 + github.com/hanwen/go-fuse/v2 v2.6.3 github.com/henrybear327/Proton-API-Bridge v1.0.0 github.com/henrybear327/go-proton-api v1.0.0 github.com/jcmturner/gokrb5/v8 v8.4.4 github.com/jlaffaye/ftp v0.2.0 - github.com/josephspurrier/goversioninfo v1.4.0 + github.com/josephspurrier/goversioninfo v1.4.1 github.com/jzelinskie/whirlpool v0.0.0-20201016144138-0675e54bb004 - github.com/klauspost/compress v1.17.9 + github.com/klauspost/compress v1.17.11 github.com/koofr/go-httpclient v0.0.0-20240520111329-e20f8f203988 github.com/koofr/go-koofrclient v0.0.0-20221207135200-cbd7fc9ad6a6 github.com/mattn/go-colorable v0.1.13 - github.com/mattn/go-runewidth v0.0.15 + github.com/mattn/go-runewidth v0.0.16 github.com/minio/minio-go/v7 v7.0.74 github.com/mitchellh/go-homedir v1.1.0 github.com/moby/sys/mountinfo v0.7.2 github.com/ncw/swift/v2 v2.0.3 - github.com/oracle/oci-go-sdk/v65 v65.69.2 + github.com/oracle/oci-go-sdk/v65 v65.78.0 github.com/patrickmn/go-cache v2.1.0+incompatible github.com/pkg/sftp v1.13.6 github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 - github.com/prometheus/client_golang v1.19.1 + github.com/prometheus/client_golang v1.20.5 github.com/putdotio/go-putio/putio v0.0.0-20200123120452-16d982cac2b8 github.com/quasilyte/go-ruleguard/dsl v0.3.22 github.com/rclone/gofakes3 v0.0.3 @@ -74,27 +74,27 @@ require ( github.com/willscott/go-nfs v0.0.3-0.20240425122109-91bc38957cc9 github.com/winfsp/cgofuse v1.5.1-0.20221118130120-84c0898ad2e0 github.com/xanzy/ssh-agent v0.3.3 - github.com/youmark/pkcs8 v0.0.0-20201027041543-1326539a0a0a + github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 github.com/yunify/qingstor-sdk-go/v3 v3.2.0 go.etcd.io/bbolt v1.3.10 goftp.io/server/v2 v2.0.1 - golang.org/x/crypto v0.25.0 - golang.org/x/net v0.27.0 - golang.org/x/oauth2 v0.21.0 - golang.org/x/sync v0.8.0 - golang.org/x/sys v0.22.0 - golang.org/x/text v0.17.0 - golang.org/x/time v0.5.0 - google.golang.org/api v0.188.0 + golang.org/x/crypto v0.29.0 + golang.org/x/net v0.31.0 + golang.org/x/oauth2 v0.24.0 + golang.org/x/sync v0.9.0 + golang.org/x/sys v0.27.0 + golang.org/x/text v0.20.0 + golang.org/x/time v0.8.0 + google.golang.org/api v0.205.0 gopkg.in/validator.v2 v2.0.1 gopkg.in/yaml.v2 v2.4.0 storj.io/uplink v1.13.1 ) require ( - cloud.google.com/go/auth v0.7.0 // indirect - cloud.google.com/go/auth/oauth2adapt v0.2.2 // indirect - cloud.google.com/go/compute/metadata v0.4.0 // indirect + cloud.google.com/go/auth v0.10.1 // indirect + cloud.google.com/go/auth/oauth2adapt v0.2.5 // indirect + cloud.google.com/go/compute/metadata v0.5.2 // indirect github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0 // indirect github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2 // indirect github.com/ProtonMail/bcrypt v0.0.0-20211005172633-e235017c1baf // indirect @@ -107,24 +107,24 @@ require ( github.com/anacrolix/generics v0.0.1 // indirect github.com/andybalholm/cascadia v1.3.2 // indirect github.com/appscode/go-querystring v0.0.0-20170504095604-0126cfb3f1dc // indirect - github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.3 // indirect - github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.11 // indirect - github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.15 // indirect - github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.15 // indirect - github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0 // indirect - github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.15 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.3 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.3.17 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.17 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.17.15 // indirect - github.com/aws/aws-sdk-go-v2/service/sso v1.22.4 // indirect - github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.4 // indirect - github.com/aws/aws-sdk-go-v2/service/sts v1.30.3 // indirect + github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.6 // indirect + github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.19 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.23 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.23 // indirect + github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1 // indirect + github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.23 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.0 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.4.4 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.4 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.4 // indirect + github.com/aws/aws-sdk-go-v2/service/sso v1.24.5 // indirect + github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.4 // indirect + github.com/aws/aws-sdk-go-v2/service/sts v1.32.4 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/bradenaw/juniper v0.15.2 // indirect github.com/bradfitz/iter v0.0.0-20191230175014-e8f45d346db8 // indirect github.com/calebcase/tmpfile v1.0.3 // indirect - github.com/cespare/xxhash/v2 v2.2.0 // indirect + github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/chilts/sid v0.0.0-20190607042430-660e94789ec9 // indirect github.com/cloudflare/circl v1.3.7 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.4 // indirect @@ -139,7 +139,7 @@ require ( github.com/gdamore/encoding v1.0.0 // indirect github.com/geoffgarside/ber v1.1.0 // indirect github.com/go-ini/ini v1.67.0 // indirect - github.com/go-logr/logr v1.4.1 // indirect + github.com/go-logr/logr v1.4.2 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-ole/go-ole v1.3.0 // indirect github.com/go-resty/resty/v2 v2.11.0 // indirect @@ -147,10 +147,9 @@ require ( github.com/gofrs/flock v0.8.1 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang-jwt/jwt/v5 v5.2.1 // indirect - github.com/golang/protobuf v1.5.4 // indirect - github.com/google/s2a-go v0.1.7 // indirect - github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect - github.com/googleapis/gax-go/v2 v2.12.5 // indirect + github.com/google/s2a-go v0.1.8 // indirect + github.com/googleapis/enterprise-certificate-proxy v0.3.4 // indirect + github.com/googleapis/gax-go/v2 v2.13.0 // indirect github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect @@ -173,15 +172,16 @@ require ( github.com/lufia/plan9stats v0.0.0-20231016141302-07b5767bb0ed // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/minio/md5-simd v1.1.2 // indirect + github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/onsi/ginkgo v1.16.5 // indirect github.com/panjf2000/ants/v2 v2.9.1 // indirect github.com/pengsrc/go-shared v0.2.1-0.20190131101655-1999055a4a14 // indirect github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect github.com/pkg/errors v0.9.1 // indirect github.com/power-devops/perfstat v0.0.0-20221212215047-62379fc7944b // indirect - github.com/prometheus/client_model v0.5.0 // indirect - github.com/prometheus/common v0.48.0 // indirect - github.com/prometheus/procfs v0.12.0 // indirect + github.com/prometheus/client_model v0.6.1 // indirect + github.com/prometheus/common v0.55.0 // indirect + github.com/prometheus/procfs v0.15.1 // indirect github.com/rasky/go-xdr v0.0.0-20170124162913-1a41d1a06c93 // indirect github.com/relvacode/iso8601 v1.3.0 // indirect github.com/rs/xid v1.5.0 // indirect @@ -200,17 +200,17 @@ require ( github.com/zeebo/blake3 v0.2.3 // indirect github.com/zeebo/errs v1.3.0 // indirect go.opencensus.io v0.24.0 // indirect - go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 // indirect - go.opentelemetry.io/otel v1.24.0 // indirect - go.opentelemetry.io/otel/metric v1.24.0 // indirect - go.opentelemetry.io/otel/trace v1.24.0 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0 // indirect + go.opentelemetry.io/otel v1.29.0 // indirect + go.opentelemetry.io/otel/metric v1.29.0 // indirect + go.opentelemetry.io/otel/trace v1.29.0 // indirect golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect golang.org/x/mod v0.19.0 // indirect golang.org/x/tools v0.23.0 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20240701130421-f6361c86f094 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240708141625-4ad9e859172b // indirect - google.golang.org/grpc v1.64.1 // indirect - google.golang.org/protobuf v1.34.2 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20241015192408-796eee8c2d53 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20241021214115-324edc3d5d38 // indirect + google.golang.org/grpc v1.67.1 // indirect + google.golang.org/protobuf v1.35.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect moul.io/http2curl/v2 v2.3.0 // indirect storj.io/common v0.0.0-20240812101423-26b53789c348 // indirect @@ -222,10 +222,10 @@ require ( require ( github.com/Microsoft/go-winio v0.6.1 // indirect - github.com/ProtonMail/go-crypto v1.0.0 + github.com/ProtonMail/go-crypto v1.1.2 github.com/golang-jwt/jwt/v4 v4.5.1 github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect - github.com/pkg/xattr v0.4.9 + github.com/pkg/xattr v0.4.10 golang.org/x/mobile v0.0.0-20240716161057-1ad2df20a8b6 - golang.org/x/term v0.22.0 + golang.org/x/term v0.26.0 ) diff --git a/go.sum b/go.sum index d1ba61b34..0677c12cd 100644 --- a/go.sum +++ b/go.sum @@ -15,18 +15,18 @@ cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKV cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= -cloud.google.com/go/auth v0.7.0 h1:kf/x9B3WTbBUHkC+1VS8wwwli9TzhSt0vSTVBmMR8Ts= -cloud.google.com/go/auth v0.7.0/go.mod h1:D+WqdrpcjmiCgWrXmLLxOVq1GACoE36chW6KXoEvuIw= -cloud.google.com/go/auth/oauth2adapt v0.2.2 h1:+TTV8aXpjeChS9M+aTtN/TjdQnzJvmzKFt//oWu7HX4= -cloud.google.com/go/auth/oauth2adapt v0.2.2/go.mod h1:wcYjgpZI9+Yu7LyYBg4pqSiaRkfEK3GQcpb7C/uyF1Q= +cloud.google.com/go/auth v0.10.1 h1:TnK46qldSfHWt2a0b/hciaiVJsmDXWy9FqyUan0uYiI= +cloud.google.com/go/auth v0.10.1/go.mod h1:xxA5AqpDrvS+Gkmo9RqrGGRh6WSNKKOXhY3zNOr38tI= +cloud.google.com/go/auth/oauth2adapt v0.2.5 h1:2p29+dePqsCHPP1bqDJcKj4qxRyYCcbzKpFyKGt3MTk= +cloud.google.com/go/auth/oauth2adapt v0.2.5/go.mod h1:AlmsELtlEBnaNTL7jCj8VQFLy6mbZv0s4Q7NGBeQ5E8= cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= -cloud.google.com/go/compute/metadata v0.4.0 h1:vHzJCWaM4g8XIcm8kopr3XmDA4Gy/lblD3EhhSux05c= -cloud.google.com/go/compute/metadata v0.4.0/go.mod h1:SIQh1Kkb4ZJ8zJ874fqVkslA29PRXuleyj6vOzlbK7M= +cloud.google.com/go/compute/metadata v0.5.2 h1:UxK4uu/Tn+I3p2dYWTfiX4wva7aYlKixAHn3fyqngqo= +cloud.google.com/go/compute/metadata v0.5.2/go.mod h1:C66sj2AluDcIqakBq/M8lw8/ybHgOZqin2obFxa/E5k= cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= @@ -39,26 +39,30 @@ cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohl cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= -github.com/Azure/azure-sdk-for-go/sdk/azcore v1.13.0 h1:GJHeeA2N7xrG3q30L2UXDyuWRzDM900/65j70wcM4Ww= -github.com/Azure/azure-sdk-for-go/sdk/azcore v1.13.0/go.mod h1:l38EPgmsp71HHLq9j7De57JcKOWPyhrsW1Awm1JS6K0= -github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.7.0 h1:tfLQ34V6F7tVSwoTf/4lH5sE0o6eCJuNDTmH09nDpbc= -github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.7.0/go.mod h1:9kIvujWAA58nmPmWB1m23fyWic1kYZMxD9CxaWn4Qpg= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.16.0 h1:JZg6HRh6W6U4OLl6lk7BZ7BLisIzM9dG1R50zUk9C/M= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.16.0/go.mod h1:YL1xnZ6QejvQHWJrX/AvhFl4WW4rqHVoKspWNVwFk0M= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.0 h1:B/dfvscEQtew9dVuoxqxrUKKv8Ih2f55PydknDamU+g= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.0/go.mod h1:fiPSssYvltE08HJchL04dOy+RD4hgrjph0cwGGMntdI= +github.com/Azure/azure-sdk-for-go/sdk/azidentity/cache v0.3.0 h1:+m0M/LFxN43KvULkDNfdXOgrjtg6UYJPFBJyuEcRCAw= +github.com/Azure/azure-sdk-for-go/sdk/azidentity/cache v0.3.0/go.mod h1:PwOyop78lveYMRs6oCxjiVyBdyCgIYH6XHIVZO9/SFQ= github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0 h1:ywEEhmNahHBihViHepv3xPBn1663uRv2t2q/ESv9seY= github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0/go.mod h1:iZDifYGJTIgIIkYRNWPENUnqx6bJ2xnSDFI2tjwZNuY= -github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage v1.5.0 h1:AifHbc4mg0x9zW52WOpKbsHaDKuRhlI7TVl47thgQ70= -github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage v1.5.0/go.mod h1:T5RfihdXtBDxt1Ch2wobif3TvzTdumDy29kahv6AV9A= -github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.3.2 h1:YUUxeiOWgdAQE3pXt2H7QXzZs0q8UBjgRbl56qo8GYM= -github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.3.2/go.mod h1:dmXQgZuiSubAecswZE+Sm8jkvEa7kQgTPVRvwL/nd0E= -github.com/Azure/azure-sdk-for-go/sdk/storage/azfile v1.2.2 h1:PmDhkIT8S5U4nkY/s78Xmf7CXT8qCliNEBhbrkBp3Q0= -github.com/Azure/azure-sdk-for-go/sdk/storage/azfile v1.2.2/go.mod h1:Kj2pCkQ47klX1aAlDnlN/BUvwBiARqIJkc9iw1Up7q8= +github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage v1.6.0 h1:PiSrjRPpkQNjrM8H0WwKMnZUdu1RGMtd/LdGKUrOo+c= +github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage v1.6.0/go.mod h1:oDrbWx4ewMylP7xHivfgixbfGBT6APAwsSoHRKotnIc= +github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.4.1 h1:cf+OIKbkmMHBaC3u78AXomweqM0oxQSgBXRZf3WH4yM= +github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.4.1/go.mod h1:ap1dmS6vQKJxSMNiGJcq4QuUQkOynyD93gLw6MDF7ek= +github.com/Azure/azure-sdk-for-go/sdk/storage/azfile v1.3.1 h1:a1U6j4GPI18JQCqgz7/DcqXA1vzvGBugm14AXZfU0gs= +github.com/Azure/azure-sdk-for-go/sdk/storage/azfile v1.3.1/go.mod h1:tZyRNcHi2/yo+ugYHTUuOrHiboKilaizLnRL5aZTe6A= github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 h1:mFRzDkZVAjdal+s7s0MwaRv9igoPqLRdzOLzw/8Xvq8= github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU= +github.com/AzureAD/microsoft-authentication-extensions-for-go/cache v0.1.1 h1:WJTmL004Abzc5wDB5VtZG2PJk5ndYDgVacGqfirKxjM= +github.com/AzureAD/microsoft-authentication-extensions-for-go/cache v0.1.1/go.mod h1:tCcJZ0uHAmvjsVYzEFivsRTN00oz5BEsRgQHu5JZ9WE= github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2 h1:XHOnouVk1mxXfQidrMEnLlPk9UMeRtyBTnEFtxkV0kU= github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= -github.com/Files-com/files-sdk-go/v3 v3.2.34 h1:j6gSzu6BF1wWH1z4itRe7eKhQSCrx/I78SDNiBBUtvI= -github.com/Files-com/files-sdk-go/v3 v3.2.34/go.mod h1:Y/bCHoPJNPKz2hw1ADXjQXJP378HODwK+g/5SR2gqfU= +github.com/Files-com/files-sdk-go/v3 v3.2.78 h1:mqZLLi/ditE8osCggrXhVSOG67xNdTLG0SdxkSB0EBI= +github.com/Files-com/files-sdk-go/v3 v3.2.78/go.mod h1:Y/bCHoPJNPKz2hw1ADXjQXJP378HODwK+g/5SR2gqfU= github.com/Masterminds/semver/v3 v3.2.0 h1:3MEsd0SM6jqZojhjLWWeBY+Kcjy9i6MQAeY7YgDP83g= github.com/Masterminds/semver/v3 v3.2.0/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ= github.com/Max-Sum/base32768 v0.0.0-20230304063302-18e6ce5945fd h1:nzE1YQBdx1bq9IlZinHa+HVffy+NmVRoKr+wHN8fpLE= @@ -73,8 +77,8 @@ github.com/ProtonMail/gluon v0.17.1-0.20230724134000-308be39be96e h1:lCsqUUACrcM github.com/ProtonMail/gluon v0.17.1-0.20230724134000-308be39be96e/go.mod h1:Og5/Dz1MiGpCJn51XujZwxiLG7WzvvjE5PRpZBQmAHo= github.com/ProtonMail/go-crypto v0.0.0-20230321155629-9a39f2531310/go.mod h1:8TI4H3IbrackdNgv+92dI+rhpCaLqM0IfpgCgenFvRE= github.com/ProtonMail/go-crypto v0.0.0-20230717121422-5aa5874ade95/go.mod h1:EjAoLdwvbIOoOQr3ihjnSoLZRtE8azugULFRteWMNc0= -github.com/ProtonMail/go-crypto v1.0.0 h1:LRuvITjQWX+WIfr930YHG2HNfjR1uOfyf5vE0kC2U78= -github.com/ProtonMail/go-crypto v1.0.0/go.mod h1:EjAoLdwvbIOoOQr3ihjnSoLZRtE8azugULFRteWMNc0= +github.com/ProtonMail/go-crypto v1.1.2 h1:A7JbD57ThNqh7XjmHE+PXpQ3Dqt3BrSAC0AL0Go3KS0= +github.com/ProtonMail/go-crypto v1.1.2/go.mod h1:rA3QumHc/FZ8pAHreoekgiAbzpNsfQAosU5td4SnOrE= github.com/ProtonMail/go-mime v0.0.0-20230322103455-7d82a3887f2f h1:tCbYj7/299ekTTXpdwKYF8eBlsYsDVoggDAuAjoK66k= github.com/ProtonMail/go-mime v0.0.0-20230322103455-7d82a3887f2f/go.mod h1:gcr0kNtGBqin9zDW9GOHcVntrwnjrK+qdJ06mWYBybw= github.com/ProtonMail/go-srp v0.0.7 h1:Sos3Qk+th4tQR64vsxGIxYpN3rdnG9Wf9K4ZloC1JrI= @@ -95,8 +99,8 @@ github.com/anacrolix/dms v1.7.1 h1:XVOpT3eoO5Ds34B1X+TE3R2ApfqGGeqotEoCVNP8BaI= github.com/anacrolix/dms v1.7.1/go.mod h1:excFJW5MKBhn5yt5ZMyeE9iFVqnO6tEGQl7YG/2tUoQ= github.com/anacrolix/generics v0.0.1 h1:4WVhK6iLb3UAAAQP6I3uYlMOHcp9FqJC9j4n81Wv9Ks= github.com/anacrolix/generics v0.0.1/go.mod h1:ff2rHB/joTV03aMSSn/AZNnaIpUw0h3njetGsaXcMy8= -github.com/anacrolix/log v0.15.2 h1:LTSf5Wm6Q4GNWPFMBP7NPYV6UBVZzZLKckL+/Lj72Oo= -github.com/anacrolix/log v0.15.2/go.mod h1:m0poRtlr41mriZlXBQ9SOVZ8yZBkLjOkDhd5Li5pITA= +github.com/anacrolix/log v0.16.0 h1:DSuyb5kAJwl3Y0X1TRcStVrTS9ST9b0BHW+7neE4Xho= +github.com/anacrolix/log v0.16.0/go.mod h1:m0poRtlr41mriZlXBQ9SOVZ8yZBkLjOkDhd5Li5pITA= github.com/andybalholm/cascadia v1.3.1/go.mod h1:R4bJ1UQfqADjvDa4P6HZHLh/3OxWWEqc0Sk8XGwHqvA= github.com/andybalholm/cascadia v1.3.2 h1:3Xi6Dw5lHF15JtdcmAHD3i1+T8plmv7BQ/nsViSLyss= github.com/andybalholm/cascadia v1.3.2/go.mod h1:7gtRlve5FxPPgIgX36uWBX58OdBsSS6lUvCFb+h7KvU= @@ -104,44 +108,44 @@ github.com/appscode/go-querystring v0.0.0-20170504095604-0126cfb3f1dc h1:LoL75er github.com/appscode/go-querystring v0.0.0-20170504095604-0126cfb3f1dc/go.mod h1:w648aMHEgFYS6xb0KVMMtZ2uMeemhiKCuD2vj6gY52A= github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z4= github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI= -github.com/aws/aws-sdk-go-v2 v1.30.3 h1:jUeBtG0Ih+ZIFH0F4UkmL9w3cSpaMv9tYYDbzILP8dY= -github.com/aws/aws-sdk-go-v2 v1.30.3/go.mod h1:nIQjQVp5sfpQcTc9mPSr1B0PaWK5ByX9MOoDadSN4lc= -github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.3 h1:tW1/Rkad38LA15X4UQtjXZXNKsCgkshC3EbmcUmghTg= -github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.3/go.mod h1:UbnqO+zjqk3uIt9yCACHJ9IVNhyhOCnYk8yA19SAWrM= -github.com/aws/aws-sdk-go-v2/config v1.27.27 h1:HdqgGt1OAP0HkEDDShEl0oSYa9ZZBSOmKpdpsDMdO90= -github.com/aws/aws-sdk-go-v2/config v1.27.27/go.mod h1:MVYamCg76dFNINkZFu4n4RjDixhVr51HLj4ErWzrVwg= -github.com/aws/aws-sdk-go-v2/credentials v1.17.27 h1:2raNba6gr2IfA0eqqiP2XiQ0UVOpGPgDSi0I9iAP+UI= -github.com/aws/aws-sdk-go-v2/credentials v1.17.27/go.mod h1:gniiwbGahQByxan6YjQUMcW4Aov6bLC3m+evgcoN4r4= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.11 h1:KreluoV8FZDEtI6Co2xuNk/UqI9iwMrOx/87PBNIKqw= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.11/go.mod h1:SeSUYBLsMYFoRvHE0Tjvn7kbxaUhl75CJi1sbfhMxkU= -github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.10 h1:zeN9UtUlA6FTx0vFSayxSX32HDw73Yb6Hh2izDSFxXY= -github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.10/go.mod h1:3HKuexPDcwLWPaqpW2UR/9n8N/u/3CKcGAzSs8p8u8g= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.15 h1:SoNJ4RlFEQEbtDcCEt+QG56MY4fm4W8rYirAmq+/DdU= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.15/go.mod h1:U9ke74k1n2bf+RIgoX1SXFed1HLs51OgUSs+Ph0KJP8= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.15 h1:C6WHdGnTDIYETAm5iErQUiVNsclNx9qbJVPIt03B6bI= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.15/go.mod h1:ZQLZqhcu+JhSrA9/NXRm8SkDvsycE+JkV3WGY41e+IM= -github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0 h1:hT8rVHwugYE2lEfdFE0QWVo81lF7jMrYJVDWI+f+VxU= -github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0/go.mod h1:8tu/lYfQfFe6IGnaOdrpVgEL2IrrDOf6/m9RQum4NkY= -github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.15 h1:Z5r7SycxmSllHYmaAZPpmN8GviDrSGhMS6bldqtXZPw= -github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.15/go.mod h1:CetW7bDE00QoGEmPUoZuRog07SGVAUVW6LFpNP0YfIg= -github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.3 h1:dT3MqvGhSoaIhRseqw2I0yH81l7wiR2vjs57O51EAm8= -github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.3/go.mod h1:GlAeCkHwugxdHaueRr4nhPuY+WW+gR8UjlcqzPr1SPI= -github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.3.17 h1:YPYe6ZmvUfDDDELqEKtAd6bo8zxhkm+XEFEzQisqUIE= -github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.3.17/go.mod h1:oBtcnYua/CgzCWYN7NZ5j7PotFDaFSUjCYVTtfyn7vw= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.17 h1:HGErhhrxZlQ044RiM+WdoZxp0p+EGM62y3L6pwA4olE= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.17/go.mod h1:RkZEx4l0EHYDJpWppMJ3nD9wZJAa8/0lq9aVC+r2UII= -github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.17.15 h1:246A4lSTXWJw/rmlQI+TT2OcqeDMKBdyjEQrafMaQdA= -github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.17.15/go.mod h1:haVfg3761/WF7YPuJOER2MP0k4UAXyHaLclKXB6usDg= -github.com/aws/aws-sdk-go-v2/service/s3 v1.58.3 h1:hT8ZAZRIfqBqHbzKTII+CIiY8G2oC9OpLedkZ51DWl8= -github.com/aws/aws-sdk-go-v2/service/s3 v1.58.3/go.mod h1:Lcxzg5rojyVPU/0eFwLtcyTaek/6Mtic5B1gJo7e/zE= -github.com/aws/aws-sdk-go-v2/service/sso v1.22.4 h1:BXx0ZIxvrJdSgSvKTZ+yRBeSqqgPM89VPlulEcl37tM= -github.com/aws/aws-sdk-go-v2/service/sso v1.22.4/go.mod h1:ooyCOXjvJEsUw7x+ZDHeISPMhtwI3ZCB7ggFMcFfWLU= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.4 h1:yiwVzJW2ZxZTurVbYWA7QOrAaCYQR72t0wrSBfoesUE= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.4/go.mod h1:0oxfLkpz3rQ/CHlx5hB7H69YUpFiI1tql6Q6Ne+1bCw= -github.com/aws/aws-sdk-go-v2/service/sts v1.30.3 h1:ZsDKRLXGWHk8WdtyYMoGNO7bTudrvuKpDKgMVRlepGE= -github.com/aws/aws-sdk-go-v2/service/sts v1.30.3/go.mod h1:zwySh8fpFyXp9yOr/KVzxOl8SRqgf/IDw5aUt9UKFcQ= -github.com/aws/smithy-go v1.20.3 h1:ryHwveWzPV5BIof6fyDvor6V3iUL7nTfiTKXHiW05nE= -github.com/aws/smithy-go v1.20.3/go.mod h1:krry+ya/rV9RDcV/Q16kpu6ypI4K2czasz0NC3qS14E= +github.com/aws/aws-sdk-go-v2 v1.32.4 h1:S13INUiTxgrPueTmrm5DZ+MiAo99zYzHEFh1UNkOxNE= +github.com/aws/aws-sdk-go-v2 v1.32.4/go.mod h1:2SK5n0a2karNTv5tbP1SjsX0uhttou00v/HpXKM1ZUo= +github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.6 h1:pT3hpW0cOHRJx8Y0DfJUEQuqPild8jRGmSFmBgvydr0= +github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.6/go.mod h1:j/I2++U0xX+cr44QjHay4Cvxj6FUbnxrgmqN3H1jTZA= +github.com/aws/aws-sdk-go-v2/config v1.28.3 h1:kL5uAptPcPKaJ4q0sDUjUIdueO18Q7JDzl64GpVwdOM= +github.com/aws/aws-sdk-go-v2/config v1.28.3/go.mod h1:SPEn1KA8YbgQnwiJ/OISU4fz7+F6Fe309Jf0QTsRCl4= +github.com/aws/aws-sdk-go-v2/credentials v1.17.44 h1:qqfs5kulLUHUEXlHEZXLJkgGoF3kkUeFUTVA585cFpU= +github.com/aws/aws-sdk-go-v2/credentials v1.17.44/go.mod h1:0Lm2YJ8etJdEdw23s+q/9wTpOeo2HhNE97XcRa7T8MA= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.19 h1:woXadbf0c7enQ2UGCi8gW/WuKmE0xIzxBF/eD94jMKQ= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.19/go.mod h1:zminj5ucw7w0r65bP6nhyOd3xL6veAUMc3ElGMoLVb4= +github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.37 h1:jHKR76E81sZvz1+x1vYYrHMxphG5LFBJPhSqEr4CLlE= +github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.37/go.mod h1:iMkyPkmoJWQKzSOtaX+8oEJxAuqr7s8laxcqGDSHeII= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.23 h1:A2w6m6Tmr+BNXjDsr7M90zkWjsu4JXHwrzPg235STs4= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.23/go.mod h1:35EVp9wyeANdujZruvHiQUAo9E3vbhnIO1mTCAxMlY0= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.23 h1:pgYW9FCabt2M25MoHYCfMrVY2ghiiBKYWUVXfwZs+sU= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.23/go.mod h1:c48kLgzO19wAu3CPkDWC28JbaJ+hfQlsdl7I2+oqIbk= +github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1 h1:VaRN3TlFdd6KxX1x3ILT5ynH6HvKgqdiXoTxAF4HQcQ= +github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1/go.mod h1:FbtygfRFze9usAadmnGJNc8KsP346kEe+y2/oyhGAGc= +github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.23 h1:1SZBDiRzzs3sNhOMVApyWPduWYGAX0imGy06XiBnCAM= +github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.23/go.mod h1:i9TkxgbZmHVh2S0La6CAXtnyFhlCX/pJ0JsOvBAS6Mk= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.0 h1:TToQNkvGguu209puTojY/ozlqy2d/SFNcoLIqTFi42g= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.0/go.mod h1:0jp+ltwkf+SwG2fm/PKo8t4y8pJSgOCO4D8Lz3k0aHQ= +github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.4.4 h1:aaPpoG15S2qHkWm4KlEyF01zovK1nW4BBbyXuHNSE90= +github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.4.4/go.mod h1:eD9gS2EARTKgGr/W5xwgY/ik9z/zqpW+m/xOQbVxrMk= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.4 h1:tHxQi/XHPK0ctd/wdOw0t7Xrc2OxcRCnVzv8lwWPu0c= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.4/go.mod h1:4GQbF1vJzG60poZqWatZlhP31y8PGCCVTvIGPdaaYJ0= +github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.4 h1:E5ZAVOmI2apR8ADb72Q63KqwwwdW1XcMeXIlrZ1Psjg= +github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.4/go.mod h1:wezzqVUOVVdk+2Z/JzQT4NxAU0NbhRe5W8pIE72jsWI= +github.com/aws/aws-sdk-go-v2/service/s3 v1.66.3 h1:neNOYJl72bHrz9ikAEED4VqWyND/Po0DnEx64RW6YM4= +github.com/aws/aws-sdk-go-v2/service/s3 v1.66.3/go.mod h1:TMhLIyRIyoGVlaEMAt+ITMbwskSTpcGsCPDq91/ihY0= +github.com/aws/aws-sdk-go-v2/service/sso v1.24.5 h1:HJwZwRt2Z2Tdec+m+fPjvdmkq2s9Ra+VR0hjF7V2o40= +github.com/aws/aws-sdk-go-v2/service/sso v1.24.5/go.mod h1:wrMCEwjFPms+V86TCQQeOxQF/If4vT44FGIOFiMC2ck= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.4 h1:zcx9LiGWZ6i6pjdcoE9oXAB6mUdeyC36Ia/QEiIvYdg= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.4/go.mod h1:Tp/ly1cTjRLGBBmNccFumbZ8oqpZlpdhFf80SrRh4is= +github.com/aws/aws-sdk-go-v2/service/sts v1.32.4 h1:yDxvkz3/uOKfxnv8YhzOi9m+2OGIxF+on3KOISbK5IU= +github.com/aws/aws-sdk-go-v2/service/sts v1.32.4/go.mod h1:9XEUty5v5UAsMiFOBJrNibZgwCeOma73jgGwwhgffa8= +github.com/aws/smithy-go v1.22.0 h1:uunKnWlcoL3zO7q+gG2Pk53joueEOsnNB28QdMsmiMM= +github.com/aws/smithy-go v1.22.0/go.mod h1:irrKGvNn1InZwb2d7fkIRNucdfwR8R+Ts3wxYa/cJHg= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bradenaw/juniper v0.15.2 h1:0JdjBGEF2jP1pOxmlNIrPhAoQN7Ng5IMAY5D0PHMW4U= @@ -159,8 +163,8 @@ github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4 github.com/calebcase/tmpfile v1.0.3 h1:BZrOWZ79gJqQ3XbAQlihYZf/YCV0H4KPIdM5K5oMpJo= github.com/calebcase/tmpfile v1.0.3/go.mod h1:UAUc01aHeC+pudPagY/lWvt2qS9ZO5Zzof6/tIUzqeI= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= -github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= +github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chilts/sid v0.0.0-20190607042430-660e94789ec9 h1:z0uK8UQqjMVYzvk4tiiu3obv2B44+XBsvgEJREQfnO8= github.com/chilts/sid v0.0.0-20190607042430-660e94789ec9/go.mod h1:Jl2neWsQaDanWORdqZ4emBl50J4/aRBBS4FyyG9/PFo= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= @@ -192,6 +196,8 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= github.com/dnaeon/go-vcr v1.2.0 h1:zHCHvJYTMh1N7xnV7zf1m1GPBF9Ad0Jk/whtQ1663qI= github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ= github.com/dop251/scsu v0.0.0-20220106150536-84ac88021d00 h1:xJBhC00smQpSZw3Kr0ErMUBXhUSjYoLRm2szxdbRBL0= @@ -225,8 +231,8 @@ github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMo github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= -github.com/gabriel-vasile/mimetype v1.4.4 h1:QjV6pZ7/XZ7ryI2KuyeEDE8wnh7fHP9YnQy+R0LnH8I= -github.com/gabriel-vasile/mimetype v1.4.4/go.mod h1:JwLei5XPtWdGiMFB5Pjle1oEeoSeEuJfJE+TtfvdB/s= +github.com/gabriel-vasile/mimetype v1.4.6 h1:3+PzJTKLkvgjeTbts6msPJt4DixhT4YtFNf1gtGe3zc= +github.com/gabriel-vasile/mimetype v1.4.6/go.mod h1:JX1qVKqZd40hUPpAfiNTe0Sne7hdfKSbOqqmkq8GCXc= github.com/gdamore/encoding v1.0.0 h1:+7OoQ1Bc6eTm5niUzBa0Ctsh6JbMW6Ra+YNuAtDBdko= github.com/gdamore/encoding v1.0.0/go.mod h1:alR0ol34c49FCSBLjhosxzcPHQbf2trDkoo5dl+VrEg= github.com/gdamore/tcell/v2 v2.7.4 h1:sg6/UnTM9jGpZU+oFYAsDahfchWAFW8Xx2yFinNSAYU= @@ -241,16 +247,16 @@ github.com/go-chi/chi/v5 v5.1.0 h1:acVI1TYaD+hhedDJ3r54HyA6sExp3HfXq7QWEEY/xMw= github.com/go-chi/chi/v5 v5.1.0/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= github.com/go-darwin/apfs v0.0.0-20211011131704-f84b94dbf348 h1:JnrjqG5iR07/8k7NqrLNilRsl3s1EPRQEGvbPyOce68= github.com/go-darwin/apfs v0.0.0-20211011131704-f84b94dbf348/go.mod h1:Czxo/d1g948LtrALAZdL04TL/HnkopquAjxYUuI02bo= -github.com/go-git/go-billy/v5 v5.5.0 h1:yEY4yhzCDuMGSv83oGxiBotRzhwhNr8VZyphhiu+mTU= -github.com/go-git/go-billy/v5 v5.5.0/go.mod h1:hmexnoNsr2SJU1Ju67OaNz5ASJY3+sHgFRpCtpDCKow= +github.com/go-git/go-billy/v5 v5.6.0 h1:w2hPNtoehvJIxR00Vb4xX94qHQi/ApZfX+nBE2Cjio8= +github.com/go-git/go-billy/v5 v5.6.0/go.mod h1:sFDq7xD3fn3E0GOwUSZqHo9lrkmx8xJhA0ZrfvjBRGM= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-ini/ini v1.67.0 h1:z6ZrTEZqSWOTyH2FlglNbNgARyHG8oLW9gMELqKr06A= github.com/go-ini/ini v1.67.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= -github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= +github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= @@ -306,8 +312,6 @@ github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvq github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= -github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= @@ -332,17 +336,17 @@ github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hf github.com/google/pprof v0.0.0-20240509144519-723abb6459b7 h1:velgFPYr1X9TDwLIfkV7fWqsFlf7TeP11M/7kPd/dVI= github.com/google/pprof v0.0.0-20240509144519-723abb6459b7/go.mod h1:kf6iHlnVGwgKolg33glAes7Yg/8iWP8ukqeldJSO7jw= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= -github.com/google/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o= -github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw= +github.com/google/s2a-go v0.1.8 h1:zZDs9gcbt9ZPLV0ndSyQk6Kacx2g/X+SKYovpnz3SMM= +github.com/google/s2a-go v0.1.8/go.mod h1:6iNWHTpQ+nfNRN5E00MSdfDwVesa8hhS32PhPO8deJA= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/googleapis/enterprise-certificate-proxy v0.3.2 h1:Vie5ybvEvT75RniqhfFxPRy3Bf7vr3h0cechB90XaQs= -github.com/googleapis/enterprise-certificate-proxy v0.3.2/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0= +github.com/googleapis/enterprise-certificate-proxy v0.3.4 h1:XYIDZApgAnrN1c855gTgghdIA6Stxb52D5RnLI1SLyw= +github.com/googleapis/enterprise-certificate-proxy v0.3.4/go.mod h1:YKe7cfqYXjKGpGvmSg28/fFvhNzinZQm8DGnaburhGA= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= -github.com/googleapis/gax-go/v2 v2.12.5 h1:8gw9KZK8TiVKB6q3zHY3SBzLnrGp6HQjyfYBYGmXdxA= -github.com/googleapis/gax-go/v2 v2.12.5/go.mod h1:BUDKcWo+RaKq5SC9vVYL0wLADa3VcfswbOMMRmB9H3E= +github.com/googleapis/gax-go/v2 v2.13.0 h1:yitjD5f7jQHhyDsnhKEBU52NdvvdSeGzlAnDPT0hH1s= +github.com/googleapis/gax-go/v2 v2.13.0/go.mod h1:Z/fvTZXF8/uw7Xu5GuslPw+bplx6SS338j1Is2S+B7A= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e h1:JKmoR8x90Iww1ks85zJ1lfDGgIiMDuIptTOhJq+zKyg= github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= @@ -350,8 +354,8 @@ github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyC github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= github.com/gorilla/sessions v1.2.1 h1:DHd3rPN5lE3Ts3D8rKkQ8x/0kqfeNmBAaiSi+o7FsgI= github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= -github.com/hanwen/go-fuse/v2 v2.5.1 h1:OQBE8zVemSocRxA4OaFJbjJ5hlpCmIWbGr7r0M4uoQQ= -github.com/hanwen/go-fuse/v2 v2.5.1/go.mod h1:xKwi1cF7nXAOBCXujD5ie0ZKsxc8GGSA1rlMJc+8IJs= +github.com/hanwen/go-fuse/v2 v2.6.3 h1:tDcEkLRx93lXu4XyN1/j8Z74VWvhHDl6qU1kNnvFUqI= +github.com/hanwen/go-fuse/v2 v2.6.3/go.mod h1:ugNaD/iv5JYyS1Rcvi57Wz7/vrLQJo10mmketmoef48= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= @@ -393,8 +397,8 @@ github.com/jcmturner/rpc/v2 v2.0.3/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJk github.com/jlaffaye/ftp v0.0.0-20190624084859-c1312a7102bf/go.mod h1:lli8NYPQOFy3O++YmYbqVgOcQ1JPCwdOy+5zSjKJ9qY= github.com/jlaffaye/ftp v0.2.0 h1:lXNvW7cBu7R/68bknOX3MrRIIqZ61zELs1P2RAiA3lg= github.com/jlaffaye/ftp v0.2.0/go.mod h1:is2Ds5qkhceAPy2xD6RLI6hmp/qysSoymZ+Z2uTnspI= -github.com/josephspurrier/goversioninfo v1.4.0 h1:Puhl12NSHUSALHSuzYwPYQkqa2E1+7SrtAPJorKK0C8= -github.com/josephspurrier/goversioninfo v1.4.0/go.mod h1:JWzv5rKQr+MmW+LvM412ToT/IkYDZjaclF2pKDss8IY= +github.com/josephspurrier/goversioninfo v1.4.1 h1:5LvrkP+n0tg91J9yTkoVnt/QgNnrI1t4uSsWjIonrqY= +github.com/josephspurrier/goversioninfo v1.4.1/go.mod h1:JWzv5rKQr+MmW+LvM412ToT/IkYDZjaclF2pKDss8IY= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= @@ -405,10 +409,12 @@ github.com/jtolio/noiseconn v0.0.0-20231127013910-f6d9ecbf1de7 h1:JcltaO1HXM5S2K github.com/jtolio/noiseconn v0.0.0-20231127013910-f6d9ecbf1de7/go.mod h1:MEkhEPFwP3yudWO0lj6vfYpLIB+3eIcuIW+e0AZzUQk= github.com/jzelinskie/whirlpool v0.0.0-20201016144138-0675e54bb004 h1:G+9t9cEtnC9jFiTxyptEKuNIAbiN5ZCQzX2a74lj3xg= github.com/jzelinskie/whirlpool v0.0.0-20201016144138-0675e54bb004/go.mod h1:KmHnJWQrgEvbuy0vcvj00gtMqbvNn1L+3YUZLK/B92c= +github.com/keybase/go-keychain v0.0.0-20231219164618-57a3676c3af6 h1:IsMZxCuZqKuao2vNdfD82fjjgPLfyHLpR41Z88viRWs= +github.com/keybase/go-keychain v0.0.0-20231219164618-57a3676c3af6/go.mod h1:3VeWNIJaW+O5xpRQbPp0Ybqu1vJd/pm7s2F473HRrkw= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA= -github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= +github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc= +github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0= github.com/klauspost/cpuid/v2 v2.0.1/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.0.12/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c= github.com/klauspost/cpuid/v2 v2.2.8 h1:+StwCXwm9PdpiEkPyzBXIy+M9KUb4ODm0Zarf1kS5BM= @@ -428,7 +434,6 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348/go.mod h1:B69LEHPfb2qLo0BaaOLcbitczOKLWTsrBG9LczfCD4k= github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= @@ -444,8 +449,9 @@ github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovk github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U= github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc= +github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/minio/md5-simd v1.1.2 h1:Gdi1DZK69+ZVMoNHRXJyNcxrMA4dSxoYHZSQbirFg34= github.com/minio/md5-simd v1.1.2/go.mod h1:MzdKDxYpY2BT9XQFocsiZf/NKVtR7nkE4RoEpN+20RM= github.com/minio/minio-go/v6 v6.0.46/go.mod h1:qD0lajrGW49lKZLtXKtCB4X/qkMf0a5tBvN2PaZg7Gg= @@ -454,13 +460,14 @@ github.com/minio/minio-go/v7 v7.0.74/go.mod h1:qydcVzV8Hqtj1VtEocfxbmVFa2siu6HGa github.com/minio/sha256-simd v0.1.1/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= -github.com/moby/sys/mountinfo v0.6.2/go.mod h1:IJb6JQeOklcdMU9F5xQ8ZALD+CUr5VlGpwtX+VE0rpI= github.com/moby/sys/mountinfo v0.7.2 h1:1shs6aH5s4o5H2zQLn796ADW1wMrIwHsyJ2v9KouLrg= github.com/moby/sys/mountinfo v0.7.2/go.mod h1:1YOa8w8Ih7uW0wALDUgT1dTTSBrZ+HiBLGws92L2RU4= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/ncw/swift/v2 v2.0.3 h1:8R9dmgFIWs+RiVlisCEfiQiik1hjuR0JnOkLxaP9ihg= github.com/ncw/swift/v2 v2.0.3/go.mod h1:cbAO76/ZwcFrFlHdXPjaqWZ9R7Hdar7HpjRXBfbjigk= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= @@ -474,10 +481,10 @@ github.com/onsi/ginkgo/v2 v2.17.3 h1:oJcvKpIb7/8uLpDDtnQuf18xVnwKp8DTD7DQ6gTd/MU github.com/onsi/ginkgo/v2 v2.17.3/go.mod h1:nP2DPOQoNsQmsVyv5rDA8JkXQoCs6goXIvr/PRJ1eCc= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= -github.com/onsi/gomega v1.33.1 h1:dsYjIxxSR755MDmKVsaFQTE22ChNBcuuTWgkUDSubOk= -github.com/onsi/gomega v1.33.1/go.mod h1:U4R44UsT+9eLIaYRB2a5qajjtQYn0hauxvRm16AVYg0= -github.com/oracle/oci-go-sdk/v65 v65.69.2 h1:lROMJ8/VakGOGObAWUxTVY2AX1wQCUIzVqfL4Fb2Ay8= -github.com/oracle/oci-go-sdk/v65 v65.69.2/go.mod h1:IBEV9l1qBzUpo7zgGaRUhbB05BVfcDGYRFBCPlTcPp0= +github.com/onsi/gomega v1.34.1 h1:EUMJIKUjM8sKjYbtxQI9A4z2o+rruxnzNvpknOXie6k= +github.com/onsi/gomega v1.34.1/go.mod h1:kU1QgUvBDLXBJq618Xvm2LUX6rSAfRaFRTcdOeDLwwY= +github.com/oracle/oci-go-sdk/v65 v65.78.0 h1:iM7lFFA7cJkUD4tmrlsAHWgL3HuTuF9mdvTAliMkcFA= +github.com/oracle/oci-go-sdk/v65 v65.78.0/go.mod h1:IBEV9l1qBzUpo7zgGaRUhbB05BVfcDGYRFBCPlTcPp0= github.com/panjf2000/ants/v2 v2.9.1 h1:Q5vh5xohbsZXGcD6hhszzGqB7jSSc2/CRr3QKIga8Kw= github.com/panjf2000/ants/v2 v2.9.1/go.mod h1:7ZxyxsqE4vvW0M7LSD8aI3cKwgFhBHbxnlN8mDqHa1I= github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc= @@ -493,22 +500,22 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/sftp v1.13.6 h1:JFZT4XbOU7l77xGSpOdW+pwIMqP044IyjXX6FGyEKFo= github.com/pkg/sftp v1.13.6/go.mod h1:tz1ryNURKu77RL+GuCzmoJYxQczL3wLNNpPWagdg4Qk= -github.com/pkg/xattr v0.4.9 h1:5883YPCtkSd8LFbs13nXplj9g9tlrwoJRjgpgMu1/fE= -github.com/pkg/xattr v0.4.9/go.mod h1:di8WF84zAKk8jzR1UBTEWh9AUlIZZ7M/JNt8e9B6ktU= +github.com/pkg/xattr v0.4.10 h1:Qe0mtiNFHQZ296vRgUjRCoPHPqH7VdTOrZx3g0T+pGA= +github.com/pkg/xattr v0.4.10/go.mod h1:di8WF84zAKk8jzR1UBTEWh9AUlIZZ7M/JNt8e9B6ktU= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/power-devops/perfstat v0.0.0-20221212215047-62379fc7944b h1:0LFwY6Q3gMACTjAbMZBjXAqTOzOwFaj2Ld6cjeQ7Rig= github.com/power-devops/perfstat v0.0.0-20221212215047-62379fc7944b/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= -github.com/prometheus/client_golang v1.19.1 h1:wZWJDwK+NameRJuPGDhlnFgx8e8HN3XHQeLaYJFJBOE= -github.com/prometheus/client_golang v1.19.1/go.mod h1:mP78NwGzrVks5S2H6ab8+ZZGJLZUq1hoULYBAYBw1Ho= +github.com/prometheus/client_golang v1.20.5 h1:cxppBPuYhUnsO6yo/aoRol4L7q7UFfdm+bR9r+8l63Y= +github.com/prometheus/client_golang v1.20.5/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw= -github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI= -github.com/prometheus/common v0.48.0 h1:QO8U2CdOzSn1BBsmXJXduaaW+dY/5QLjfB8svtSzKKE= -github.com/prometheus/common v0.48.0/go.mod h1:0/KsvlIEfPQCQ5I2iNSAWKPZziNCvRs5EC6ILDTlAPc= -github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo= -github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= +github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= +github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= +github.com/prometheus/common v0.55.0 h1:KEi6DK7lXW/m7Ig5i47x0vRzuBsHuvJdi5ee6Y3G1dc= +github.com/prometheus/common v0.55.0/go.mod h1:2SECS4xJG1kd8XF9IcM1gMX6510RAEL65zxzNImwdc8= +github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc= +github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= github.com/putdotio/go-putio/putio v0.0.0-20200123120452-16d982cac2b8 h1:Y258uzXU/potCYnQd1r6wlAnoMB68BiCkCcCnKx1SH8= github.com/putdotio/go-putio/putio v0.0.0-20200123120452-16d982cac2b8/go.mod h1:bSJjRokAHHOhA+XFxplld8w2R/dXLH7Z3BZ532vhFwU= github.com/quasilyte/go-ruleguard/dsl v0.3.22 h1:wd8zkOhSNr+I+8Qeciml08ivDt1pSXe60+5DqOpCjPE= @@ -521,6 +528,8 @@ github.com/rasky/go-xdr v0.0.0-20170124162913-1a41d1a06c93 h1:UVArwN/wkKjMVhh2EQ github.com/rasky/go-xdr v0.0.0-20170124162913-1a41d1a06c93/go.mod h1:Nfe4efndBz4TibWycNE+lqyJZiMX4ycx+QKV8Ta0f/o= github.com/rclone/gofakes3 v0.0.3 h1:0sKCxJ8TUUAG5KXGuc/fcDKGnzB/j6IjNQui9ntIZPo= github.com/rclone/gofakes3 v0.0.3/go.mod h1:z7+o2VUwitO0WuVHReQlOW9jZ03LpeJ0PUFSULyTIds= +github.com/redis/go-redis/v9 v9.6.1 h1:HHDteefn6ZkTtY5fGUE8tj8uy85AHk6zP7CpzIAM0y4= +github.com/redis/go-redis/v9 v9.6.1/go.mod h1:0C0c6ycQsdpVNQpxb1njEQIqkx5UcsM8FJCQLgE9+RA= github.com/relvacode/iso8601 v1.3.0 h1:HguUjsGpIMh/zsTczGN3DVJFxTU/GX+MMmzcKoMO7ko= github.com/relvacode/iso8601 v1.3.0/go.mod h1:FlNp+jz+TXpyRqgmM7tnzHHzBnz776kmAH2h3sZCn0I= github.com/rfjakob/eme v1.1.2 h1:SxziR8msSOElPayZNFfQw4Tjx/Sbaeeh3eRvrHVMUs4= @@ -614,8 +623,8 @@ github.com/winfsp/cgofuse v1.5.1-0.20221118130120-84c0898ad2e0 h1:j3un8DqYvvAOqK github.com/winfsp/cgofuse v1.5.1-0.20221118130120-84c0898ad2e0/go.mod h1:uxjoF2jEYT3+x+vC2KJddEGdk/LU8pRowXmyVMHSV5I= github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM= github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw= -github.com/youmark/pkcs8 v0.0.0-20201027041543-1326539a0a0a h1:fZHgsYlfvtyqToslyjUt3VOPF4J7aK/3MPcK7xp3PDk= -github.com/youmark/pkcs8 v0.0.0-20201027041543-1326539a0a0a/go.mod h1:ul22v+Nro/R083muKhosV54bj5niojjWZvU8xrevuH4= +github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 h1:ilQV1hzziu+LLM3zUTJ0trRztfwgjqKnBWNtSRkbmwM= +github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78/go.mod h1:aL8wCCfTfSfmXjznFBSZNN13rSJjlIOI1fUNAtF7rmI= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -643,14 +652,14 @@ go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 h1:jq9TW8u3so/bN+JPT166wjOI6/vQPF6Xe7nMNIltagk= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0/go.mod h1:p8pYQP+m5XfbZm9fxtSKAbM6oIllS7s2AfxrChvc7iw= -go.opentelemetry.io/otel v1.24.0 h1:0LAOdjNmQeSTzGBzduGe/rU4tZhMwL5rWgtp9Ku5Jfo= -go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo= -go.opentelemetry.io/otel/metric v1.24.0 h1:6EhoGWWK28x1fbpA4tYTOWBkPefTDQnb8WSGXlc88kI= -go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco= -go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y1YELI= -go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0 h1:TT4fX+nBOA/+LUkobKGW1ydGcn+G3vRw9+g5HwCphpk= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0/go.mod h1:L7UH0GbB0p47T4Rri3uHjbpCFYrVrwc1I25QhNPiGK8= +go.opentelemetry.io/otel v1.29.0 h1:PdomN/Al4q/lN6iBJEN3AwPvUiHPMlt93c8bqTG5Llw= +go.opentelemetry.io/otel v1.29.0/go.mod h1:N/WtXPs1CNCUEx+Agz5uouwCba+i+bJGFicT8SR4NP8= +go.opentelemetry.io/otel/metric v1.29.0 h1:vPf/HFWTNkPu1aYeIsc98l4ktOQaL6LeSoeV2g+8YLc= +go.opentelemetry.io/otel/metric v1.29.0/go.mod h1:auu/QWieFVWx+DmQOUMgj0F8LHWdgalxXqvp7BII/W8= +go.opentelemetry.io/otel/trace v1.29.0 h1:J/8ZNK4XgR7a21DZUAsbF8pZ5Jcw1VhACmnYt39JTi4= +go.opentelemetry.io/otel/trace v1.29.0/go.mod h1:eHl3w0sp3paPkYstJOmAimxhiFXPg+MMTlEh3nsQgWQ= go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A= go.uber.org/goleak v1.2.1/go.mod h1:qlT2yGI9QafXHhZZLxlSuNsMw3FFLxBr+tBRlmO1xH4= go.uber.org/mock v0.3.0 h1:3mUxI1No2/60yUYax92Pt8eNOEecx2D3lcXZh2NEZJo= @@ -665,7 +674,6 @@ golang.org/x/crypto v0.0.0-20190513172903-22d7a77e9e5f/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= @@ -675,8 +683,8 @@ golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2Uz golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= -golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30= -golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M= +golang.org/x/crypto v0.29.0 h1:L5SG1JTTXupVV3n6sUqMTeWbjAyfPwoda2DLX8J8FrQ= +golang.org/x/crypto v0.29.0/go.mod h1:+F4F4N5hv6v38hfeYwTdx20oUvLLc+QfrE9Ax9HtgRg= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -759,16 +767,16 @@ golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= -golang.org/x/net v0.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys= -golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE= +golang.org/x/net v0.31.0 h1:68CPQngjLL0r2AlUKiSxtQFKvzRVbnzLwMUn5SzcLHo= +golang.org/x/net v0.31.0/go.mod h1:P4fl1q7dY2hnZFxEk4pPSkDHF+QqjitcnDjUQyMM+pM= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.21.0 h1:tsimM75w1tF/uws5rbeHzIWxEqElMehnc+iW793zsZs= -golang.org/x/oauth2 v0.21.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= +golang.org/x/oauth2 v0.24.0 h1:KTBBxWqUa0ykRPLtV69rRto9TLXcqYkeswu48x/gvNE= +golang.org/x/oauth2 v0.24.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -778,12 +786,11 @@ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= -golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= -golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.9.0 h1:fEo0HyrW1GIgZdpbhCRO0PkJajUS5H9IFUztCgEo2jQ= +golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -839,8 +846,8 @@ golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI= -golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s= +golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= @@ -851,8 +858,8 @@ golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY= golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= -golang.org/x/term v0.22.0 h1:BbsgPEJULsl2fV/AT3v15Mjva5yXKQDyKf+TbDz7QJk= -golang.org/x/term v0.22.0/go.mod h1:F3qCibpT5AMpCRfhfT53vVJwhLtIVHhB9XDjfFvnMI4= +golang.org/x/term v0.26.0 h1:WEQa6V3Gja/BhNxg540hBip/kkaYtRg3cxg4oXSw4AU= +golang.org/x/term v0.26.0/go.mod h1:Si5m1o57C5nBNQo5z1iq+XDijt21BDBDp2bK0QI8e3E= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -866,14 +873,14 @@ golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc= -golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= +golang.org/x/text v0.20.0 h1:gK/Kv2otX8gz+wn7Rmb3vT96ZwuoxnQlY+HlJVj7Qug= +golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= -golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +golang.org/x/time v0.8.0 h1:9i3RxcPv3PZnitoVGMPDKZSq1xW1gK1Xy3ArNOGZfEg= +golang.org/x/time v0.8.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= @@ -944,8 +951,8 @@ google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0M google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= -google.golang.org/api v0.188.0 h1:51y8fJ/b1AaaBRJr4yWm96fPcuxSo0JcegXE3DaHQHw= -google.golang.org/api v0.188.0/go.mod h1:VR0d+2SIiWOYG3r/jdm7adPW9hI2aRv9ETOSCQ9Beag= +google.golang.org/api v0.205.0 h1:LFaxkAIpDb/GsrWV20dMMo5MR0h8UARTbn24LmD+0Pg= +google.golang.org/api v0.205.0/go.mod h1:NrK1EMqO8Xk6l6QwRAmrXXg2v6dzukhlOyvkYtnvUuc= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -981,10 +988,10 @@ google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7Fc google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto/googleapis/api v0.0.0-20240701130421-f6361c86f094 h1:0+ozOGcrp+Y8Aq8TLNN2Aliibms5LEzsq99ZZmAGYm0= -google.golang.org/genproto/googleapis/api v0.0.0-20240701130421-f6361c86f094/go.mod h1:fJ/e3If/Q67Mj99hin0hMhiNyCRmt6BQ2aWIJshUSJw= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240708141625-4ad9e859172b h1:04+jVzTs2XBnOZcPsLnmrTGqltqJbZQ1Ey26hjYdQQ0= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240708141625-4ad9e859172b/go.mod h1:Ue6ibwXGpU+dqIcODieyLOcgj7z8+IcskoNIgZxtrFY= +google.golang.org/genproto/googleapis/api v0.0.0-20241015192408-796eee8c2d53 h1:fVoAXEKA4+yufmbdVYv+SE73+cPZbbbe8paLsHfkK+U= +google.golang.org/genproto/googleapis/api v0.0.0-20241015192408-796eee8c2d53/go.mod h1:riSXTwQ4+nqmPGtobMFyW5FqVAmIs0St6VPp4Ug7CE4= +google.golang.org/genproto/googleapis/rpc v0.0.0-20241021214115-324edc3d5d38 h1:zciRKQ4kBpFgpfC5QQCVtnnNAcLIqweL7plyZRQHVpI= +google.golang.org/genproto/googleapis/rpc v0.0.0-20241021214115-324edc3d5d38/go.mod h1:GX3210XPVPUjJbTUbvwI8f2IpZDMZuPJWDzDuebbviI= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= @@ -998,8 +1005,8 @@ google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3Iji google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= -google.golang.org/grpc v1.64.1 h1:LKtvyfbX3UGVPFcGqJ9ItpVWW6oN/2XqTxfAnwRRXiA= -google.golang.org/grpc v1.64.1/go.mod h1:hiQF4LFZelK2WKaP6W0L92zGHtiQdZxk8CrSdvyjeP0= +google.golang.org/grpc v1.67.1 h1:zWnc1Vrcno+lHZCOofnIMvycFcc0QRGIzm9dhnDX68E= +google.golang.org/grpc v1.67.1/go.mod h1:1gLDyUQU7CTLJI90u3nXZ9ekeghjeM7pTDZlqFNg2AA= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -1010,8 +1017,8 @@ google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2 google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= -google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= -google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= +google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA= +google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= From 1317fdb9b85b5b3f38984a595a11a0878541eb0c Mon Sep 17 00:00:00 2001 From: Nick Craig-Wood Date: Mon, 11 Nov 2024 17:54:59 +0000 Subject: [PATCH 31/39] build: fix comments after golangci-lint upgrade --- backend/onedrive/api/types.go | 32 ++++++++++++++++++++++---------- cmd/bisync/log.go | 3 ++- lib/multipart/multipart.go | 3 ++- 3 files changed, 26 insertions(+), 12 deletions(-) diff --git a/backend/onedrive/api/types.go b/backend/onedrive/api/types.go index 0332f1c12..7fe032c23 100644 --- a/backend/onedrive/api/types.go +++ b/backend/onedrive/api/types.go @@ -202,9 +202,14 @@ type SharingLinkType struct { type LinkType string const ( - ViewLinkType LinkType = "view" // ViewLinkType (role: read) A view-only sharing link, allowing read-only access. - EditLinkType LinkType = "edit" // EditLinkType (role: write) An edit sharing link, allowing read-write access. - EmbedLinkType LinkType = "embed" // EmbedLinkType (role: read) A view-only sharing link that can be used to embed content into a host webpage. Embed links are not available for OneDrive for Business or SharePoint. + // ViewLinkType (role: read) A view-only sharing link, allowing read-only access. + ViewLinkType LinkType = "view" + // EditLinkType (role: write) An edit sharing link, allowing read-write access. + EditLinkType LinkType = "edit" + // EmbedLinkType (role: read) A view-only sharing link that can be used to embed + // content into a host webpage. Embed links are not available for OneDrive for + // Business or SharePoint. + EmbedLinkType LinkType = "embed" ) // LinkScope represents the scope of the link represented by this permission. @@ -212,9 +217,12 @@ const ( type LinkScope string const ( - AnonymousScope LinkScope = "anonymous" // AnonymousScope = Anyone with the link has access, without needing to sign in. This may include people outside of your organization. - OrganizationScope LinkScope = "organization" // OrganizationScope = Anyone signed into your organization (tenant) can use the link to get access. Only available in OneDrive for Business and SharePoint. - + // AnonymousScope = Anyone with the link has access, without needing to sign in. + // This may include people outside of your organization. + AnonymousScope LinkScope = "anonymous" + // OrganizationScope = Anyone signed into your organization (tenant) can use the + // link to get access. Only available in OneDrive for Business and SharePoint. + OrganizationScope LinkScope = "organization" ) // PermissionsType provides information about a sharing permission granted for a DriveItem resource. @@ -236,10 +244,14 @@ type PermissionsType struct { type Role string const ( - ReadRole Role = "read" // ReadRole provides the ability to read the metadata and contents of the item. - WriteRole Role = "write" // WriteRole provides the ability to read and modify the metadata and contents of the item. - OwnerRole Role = "owner" // OwnerRole represents the owner role for SharePoint and OneDrive for Business. - MemberRole Role = "member" // MemberRole represents the member role for SharePoint and OneDrive for Business. + // ReadRole provides the ability to read the metadata and contents of the item. + ReadRole Role = "read" + // WriteRole provides the ability to read and modify the metadata and contents of the item. + WriteRole Role = "write" + // OwnerRole represents the owner role for SharePoint and OneDrive for Business. + OwnerRole Role = "owner" + // MemberRole represents the member role for SharePoint and OneDrive for Business. + MemberRole Role = "member" ) // PermissionsResponse is the response to the list permissions method diff --git a/cmd/bisync/log.go b/cmd/bisync/log.go index 0d7f4b2f7..7dce79176 100644 --- a/cmd/bisync/log.go +++ b/cmd/bisync/log.go @@ -66,7 +66,8 @@ func quotePath(path string) string { return escapePath(path, true) } -var Colors bool // Colors controls whether terminal colors are enabled +// Colors controls whether terminal colors are enabled +var Colors bool // Color handles terminal colors for bisync func Color(style string, s string) string { diff --git a/lib/multipart/multipart.go b/lib/multipart/multipart.go index c388acc01..1545f4ced 100644 --- a/lib/multipart/multipart.go +++ b/lib/multipart/multipart.go @@ -17,7 +17,8 @@ import ( ) const ( - BufferSize = 1024 * 1024 // BufferSize is the default size of the pages used in the reader + // BufferSize is the default size of the pages used in the reader + BufferSize = 1024 * 1024 bufferCacheSize = 64 // max number of buffers to keep in cache bufferCacheFlushTime = 5 * time.Second // flush the cached buffers after this long ) From 173b2ac956da6bbc7565e0aee61ac412f512b5ee Mon Sep 17 00:00:00 2001 From: Nick Craig-Wood Date: Mon, 11 Nov 2024 18:12:39 +0000 Subject: [PATCH 32/39] serve sftp: update github.com/pkg/sftp to v1.13.7 and fix deadlock in tests Before this change, upgrading to v1.13.7 caused a deadlock in the tests. This was caused by additional locking in the sftp package exposing a bad choice by the rclone code. See https://github.com/pkg/sftp/issues/603 and thanks to @puellanivis for the fix suggestion. --- backend/sftp/sftp.go | 4 ++-- go.mod | 2 +- go.sum | 7 +++++-- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/backend/sftp/sftp.go b/backend/sftp/sftp.go index c3c60aade..3becf7b5c 100644 --- a/backend/sftp/sftp.go +++ b/backend/sftp/sftp.go @@ -2101,10 +2101,10 @@ func (file *objectReader) Read(p []byte) (n int, err error) { // Close a reader of a remote sftp file func (file *objectReader) Close() (err error) { - // Close the sftpFile - this will likely cause the WriteTo to error - err = file.sftpFile.Close() // Close the pipeReader so writes to the pipeWriter fail _ = file.pipeReader.Close() + // Close the sftpFile - this will likely cause the WriteTo to error + err = file.sftpFile.Close() // Wait for the background process to finish <-file.done // Show connection no longer in use diff --git a/go.mod b/go.mod index eada8a54a..77bf388b6 100644 --- a/go.mod +++ b/go.mod @@ -54,7 +54,7 @@ require ( github.com/ncw/swift/v2 v2.0.3 github.com/oracle/oci-go-sdk/v65 v65.78.0 github.com/patrickmn/go-cache v2.1.0+incompatible - github.com/pkg/sftp v1.13.6 + github.com/pkg/sftp v1.13.7 github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 github.com/prometheus/client_golang v1.20.5 github.com/putdotio/go-putio/putio v0.0.0-20200123120452-16d982cac2b8 diff --git a/go.sum b/go.sum index 0677c12cd..68b597bbb 100644 --- a/go.sum +++ b/go.sum @@ -498,8 +498,8 @@ github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjL github.com/pkg/diff v0.0.0-20200914180035-5b29258ca4f7/go.mod h1:zO8QMzTeZd5cpnIkz/Gn6iK0jDfGicM1nynOkkPIl28= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/sftp v1.13.6 h1:JFZT4XbOU7l77xGSpOdW+pwIMqP044IyjXX6FGyEKFo= -github.com/pkg/sftp v1.13.6/go.mod h1:tz1ryNURKu77RL+GuCzmoJYxQczL3wLNNpPWagdg4Qk= +github.com/pkg/sftp v1.13.7 h1:uv+I3nNJvlKZIQGSr8JVQLNHFU9YhhNpvC14Y6KgmSM= +github.com/pkg/sftp v1.13.7/go.mod h1:KMKI0t3T6hfA+lTR/ssZdunHo+uwq7ghoN09/FSu3DY= github.com/pkg/xattr v0.4.10 h1:Qe0mtiNFHQZ296vRgUjRCoPHPqH7VdTOrZx3g0T+pGA= github.com/pkg/xattr v0.4.10/go.mod h1:di8WF84zAKk8jzR1UBTEWh9AUlIZZ7M/JNt8e9B6ktU= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= @@ -683,6 +683,7 @@ golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2Uz golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= +golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= golang.org/x/crypto v0.29.0 h1:L5SG1JTTXupVV3n6sUqMTeWbjAyfPwoda2DLX8J8FrQ= golang.org/x/crypto v0.29.0/go.mod h1:+F4F4N5hv6v38hfeYwTdx20oUvLLc+QfrE9Ax9HtgRg= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -845,6 +846,7 @@ golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s= golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= @@ -857,6 +859,7 @@ golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY= golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= +golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0= golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= golang.org/x/term v0.26.0 h1:WEQa6V3Gja/BhNxg540hBip/kkaYtRg3cxg4oXSw4AU= golang.org/x/term v0.26.0/go.mod h1:Si5m1o57C5nBNQo5z1iq+XDijt21BDBDp2bK0QI8e3E= From abe884e74473e8a60beacc7b013ca6db899adcb9 Mon Sep 17 00:00:00 2001 From: Dimitrios Slamaris Date: Tue, 12 Nov 2024 12:42:54 +0100 Subject: [PATCH 33/39] bisync: fix output capture restoring the wrong output for logrus Before this change, if rclone is used as a library and logrus is used after a call to rc `sync/bisync`, logging does not work anymore and leads to writing to a closed pipe. This change restores the output correctly. Fixes #8158 --- cmd/bisync/bilib/output.go | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/cmd/bisync/bilib/output.go b/cmd/bisync/bilib/output.go index ccd85c125..c35abde86 100644 --- a/cmd/bisync/bilib/output.go +++ b/cmd/bisync/bilib/output.go @@ -5,20 +5,13 @@ import ( "bytes" "log" - "github.com/rclone/rclone/fs" "github.com/sirupsen/logrus" ) // CaptureOutput runs a function capturing its output. func CaptureOutput(fun func()) []byte { logSave := log.Writer() - logrusSave := logrus.StandardLogger().Writer() - defer func() { - err := logrusSave.Close() - if err != nil { - fs.Errorf(nil, "error closing logrusSave: %v", err) - } - }() + logrusSave := logrus.StandardLogger().Out buf := &bytes.Buffer{} log.SetOutput(buf) logrus.SetOutput(buf) From e50f995d879d5efcd36a001b8ba64a93242c4929 Mon Sep 17 00:00:00 2001 From: Nick Craig-Wood Date: Tue, 12 Nov 2024 12:29:44 +0000 Subject: [PATCH 34/39] operations: fix TestRemoveExisting on crypt backends by shortening the file name --- fs/operations/operations_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/operations/operations_test.go b/fs/operations/operations_test.go index 2a5c3cb6c..3f02c1bf1 100644 --- a/fs/operations/operations_test.go +++ b/fs/operations/operations_test.go @@ -1893,7 +1893,7 @@ func TestRemoveExisting(t *testing.T) { } file1 := r.WriteObject(ctx, "sub dir/test remove existing", "hello world", t1) - file2 := r.WriteObject(ctx, "sub dir/test remove existing with long name 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890", "hello long name world", t1) + file2 := r.WriteObject(ctx, "sub dir/test remove existing with long name 123456789012345678901234567890123456789012345678901234567890123456789", "hello long name world", t1) r.CheckRemoteItems(t, file1, file2) From f639cd9c78984aa793d72ea8cf7920db45270c4e Mon Sep 17 00:00:00 2001 From: Nick Craig-Wood Date: Tue, 12 Nov 2024 13:05:57 +0000 Subject: [PATCH 35/39] onedrive: fix integration tests after precision change We changed the precision of the onedrive personal backend in c053429b9c0bbca5 from 1mS to 1S. However the tests did not get updated. This changes the time tests to use `fstest.AssertTimeEqualWithPrecision` which compares with precision so hopefully won't break again. --- backend/onedrive/onedrive_internal_test.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/backend/onedrive/onedrive_internal_test.go b/backend/onedrive/onedrive_internal_test.go index 5ac2141d0..843ede35f 100644 --- a/backend/onedrive/onedrive_internal_test.go +++ b/backend/onedrive/onedrive_internal_test.go @@ -215,11 +215,11 @@ func (f *Fs) TestDirectoryMetadata(t *testing.T, r *fstest.Run) { compareDirMeta(expectedMeta, actualMeta, false) // modtime - assert.Equal(t, t1.Truncate(f.Precision()), newDst.ModTime(ctx)) + fstest.AssertTimeEqualWithPrecision(t, newDst.Remote(), t1, newDst.ModTime(ctx), f.Precision()) // try changing it and re-check it newDst, err = operations.SetDirModTime(ctx, f, newDst, "", t2) assert.NoError(t, err) - assert.Equal(t, t2.Truncate(f.Precision()), newDst.ModTime(ctx)) + fstest.AssertTimeEqualWithPrecision(t, newDst.Remote(), t2, newDst.ModTime(ctx), f.Precision()) // ensure that f.DirSetModTime also works err = f.DirSetModTime(ctx, "subdir", t3) assert.NoError(t, err) @@ -227,7 +227,7 @@ func (f *Fs) TestDirectoryMetadata(t *testing.T, r *fstest.Run) { assert.NoError(t, err) entries.ForDir(func(dir fs.Directory) { if dir.Remote() == "subdir" { - assert.True(t, t3.Truncate(f.Precision()).Equal(dir.ModTime(ctx)), fmt.Sprintf("got %v", dir.ModTime(ctx))) + fstest.AssertTimeEqualWithPrecision(t, dir.Remote(), t3, dir.ModTime(ctx), f.Precision()) } }) From 1e2b354456882ed22d8674b8bf37de55e0069514 Mon Sep 17 00:00:00 2001 From: Nick Craig-Wood Date: Thu, 14 Nov 2024 16:13:57 +0000 Subject: [PATCH 36/39] Merge commit from fork Before this change, if writing to a local backend with --metadata and --links, if the incoming metadata contained mode or ownership information then rclone would apply the mode/ownership to the destination of the link not the link itself. This fixes the problem by using the link safe sycall variants lchown/fchmodat when --links and --metadata is in use. Note that Linux does not support setting permissions on symlinks, so rclone emits a debug message in this case. This also fixes setting times on symlinks on Windows which wasn't implemented for atime, mtime and was incorrectly setting the target of the symlink for btime. See: https://github.com/rclone/rclone/security/advisories/GHSA-hrxh-9w67-g4cv --- backend/local/lchmod.go | 16 ++++++ backend/local/lchmod_unix.go | 41 +++++++++++++++ backend/local/lchtimes.go | 2 +- backend/local/lchtimes_windows.go | 19 +++++++ backend/local/local_internal_test.go | 76 ++++++++++++++++++++++++---- backend/local/metadata.go | 23 +++++++-- backend/local/setbtime.go | 6 +++ backend/local/setbtime_windows.go | 37 ++++++++++++-- 8 files changed, 202 insertions(+), 18 deletions(-) create mode 100644 backend/local/lchmod.go create mode 100644 backend/local/lchmod_unix.go create mode 100644 backend/local/lchtimes_windows.go diff --git a/backend/local/lchmod.go b/backend/local/lchmod.go new file mode 100644 index 000000000..823718dfe --- /dev/null +++ b/backend/local/lchmod.go @@ -0,0 +1,16 @@ +//go:build windows || plan9 || js || linux + +package local + +import "os" + +const haveLChmod = false + +// lChmod changes the mode of the named file to mode. If the file is a symbolic +// link, it changes the link, not the target. If there is an error, +// it will be of type *PathError. +func lChmod(name string, mode os.FileMode) error { + // Can't do this safely on this OS - chmoding a symlink always + // changes the destination. + return nil +} diff --git a/backend/local/lchmod_unix.go b/backend/local/lchmod_unix.go new file mode 100644 index 000000000..f1fdc4745 --- /dev/null +++ b/backend/local/lchmod_unix.go @@ -0,0 +1,41 @@ +//go:build !windows && !plan9 && !js && !linux + +package local + +import ( + "os" + "syscall" + + "golang.org/x/sys/unix" +) + +const haveLChmod = true + +// syscallMode returns the syscall-specific mode bits from Go's portable mode bits. +// +// Borrowed from the syscall source since it isn't public. +func syscallMode(i os.FileMode) (o uint32) { + o |= uint32(i.Perm()) + if i&os.ModeSetuid != 0 { + o |= syscall.S_ISUID + } + if i&os.ModeSetgid != 0 { + o |= syscall.S_ISGID + } + if i&os.ModeSticky != 0 { + o |= syscall.S_ISVTX + } + return o +} + +// lChmod changes the mode of the named file to mode. If the file is a symbolic +// link, it changes the link, not the target. If there is an error, +// it will be of type *PathError. +func lChmod(name string, mode os.FileMode) error { + // NB linux does not support AT_SYMLINK_NOFOLLOW as a parameter to fchmodat + // and returns ENOTSUP if you try, so we don't support this on linux + if e := unix.Fchmodat(unix.AT_FDCWD, name, syscallMode(mode), unix.AT_SYMLINK_NOFOLLOW); e != nil { + return &os.PathError{Op: "lChmod", Path: name, Err: e} + } + return nil +} diff --git a/backend/local/lchtimes.go b/backend/local/lchtimes.go index c8f03ef46..fcabdcc34 100644 --- a/backend/local/lchtimes.go +++ b/backend/local/lchtimes.go @@ -1,4 +1,4 @@ -//go:build windows || plan9 || js +//go:build plan9 || js package local diff --git a/backend/local/lchtimes_windows.go b/backend/local/lchtimes_windows.go new file mode 100644 index 000000000..a6dec9a12 --- /dev/null +++ b/backend/local/lchtimes_windows.go @@ -0,0 +1,19 @@ +//go:build windows + +package local + +import ( + "time" +) + +const haveLChtimes = true + +// lChtimes changes the access and modification times of the named +// link, similar to the Unix utime() or utimes() functions. +// +// The underlying filesystem may truncate or round the values to a +// less precise time unit. +// If there is an error, it will be of type *PathError. +func lChtimes(name string, atime time.Time, mtime time.Time) error { + return setTimes(name, atime, mtime, time.Time{}, true) +} diff --git a/backend/local/local_internal_test.go b/backend/local/local_internal_test.go index ea0fdc765..b3b9b8ba1 100644 --- a/backend/local/local_internal_test.go +++ b/backend/local/local_internal_test.go @@ -268,22 +268,66 @@ func TestMetadata(t *testing.T) { r := fstest.NewRun(t) const filePath = "metafile.txt" when := time.Now() - const dayLength = len("2001-01-01") - whenRFC := when.Format(time.RFC3339Nano) r.WriteFile(filePath, "metadata file contents", when) f := r.Flocal.(*Fs) + // Set fs into "-l" / "--links" mode + f.opt.TranslateSymlinks = true + + // Write a symlink to the file + symlinkPath := "metafile-link.txt" + osSymlinkPath := filepath.Join(f.root, symlinkPath) + symlinkPath += linkSuffix + require.NoError(t, os.Symlink(filePath, osSymlinkPath)) + symlinkModTime := fstest.Time("2002-02-03T04:05:10.123123123Z") + require.NoError(t, lChtimes(osSymlinkPath, symlinkModTime, symlinkModTime)) + // Get the object obj, err := f.NewObject(ctx, filePath) require.NoError(t, err) o := obj.(*Object) + // Get the symlink object + symlinkObj, err := f.NewObject(ctx, symlinkPath) + require.NoError(t, err) + symlinkO := symlinkObj.(*Object) + + // Record metadata for o + oMeta, err := o.Metadata(ctx) + require.NoError(t, err) + + // Test symlink first to check it doesn't mess up file + t.Run("Symlink", func(t *testing.T) { + testMetadata(t, r, symlinkO, symlinkModTime) + }) + + // Read it again + oMetaNew, err := o.Metadata(ctx) + require.NoError(t, err) + + // Check that operating on the symlink didn't change the file it was pointing to + // See: https://github.com/rclone/rclone/security/advisories/GHSA-hrxh-9w67-g4cv + assert.Equal(t, oMeta, oMetaNew, "metadata setting on symlink messed up file") + + // Now run the same tests on the file + t.Run("File", func(t *testing.T) { + testMetadata(t, r, o, when) + }) +} + +func testMetadata(t *testing.T, r *fstest.Run, o *Object, when time.Time) { + ctx := context.Background() + whenRFC := when.Format(time.RFC3339Nano) + const dayLength = len("2001-01-01") + + f := r.Flocal.(*Fs) features := f.Features() - var hasXID, hasAtime, hasBtime bool + var hasXID, hasAtime, hasBtime, canSetXattrOnLinks bool switch runtime.GOOS { case "darwin", "freebsd", "netbsd", "linux": hasXID, hasAtime, hasBtime = true, true, true + canSetXattrOnLinks = runtime.GOOS != "linux" case "openbsd", "solaris": hasXID, hasAtime = true, true case "windows": @@ -306,6 +350,10 @@ func TestMetadata(t *testing.T) { require.NoError(t, err) assert.Nil(t, m) + if !canSetXattrOnLinks && o.translatedLink { + t.Skip("Skip remainder of test as can't set xattr on symlinks on this OS") + } + inM := fs.Metadata{ "potato": "chips", "cabbage": "soup", @@ -320,18 +368,21 @@ func TestMetadata(t *testing.T) { }) checkTime := func(m fs.Metadata, key string, when time.Time) { + t.Helper() mt, ok := o.parseMetadataTime(m, key) assert.True(t, ok) dt := mt.Sub(when) precision := time.Second - assert.True(t, dt >= -precision && dt <= precision, fmt.Sprintf("%s: dt %v outside +/- precision %v", key, dt, precision)) + assert.True(t, dt >= -precision && dt <= precision, fmt.Sprintf("%s: dt %v outside +/- precision %v want %v got %v", key, dt, precision, mt, when)) } checkInt := func(m fs.Metadata, key string, base int) int { + t.Helper() value, ok := o.parseMetadataInt(m, key, base) assert.True(t, ok) return value } + t.Run("Read", func(t *testing.T) { m, err := o.Metadata(ctx) require.NoError(t, err) @@ -341,13 +392,12 @@ func TestMetadata(t *testing.T) { checkInt(m, "mode", 8) checkTime(m, "mtime", when) - assert.Equal(t, len(whenRFC), len(m["mtime"])) assert.Equal(t, whenRFC[:dayLength], m["mtime"][:dayLength]) - if hasAtime { + if hasAtime && !o.translatedLink { // symlinks generally don't record atime checkTime(m, "atime", when) } - if hasBtime { + if hasBtime && !o.translatedLink { // symlinks generally don't record btime checkTime(m, "btime", when) } if hasXID { @@ -371,6 +421,10 @@ func TestMetadata(t *testing.T) { "mode": "0767", "potato": "wedges", } + if !canSetXattrOnLinks && o.translatedLink { + // Don't change xattr if not supported on symlinks + delete(newM, "potato") + } err := o.writeMetadata(newM) require.NoError(t, err) @@ -380,7 +434,11 @@ func TestMetadata(t *testing.T) { mode := checkInt(m, "mode", 8) if runtime.GOOS != "windows" { - assert.Equal(t, 0767, mode&0777, fmt.Sprintf("mode wrong - expecting 0767 got 0%o", mode&0777)) + expectedMode := 0767 + if o.translatedLink && runtime.GOOS == "linux" { + expectedMode = 0777 // perms of symlinks always read as 0777 on linux + } + assert.Equal(t, expectedMode, mode&0777, fmt.Sprintf("mode wrong - expecting 0%o got 0%o", expectedMode, mode&0777)) } checkTime(m, "mtime", newMtime) @@ -390,7 +448,7 @@ func TestMetadata(t *testing.T) { if haveSetBTime { checkTime(m, "btime", newBtime) } - if xattrSupported { + if xattrSupported && (canSetXattrOnLinks || !o.translatedLink) { assert.Equal(t, "wedges", m["potato"]) } }) diff --git a/backend/local/metadata.go b/backend/local/metadata.go index 7ab69af30..75b195e64 100644 --- a/backend/local/metadata.go +++ b/backend/local/metadata.go @@ -105,7 +105,11 @@ func (o *Object) writeMetadataToFile(m fs.Metadata) (outErr error) { } if haveSetBTime { if btimeOK { - err = setBTime(o.path, btime) + if o.translatedLink { + err = lsetBTime(o.path, btime) + } else { + err = setBTime(o.path, btime) + } if err != nil { outErr = fmt.Errorf("failed to set birth (creation) time: %w", err) } @@ -121,7 +125,11 @@ func (o *Object) writeMetadataToFile(m fs.Metadata) (outErr error) { if runtime.GOOS == "windows" || runtime.GOOS == "plan9" { fs.Debugf(o, "Ignoring request to set ownership %o.%o on this OS", gid, uid) } else { - err = os.Chown(o.path, uid, gid) + if o.translatedLink { + err = os.Lchown(o.path, uid, gid) + } else { + err = os.Chown(o.path, uid, gid) + } if err != nil { outErr = fmt.Errorf("failed to change ownership: %w", err) } @@ -132,7 +140,16 @@ func (o *Object) writeMetadataToFile(m fs.Metadata) (outErr error) { if mode >= 0 { umode := uint(mode) if umode <= math.MaxUint32 { - err = os.Chmod(o.path, os.FileMode(umode)) + if o.translatedLink { + if haveLChmod { + err = lChmod(o.path, os.FileMode(umode)) + } else { + fs.Debugf(o, "Unable to set mode %v on a symlink on this OS", os.FileMode(umode)) + err = nil + } + } else { + err = os.Chmod(o.path, os.FileMode(umode)) + } if err != nil { outErr = fmt.Errorf("failed to change permissions: %w", err) } diff --git a/backend/local/setbtime.go b/backend/local/setbtime.go index 5c946348f..bb37b1735 100644 --- a/backend/local/setbtime.go +++ b/backend/local/setbtime.go @@ -13,3 +13,9 @@ func setBTime(name string, btime time.Time) error { // Does nothing return nil } + +// lsetBTime changes the birth time of the link passed in +func lsetBTime(name string, btime time.Time) error { + // Does nothing + return nil +} diff --git a/backend/local/setbtime_windows.go b/backend/local/setbtime_windows.go index 510a4da6a..8ae499826 100644 --- a/backend/local/setbtime_windows.go +++ b/backend/local/setbtime_windows.go @@ -9,15 +9,20 @@ import ( const haveSetBTime = true -// setBTime sets the birth time of the file passed in -func setBTime(name string, btime time.Time) (err error) { +// setTimes sets any of atime, mtime or btime +// if link is set it sets a link rather than the target +func setTimes(name string, atime, mtime, btime time.Time, link bool) (err error) { pathp, err := syscall.UTF16PtrFromString(name) if err != nil { return err } + fileFlag := uint32(syscall.FILE_FLAG_BACKUP_SEMANTICS) + if link { + fileFlag |= syscall.FILE_FLAG_OPEN_REPARSE_POINT + } h, err := syscall.CreateFile(pathp, syscall.FILE_WRITE_ATTRIBUTES, syscall.FILE_SHARE_WRITE, nil, - syscall.OPEN_EXISTING, syscall.FILE_FLAG_BACKUP_SEMANTICS, 0) + syscall.OPEN_EXISTING, fileFlag, 0) if err != nil { return err } @@ -27,6 +32,28 @@ func setBTime(name string, btime time.Time) (err error) { err = closeErr } }() - bFileTime := syscall.NsecToFiletime(btime.UnixNano()) - return syscall.SetFileTime(h, &bFileTime, nil, nil) + var patime, pmtime, pbtime *syscall.Filetime + if !atime.IsZero() { + t := syscall.NsecToFiletime(atime.UnixNano()) + patime = &t + } + if !mtime.IsZero() { + t := syscall.NsecToFiletime(mtime.UnixNano()) + pmtime = &t + } + if !btime.IsZero() { + t := syscall.NsecToFiletime(btime.UnixNano()) + pbtime = &t + } + return syscall.SetFileTime(h, pbtime, patime, pmtime) +} + +// setBTime sets the birth time of the file passed in +func setBTime(name string, btime time.Time) (err error) { + return setTimes(name, time.Time{}, time.Time{}, btime, false) +} + +// lsetBTime changes the birth time of the link passed in +func lsetBTime(name string, btime time.Time) error { + return setTimes(name, time.Time{}, time.Time{}, btime, true) } From 8cc1020a58b9f08b2450132733e309758df41b63 Mon Sep 17 00:00:00 2001 From: Nick Craig-Wood Date: Thu, 14 Nov 2024 16:15:49 +0000 Subject: [PATCH 37/39] Add Dimitrios Slamaris to contributors --- docs/content/authors.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/content/authors.md b/docs/content/authors.md index ddc85ad0c..45010fcb9 100644 --- a/docs/content/authors.md +++ b/docs/content/authors.md @@ -908,3 +908,4 @@ put them back in again.` >}} * Moises Lima * Dimitar Ivanov * shenpengfeng + * Dimitrios Slamaris From 84b64dcdf9014044f1d0ba6b17e2001ac77f07ba Mon Sep 17 00:00:00 2001 From: Nick Craig-Wood Date: Thu, 14 Nov 2024 16:20:06 +0000 Subject: [PATCH 38/39] Revert "Merge commit from fork" This reverts commit 1e2b354456882ed22d8674b8bf37de55e0069514. --- backend/local/lchmod.go | 16 ------ backend/local/lchmod_unix.go | 41 --------------- backend/local/lchtimes.go | 2 +- backend/local/lchtimes_windows.go | 19 ------- backend/local/local_internal_test.go | 76 ++++------------------------ backend/local/metadata.go | 23 ++------- backend/local/setbtime.go | 6 --- backend/local/setbtime_windows.go | 37 ++------------ 8 files changed, 18 insertions(+), 202 deletions(-) delete mode 100644 backend/local/lchmod.go delete mode 100644 backend/local/lchmod_unix.go delete mode 100644 backend/local/lchtimes_windows.go diff --git a/backend/local/lchmod.go b/backend/local/lchmod.go deleted file mode 100644 index 823718dfe..000000000 --- a/backend/local/lchmod.go +++ /dev/null @@ -1,16 +0,0 @@ -//go:build windows || plan9 || js || linux - -package local - -import "os" - -const haveLChmod = false - -// lChmod changes the mode of the named file to mode. If the file is a symbolic -// link, it changes the link, not the target. If there is an error, -// it will be of type *PathError. -func lChmod(name string, mode os.FileMode) error { - // Can't do this safely on this OS - chmoding a symlink always - // changes the destination. - return nil -} diff --git a/backend/local/lchmod_unix.go b/backend/local/lchmod_unix.go deleted file mode 100644 index f1fdc4745..000000000 --- a/backend/local/lchmod_unix.go +++ /dev/null @@ -1,41 +0,0 @@ -//go:build !windows && !plan9 && !js && !linux - -package local - -import ( - "os" - "syscall" - - "golang.org/x/sys/unix" -) - -const haveLChmod = true - -// syscallMode returns the syscall-specific mode bits from Go's portable mode bits. -// -// Borrowed from the syscall source since it isn't public. -func syscallMode(i os.FileMode) (o uint32) { - o |= uint32(i.Perm()) - if i&os.ModeSetuid != 0 { - o |= syscall.S_ISUID - } - if i&os.ModeSetgid != 0 { - o |= syscall.S_ISGID - } - if i&os.ModeSticky != 0 { - o |= syscall.S_ISVTX - } - return o -} - -// lChmod changes the mode of the named file to mode. If the file is a symbolic -// link, it changes the link, not the target. If there is an error, -// it will be of type *PathError. -func lChmod(name string, mode os.FileMode) error { - // NB linux does not support AT_SYMLINK_NOFOLLOW as a parameter to fchmodat - // and returns ENOTSUP if you try, so we don't support this on linux - if e := unix.Fchmodat(unix.AT_FDCWD, name, syscallMode(mode), unix.AT_SYMLINK_NOFOLLOW); e != nil { - return &os.PathError{Op: "lChmod", Path: name, Err: e} - } - return nil -} diff --git a/backend/local/lchtimes.go b/backend/local/lchtimes.go index fcabdcc34..c8f03ef46 100644 --- a/backend/local/lchtimes.go +++ b/backend/local/lchtimes.go @@ -1,4 +1,4 @@ -//go:build plan9 || js +//go:build windows || plan9 || js package local diff --git a/backend/local/lchtimes_windows.go b/backend/local/lchtimes_windows.go deleted file mode 100644 index a6dec9a12..000000000 --- a/backend/local/lchtimes_windows.go +++ /dev/null @@ -1,19 +0,0 @@ -//go:build windows - -package local - -import ( - "time" -) - -const haveLChtimes = true - -// lChtimes changes the access and modification times of the named -// link, similar to the Unix utime() or utimes() functions. -// -// The underlying filesystem may truncate or round the values to a -// less precise time unit. -// If there is an error, it will be of type *PathError. -func lChtimes(name string, atime time.Time, mtime time.Time) error { - return setTimes(name, atime, mtime, time.Time{}, true) -} diff --git a/backend/local/local_internal_test.go b/backend/local/local_internal_test.go index b3b9b8ba1..ea0fdc765 100644 --- a/backend/local/local_internal_test.go +++ b/backend/local/local_internal_test.go @@ -268,66 +268,22 @@ func TestMetadata(t *testing.T) { r := fstest.NewRun(t) const filePath = "metafile.txt" when := time.Now() + const dayLength = len("2001-01-01") + whenRFC := when.Format(time.RFC3339Nano) r.WriteFile(filePath, "metadata file contents", when) f := r.Flocal.(*Fs) - // Set fs into "-l" / "--links" mode - f.opt.TranslateSymlinks = true - - // Write a symlink to the file - symlinkPath := "metafile-link.txt" - osSymlinkPath := filepath.Join(f.root, symlinkPath) - symlinkPath += linkSuffix - require.NoError(t, os.Symlink(filePath, osSymlinkPath)) - symlinkModTime := fstest.Time("2002-02-03T04:05:10.123123123Z") - require.NoError(t, lChtimes(osSymlinkPath, symlinkModTime, symlinkModTime)) - // Get the object obj, err := f.NewObject(ctx, filePath) require.NoError(t, err) o := obj.(*Object) - // Get the symlink object - symlinkObj, err := f.NewObject(ctx, symlinkPath) - require.NoError(t, err) - symlinkO := symlinkObj.(*Object) - - // Record metadata for o - oMeta, err := o.Metadata(ctx) - require.NoError(t, err) - - // Test symlink first to check it doesn't mess up file - t.Run("Symlink", func(t *testing.T) { - testMetadata(t, r, symlinkO, symlinkModTime) - }) - - // Read it again - oMetaNew, err := o.Metadata(ctx) - require.NoError(t, err) - - // Check that operating on the symlink didn't change the file it was pointing to - // See: https://github.com/rclone/rclone/security/advisories/GHSA-hrxh-9w67-g4cv - assert.Equal(t, oMeta, oMetaNew, "metadata setting on symlink messed up file") - - // Now run the same tests on the file - t.Run("File", func(t *testing.T) { - testMetadata(t, r, o, when) - }) -} - -func testMetadata(t *testing.T, r *fstest.Run, o *Object, when time.Time) { - ctx := context.Background() - whenRFC := when.Format(time.RFC3339Nano) - const dayLength = len("2001-01-01") - - f := r.Flocal.(*Fs) features := f.Features() - var hasXID, hasAtime, hasBtime, canSetXattrOnLinks bool + var hasXID, hasAtime, hasBtime bool switch runtime.GOOS { case "darwin", "freebsd", "netbsd", "linux": hasXID, hasAtime, hasBtime = true, true, true - canSetXattrOnLinks = runtime.GOOS != "linux" case "openbsd", "solaris": hasXID, hasAtime = true, true case "windows": @@ -350,10 +306,6 @@ func testMetadata(t *testing.T, r *fstest.Run, o *Object, when time.Time) { require.NoError(t, err) assert.Nil(t, m) - if !canSetXattrOnLinks && o.translatedLink { - t.Skip("Skip remainder of test as can't set xattr on symlinks on this OS") - } - inM := fs.Metadata{ "potato": "chips", "cabbage": "soup", @@ -368,21 +320,18 @@ func testMetadata(t *testing.T, r *fstest.Run, o *Object, when time.Time) { }) checkTime := func(m fs.Metadata, key string, when time.Time) { - t.Helper() mt, ok := o.parseMetadataTime(m, key) assert.True(t, ok) dt := mt.Sub(when) precision := time.Second - assert.True(t, dt >= -precision && dt <= precision, fmt.Sprintf("%s: dt %v outside +/- precision %v want %v got %v", key, dt, precision, mt, when)) + assert.True(t, dt >= -precision && dt <= precision, fmt.Sprintf("%s: dt %v outside +/- precision %v", key, dt, precision)) } checkInt := func(m fs.Metadata, key string, base int) int { - t.Helper() value, ok := o.parseMetadataInt(m, key, base) assert.True(t, ok) return value } - t.Run("Read", func(t *testing.T) { m, err := o.Metadata(ctx) require.NoError(t, err) @@ -392,12 +341,13 @@ func testMetadata(t *testing.T, r *fstest.Run, o *Object, when time.Time) { checkInt(m, "mode", 8) checkTime(m, "mtime", when) + assert.Equal(t, len(whenRFC), len(m["mtime"])) assert.Equal(t, whenRFC[:dayLength], m["mtime"][:dayLength]) - if hasAtime && !o.translatedLink { // symlinks generally don't record atime + if hasAtime { checkTime(m, "atime", when) } - if hasBtime && !o.translatedLink { // symlinks generally don't record btime + if hasBtime { checkTime(m, "btime", when) } if hasXID { @@ -421,10 +371,6 @@ func testMetadata(t *testing.T, r *fstest.Run, o *Object, when time.Time) { "mode": "0767", "potato": "wedges", } - if !canSetXattrOnLinks && o.translatedLink { - // Don't change xattr if not supported on symlinks - delete(newM, "potato") - } err := o.writeMetadata(newM) require.NoError(t, err) @@ -434,11 +380,7 @@ func testMetadata(t *testing.T, r *fstest.Run, o *Object, when time.Time) { mode := checkInt(m, "mode", 8) if runtime.GOOS != "windows" { - expectedMode := 0767 - if o.translatedLink && runtime.GOOS == "linux" { - expectedMode = 0777 // perms of symlinks always read as 0777 on linux - } - assert.Equal(t, expectedMode, mode&0777, fmt.Sprintf("mode wrong - expecting 0%o got 0%o", expectedMode, mode&0777)) + assert.Equal(t, 0767, mode&0777, fmt.Sprintf("mode wrong - expecting 0767 got 0%o", mode&0777)) } checkTime(m, "mtime", newMtime) @@ -448,7 +390,7 @@ func testMetadata(t *testing.T, r *fstest.Run, o *Object, when time.Time) { if haveSetBTime { checkTime(m, "btime", newBtime) } - if xattrSupported && (canSetXattrOnLinks || !o.translatedLink) { + if xattrSupported { assert.Equal(t, "wedges", m["potato"]) } }) diff --git a/backend/local/metadata.go b/backend/local/metadata.go index 75b195e64..7ab69af30 100644 --- a/backend/local/metadata.go +++ b/backend/local/metadata.go @@ -105,11 +105,7 @@ func (o *Object) writeMetadataToFile(m fs.Metadata) (outErr error) { } if haveSetBTime { if btimeOK { - if o.translatedLink { - err = lsetBTime(o.path, btime) - } else { - err = setBTime(o.path, btime) - } + err = setBTime(o.path, btime) if err != nil { outErr = fmt.Errorf("failed to set birth (creation) time: %w", err) } @@ -125,11 +121,7 @@ func (o *Object) writeMetadataToFile(m fs.Metadata) (outErr error) { if runtime.GOOS == "windows" || runtime.GOOS == "plan9" { fs.Debugf(o, "Ignoring request to set ownership %o.%o on this OS", gid, uid) } else { - if o.translatedLink { - err = os.Lchown(o.path, uid, gid) - } else { - err = os.Chown(o.path, uid, gid) - } + err = os.Chown(o.path, uid, gid) if err != nil { outErr = fmt.Errorf("failed to change ownership: %w", err) } @@ -140,16 +132,7 @@ func (o *Object) writeMetadataToFile(m fs.Metadata) (outErr error) { if mode >= 0 { umode := uint(mode) if umode <= math.MaxUint32 { - if o.translatedLink { - if haveLChmod { - err = lChmod(o.path, os.FileMode(umode)) - } else { - fs.Debugf(o, "Unable to set mode %v on a symlink on this OS", os.FileMode(umode)) - err = nil - } - } else { - err = os.Chmod(o.path, os.FileMode(umode)) - } + err = os.Chmod(o.path, os.FileMode(umode)) if err != nil { outErr = fmt.Errorf("failed to change permissions: %w", err) } diff --git a/backend/local/setbtime.go b/backend/local/setbtime.go index bb37b1735..5c946348f 100644 --- a/backend/local/setbtime.go +++ b/backend/local/setbtime.go @@ -13,9 +13,3 @@ func setBTime(name string, btime time.Time) error { // Does nothing return nil } - -// lsetBTime changes the birth time of the link passed in -func lsetBTime(name string, btime time.Time) error { - // Does nothing - return nil -} diff --git a/backend/local/setbtime_windows.go b/backend/local/setbtime_windows.go index 8ae499826..510a4da6a 100644 --- a/backend/local/setbtime_windows.go +++ b/backend/local/setbtime_windows.go @@ -9,20 +9,15 @@ import ( const haveSetBTime = true -// setTimes sets any of atime, mtime or btime -// if link is set it sets a link rather than the target -func setTimes(name string, atime, mtime, btime time.Time, link bool) (err error) { +// setBTime sets the birth time of the file passed in +func setBTime(name string, btime time.Time) (err error) { pathp, err := syscall.UTF16PtrFromString(name) if err != nil { return err } - fileFlag := uint32(syscall.FILE_FLAG_BACKUP_SEMANTICS) - if link { - fileFlag |= syscall.FILE_FLAG_OPEN_REPARSE_POINT - } h, err := syscall.CreateFile(pathp, syscall.FILE_WRITE_ATTRIBUTES, syscall.FILE_SHARE_WRITE, nil, - syscall.OPEN_EXISTING, fileFlag, 0) + syscall.OPEN_EXISTING, syscall.FILE_FLAG_BACKUP_SEMANTICS, 0) if err != nil { return err } @@ -32,28 +27,6 @@ func setTimes(name string, atime, mtime, btime time.Time, link bool) (err error) err = closeErr } }() - var patime, pmtime, pbtime *syscall.Filetime - if !atime.IsZero() { - t := syscall.NsecToFiletime(atime.UnixNano()) - patime = &t - } - if !mtime.IsZero() { - t := syscall.NsecToFiletime(mtime.UnixNano()) - pmtime = &t - } - if !btime.IsZero() { - t := syscall.NsecToFiletime(btime.UnixNano()) - pbtime = &t - } - return syscall.SetFileTime(h, pbtime, patime, pmtime) -} - -// setBTime sets the birth time of the file passed in -func setBTime(name string, btime time.Time) (err error) { - return setTimes(name, time.Time{}, time.Time{}, btime, false) -} - -// lsetBTime changes the birth time of the link passed in -func lsetBTime(name string, btime time.Time) error { - return setTimes(name, time.Time{}, time.Time{}, btime, true) + bFileTime := syscall.NsecToFiletime(btime.UnixNano()) + return syscall.SetFileTime(h, &bFileTime, nil, nil) } From 01ccf204f42b4f68541b16843292439090a2dcf0 Mon Sep 17 00:00:00 2001 From: Nick Craig-Wood Date: Wed, 13 Nov 2024 11:55:28 +0000 Subject: [PATCH 39/39] local: fix permission and ownership on symlinks with --links and --metadata Before this change, if writing to a local backend with --metadata and --links, if the incoming metadata contained mode or ownership information then rclone would apply the mode/ownership to the destination of the link not the link itself. This fixes the problem by using the link safe sycall variants lchown/fchmodat when --links and --metadata is in use. Note that Linux does not support setting permissions on symlinks, so rclone emits a debug message in this case. This also fixes setting times on symlinks on Windows which wasn't implemented for atime, mtime and was incorrectly setting the target of the symlink for btime. See: https://github.com/rclone/rclone/security/advisories/GHSA-hrxh-9w67-g4cv --- backend/local/lchmod.go | 16 ++++++ backend/local/lchmod_unix.go | 41 +++++++++++++++ backend/local/lchtimes.go | 2 +- backend/local/lchtimes_windows.go | 19 +++++++ backend/local/local_internal_test.go | 76 ++++++++++++++++++++++++---- backend/local/metadata.go | 23 +++++++-- backend/local/setbtime.go | 6 +++ backend/local/setbtime_windows.go | 37 ++++++++++++-- 8 files changed, 202 insertions(+), 18 deletions(-) create mode 100644 backend/local/lchmod.go create mode 100644 backend/local/lchmod_unix.go create mode 100644 backend/local/lchtimes_windows.go diff --git a/backend/local/lchmod.go b/backend/local/lchmod.go new file mode 100644 index 000000000..823718dfe --- /dev/null +++ b/backend/local/lchmod.go @@ -0,0 +1,16 @@ +//go:build windows || plan9 || js || linux + +package local + +import "os" + +const haveLChmod = false + +// lChmod changes the mode of the named file to mode. If the file is a symbolic +// link, it changes the link, not the target. If there is an error, +// it will be of type *PathError. +func lChmod(name string, mode os.FileMode) error { + // Can't do this safely on this OS - chmoding a symlink always + // changes the destination. + return nil +} diff --git a/backend/local/lchmod_unix.go b/backend/local/lchmod_unix.go new file mode 100644 index 000000000..f1fdc4745 --- /dev/null +++ b/backend/local/lchmod_unix.go @@ -0,0 +1,41 @@ +//go:build !windows && !plan9 && !js && !linux + +package local + +import ( + "os" + "syscall" + + "golang.org/x/sys/unix" +) + +const haveLChmod = true + +// syscallMode returns the syscall-specific mode bits from Go's portable mode bits. +// +// Borrowed from the syscall source since it isn't public. +func syscallMode(i os.FileMode) (o uint32) { + o |= uint32(i.Perm()) + if i&os.ModeSetuid != 0 { + o |= syscall.S_ISUID + } + if i&os.ModeSetgid != 0 { + o |= syscall.S_ISGID + } + if i&os.ModeSticky != 0 { + o |= syscall.S_ISVTX + } + return o +} + +// lChmod changes the mode of the named file to mode. If the file is a symbolic +// link, it changes the link, not the target. If there is an error, +// it will be of type *PathError. +func lChmod(name string, mode os.FileMode) error { + // NB linux does not support AT_SYMLINK_NOFOLLOW as a parameter to fchmodat + // and returns ENOTSUP if you try, so we don't support this on linux + if e := unix.Fchmodat(unix.AT_FDCWD, name, syscallMode(mode), unix.AT_SYMLINK_NOFOLLOW); e != nil { + return &os.PathError{Op: "lChmod", Path: name, Err: e} + } + return nil +} diff --git a/backend/local/lchtimes.go b/backend/local/lchtimes.go index c8f03ef46..fcabdcc34 100644 --- a/backend/local/lchtimes.go +++ b/backend/local/lchtimes.go @@ -1,4 +1,4 @@ -//go:build windows || plan9 || js +//go:build plan9 || js package local diff --git a/backend/local/lchtimes_windows.go b/backend/local/lchtimes_windows.go new file mode 100644 index 000000000..a6dec9a12 --- /dev/null +++ b/backend/local/lchtimes_windows.go @@ -0,0 +1,19 @@ +//go:build windows + +package local + +import ( + "time" +) + +const haveLChtimes = true + +// lChtimes changes the access and modification times of the named +// link, similar to the Unix utime() or utimes() functions. +// +// The underlying filesystem may truncate or round the values to a +// less precise time unit. +// If there is an error, it will be of type *PathError. +func lChtimes(name string, atime time.Time, mtime time.Time) error { + return setTimes(name, atime, mtime, time.Time{}, true) +} diff --git a/backend/local/local_internal_test.go b/backend/local/local_internal_test.go index ea0fdc765..b3b9b8ba1 100644 --- a/backend/local/local_internal_test.go +++ b/backend/local/local_internal_test.go @@ -268,22 +268,66 @@ func TestMetadata(t *testing.T) { r := fstest.NewRun(t) const filePath = "metafile.txt" when := time.Now() - const dayLength = len("2001-01-01") - whenRFC := when.Format(time.RFC3339Nano) r.WriteFile(filePath, "metadata file contents", when) f := r.Flocal.(*Fs) + // Set fs into "-l" / "--links" mode + f.opt.TranslateSymlinks = true + + // Write a symlink to the file + symlinkPath := "metafile-link.txt" + osSymlinkPath := filepath.Join(f.root, symlinkPath) + symlinkPath += linkSuffix + require.NoError(t, os.Symlink(filePath, osSymlinkPath)) + symlinkModTime := fstest.Time("2002-02-03T04:05:10.123123123Z") + require.NoError(t, lChtimes(osSymlinkPath, symlinkModTime, symlinkModTime)) + // Get the object obj, err := f.NewObject(ctx, filePath) require.NoError(t, err) o := obj.(*Object) + // Get the symlink object + symlinkObj, err := f.NewObject(ctx, symlinkPath) + require.NoError(t, err) + symlinkO := symlinkObj.(*Object) + + // Record metadata for o + oMeta, err := o.Metadata(ctx) + require.NoError(t, err) + + // Test symlink first to check it doesn't mess up file + t.Run("Symlink", func(t *testing.T) { + testMetadata(t, r, symlinkO, symlinkModTime) + }) + + // Read it again + oMetaNew, err := o.Metadata(ctx) + require.NoError(t, err) + + // Check that operating on the symlink didn't change the file it was pointing to + // See: https://github.com/rclone/rclone/security/advisories/GHSA-hrxh-9w67-g4cv + assert.Equal(t, oMeta, oMetaNew, "metadata setting on symlink messed up file") + + // Now run the same tests on the file + t.Run("File", func(t *testing.T) { + testMetadata(t, r, o, when) + }) +} + +func testMetadata(t *testing.T, r *fstest.Run, o *Object, when time.Time) { + ctx := context.Background() + whenRFC := when.Format(time.RFC3339Nano) + const dayLength = len("2001-01-01") + + f := r.Flocal.(*Fs) features := f.Features() - var hasXID, hasAtime, hasBtime bool + var hasXID, hasAtime, hasBtime, canSetXattrOnLinks bool switch runtime.GOOS { case "darwin", "freebsd", "netbsd", "linux": hasXID, hasAtime, hasBtime = true, true, true + canSetXattrOnLinks = runtime.GOOS != "linux" case "openbsd", "solaris": hasXID, hasAtime = true, true case "windows": @@ -306,6 +350,10 @@ func TestMetadata(t *testing.T) { require.NoError(t, err) assert.Nil(t, m) + if !canSetXattrOnLinks && o.translatedLink { + t.Skip("Skip remainder of test as can't set xattr on symlinks on this OS") + } + inM := fs.Metadata{ "potato": "chips", "cabbage": "soup", @@ -320,18 +368,21 @@ func TestMetadata(t *testing.T) { }) checkTime := func(m fs.Metadata, key string, when time.Time) { + t.Helper() mt, ok := o.parseMetadataTime(m, key) assert.True(t, ok) dt := mt.Sub(when) precision := time.Second - assert.True(t, dt >= -precision && dt <= precision, fmt.Sprintf("%s: dt %v outside +/- precision %v", key, dt, precision)) + assert.True(t, dt >= -precision && dt <= precision, fmt.Sprintf("%s: dt %v outside +/- precision %v want %v got %v", key, dt, precision, mt, when)) } checkInt := func(m fs.Metadata, key string, base int) int { + t.Helper() value, ok := o.parseMetadataInt(m, key, base) assert.True(t, ok) return value } + t.Run("Read", func(t *testing.T) { m, err := o.Metadata(ctx) require.NoError(t, err) @@ -341,13 +392,12 @@ func TestMetadata(t *testing.T) { checkInt(m, "mode", 8) checkTime(m, "mtime", when) - assert.Equal(t, len(whenRFC), len(m["mtime"])) assert.Equal(t, whenRFC[:dayLength], m["mtime"][:dayLength]) - if hasAtime { + if hasAtime && !o.translatedLink { // symlinks generally don't record atime checkTime(m, "atime", when) } - if hasBtime { + if hasBtime && !o.translatedLink { // symlinks generally don't record btime checkTime(m, "btime", when) } if hasXID { @@ -371,6 +421,10 @@ func TestMetadata(t *testing.T) { "mode": "0767", "potato": "wedges", } + if !canSetXattrOnLinks && o.translatedLink { + // Don't change xattr if not supported on symlinks + delete(newM, "potato") + } err := o.writeMetadata(newM) require.NoError(t, err) @@ -380,7 +434,11 @@ func TestMetadata(t *testing.T) { mode := checkInt(m, "mode", 8) if runtime.GOOS != "windows" { - assert.Equal(t, 0767, mode&0777, fmt.Sprintf("mode wrong - expecting 0767 got 0%o", mode&0777)) + expectedMode := 0767 + if o.translatedLink && runtime.GOOS == "linux" { + expectedMode = 0777 // perms of symlinks always read as 0777 on linux + } + assert.Equal(t, expectedMode, mode&0777, fmt.Sprintf("mode wrong - expecting 0%o got 0%o", expectedMode, mode&0777)) } checkTime(m, "mtime", newMtime) @@ -390,7 +448,7 @@ func TestMetadata(t *testing.T) { if haveSetBTime { checkTime(m, "btime", newBtime) } - if xattrSupported { + if xattrSupported && (canSetXattrOnLinks || !o.translatedLink) { assert.Equal(t, "wedges", m["potato"]) } }) diff --git a/backend/local/metadata.go b/backend/local/metadata.go index 7ab69af30..75b195e64 100644 --- a/backend/local/metadata.go +++ b/backend/local/metadata.go @@ -105,7 +105,11 @@ func (o *Object) writeMetadataToFile(m fs.Metadata) (outErr error) { } if haveSetBTime { if btimeOK { - err = setBTime(o.path, btime) + if o.translatedLink { + err = lsetBTime(o.path, btime) + } else { + err = setBTime(o.path, btime) + } if err != nil { outErr = fmt.Errorf("failed to set birth (creation) time: %w", err) } @@ -121,7 +125,11 @@ func (o *Object) writeMetadataToFile(m fs.Metadata) (outErr error) { if runtime.GOOS == "windows" || runtime.GOOS == "plan9" { fs.Debugf(o, "Ignoring request to set ownership %o.%o on this OS", gid, uid) } else { - err = os.Chown(o.path, uid, gid) + if o.translatedLink { + err = os.Lchown(o.path, uid, gid) + } else { + err = os.Chown(o.path, uid, gid) + } if err != nil { outErr = fmt.Errorf("failed to change ownership: %w", err) } @@ -132,7 +140,16 @@ func (o *Object) writeMetadataToFile(m fs.Metadata) (outErr error) { if mode >= 0 { umode := uint(mode) if umode <= math.MaxUint32 { - err = os.Chmod(o.path, os.FileMode(umode)) + if o.translatedLink { + if haveLChmod { + err = lChmod(o.path, os.FileMode(umode)) + } else { + fs.Debugf(o, "Unable to set mode %v on a symlink on this OS", os.FileMode(umode)) + err = nil + } + } else { + err = os.Chmod(o.path, os.FileMode(umode)) + } if err != nil { outErr = fmt.Errorf("failed to change permissions: %w", err) } diff --git a/backend/local/setbtime.go b/backend/local/setbtime.go index 5c946348f..bb37b1735 100644 --- a/backend/local/setbtime.go +++ b/backend/local/setbtime.go @@ -13,3 +13,9 @@ func setBTime(name string, btime time.Time) error { // Does nothing return nil } + +// lsetBTime changes the birth time of the link passed in +func lsetBTime(name string, btime time.Time) error { + // Does nothing + return nil +} diff --git a/backend/local/setbtime_windows.go b/backend/local/setbtime_windows.go index 510a4da6a..8ae499826 100644 --- a/backend/local/setbtime_windows.go +++ b/backend/local/setbtime_windows.go @@ -9,15 +9,20 @@ import ( const haveSetBTime = true -// setBTime sets the birth time of the file passed in -func setBTime(name string, btime time.Time) (err error) { +// setTimes sets any of atime, mtime or btime +// if link is set it sets a link rather than the target +func setTimes(name string, atime, mtime, btime time.Time, link bool) (err error) { pathp, err := syscall.UTF16PtrFromString(name) if err != nil { return err } + fileFlag := uint32(syscall.FILE_FLAG_BACKUP_SEMANTICS) + if link { + fileFlag |= syscall.FILE_FLAG_OPEN_REPARSE_POINT + } h, err := syscall.CreateFile(pathp, syscall.FILE_WRITE_ATTRIBUTES, syscall.FILE_SHARE_WRITE, nil, - syscall.OPEN_EXISTING, syscall.FILE_FLAG_BACKUP_SEMANTICS, 0) + syscall.OPEN_EXISTING, fileFlag, 0) if err != nil { return err } @@ -27,6 +32,28 @@ func setBTime(name string, btime time.Time) (err error) { err = closeErr } }() - bFileTime := syscall.NsecToFiletime(btime.UnixNano()) - return syscall.SetFileTime(h, &bFileTime, nil, nil) + var patime, pmtime, pbtime *syscall.Filetime + if !atime.IsZero() { + t := syscall.NsecToFiletime(atime.UnixNano()) + patime = &t + } + if !mtime.IsZero() { + t := syscall.NsecToFiletime(mtime.UnixNano()) + pmtime = &t + } + if !btime.IsZero() { + t := syscall.NsecToFiletime(btime.UnixNano()) + pbtime = &t + } + return syscall.SetFileTime(h, pbtime, patime, pmtime) +} + +// setBTime sets the birth time of the file passed in +func setBTime(name string, btime time.Time) (err error) { + return setTimes(name, time.Time{}, time.Time{}, btime, false) +} + +// lsetBTime changes the birth time of the link passed in +func lsetBTime(name string, btime time.Time) error { + return setTimes(name, time.Time{}, time.Time{}, btime, true) }