1
0
mirror of https://github.com/rclone/rclone.git synced 2026-01-04 17:43:50 +00:00

Add support for multiple hash types.

Add support for multiple hash types with negotiation of common hash types for comparison.

Manually rebased version of #277 (see discussion there)
This commit is contained in:
klauspost
2016-01-11 13:39:33 +01:00
parent 2142c75846
commit 78c3a5ccfa
22 changed files with 815 additions and 135 deletions

View File

@@ -74,6 +74,7 @@ type Object struct {
remote string // The remote path
info api.File // Info from the b2 object if known
modTime time.Time // The modified time of the object if known
sha1 string // SHA-1 hash if known
}
// ------------------------------------------------------------
@@ -580,6 +581,11 @@ func (f *Fs) Purge() error {
return errReturn
}
// Hashes returns the supported hash sets.
func (f *Fs) Hashes() fs.HashSet {
return fs.HashSet(fs.HashSHA1)
}
// ------------------------------------------------------------
// Fs returns the parent Fs
@@ -600,9 +606,16 @@ func (o *Object) Remote() string {
return o.remote
}
// Md5sum returns the Md5sum of an object returning a lowercase hex string
func (o *Object) Md5sum() (string, error) {
return "", nil
// Hash returns the Sha-1 of an object returning a lowercase hex string
// Hash returns the Md5sum of an object returning a lowercase hex string
func (o *Object) Hash(t fs.HashType) (string, error) {
if t != fs.HashSHA1 {
return "", fs.ErrHashUnsupported
}
// Error is logged in readFileMetadata
_ = o.readFileMetadata()
return o.sha1, nil
}
// Size returns the size of an object in bytes
@@ -652,23 +665,40 @@ func parseTimeString(timeString string) (result time.Time, err error) {
//
// It attempts to read the objects mtime and if that isn't present the
// LastModified returned in the http headers
//
// SHA-1 will also be updated once the request has completed.
func (o *Object) ModTime() (result time.Time) {
if !o.modTime.IsZero() {
return o.modTime
// The error is logged in readFileMetadata
_ = o.readFileMetadata()
return o.modTime
}
// readFileMetadata attempts to read the modified time and
// SHA-1 hash of the remote object.
//
// If the objects mtime and if that isn't present the
// LastModified returned in the http headers.
//
// It is safe to call this function multiple times, and the
// result is cached between calls.
func (o *Object) readFileMetadata() error {
// Return if already know it
if !o.modTime.IsZero() && o.sha1 != "" {
return nil
}
// Return the current time if can't read metadata
result = time.Now()
// Set modtime to now, as default value.
o.modTime = time.Now()
// Read metadata (need ID)
// Read metadata (we need the ID)
err := o.readMetaData()
if err != nil {
fs.Debug(o, "Failed to read metadata: %v", err)
return result
fs.Debug(o, "Failed to get file metadata: %v", err)
return err
}
// Return the UploadTimestamp if can't get file info
result = time.Time(o.info.UploadTimestamp)
// Use the UploadTimestamp if can't get file info
o.modTime = time.Time(o.info.UploadTimestamp)
// Now read the metadata for the modified time
opts := rest.Opts{
@@ -682,17 +712,20 @@ func (o *Object) ModTime() (result time.Time) {
_, err = o.fs.srv.CallJSON(&opts, &request, &response)
if err != nil {
fs.Debug(o, "Failed to get file info: %v", err)
return result
return err
}
o.sha1 = response.SHA1
// Parse the result
timeString := response.Info[timeKey]
parsed, err := parseTimeString(timeString)
if err != nil {
fs.Debug(o, "Failed to parse mod time string %q: %v", timeString, err)
return result
return err
}
return parsed
o.modTime = parsed
return nil
}
// SetModTime sets the modification time of the local fs object
@@ -785,6 +818,9 @@ func (o *Object) Open() (in io.ReadCloser, err error) {
} else {
o.modTime = parsed
}
if o.sha1 == "" {
o.sha1 = resp.Header.Get(sha1Header)
}
return newOpenFile(o, resp), nil
}
@@ -939,6 +975,7 @@ func (o *Object) Update(in io.Reader, modTime time.Time, size int64) (err error)
o.info.Action = "upload"
o.info.Size = response.Size
o.info.UploadTimestamp = api.Timestamp(time.Now()) // FIXME not quite right
o.sha1 = response.SHA1
return nil
}