diff options
Diffstat (limited to 'filesystem/path.go')
| -rw-r--r-- | filesystem/path.go | 83 |
1 files changed, 60 insertions, 23 deletions
diff --git a/filesystem/path.go b/filesystem/path.go index d788a6b..8cfb235 100644 --- a/filesystem/path.go +++ b/filesystem/path.go @@ -20,18 +20,26 @@ package filesystem import ( + "fmt" "log" "os" "path/filepath" + "golang.org/x/sys/unix" + "github.com/pkg/errors" ) -// We only check the unix permissions and the sticky bit -const permMask = os.ModeSticky | os.ModePerm +// OpenFileOverridingUmask calls os.OpenFile but with the umask overridden so +// that no permission bits are masked out if the file is created. +func OpenFileOverridingUmask(name string, flag int, perm os.FileMode) (*os.File, error) { + oldMask := unix.Umask(0) + defer unix.Umask(oldMask) + return os.OpenFile(name, flag, perm) +} -// cannonicalizePath turns path into an absolute path without symlinks. -func cannonicalizePath(path string) (string, error) { +// canonicalizePath turns path into an absolute path without symlinks. +func canonicalizePath(path string) (string, error) { path, err := filepath.Abs(path) if err != nil { return "", err @@ -56,36 +64,65 @@ func loggedStat(name string) (os.FileInfo, error) { return info, err } +// loggedLstat runs os.Lstat (doesn't dereference trailing symlink), but it logs +// the error if lstat returns any error other than nil or IsNotExist. +func loggedLstat(name string) (os.FileInfo, error) { + info, err := os.Lstat(name) + if err != nil && !os.IsNotExist(err) { + log.Print(err) + } + return info, err +} + // isDir returns true if the path exists and is that of a directory. func isDir(path string) bool { info, err := loggedStat(path) return err == nil && info.IsDir() } -// isDevice returns true if the path exists and is that of a directory. -func isDevice(path string) bool { +// isRegularFile returns true if the path exists and is that of a regular file. +func isRegularFile(path string) bool { info, err := loggedStat(path) - return err == nil && info.Mode()&os.ModeDevice != 0 + return err == nil && info.Mode().IsRegular() } -// isDirCheckPerm returns true if the path exists and is a directory. If the -// specified permissions and sticky bit of mode do not match the path, and error -// is logged. -func isDirCheckPerm(path string, mode os.FileMode) bool { - info, err := loggedStat(path) - // Check if directory - if err != nil || !info.IsDir() { - return false +// HaveReadAccessTo returns true if the process has read access to a file or +// directory, without actually opening it. +func HaveReadAccessTo(path string) bool { + return unix.Access(path, unix.R_OK) == nil +} + +// DeviceNumber represents a combined major:minor device number. +type DeviceNumber uint64 + +func (num DeviceNumber) String() string { + return fmt.Sprintf("%d:%d", unix.Major(uint64(num)), unix.Minor(uint64(num))) +} + +func newDeviceNumberFromString(str string) (DeviceNumber, error) { + var major, minor uint32 + if count, _ := fmt.Sscanf(str, "%d:%d", &major, &minor); count != 2 { + return 0, errors.Errorf("invalid device number string %q", str) } - // Check for bad permissions - if info.Mode()&permMask != mode&permMask { - log.Printf("directory %s has incorrect permissions", path) + return DeviceNumber(unix.Mkdev(major, minor)), nil +} + +// getDeviceNumber returns the device number of the device node at the given +// path. If there is a symlink at the path, it is dereferenced. +func getDeviceNumber(path string) (DeviceNumber, error) { + var stat unix.Stat_t + if err := unix.Stat(path, &stat); err != nil { + return 0, err } - return true + return DeviceNumber(stat.Rdev), nil } -// isRegularFile returns true if the path exists and is that of a regular file. -func isRegularFile(path string) bool { - info, err := loggedStat(path) - return err == nil && info.Mode().IsRegular() +// getNumberOfContainingDevice returns the device number of the filesystem which +// contains the given file. If the file is a symlink, it is not dereferenced. +func getNumberOfContainingDevice(path string) (DeviceNumber, error) { + var stat unix.Stat_t + if err := unix.Lstat(path, &stat); err != nil { + return 0, err + } + return DeviceNumber(stat.Dev), nil } |