mirror of
https://github.com/rclone/rclone.git
synced 2025-01-09 15:58:28 +01:00
press: various fixups
This commit is contained in:
parent
10a3129049
commit
954a23ed5d
@ -13,7 +13,6 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"regexp"
|
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -38,6 +37,7 @@ const (
|
|||||||
|
|
||||||
bufferSize = 8388608
|
bufferSize = 8388608
|
||||||
heuristicBytes = 1048576
|
heuristicBytes = 1048576
|
||||||
|
minCompressionRatio = 1.1
|
||||||
|
|
||||||
metaFileExt = ".meta"
|
metaFileExt = ".meta"
|
||||||
uncompressedFileExt = ".bin"
|
uncompressedFileExt = ".bin"
|
||||||
@ -49,8 +49,6 @@ const (
|
|||||||
Gzip = 2
|
Gzip = 2
|
||||||
)
|
)
|
||||||
|
|
||||||
var unconpressibleRegexp = regexp.MustCompile("(^(video|image|audio)/.*)|(^.*?/(x-7z-compressed|zip|gzip|x-rar-compressed|zstd|x-xz|lzip|warc))")
|
|
||||||
|
|
||||||
// Register with Fs
|
// Register with Fs
|
||||||
func init() {
|
func init() {
|
||||||
// Build compression mode options.
|
// Build compression mode options.
|
||||||
@ -71,13 +69,21 @@ func init() {
|
|||||||
Help: "Remote to compress.",
|
Help: "Remote to compress.",
|
||||||
Required: true,
|
Required: true,
|
||||||
}, {
|
}, {
|
||||||
Name: "compression_mode",
|
Name: "mode",
|
||||||
Help: "Compression mode.",
|
Help: "Compression mode.",
|
||||||
Default: "gzip",
|
Default: "gzip",
|
||||||
Examples: compressionModeOptions,
|
Examples: compressionModeOptions,
|
||||||
}, {
|
}, {
|
||||||
Name: "compression_level",
|
Name: "level",
|
||||||
Help: "gzip compression level -2 to 9",
|
Help: `GZIP compression level (-2 to 9).
|
||||||
|
|
||||||
|
Generally -1 (default, equivalent to 5) is recommended.
|
||||||
|
Levels 1 to 9 increase compressiong at the cost of speed.. Going past 6
|
||||||
|
generally offers very little return.
|
||||||
|
|
||||||
|
Level -2 uses Huffmann encoding only. Only use if you now what you
|
||||||
|
are doing
|
||||||
|
Level 0 turns off compression.`,
|
||||||
Default: sgzip.DefaultCompression,
|
Default: sgzip.DefaultCompression,
|
||||||
Advanced: true,
|
Advanced: true,
|
||||||
}},
|
}},
|
||||||
@ -87,8 +93,8 @@ func init() {
|
|||||||
// Options defines the configuration for this backend
|
// Options defines the configuration for this backend
|
||||||
type Options struct {
|
type Options struct {
|
||||||
Remote string `config:"remote"`
|
Remote string `config:"remote"`
|
||||||
CompressionMode string `config:"compression_mode"`
|
CompressionMode string `config:"mode"`
|
||||||
CompressionLevel int `config:"compression_level"`
|
CompressionLevel int `config:"level"`
|
||||||
}
|
}
|
||||||
|
|
||||||
/*** FILESYSTEM FUNCTIONS ***/
|
/*** FILESYSTEM FUNCTIONS ***/
|
||||||
@ -150,7 +156,7 @@ func NewFs(name, rpath string, m configmap.Mapper) (fs.Fs, error) {
|
|||||||
// ANDed with the ones from wrappedFs
|
// ANDed with the ones from wrappedFs
|
||||||
f.features = (&fs.Features{
|
f.features = (&fs.Features{
|
||||||
CaseInsensitive: true,
|
CaseInsensitive: true,
|
||||||
DuplicateFiles: true,
|
DuplicateFiles: false,
|
||||||
ReadMimeType: false,
|
ReadMimeType: false,
|
||||||
WriteMimeType: false,
|
WriteMimeType: false,
|
||||||
GetTier: true,
|
GetTier: true,
|
||||||
@ -161,8 +167,8 @@ func NewFs(name, rpath string, m configmap.Mapper) (fs.Fs, error) {
|
|||||||
// We support reading MIME types no matter the wrapped fs
|
// We support reading MIME types no matter the wrapped fs
|
||||||
f.features.ReadMimeType = true
|
f.features.ReadMimeType = true
|
||||||
// We can only support putstream if we have serverside copy or move
|
// We can only support putstream if we have serverside copy or move
|
||||||
if wrappedFs.Features().Move == nil && wrappedFs.Features().Copy == nil {
|
if !operations.CanServerSideMove(wrappedFs) {
|
||||||
f.features.PutStream = nil
|
f.features.Disable("PutStream")
|
||||||
}
|
}
|
||||||
|
|
||||||
return f, err
|
return f, err
|
||||||
@ -350,22 +356,39 @@ func (f *Fs) NewObject(ctx context.Context, remote string) (fs.Object, error) {
|
|||||||
return f.newObject(o, mo, meta), err
|
return f.newObject(o, mo, meta), err
|
||||||
}
|
}
|
||||||
|
|
||||||
// findMimeType attempts to find the mime type of the object so we can determine compressibility
|
// checkCompressAndType attempts to find the mime type of the object so we can determine compressibility
|
||||||
// returns a multireader with the bytes that were read to determine mime type
|
// returns a multireader with the bytes that were read to determine mime type
|
||||||
func findMimeType(in io.Reader) (newReader io.Reader, mimeType string, err error) {
|
func checkCompressAndType(in io.Reader) (newReader io.Reader, compressible bool, mimeType string, err error) {
|
||||||
in, wrap := accounting.UnWrap(in)
|
in, wrap := accounting.UnWrap(in)
|
||||||
var b bytes.Buffer
|
buf := make([]byte, heuristicBytes)
|
||||||
_, err = io.CopyN(&b, in, heuristicBytes)
|
n, err := in.Read(buf)
|
||||||
|
buf = buf[:n]
|
||||||
if err != nil && err != io.EOF {
|
if err != nil && err != io.EOF {
|
||||||
return nil, "", err
|
return nil, false, "", err
|
||||||
}
|
}
|
||||||
mime := mimetype.Detect(b.Bytes())
|
mime := mimetype.Detect(buf)
|
||||||
in = io.MultiReader(bytes.NewReader(b.Bytes()), in)
|
compressible, err = isCompressible(bytes.NewReader(buf))
|
||||||
return wrap(in), mime.String(), nil
|
if err != nil {
|
||||||
|
return nil, false, "", err
|
||||||
|
}
|
||||||
|
in = io.MultiReader(bytes.NewReader(buf), in)
|
||||||
|
return wrap(in), compressible, mime.String(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func isCompressible(mime string) bool {
|
// isCompressible checks the compression ratio of the provided data and returns true if the ratio exceeds
|
||||||
return !unconpressibleRegexp.MatchString(mime)
|
// the configured threshold
|
||||||
|
func isCompressible(r io.Reader) (bool, error) {
|
||||||
|
var b bytes.Buffer
|
||||||
|
w, err := sgzip.NewWriterLevel(&b, sgzip.DefaultCompression)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
n, err := io.Copy(w, r)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
ratio := float64(n) / float64(b.Len())
|
||||||
|
return ratio > minCompressionRatio, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verifies an object hash
|
// Verifies an object hash
|
||||||
@ -394,7 +417,7 @@ type compressionResult struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Put a compressed version of a file. Returns a wrappable object and metadata.
|
// Put a compressed version of a file. Returns a wrappable object and metadata.
|
||||||
func (f *Fs) putCompress(ctx context.Context, in io.Reader, src fs.ObjectInfo, options []fs.OpenOption, put putFn, mimeType string, verifyCompressedObject bool) (fs.Object, *ObjectMetadata, error) {
|
func (f *Fs) putCompress(ctx context.Context, in io.Reader, src fs.ObjectInfo, options []fs.OpenOption, put putFn, mimeType string) (fs.Object, *ObjectMetadata, error) {
|
||||||
// Unwrap reader accounting
|
// Unwrap reader accounting
|
||||||
in, wrap := accounting.UnWrap(in)
|
in, wrap := accounting.UnWrap(in)
|
||||||
|
|
||||||
@ -422,17 +445,20 @@ func (f *Fs) putCompress(ctx context.Context, in io.Reader, src fs.ObjectInfo, o
|
|||||||
closeErr := pipeWriter.Close()
|
closeErr := pipeWriter.Close()
|
||||||
if closeErr != nil {
|
if closeErr != nil {
|
||||||
fs.Errorf(nil, "Failed to close pipe: %v", closeErr)
|
fs.Errorf(nil, "Failed to close pipe: %v", closeErr)
|
||||||
|
if err == nil {
|
||||||
|
err = closeErr
|
||||||
|
}
|
||||||
}
|
}
|
||||||
results <- compressionResult{err: err, meta: gz.MetaData()}
|
results <- compressionResult{err: err, meta: gz.MetaData()}
|
||||||
}()
|
}()
|
||||||
wrappedIn := wrap(bufio.NewReaderSize(pipeReader, bufferSize)) // Probably no longer needed as sgzip has it's own buffering
|
wrappedIn := wrap(bufio.NewReaderSize(pipeReader, bufferSize)) // Probably no longer needed as sgzip has it's own buffering
|
||||||
|
|
||||||
// If verifyCompressedObject is on, find a hash the destination supports to compute a hash of
|
// Find a hash the destination supports to compute a hash of
|
||||||
// the compressed data.
|
// the compressed data.
|
||||||
ht := f.Fs.Hashes().GetOne()
|
ht := f.Fs.Hashes().GetOne()
|
||||||
var hasher *hash.MultiHasher
|
var hasher *hash.MultiHasher
|
||||||
var err error
|
var err error
|
||||||
if ht != hash.None && verifyCompressedObject {
|
if ht != hash.None {
|
||||||
// unwrap the accounting again
|
// unwrap the accounting again
|
||||||
wrappedIn, wrap = accounting.UnWrap(wrappedIn)
|
wrappedIn, wrap = accounting.UnWrap(wrappedIn)
|
||||||
hasher, err = hash.NewMultiHasherTypes(hash.NewHashSet(ht))
|
hasher, err = hash.NewMultiHasherTypes(hash.NewHashSet(ht))
|
||||||
@ -483,17 +509,15 @@ func (f *Fs) putCompress(ctx context.Context, in io.Reader, src fs.ObjectInfo, o
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Put an uncompressed version of a file. Returns a wrappable object and metadata.
|
// Put an uncompressed version of a file. Returns a wrappable object and metadata.
|
||||||
func (f *Fs) putUncompress(ctx context.Context, in io.Reader, src fs.ObjectInfo, options []fs.OpenOption, put putFn, mimeType string, verifyCompressedObject bool) (fs.Object, *ObjectMetadata, error) {
|
func (f *Fs) putUncompress(ctx context.Context, in io.Reader, src fs.ObjectInfo, options []fs.OpenOption, put putFn, mimeType string) (fs.Object, *ObjectMetadata, error) {
|
||||||
// Unwrap the accounting, add our metadata hasher, then wrap it back on
|
// Unwrap the accounting, add our metadata hasher, then wrap it back on
|
||||||
in, wrap := accounting.UnWrap(in)
|
in, wrap := accounting.UnWrap(in)
|
||||||
|
|
||||||
hs := hash.NewHashSet(hash.MD5)
|
hs := hash.NewHashSet(hash.MD5)
|
||||||
ht := f.Fs.Hashes().GetOne()
|
ht := f.Fs.Hashes().GetOne()
|
||||||
if verifyCompressedObject {
|
|
||||||
if !hs.Contains(ht) {
|
if !hs.Contains(ht) {
|
||||||
hs.Add(ht)
|
hs.Add(ht)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
metaHasher, err := hash.NewMultiHasherTypes(hs)
|
metaHasher, err := hash.NewMultiHasherTypes(hs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
@ -513,7 +537,7 @@ func (f *Fs) putUncompress(ctx context.Context, in io.Reader, src fs.ObjectInfo,
|
|||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
// Check the hashes of the compressed data if we were comparing them
|
// Check the hashes of the compressed data if we were comparing them
|
||||||
if ht != hash.None && verifyCompressedObject {
|
if ht != hash.None {
|
||||||
err := f.verifyObjectHash(ctx, o, metaHasher, ht)
|
err := f.verifyObjectHash(ctx, o, metaHasher, ht)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
@ -529,7 +553,7 @@ func (f *Fs) putUncompress(ctx context.Context, in io.Reader, src fs.ObjectInfo,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// This function will write a metadata struct to a metadata Object for an src. Returns a wrappable metadata object.
|
// This function will write a metadata struct to a metadata Object for an src. Returns a wrappable metadata object.
|
||||||
func (f *Fs) putMetadata(ctx context.Context, meta *ObjectMetadata, src fs.ObjectInfo, options []fs.OpenOption, put putFn, verifyCompressedObject bool) (mo fs.Object, err error) {
|
func (f *Fs) putMetadata(ctx context.Context, meta *ObjectMetadata, src fs.ObjectInfo, options []fs.OpenOption, put putFn) (mo fs.Object, err error) {
|
||||||
// Generate the metadata contents
|
// Generate the metadata contents
|
||||||
var b bytes.Buffer
|
var b bytes.Buffer
|
||||||
gzipWriter := gzip.NewWriter(&b)
|
gzipWriter := gzip.NewWriter(&b)
|
||||||
@ -560,21 +584,21 @@ func (f *Fs) putMetadata(ctx context.Context, meta *ObjectMetadata, src fs.Objec
|
|||||||
// This function will put both the data and metadata for an Object.
|
// This function will put both the data and metadata for an Object.
|
||||||
// putData is the function used for data, while putMeta is the function used for metadata.
|
// putData is the function used for data, while putMeta is the function used for metadata.
|
||||||
func (f *Fs) putWithCustomFunctions(ctx context.Context, in io.Reader, src fs.ObjectInfo, options []fs.OpenOption,
|
func (f *Fs) putWithCustomFunctions(ctx context.Context, in io.Reader, src fs.ObjectInfo, options []fs.OpenOption,
|
||||||
putData putFn, putMeta putFn, compressible bool, mimeType string, verifyCompressedObject bool) (*Object, error) {
|
putData putFn, putMeta putFn, compressible bool, mimeType string) (*Object, error) {
|
||||||
// Put file then metadata
|
// Put file then metadata
|
||||||
var dataObject fs.Object
|
var dataObject fs.Object
|
||||||
var meta *ObjectMetadata
|
var meta *ObjectMetadata
|
||||||
var err error
|
var err error
|
||||||
if compressible {
|
if compressible {
|
||||||
dataObject, meta, err = f.putCompress(ctx, in, src, options, putData, mimeType, verifyCompressedObject)
|
dataObject, meta, err = f.putCompress(ctx, in, src, options, putData, mimeType)
|
||||||
} else {
|
} else {
|
||||||
dataObject, meta, err = f.putUncompress(ctx, in, src, options, putData, mimeType, verifyCompressedObject)
|
dataObject, meta, err = f.putUncompress(ctx, in, src, options, putData, mimeType)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
mo, err := f.putMetadata(ctx, meta, src, options, putMeta, verifyCompressedObject)
|
mo, err := f.putMetadata(ctx, meta, src, options, putMeta)
|
||||||
|
|
||||||
// meta data upload may fail. in this case we try to remove the original object
|
// meta data upload may fail. in this case we try to remove the original object
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -593,17 +617,17 @@ func (f *Fs) putWithCustomFunctions(ctx context.Context, in io.Reader, src fs.Ob
|
|||||||
// will return the object and the error, otherwise will return
|
// will return the object and the error, otherwise will return
|
||||||
// nil and the error
|
// nil and the error
|
||||||
func (f *Fs) Put(ctx context.Context, in io.Reader, src fs.ObjectInfo, options ...fs.OpenOption) (fs.Object, error) {
|
func (f *Fs) Put(ctx context.Context, in io.Reader, src fs.ObjectInfo, options ...fs.OpenOption) (fs.Object, error) {
|
||||||
// If there's already an existent objects we need to make sure to explcitly update it to make sure we don't leave
|
// If there's already an existent objects we need to make sure to explicitly update it to make sure we don't leave
|
||||||
// orphaned data. Alternatively we could also deleted (which would simpler) but has the disadvantage that it
|
// orphaned data. Alternatively we could also deleted (which would simpler) but has the disadvantage that it
|
||||||
// destroys all server-side versioning.
|
// destroys all server-side versioning.
|
||||||
o, err := f.NewObject(ctx, src.Remote())
|
o, err := f.NewObject(ctx, src.Remote())
|
||||||
if err == fs.ErrorObjectNotFound {
|
if err == fs.ErrorObjectNotFound {
|
||||||
// Get our file compressibility
|
// Get our file compressibility
|
||||||
in, mimeType, err := findMimeType(in)
|
in, compressible, mimeType, err := checkCompressAndType(in)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return f.putWithCustomFunctions(ctx, in, src, options, f.Fs.Put, f.Fs.Put, isCompressible(mimeType), mimeType, true)
|
return f.putWithCustomFunctions(ctx, in, src, options, f.Fs.Put, f.Fs.Put, compressible, mimeType)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -619,50 +643,33 @@ func (f *Fs) PutStream(ctx context.Context, in io.Reader, src fs.ObjectInfo, opt
|
|||||||
}
|
}
|
||||||
found := err == nil
|
found := err == nil
|
||||||
|
|
||||||
in, mimeType, err := findMimeType(in)
|
in, compressible, mimeType, err := checkCompressAndType(in)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
compressible := isCompressible(mimeType)
|
newObj, err := f.putWithCustomFunctions(ctx, in, src, options, f.Fs.Features().PutStream, f.Fs.Put, compressible, mimeType)
|
||||||
newObj, err := f.putWithCustomFunctions(ctx, in, src, options, f.Fs.Features().PutStream, f.Fs.Put, compressible, mimeType, true)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Our transfer is now complete if we allready had an object with the same name we can safely remove it now
|
// Our transfer is now complete. We have to make sure to remove the old object because our new object will
|
||||||
// this is necessary to make sure we don't leave the remote in an inconsistent state.
|
// have a different name except when both the old and the new object where uncompressed.
|
||||||
if found {
|
if found && (oldObj.(*Object).meta.Mode != Uncompressed || compressible) {
|
||||||
err = oldObj.(*Object).Object.Remove(ctx)
|
err = oldObj.(*Object).Object.Remove(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrap(err, "Could remove original object")
|
return nil, errors.Wrap(err, "Could remove original object")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
moveFs, ok := f.Fs.(fs.Mover)
|
// If our new object is compressed we have to rename it with the correct size.
|
||||||
var wrapObj fs.Object
|
// Uncompressed objects don't store the size in the name so we they'll allready have the correct name.
|
||||||
if ok {
|
if compressible {
|
||||||
wrapObj, err = moveFs.Move(ctx, newObj.Object, f.dataName(src.Remote(), newObj.size, compressible))
|
wrapObj, err := operations.Move(ctx, f.Fs, nil, f.dataName(src.Remote(), newObj.size, compressible), newObj.Object)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrap(err, "Couldn't rename streamed object.")
|
return nil, errors.Wrap(err, "Couldn't rename streamed Object.")
|
||||||
}
|
}
|
||||||
newObj.Object = wrapObj
|
newObj.Object = wrapObj
|
||||||
return newObj, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we don't have move we'll need to resort to serverside copy and remove
|
|
||||||
copyFs, ok := f.Fs.(fs.Copier)
|
|
||||||
if ok {
|
|
||||||
wrapObj, err := copyFs.Copy(ctx, newObj.Object, f.dataName(src.Remote(), newObj.size, compressible))
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.Wrap(err, "Could't copy streamed object.")
|
|
||||||
}
|
|
||||||
// Remove the original
|
|
||||||
err = newObj.Remove(ctx)
|
|
||||||
if err != nil {
|
|
||||||
return wrapObj, errors.Wrap(err, "Couldn't remove original streamed object. Remote may be in an incositent state.")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
newObj.Object = wrapObj
|
|
||||||
return newObj, nil
|
return newObj, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -935,7 +942,6 @@ func (f *Fs) PublicLink(ctx context.Context, remote string, duration fs.Duration
|
|||||||
|
|
||||||
// ObjectMetadata describes the metadata for an Object.
|
// ObjectMetadata describes the metadata for an Object.
|
||||||
type ObjectMetadata struct {
|
type ObjectMetadata struct {
|
||||||
Size int64 // Uncompressed size of the file.
|
|
||||||
Mode int // Compression mode of the file.
|
Mode int // Compression mode of the file.
|
||||||
Hash []byte // MD5 hash of the file.
|
Hash []byte // MD5 hash of the file.
|
||||||
MimeType string // Mime type of the file
|
MimeType string // Mime type of the file
|
||||||
@ -1009,25 +1015,8 @@ func (o *Object) Remove(ctx context.Context) error {
|
|||||||
|
|
||||||
// ReadCloserWrapper combines a Reader and a Closer to a ReadCloser
|
// ReadCloserWrapper combines a Reader and a Closer to a ReadCloser
|
||||||
type ReadCloserWrapper struct {
|
type ReadCloserWrapper struct {
|
||||||
dataSource io.Reader
|
io.Reader
|
||||||
closer io.Closer
|
io.Closer
|
||||||
}
|
|
||||||
|
|
||||||
func combineReaderAndCloser(dataSource io.Reader, closer io.Closer) *ReadCloserWrapper {
|
|
||||||
rc := new(ReadCloserWrapper)
|
|
||||||
rc.dataSource = dataSource
|
|
||||||
rc.closer = closer
|
|
||||||
return rc
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read function
|
|
||||||
func (w *ReadCloserWrapper) Read(p []byte) (n int, err error) {
|
|
||||||
return w.dataSource.Read(p)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Close function
|
|
||||||
func (w *ReadCloserWrapper) Close() error {
|
|
||||||
return w.closer.Close()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update in to the object with the modTime given of the given size
|
// Update in to the object with the modTime given of the given size
|
||||||
@ -1041,18 +1030,17 @@ func (o *Object) Update(ctx context.Context, in io.Reader, src fs.ObjectInfo, op
|
|||||||
return o.mo, o.mo.Update(ctx, in, src, options...)
|
return o.mo, o.mo.Update(ctx, in, src, options...)
|
||||||
}
|
}
|
||||||
|
|
||||||
in, mimeType, err := findMimeType(in)
|
in, compressible, mimeType, err := checkCompressAndType(in)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
compressible := isCompressible(mimeType)
|
|
||||||
|
|
||||||
// Since we are storing the filesize in the name the new object may have different name than the old
|
// Since we are storing the filesize in the name the new object may have different name than the old
|
||||||
// We'll make sure to delete the old object in this case
|
// We'll make sure to delete the old object in this case
|
||||||
var newObject *Object
|
var newObject *Object
|
||||||
origName := o.Remote()
|
origName := o.Remote()
|
||||||
if o.meta.Mode != Uncompressed || compressible {
|
if o.meta.Mode != Uncompressed || compressible {
|
||||||
newObject, err = o.f.putWithCustomFunctions(ctx, in, o.f.wrapInfo(src, origName, src.Size()), options, o.f.Fs.Put, updateMeta, compressible, mimeType, true)
|
newObject, err = o.f.putWithCustomFunctions(ctx, in, o.f.wrapInfo(src, origName, src.Size()), options, o.f.Fs.Put, updateMeta, compressible, mimeType)
|
||||||
if newObject.Object.Remote() != o.Object.Remote() {
|
if newObject.Object.Remote() != o.Object.Remote() {
|
||||||
if removeErr := o.Object.Remove(ctx); removeErr != nil {
|
if removeErr := o.Object.Remove(ctx); removeErr != nil {
|
||||||
return removeErr
|
return removeErr
|
||||||
@ -1064,7 +1052,7 @@ func (o *Object) Update(ctx context.Context, in io.Reader, src fs.ObjectInfo, op
|
|||||||
return o.Object, o.Object.Update(ctx, in, src, options...)
|
return o.Object, o.Object.Update(ctx, in, src, options...)
|
||||||
}
|
}
|
||||||
// If we are, just update the object and metadata
|
// If we are, just update the object and metadata
|
||||||
newObject, err = o.f.putWithCustomFunctions(ctx, in, src, options, update, updateMeta, compressible, mimeType, true)
|
newObject, err = o.f.putWithCustomFunctions(ctx, in, src, options, update, updateMeta, compressible, mimeType)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -1163,13 +1151,13 @@ func (o *Object) MimeType(ctx context.Context) string {
|
|||||||
// Hash returns the selected checksum of the file
|
// Hash returns the selected checksum of the file
|
||||||
// If no checksum is available it returns ""
|
// If no checksum is available it returns ""
|
||||||
func (o *Object) Hash(ctx context.Context, ht hash.Type) (string, error) {
|
func (o *Object) Hash(ctx context.Context, ht hash.Type) (string, error) {
|
||||||
|
if ht != hash.MD5 {
|
||||||
|
return "", hash.ErrUnsupported
|
||||||
|
}
|
||||||
err := o.loadMetadataIfNotLoaded(ctx)
|
err := o.loadMetadataIfNotLoaded(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
if ht&hash.MD5 == 0 {
|
|
||||||
return "", hash.ErrUnsupported
|
|
||||||
}
|
|
||||||
return hex.EncodeToString(o.meta.Hash), nil
|
return hex.EncodeToString(o.meta.Hash), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1240,7 +1228,7 @@ func (o *Object) Open(ctx context.Context, options ...fs.OpenOption) (rc io.Read
|
|||||||
fileReader = file
|
fileReader = file
|
||||||
}
|
}
|
||||||
// Return a ReadCloser
|
// Return a ReadCloser
|
||||||
return combineReaderAndCloser(fileReader, chunkedReader), nil
|
return ReadCloserWrapper{Reader: fileReader, Closer: chunkedReader}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ObjectInfo describes a wrapped fs.ObjectInfo for being the source
|
// ObjectInfo describes a wrapped fs.ObjectInfo for being the source
|
||||||
@ -1305,9 +1293,6 @@ func (o *ObjectInfo) Hash(ctx context.Context, ht hash.Type) (string, error) {
|
|||||||
if ht != hash.MD5 {
|
if ht != hash.MD5 {
|
||||||
return "", hash.ErrUnsupported
|
return "", hash.ErrUnsupported
|
||||||
}
|
}
|
||||||
if o.Size() != o.src.Size() {
|
|
||||||
return "", hash.ErrUnsupported
|
|
||||||
}
|
|
||||||
value, err := o.src.Hash(ctx, ht)
|
value, err := o.src.Hash(ctx, ht)
|
||||||
if err == hash.ErrUnsupported {
|
if err == hash.ErrUnsupported {
|
||||||
return "", hash.ErrUnsupported
|
return "", hash.ErrUnsupported
|
||||||
|
@ -8,7 +8,7 @@ Press (Experimental)
|
|||||||
-----------------------------------------
|
-----------------------------------------
|
||||||
|
|
||||||
The `press` remote adds compression to another remote. It is best used with remotes containing
|
The `press` remote adds compression to another remote. It is best used with remotes containing
|
||||||
many large compressible files or on top of other remotes like crypt.
|
many large compressible files.
|
||||||
|
|
||||||
Please read the [warnings](#warnings) before using this remote.
|
Please read the [warnings](#warnings) before using this remote.
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user