mirror of https://github.com/rclone/rclone
pixeldrain: add support for metadata setting in put and rename requests
This commit is contained in:
parent
803fa4411b
commit
7f8fb01fc8
|
@ -129,6 +129,28 @@ func apiErrorHandler(resp *http.Response) (err error) {
|
|||
return e
|
||||
}
|
||||
|
||||
func paramsFromMetadata(meta fs.Metadata) (params url.Values) {
|
||||
params = make(url.Values)
|
||||
|
||||
if modified, ok := meta["mtime"]; ok {
|
||||
params.Set("modified", modified)
|
||||
}
|
||||
if created, ok := meta["btime"]; ok {
|
||||
params.Set("created", created)
|
||||
}
|
||||
if mode, ok := meta["mode"]; ok {
|
||||
params.Set("mode", mode)
|
||||
}
|
||||
if shared, ok := meta["shared"]; ok {
|
||||
params.Set("shared", shared)
|
||||
}
|
||||
if loggingEnabled, ok := meta["logging_enabled"]; ok {
|
||||
params.Set("logging_enabled", loggingEnabled)
|
||||
}
|
||||
|
||||
return params
|
||||
}
|
||||
|
||||
// nodeToObject converts a single FilesystemNode API response to an object. The
|
||||
// node is usually a single element from a directory listing
|
||||
func (f *Fs) nodeToObject(node FilesystemNode) (o *Object) {
|
||||
|
@ -152,7 +174,16 @@ func (f *Fs) escapePath(p string) (out string) {
|
|||
return strings.Join(parts, "/")
|
||||
}
|
||||
|
||||
func (f *Fs) put(ctx context.Context, path string, body io.Reader, options []fs.OpenOption) (node FilesystemNode, err error) {
|
||||
func (f *Fs) put(
|
||||
ctx context.Context,
|
||||
path string,
|
||||
body io.Reader,
|
||||
meta fs.Metadata,
|
||||
options []fs.OpenOption,
|
||||
) (node FilesystemNode, err error) {
|
||||
var params = paramsFromMetadata(meta)
|
||||
params.Set("make_parents", "true")
|
||||
|
||||
resp, err := f.srv.CallJSON(
|
||||
ctx,
|
||||
&rest.Opts{
|
||||
|
@ -161,7 +192,7 @@ func (f *Fs) put(ctx context.Context, path string, body io.Reader, options []fs.
|
|||
Body: body,
|
||||
// Tell the server to automatically create parent directories if
|
||||
// they don't exist yet
|
||||
Parameters: url.Values{"make_parents": []string{"true"}},
|
||||
Parameters: params,
|
||||
Options: options,
|
||||
},
|
||||
nil,
|
||||
|
@ -227,25 +258,9 @@ func (f *Fs) changeLog(ctx context.Context, start, end time.Time) (changeLog Cha
|
|||
}
|
||||
|
||||
func (f *Fs) update(ctx context.Context, path string, fields fs.Metadata) (node FilesystemNode, err error) {
|
||||
var params = make(url.Values)
|
||||
var params = paramsFromMetadata(fields)
|
||||
params.Set("action", "update")
|
||||
|
||||
if modified, ok := fields["mtime"]; ok {
|
||||
params.Set("modified", modified)
|
||||
}
|
||||
if created, ok := fields["btime"]; ok {
|
||||
params.Set("created", created)
|
||||
}
|
||||
if mode, ok := fields["mode"]; ok {
|
||||
params.Set("mode", mode)
|
||||
}
|
||||
if shared, ok := fields["shared"]; ok {
|
||||
params.Set("shared", shared)
|
||||
}
|
||||
if loggingEnabled, ok := fields["logging_enabled"]; ok {
|
||||
params.Set("logging_enabled", loggingEnabled)
|
||||
}
|
||||
|
||||
resp, err := f.srv.CallJSON(
|
||||
ctx,
|
||||
&rest.Opts{
|
||||
|
@ -271,7 +286,8 @@ func (f *Fs) mkdir(ctx context.Context, dir string) (err error) {
|
|||
MultipartParams: url.Values{"action": []string{"mkdirall"}},
|
||||
NoResponse: true,
|
||||
},
|
||||
nil, nil,
|
||||
nil,
|
||||
nil,
|
||||
)
|
||||
return err
|
||||
}
|
||||
|
@ -279,36 +295,42 @@ func (f *Fs) mkdir(ctx context.Context, dir string) (err error) {
|
|||
var errIncompatibleSourceFS = errors.New("source filesystem is not the same as target")
|
||||
|
||||
// Renames a file on the server side. Can be used for both directories and files
|
||||
func (f *Fs) rename(ctx context.Context, src fs.Fs, from, to string) (err error) {
|
||||
func (f *Fs) rename(ctx context.Context, src fs.Fs, from, to string, meta fs.Metadata) (node FilesystemNode, err error) {
|
||||
srcFs, ok := src.(*Fs)
|
||||
if !ok {
|
||||
// This is not a pixeldrain FS, can't move
|
||||
return errIncompatibleSourceFS
|
||||
return node, errIncompatibleSourceFS
|
||||
} else if srcFs.opt.DirectoryID != f.opt.DirectoryID {
|
||||
// Path is not in the same root dir, can't move
|
||||
return errIncompatibleSourceFS
|
||||
return node, errIncompatibleSourceFS
|
||||
}
|
||||
|
||||
_, err = f.srv.CallJSON(
|
||||
var params = paramsFromMetadata(meta)
|
||||
params.Set("action", "rename")
|
||||
|
||||
// The target is always in our own filesystem so here we use our
|
||||
// own pathPrefix
|
||||
params.Set("target", f.pathPrefix+to)
|
||||
|
||||
// Create parent directories if the parent directory of the file
|
||||
// does not exist yet
|
||||
params.Set("make_parents", "true")
|
||||
|
||||
resp, err := f.srv.CallJSON(
|
||||
ctx,
|
||||
&rest.Opts{
|
||||
Method: "POST",
|
||||
// Important: We use the source FS path prefix here
|
||||
Path: srcFs.escapePath(from),
|
||||
MultipartParams: url.Values{
|
||||
"action": []string{"rename"},
|
||||
// The target is always in our own filesystem so here we use our
|
||||
// own pathPrefix
|
||||
"target": []string{f.pathPrefix + to},
|
||||
// Create parent directories if the parent directory of the file
|
||||
// does not exist yet
|
||||
"make_parents": []string{"true"},
|
||||
},
|
||||
NoResponse: true,
|
||||
Path: srcFs.escapePath(from),
|
||||
MultipartParams: params,
|
||||
},
|
||||
nil, nil,
|
||||
nil,
|
||||
&node,
|
||||
)
|
||||
return err
|
||||
if err != nil {
|
||||
return node, err
|
||||
}
|
||||
return node, resp.Body.Close()
|
||||
}
|
||||
|
||||
func (f *Fs) delete(ctx context.Context, path string, recursive bool) (err error) {
|
||||
|
|
|
@ -226,32 +226,25 @@ func (f *Fs) NewObject(ctx context.Context, remote string) (fs.Object, error) {
|
|||
//
|
||||
// The new object may have been created if an error is returned
|
||||
func (f *Fs) Put(ctx context.Context, in io.Reader, src fs.ObjectInfo, options ...fs.OpenOption) (fs.Object, error) {
|
||||
_, err := f.put(ctx, src.Remote(), in, options)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to put object: %w", err)
|
||||
}
|
||||
|
||||
meta, err := fs.GetMetadataOptions(ctx, f, src, options)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get object metadata")
|
||||
}
|
||||
if meta == nil {
|
||||
meta = make(fs.Metadata)
|
||||
}
|
||||
|
||||
// Overwrite the mtime if it was not already set in the metadata
|
||||
if _, ok := meta["mtime"]; !ok {
|
||||
if meta == nil {
|
||||
meta = make(fs.Metadata)
|
||||
}
|
||||
meta["mtime"] = src.ModTime(ctx).Format(timeFormat)
|
||||
}
|
||||
|
||||
// Can't set modtime in the same request as the original upload. So we send
|
||||
// this followup request
|
||||
fsp, err := f.update(ctx, src.Remote(), meta)
|
||||
node, err := f.put(ctx, src.Remote(), in, meta, options)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("failed to put object: %w", err)
|
||||
}
|
||||
|
||||
return f.nodeToObject(fsp), nil
|
||||
return f.nodeToObject(node), nil
|
||||
}
|
||||
|
||||
// Mkdir creates the container if it doesn't exist
|
||||
|
@ -340,19 +333,14 @@ func (f *Fs) Move(ctx context.Context, src fs.Object, remote string) (fs.Object,
|
|||
return nil, fs.ErrorCantMove
|
||||
}
|
||||
|
||||
err := f.rename(ctx, srcObj.fs, srcObj.base.Path, remote)
|
||||
node, err := f.rename(ctx, srcObj.fs, srcObj.base.Path, remote, fs.GetConfig(ctx).MetadataSet)
|
||||
if err == errIncompatibleSourceFS {
|
||||
return nil, fs.ErrorCantMove
|
||||
} else if err == errNotFound {
|
||||
return nil, fs.ErrorObjectNotFound
|
||||
}
|
||||
|
||||
// The node only got its path changed, so we just copy the original Object
|
||||
// and change the path variable. This prevents us from having to make
|
||||
// another request to get the updated node
|
||||
var nodeCopy = srcObj.base
|
||||
nodeCopy.Path = remote
|
||||
return f.nodeToObject(nodeCopy), err
|
||||
return f.nodeToObject(node), nil
|
||||
}
|
||||
|
||||
// =======================================
|
||||
|
@ -369,7 +357,7 @@ var _ fs.DirMover = (*Fs)(nil)
|
|||
//
|
||||
// If destination exists then return fs.ErrorDirExists
|
||||
func (f *Fs) DirMove(ctx context.Context, src fs.Fs, srcRemote, dstRemote string) (err error) {
|
||||
err = f.rename(ctx, src, srcRemote, dstRemote)
|
||||
_, err = f.rename(ctx, src, srcRemote, dstRemote, nil)
|
||||
if err == errIncompatibleSourceFS {
|
||||
return fs.ErrorCantDirMove
|
||||
} else if err == errNotFound {
|
||||
|
|
Loading…
Reference in New Issue