]> git.pld-linux.org Git - packages/rclone.git/blame - webdav-modtime.patch
up to 1.62.2
[packages/rclone.git] / webdav-modtime.patch
CommitLineData
a5880a6d
JP
1From b9c0e1efdb88ac08ae6053eaeb2f3034a3416e51 Mon Sep 17 00:00:00 2001
2From: Jan Palus <jpalus@fastmail.com>
3Date: Sat, 16 Apr 2022 23:06:53 +0200
4Subject: [PATCH 1/3] webdav: add support for spec compliant modification time
5 update
6
7rfc4918 section 15.7 states that getlastmodified SHOULD be protected
8(read-only) but does not mandate it. implementations are free to choose
9whether it is possible to update modification time. one such
10implementation operating in the wild that allows it is FastMail WebDav
11access. since specification recommends property to be protected make it
12disabled by default.
13---
14 backend/webdav/webdav.go | 63 ++++++++++++++++++++++++++++++++++++++--
15 1 file changed, 61 insertions(+), 2 deletions(-)
16
17diff --git a/backend/webdav/webdav.go b/backend/webdav/webdav.go
18index 9564ae601..20f2b45ea 100644
19--- a/backend/webdav/webdav.go
20+++ b/backend/webdav/webdav.go
21@@ -124,6 +124,11 @@ You can set multiple headers, e.g. '"Cookie","name=value","Authorization","xxx"'
22 `,
23 Default: fs.CommaSepList{},
24 Advanced: true,
25+ }, {
26+ Name: "update_modtime",
27+ Help: "Adjust modification time on servers which allow DAV:getlastmodified property update",
28+ Default: false,
29+ Advanced: true,
30 }},
31 })
32 }
33@@ -138,6 +143,7 @@ type Options struct {
34 BearerTokenCommand string `config:"bearer_token_command"`
35 Enc encoder.MultiEncoder `config:"encoding"`
36 Headers fs.CommaSepList `config:"headers"`
37+ UpdateModTime bool `config:"update_modtime"`
38 }
39
40 // Fs represents a remote webdav
41@@ -405,6 +411,13 @@ func NewFs(ctx context.Context, name, root string, m configmap.Mapper) (fs.Fs, e
42 return nil, err
43 }
44
45+ var precision time.Duration
46+ if opt.UpdateModTime {
47+ precision = time.Second
48+ } else {
49+ precision = fs.ModTimeNotSupported
50+ }
51+
52 f := &Fs{
53 name: name,
54 root: root,
55@@ -412,7 +425,7 @@ func NewFs(ctx context.Context, name, root string, m configmap.Mapper) (fs.Fs, e
56 endpoint: u,
57 endpointURL: u.String(),
58 pacer: fs.NewPacer(ctx, pacer.NewDefault(pacer.MinSleep(minSleep), pacer.MaxSleep(maxSleep), pacer.DecayConstant(decayConstant))),
59- precision: fs.ModTimeNotSupported,
60+ precision: precision,
61 }
62
63 client := fshttp.NewClient(ctx)
64@@ -634,6 +647,16 @@ var owncloudProps = []byte(`<?xml version="1.0"?>
65 </d:prop>
66 </d:propfind>
67 `)
68+var modtimeUpdatePropStart = `<?xml version="1.0"?>
69+<d:propertyupdate xmlns:d="DAV:">
70+ <d:set>
71+ <d:prop>
72+ <d:getlastmodified>`
73+var modtimeUpdatePropEnd = `</d:getlastmodified>
74+ </d:prop>
75+ </d:set>
76+</d:propertyupdate>
77+`
78
79 // list the objects into the function supplied
80 //
81@@ -1251,7 +1274,37 @@ func (o *Object) ModTime(ctx context.Context) time.Time {
82
83 // SetModTime sets the modification time of the local fs object
84 func (o *Object) SetModTime(ctx context.Context, modTime time.Time) error {
85- return fs.ErrorCantSetModTime
86+ if !o.fs.opt.UpdateModTime {
87+ return fs.ErrorCantSetModTime
88+ }
89+ opts := rest.Opts{
90+ Method: "PROPPATCH",
91+ Path: o.filePath(),
92+ }
93+ var body bytes.Buffer
94+ body.WriteString(modtimeUpdatePropStart)
95+ body.WriteString(modTime.Format(time.RFC1123))
96+ body.WriteString(modtimeUpdatePropEnd)
97+ opts.Body = &body
98+
99+ var result api.Multistatus
100+ var resp *http.Response
101+ var err error
102+ err = o.fs.pacer.Call(func() (bool, error) {
103+ resp, err = o.fs.srv.CallXML(ctx, &opts, nil, &result)
104+ return o.fs.shouldRetry(ctx, resp, err)
105+ })
106+ if err != nil {
107+ return err
108+ }
109+ if len(result.Responses) < 1 {
110+ return fs.ErrorObjectNotFound
111+ }
112+ item := result.Responses[0]
113+ if !item.Props.StatusOK() {
114+ return fs.ErrorObjectNotFound
115+ }
116+ return nil
117 }
118
119 // Storable returns a boolean showing whether this object storable
120@@ -1337,6 +1390,12 @@ func (o *Object) Update(ctx context.Context, in io.Reader, src fs.ObjectInfo, op
121 _ = o.Remove(ctx)
122 return err
123 }
124+ if !o.fs.useOCMtime && o.fs.opt.UpdateModTime {
125+ err = o.SetModTime(ctx, src.ModTime(ctx))
126+ if err != nil {
127+ return fmt.Errorf("Update ModTime failed: %w", err)
128+ }
129+ }
130 // read metadata from remote
131 o.hasMetaData = false
132 return o.readMetaData(ctx)
133--
1342.37.0
135
136From 9394b57866019df139fc0ce96a7a3572fad57666 Mon Sep 17 00:00:00 2001
137From: Jan Palus <jpalus@fastmail.com>
138Date: Wed, 27 Apr 2022 10:17:51 +0200
139Subject: [PATCH 2/3] webdav: switch to tristate for update_modtime
140
141---
142 backend/webdav/webdav.go | 17 ++++++++++-------
143 1 file changed, 10 insertions(+), 7 deletions(-)
144
145diff --git a/backend/webdav/webdav.go b/backend/webdav/webdav.go
146index 20f2b45ea..d4c331de8 100644
147--- a/backend/webdav/webdav.go
148+++ b/backend/webdav/webdav.go
149@@ -125,9 +125,12 @@ You can set multiple headers, e.g. '"Cookie","name=value","Authorization","xxx"'
150 Default: fs.CommaSepList{},
151 Advanced: true,
152 }, {
153- Name: "update_modtime",
154- Help: "Adjust modification time on servers which allow DAV:getlastmodified property update",
155- Default: false,
156+ Name: "update_modtime",
157+ Help: `Adjust modification time on servers which allow DAV:getlastmodified property update.
158+
159+Use provider's default if unset.
160+`,
161+ Default: fs.Tristate{},
162 Advanced: true,
163 }},
164 })
165@@ -143,7 +146,7 @@ type Options struct {
166 BearerTokenCommand string `config:"bearer_token_command"`
167 Enc encoder.MultiEncoder `config:"encoding"`
168 Headers fs.CommaSepList `config:"headers"`
169- UpdateModTime bool `config:"update_modtime"`
170+ UpdateModTime fs.Tristate `config:"update_modtime"`
171 }
172
173 // Fs represents a remote webdav
174@@ -412,7 +415,7 @@ func NewFs(ctx context.Context, name, root string, m configmap.Mapper) (fs.Fs, e
175 }
176
177 var precision time.Duration
178- if opt.UpdateModTime {
179+ if opt.UpdateModTime.Valid && opt.UpdateModTime.Value {
180 precision = time.Second
181 } else {
182 precision = fs.ModTimeNotSupported
183@@ -1274,7 +1277,7 @@ func (o *Object) ModTime(ctx context.Context) time.Time {
184
185 // SetModTime sets the modification time of the local fs object
186 func (o *Object) SetModTime(ctx context.Context, modTime time.Time) error {
187- if !o.fs.opt.UpdateModTime {
188+ if !o.fs.opt.UpdateModTime.Valid || !o.fs.opt.UpdateModTime.Value {
189 return fs.ErrorCantSetModTime
190 }
191 opts := rest.Opts{
192@@ -1390,7 +1393,7 @@ func (o *Object) Update(ctx context.Context, in io.Reader, src fs.ObjectInfo, op
193 _ = o.Remove(ctx)
194 return err
195 }
196- if !o.fs.useOCMtime && o.fs.opt.UpdateModTime {
197+ if !o.fs.useOCMtime && o.fs.opt.UpdateModTime.Valid && o.fs.opt.UpdateModTime.Value {
198 err = o.SetModTime(ctx, src.ModTime(ctx))
199 if err != nil {
200 return fmt.Errorf("Update ModTime failed: %w", err)
201--
2022.37.0
203
204From 6775d10cc030e2e4b78ca774087bbb494cb0f79b Mon Sep 17 00:00:00 2001
205From: Jan Palus <jpalus@fastmail.com>
206Date: Thu, 28 Apr 2022 22:20:40 +0200
207Subject: [PATCH 3/3] webdav: add fastmail provider
208
209enables by default modtime update with PROPPATCH
210---
211 backend/webdav/webdav.go | 9 +++++++++
212 1 file changed, 9 insertions(+)
213
214diff --git a/backend/webdav/webdav.go b/backend/webdav/webdav.go
215index d4c331de8..50152503e 100644
216--- a/backend/webdav/webdav.go
217+++ b/backend/webdav/webdav.go
218@@ -87,6 +87,9 @@ func init() {
219 }, {
220 Value: "sharepoint-ntlm",
221 Help: "Sharepoint with NTLM authentication, usually self-hosted or on-premises",
222+ }, {
223+ Value: "fastmail",
224+ Help: "Fastmail",
225 }, {
226 Value: "other",
227 Help: "Other site/service or software",
228@@ -596,6 +599,12 @@ func (f *Fs) setQuirks(ctx context.Context, vendor string) error {
229 // so we must perform an extra check to detect this
230 // condition and return a proper error code.
231 f.checkBeforePurge = true
232+ case "fastmail":
233+ if !f.opt.UpdateModTime.Valid {
234+ f.precision = time.Second
235+ f.opt.UpdateModTime.Valid = true
236+ f.opt.UpdateModTime.Value = true
237+ }
238 case "other":
239 default:
240 fs.Debugf(f, "Unknown vendor %q", vendor)
241--
2422.37.0
243
This page took 0.220926 seconds and 4 git commands to generate.