mirror of
https://github.com/rclone/rclone.git
synced 2024-11-25 17:57:44 +08:00
webdav: fix SetModTime erasing checksums on owncloud and nextcloud
Before this change, calling SetModTime on owncloud and nextcloud would inadvertently erase the object's stored hashes. This change fixes the issue, which was discovered by the bisync integration tests.
This commit is contained in:
parent
75df38f6ee
commit
71069ed5c1
|
@ -759,7 +759,7 @@ func (f *Fs) listAll(ctx context.Context, dir string, directoriesOnly bool, file
|
||||||
}
|
}
|
||||||
return found, fmt.Errorf("couldn't list files: %w", err)
|
return found, fmt.Errorf("couldn't list files: %w", err)
|
||||||
}
|
}
|
||||||
//fmt.Printf("result = %#v", &result)
|
// fmt.Printf("result = %#v", &result)
|
||||||
baseURL, err := rest.URLJoin(f.endpoint, opts.Path)
|
baseURL, err := rest.URLJoin(f.endpoint, opts.Path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, fmt.Errorf("couldn't join URL: %w", err)
|
return false, fmt.Errorf("couldn't join URL: %w", err)
|
||||||
|
@ -1110,7 +1110,7 @@ func (f *Fs) copyOrMove(ctx context.Context, src fs.Object, remote string, metho
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("copy NewObject failed: %w", err)
|
return nil, fmt.Errorf("copy NewObject failed: %w", err)
|
||||||
}
|
}
|
||||||
if f.useOCMtime && resp.Header.Get("X-OC-Mtime") != "accepted" && f.propsetMtime {
|
if f.useOCMtime && resp.Header.Get("X-OC-Mtime") != "accepted" && f.propsetMtime && !dstObj.ModTime(ctx).Equal(src.ModTime(ctx)) {
|
||||||
fs.Debugf(dstObj, "Setting modtime after copy to %v", src.ModTime(ctx))
|
fs.Debugf(dstObj, "Setting modtime after copy to %v", src.ModTime(ctx))
|
||||||
err = dstObj.SetModTime(ctx, src.ModTime(ctx))
|
err = dstObj.SetModTime(ctx, src.ModTime(ctx))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -1364,15 +1364,38 @@ var owncloudPropset = `<?xml version="1.0" encoding="utf-8" ?>
|
||||||
</D:propertyupdate>
|
</D:propertyupdate>
|
||||||
`
|
`
|
||||||
|
|
||||||
|
var owncloudPropsetWithChecksum = `<?xml version="1.0" encoding="utf-8" ?>
|
||||||
|
<D:propertyupdate xmlns:D="DAV:" xmlns:oc="http://owncloud.org/ns">
|
||||||
|
<D:set>
|
||||||
|
<D:prop>
|
||||||
|
<lastmodified xmlns="DAV:">%d</lastmodified>
|
||||||
|
<oc:checksums>
|
||||||
|
<oc:checksum>%s</oc:checksum>
|
||||||
|
</oc:checksums>
|
||||||
|
</D:prop>
|
||||||
|
</D:set>
|
||||||
|
</D:propertyupdate>
|
||||||
|
`
|
||||||
|
|
||||||
// SetModTime sets the modification time of the local fs object
|
// SetModTime sets the modification time of the local fs object
|
||||||
func (o *Object) SetModTime(ctx context.Context, modTime time.Time) error {
|
func (o *Object) SetModTime(ctx context.Context, modTime time.Time) error {
|
||||||
if o.fs.propsetMtime {
|
if o.fs.propsetMtime {
|
||||||
|
checksums := ""
|
||||||
|
if o.fs.hasOCSHA1 && o.sha1 != "" {
|
||||||
|
checksums = "SHA1:" + o.sha1
|
||||||
|
} else if o.fs.hasOCMD5 && o.md5 != "" {
|
||||||
|
checksums = "MD5:" + o.md5
|
||||||
|
}
|
||||||
|
|
||||||
opts := rest.Opts{
|
opts := rest.Opts{
|
||||||
Method: "PROPPATCH",
|
Method: "PROPPATCH",
|
||||||
Path: o.filePath(),
|
Path: o.filePath(),
|
||||||
NoRedirect: true,
|
NoRedirect: true,
|
||||||
Body: strings.NewReader(fmt.Sprintf(owncloudPropset, modTime.Unix())),
|
Body: strings.NewReader(fmt.Sprintf(owncloudPropset, modTime.Unix())),
|
||||||
}
|
}
|
||||||
|
if checksums != "" {
|
||||||
|
opts.Body = strings.NewReader(fmt.Sprintf(owncloudPropsetWithChecksum, modTime.Unix(), checksums))
|
||||||
|
}
|
||||||
var result api.Multistatus
|
var result api.Multistatus
|
||||||
var resp *http.Response
|
var resp *http.Response
|
||||||
var err error
|
var err error
|
||||||
|
@ -1395,6 +1418,14 @@ func (o *Object) SetModTime(ctx context.Context, modTime time.Time) error {
|
||||||
o.modTime = modTime
|
o.modTime = modTime
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
// got an error, but it's possible it actually worked, so double-check
|
||||||
|
newO, err := o.fs.NewObject(ctx, o.remote)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if newO.ModTime(ctx).Equal(modTime) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
// fallback
|
// fallback
|
||||||
return fs.ErrorCantSetModTime
|
return fs.ErrorCantSetModTime
|
||||||
}
|
}
|
||||||
|
@ -1521,7 +1552,6 @@ func (o *Object) updateSimple(ctx context.Context, body io.Reader, getBody func(
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove an object
|
// Remove an object
|
||||||
|
|
|
@ -90,6 +90,7 @@ var logReplacements = []string{
|
||||||
`^NOTICE: .*?: Forced to upload files to set modification times on this backend.$`, dropMe,
|
`^NOTICE: .*?: Forced to upload files to set modification times on this backend.$`, dropMe,
|
||||||
`^INFO : .*? Committing uploads - please wait...$`, dropMe,
|
`^INFO : .*? Committing uploads - please wait...$`, dropMe,
|
||||||
`^INFO : .*?: src and dst identical but can't set mod time without deleting and re-uploading$`, dropMe,
|
`^INFO : .*?: src and dst identical but can't set mod time without deleting and re-uploading$`, dropMe,
|
||||||
|
`^INFO : .*?: src and dst identical but can't set mod time without re-uploading$`, dropMe,
|
||||||
// ignore crypt info messages
|
// ignore crypt info messages
|
||||||
`^INFO : .*?: Crypt detected! Using cryptcheck instead of check. \(Use --size-only or --ignore-checksum to disable\)$`, dropMe,
|
`^INFO : .*?: Crypt detected! Using cryptcheck instead of check. \(Use --size-only or --ignore-checksum to disable\)$`, dropMe,
|
||||||
// ignore drive info messages
|
// ignore drive info messages
|
||||||
|
|
Loading…
Reference in New Issue
Block a user