mirror of
https://github.com/outbackdingo/debos.git
synced 2026-01-27 10:18:47 +00:00
Various filesystem operations here and there are done without checking the return value, so when it fails nobody knows and the user waste his time understanding what's going on. Checking return values is useful. Signed-off-by: Arnaud Rebillout <arnaud.rebillout@collabora.com>
115 lines
2.2 KiB
Go
115 lines
2.2 KiB
Go
package debos
|
|
|
|
import (
|
|
"fmt"
|
|
"io"
|
|
"io/ioutil"
|
|
"log"
|
|
"os"
|
|
"path"
|
|
"path/filepath"
|
|
"strings"
|
|
)
|
|
|
|
func CleanPathAt(path, at string) string {
|
|
if filepath.IsAbs(path) {
|
|
return filepath.Clean(path)
|
|
}
|
|
|
|
return filepath.Join(at, path)
|
|
}
|
|
|
|
func CleanPath(path string) string {
|
|
cwd, _ := os.Getwd()
|
|
return CleanPathAt(path, cwd)
|
|
}
|
|
|
|
func CopyFile(src, dst string, mode os.FileMode) error {
|
|
in, err := os.Open(src)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer in.Close()
|
|
tmp, err := ioutil.TempFile(filepath.Dir(dst), "")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
_, err = io.Copy(tmp, in)
|
|
if err != nil {
|
|
tmp.Close()
|
|
os.Remove(tmp.Name())
|
|
return err
|
|
}
|
|
if err = tmp.Close(); err != nil {
|
|
os.Remove(tmp.Name())
|
|
return err
|
|
}
|
|
if err = os.Chmod(tmp.Name(), mode); err != nil {
|
|
os.Remove(tmp.Name())
|
|
return err
|
|
}
|
|
|
|
if err = os.Rename(tmp.Name(), dst); err != nil {
|
|
os.Remove(tmp.Name())
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func CopyTree(sourcetree, desttree string) error {
|
|
fmt.Printf("Overlaying %s on %s\n", sourcetree, desttree)
|
|
walker := func(p string, info os.FileInfo, err error) error {
|
|
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
suffix, _ := filepath.Rel(sourcetree, p)
|
|
target := path.Join(desttree, suffix)
|
|
switch info.Mode() & os.ModeType {
|
|
case 0:
|
|
err := CopyFile(p, target, info.Mode())
|
|
if err != nil {
|
|
log.Panicf("Failed to copy file %s: %v", p, err)
|
|
}
|
|
case os.ModeDir:
|
|
os.Mkdir(target, info.Mode())
|
|
case os.ModeSymlink:
|
|
link, err := os.Readlink(p)
|
|
if err != nil {
|
|
log.Panicf("Failed to read symlink %s: %v", suffix, err)
|
|
}
|
|
os.Symlink(link, target)
|
|
default:
|
|
log.Panicf("Not handled /%s %v", suffix, info.Mode())
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
return filepath.Walk(sourcetree, walker)
|
|
}
|
|
|
|
func RealPath(path string) (string, error) {
|
|
p, err := filepath.EvalSymlinks(path)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
return filepath.Abs(p)
|
|
}
|
|
|
|
func RestrictedPath(prefix, dest string) (string, error) {
|
|
var err error
|
|
destination := path.Join(prefix, dest)
|
|
destination, err = filepath.Abs(destination)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
if !strings.HasPrefix(destination, prefix) {
|
|
return "", fmt.Errorf("The resulting path points outside of prefix '%s': '%s'\n", prefix, destination)
|
|
}
|
|
return destination, nil
|
|
}
|