Created
June 5, 2012 17:46
-
-
Save jaybill/2876519 to your computer and use it in GitHub Desktop.
How to copy a directory tree (preserving permissions) in Go.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import "fmt" | |
import "os" | |
import "io" | |
import "io/ioutil" | |
import "log" | |
// Copies file source to destination dest. | |
func CopyFile(source string, dest string) (err error) { | |
sf, err := os.Open(source) | |
if err != nil { | |
return err | |
} | |
defer sf.Close() | |
df, err := os.Create(dest) | |
if err != nil { | |
return err | |
} | |
defer df.Close() | |
_, err = io.Copy(df, sf) | |
if err == nil { | |
si, err := os.Stat(source) | |
if err != nil { | |
err = os.Chmod(dest, si.Mode()) | |
} | |
} | |
return | |
} | |
// Recursively copies a directory tree, attempting to preserve permissions. | |
// Source directory must exist, destination directory must *not* exist. | |
func CopyDir(source string, dest string) (err error) { | |
// get properties of source dir | |
fi, err := os.Stat(source) | |
if err != nil { | |
return err | |
} | |
if !fi.IsDir() { | |
return &CustomError{"Source is not a directory"} | |
} | |
// ensure dest dir does not already exist | |
_, err = os.Open(dest) | |
if !os.IsNotExist(err) { | |
return &CustomError{"Destination already exists"} | |
} | |
// create dest dir | |
err = os.MkdirAll(dest, fi.Mode()) | |
if err != nil { | |
return err | |
} | |
entries, err := ioutil.ReadDir(source) | |
for _, entry := range entries { | |
sfp := source + "/" + entry.Name() | |
dfp := dest + "/" + entry.Name() | |
if entry.IsDir() { | |
err = CopyDir(sfp, dfp) | |
if err != nil { | |
log.Println(err) | |
} | |
} else { | |
// perform copy | |
err = CopyFile(sfp, dfp) | |
if err != nil { | |
log.Println(err) | |
} | |
} | |
} | |
return | |
} | |
// A struct for returning custom error messages | |
type CustomError struct { | |
What string | |
} | |
// Returns the error message defined in What as a string | |
func (e *CustomError) Error() string { | |
return e.What | |
} | |
func main() { | |
err = CopyDir("/home/jaybill/data", "/home/jaybill/backup") | |
if err != nil { | |
log.Fatal(err) | |
} else { | |
log.Print("Files copied.") | |
} | |
} |
Here is a clean implementation: https://gist.github.com/m4ng0squ4sh/92462b38df26839a3ca324697c8cba04
This seems useful, but the link to the @r0l1 clean implementation seems to be broken unfortunately, and I think it should be here: https://gist.github.com/r0l1/92462b38df26839a3ca324697c8cba04
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
And don't use log.Println! Return the error instead!