]> git.pld-linux.org Git - packages/rclone.git/blob - webdav-modtime.patch
up to 1.66.0
[packages/rclone.git] / webdav-modtime.patch
1 From b9c0e1efdb88ac08ae6053eaeb2f3034a3416e51 Mon Sep 17 00:00:00 2001
2 From: Jan Palus <jpalus@fastmail.com>
3 Date: Sat, 16 Apr 2022 23:06:53 +0200
4 Subject: [PATCH 1/3] webdav: add support for spec compliant modification time
5  update
6
7 rfc4918 section 15.7 states that getlastmodified SHOULD be protected
8 (read-only) but does not mandate it. implementations are free to choose
9 whether it is possible to update modification time. one such
10 implementation operating in the wild that allows it is FastMail WebDav
11 access. since specification recommends property to be protected make it
12 disabled by default.
13 ---
14  backend/webdav/webdav.go | 63 ++++++++++++++++++++++++++++++++++++++--
15  1 file changed, 61 insertions(+), 2 deletions(-)
16
17 diff --git a/backend/webdav/webdav.go b/backend/webdav/webdav.go
18 index 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 -- 
134 2.37.0
135
136 From 9394b57866019df139fc0ce96a7a3572fad57666 Mon Sep 17 00:00:00 2001
137 From: Jan Palus <jpalus@fastmail.com>
138 Date: Wed, 27 Apr 2022 10:17:51 +0200
139 Subject: [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
145 diff --git a/backend/webdav/webdav.go b/backend/webdav/webdav.go
146 index 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 -- 
202 2.37.0
203
204 From 6775d10cc030e2e4b78ca774087bbb494cb0f79b Mon Sep 17 00:00:00 2001
205 From: Jan Palus <jpalus@fastmail.com>
206 Date: Thu, 28 Apr 2022 22:20:40 +0200
207 Subject: [PATCH 3/3] webdav: add fastmail provider
208
209 enables by default modtime update with PROPPATCH
210 ---
211  backend/webdav/webdav.go | 9 +++++++++
212  1 file changed, 9 insertions(+)
213
214 diff --git a/backend/webdav/webdav.go b/backend/webdav/webdav.go
215 index 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 -- 
242 2.37.0
243
This page took 0.09243 seconds and 3 git commands to generate.