diff --git a/backend/webdav/webdav.go b/backend/webdav/webdav.go
index de19e0abd..206b11bd1 100644
--- a/backend/webdav/webdav.go
+++ b/backend/webdav/webdav.go
@@ -175,6 +175,7 @@ type Fs struct {
precision time.Duration // mod time precision
canStream bool // set if can stream
useOCMtime bool // set if can use X-OC-Mtime
+ propsetMtime bool // set if can use propset
retryWithZeroDepth bool // some vendors (sharepoint) won't list files when Depth is 1 (our default)
checkBeforePurge bool // enables extra check that directory to purge really exists
hasOCMD5 bool // set if can use owncloud style checksums for MD5
@@ -582,11 +583,13 @@ func (f *Fs) setQuirks(ctx context.Context, vendor string) error {
f.canStream = true
f.precision = time.Second
f.useOCMtime = true
+ f.propsetMtime = true
f.hasOCMD5 = true
f.hasOCSHA1 = true
case "nextcloud":
f.precision = time.Second
f.useOCMtime = true
+ f.propsetMtime = true
f.hasOCSHA1 = true
f.canChunk = true
if err := f.verifyChunkConfig(); err != nil {
@@ -1299,8 +1302,53 @@ func (o *Object) ModTime(ctx context.Context) time.Time {
return o.modTime
}
+// Set modified time using propset
+//
+// /ocm/remote.php/webdav/office/wir.jpgHTTP/1.1 200 OK
+var owncloudPropset = `
+
+
+
+ %d
+
+
+
+`
+
// SetModTime sets the modification time of the local fs object
func (o *Object) SetModTime(ctx context.Context, modTime time.Time) error {
+ if o.fs.propsetMtime {
+ opts := rest.Opts{
+ Method: "PROPPATCH",
+ Path: o.filePath(),
+ NoRedirect: true,
+ Body: strings.NewReader(fmt.Sprintf(owncloudPropset, modTime.Unix())),
+ }
+ var result api.Multistatus
+ var resp *http.Response
+ var err error
+ err = o.fs.pacer.Call(func() (bool, error) {
+ resp, err = o.fs.srv.CallXML(ctx, &opts, nil, &result)
+ return o.fs.shouldRetry(ctx, resp, err)
+ })
+ if err != nil {
+ if apiErr, ok := err.(*api.Error); ok {
+ // does not exist
+ if apiErr.StatusCode == http.StatusNotFound {
+ return fs.ErrorObjectNotFound
+ }
+ }
+ return fmt.Errorf("couldn't set modified time: %w", err)
+ }
+ // FIXME check if response is valid
+ if len(result.Responses) == 1 && result.Responses[0].Props.StatusOK() {
+ // update cached modtime
+ o.modTime = modTime
+ return nil
+ }
+ // fallback
+ return fs.ErrorCantSetModTime
+ }
return fs.ErrorCantSetModTime
}