file.go
func FileCopyDir(source string, dest string) (err error) {
	// get properties of source dir
	fileInfo, err := os.Stat(source)
	if err != nil {
		return err
	}
	if !fileInfo.IsDir() {
		return &FileCopyError{"Source is not a directory"}
	}
	// ensure dest dir does not already exist
	_, err = os.Open(dest)
	if !os.IsNotExist(err) {
		return &FileCopyError{"Destination already exists"}
	}
	// create dest dir
	err = os.MkdirAll(dest, fileInfo.Mode())
	if err != nil {
		return err
	}
	entries, err := ioutil.ReadDir(source)
	for _, entry := range entries {
		sourcePath := filepath.Join(source, entry.Name())
		destinationPath := filepath.Join(dest, entry.Name())
		if entry.IsDir() {
			err = FileCopyDir(sourcePath, destinationPath)
		} else {
			// perform copy
			err = FileCopy(sourcePath, destinationPath)
		}
		if err != nil {
			return err
		}
	}
	return err
}
func FileCopyDir(source string, dest string) (err error) {
	// get properties of source dir
	fileInfo, err := os.Stat(source)
	if err != nil {
		return err
	}
	if !fileInfo.IsDir() {
		return &FileCopyError{"Source is not a directory"}
	}
	// ensure dest dir does not already exist
	_, err = os.Open(dest)
	if !os.IsNotExist(err) {
		return &FileCopyError{"Destination already exists"}
	}
	// create dest dir
	err = os.MkdirAll(dest, fileInfo.Mode())
	if err != nil {
		return err
	}
	entries, err := ioutil.ReadDir(source)
	for _, entry := range entries {
		sourcePath := filepath.Join(source, entry.Name())
		destinationPath := filepath.Join(dest, entry.Name())
		if entry.IsDir() {
			err = FileCopyDir(sourcePath, destinationPath)
		} else {
			// perform copy
			err = FileCopy(sourcePath, destinationPath)
		}
		if err != nil {
			return err
		}
	}
	return err
}
// FileCopyDir recursively copies a directory tree, attempting to preserve permissions.
// Source directory must exist, destination directory must *not* exist.
// Based on Jaybill McCarthy's code which can be found at http://jayblog.jaybill.com/post/id/26