|
7 | 7 | "os"
|
8 | 8 | "path"
|
9 | 9 | "sync/atomic"
|
| 10 | + "syscall" |
10 | 11 | "time"
|
11 | 12 |
|
12 | 13 | "github.com/kr/fs"
|
@@ -680,6 +681,54 @@ func (c *Client) Mkdir(path string) error {
|
680 | 681 | }
|
681 | 682 | }
|
682 | 683 |
|
| 684 | +// MkdirAll creates a directory named path, along with any necessary parents, |
| 685 | +// and returns nil, or else returns an error. |
| 686 | +// If path is already a directory, MkdirAll does nothing and returns nil. |
| 687 | +// If path contains a regular file, an error is returned |
| 688 | +func (c *Client) MkdirAll(path string) error { |
| 689 | + // Most of this code mimics https://golang.org/src/os/path.go?s=514:561#L13 |
| 690 | + // Fast path: if we can tell whether path is a directory or file, stop with success or error. |
| 691 | + dir, err := c.Stat(path) |
| 692 | + if err == nil { |
| 693 | + if dir.IsDir() { |
| 694 | + return nil |
| 695 | + } |
| 696 | + return &os.PathError{Op: "mkdir", Path: path, Err: syscall.ENOTDIR} |
| 697 | + } |
| 698 | + |
| 699 | + // Slow path: make sure parent exists and then call Mkdir for path. |
| 700 | + i := len(path) |
| 701 | + for i > 0 && os.IsPathSeparator(path[i-1]) { // Skip trailing path separator. |
| 702 | + i-- |
| 703 | + } |
| 704 | + |
| 705 | + j := i |
| 706 | + for j > 0 && !os.IsPathSeparator(path[j-1]) { // Scan backward over element. |
| 707 | + j-- |
| 708 | + } |
| 709 | + |
| 710 | + if j > 1 { |
| 711 | + // Create parent |
| 712 | + err = c.MkdirAll(path[0 : j-1]) |
| 713 | + if err != nil { |
| 714 | + return err |
| 715 | + } |
| 716 | + } |
| 717 | + |
| 718 | + // Parent now exists; invoke Mkdir and use its result. |
| 719 | + err = c.Mkdir(path) |
| 720 | + if err != nil { |
| 721 | + // Handle arguments like "foo/." by |
| 722 | + // double-checking that directory doesn't exist. |
| 723 | + dir, err1 := c.Lstat(path) |
| 724 | + if err1 == nil && dir.IsDir() { |
| 725 | + return nil |
| 726 | + } |
| 727 | + return err |
| 728 | + } |
| 729 | + return nil |
| 730 | +} |
| 731 | + |
683 | 732 | // applyOptions applies options functions to the Client.
|
684 | 733 | // If an error is encountered, option processing ceases.
|
685 | 734 | func (c *Client) applyOptions(opts ...ClientOption) error {
|
|
0 commit comments