aboutsummaryrefslogtreecommitdiff
path: root/lib/ssh/sftp/client.go
diff options
context:
space:
mode:
authorShulhan <ms@kilabit.info>2023-12-17 01:01:56 +0700
committerShulhan <ms@kilabit.info>2023-12-17 03:12:43 +0700
commit52ddfffc17fb81d11684db9d073bc565e232c4a8 (patch)
treed97c73c0f8fad64d82f7f71afcba8b4dbda16efd /lib/ssh/sftp/client.go
parentcc1b44567b77dda34203f0fcddeecc2d093a2480 (diff)
downloadpakakeh.go-52ddfffc17fb81d11684db9d073bc565e232c4a8.tar.xz
ssh/sftp: implement method MkdirAll on Client
The MkdirAll create directory on the server, from left to right. Each directory is separated by '/', where the left part is the parent of the right part. This method is similar to [os.MkdirAll].
Diffstat (limited to 'lib/ssh/sftp/client.go')
-rw-r--r--lib/ssh/sftp/client.go74
1 files changed, 74 insertions, 0 deletions
diff --git a/lib/ssh/sftp/client.go b/lib/ssh/sftp/client.go
index 47364f4f..79c89b48 100644
--- a/lib/ssh/sftp/client.go
+++ b/lib/ssh/sftp/client.go
@@ -10,6 +10,8 @@ import (
"io"
"io/fs"
"os"
+ "path"
+ "strings"
"sync"
"time"
@@ -273,6 +275,78 @@ func (cl *Client) Mkdir(path string, fa *FileAttrs) (err error) {
return nil
}
+// MkdirAll create directory on the server, from left to right.
+// Each directory is separated by '/', where the left part is the parent of
+// the right part.
+// This method is similar to [os.MkdirAll].
+//
+// Note that using `~` as home directory is not working.
+// If you want to create directory under home, use relative path, for
+// example "a/b/c" will create directory "~/a/b/c".
+func (cl *Client) MkdirAll(dir string, fa *FileAttrs) (err error) {
+ var logp = `MkdirAll`
+
+ if fa == nil {
+ fa = newFileAttrs()
+ fa.SetPermissions(0700)
+ }
+
+ dir = path.Clean(dir)
+ var (
+ listDir = strings.Split(dir, `/`)
+
+ req *packet
+ res *packet
+ lastErr error
+ item string
+ payload []byte
+ )
+ dir = ``
+ for _, item = range listDir {
+ if item == `` && len(listDir) > 1 {
+ // The first item of "/a/b" in [strings.Split] is
+ // empty, which indicate the root.
+ item = `/`
+ }
+ dir = path.Join(dir, item)
+ if dir == `/` {
+ // Skip creating root, since it should be already
+ // exist.
+ continue
+ }
+ if dir == `` {
+ // Skip creating home directory, since it should be
+ // already exist.
+ continue
+ }
+
+ req = cl.generatePacket()
+ payload = req.fxpMkdir(dir, fa)
+
+ res, err = cl.send(payload)
+ if err != nil {
+ return fmt.Errorf(`%s: %w`, logp, err)
+ }
+ if res.kind != packetKindFxpStatus {
+ return errUnexpectedResponse(packetKindFxpStatus, res.kind)
+ }
+ if res.code != statusCodeOK {
+ if res.code == statusCodeFailure {
+ // Directory may already exist but its
+ // returned as failure, keep going.
+ continue
+ }
+ lastErr = handleStatusCode(res.code, res.message)
+ }
+ // Reset last error if its success.
+ lastErr = nil
+ }
+ if lastErr != nil {
+ return lastErr
+ }
+ return nil
+}
+
// Open the remote file for read only.
func (cl *Client) Open(remoteFile string) (fh *FileHandle, err error) {
return cl.OpenFile(remoteFile, OpenFlagRead, nil)