From 8bad3ca45a28cb752c41ee7b7d4dfc5082e76eb0 Mon Sep 17 00:00:00 2001 From: "W. Trevor King" Date: Fri, 6 Apr 2018 10:34:29 -0700 Subject: [PATCH] fileutils: Use ModeType as the mask for mode checks POSIX provides S_IS*(m) macros to portably interpret the mode type, but does not define values for each type [1]. Alban pointed out that st_mode is not a bitfield on Linux [2]. For example, Linux defines [3]: S_IFBLK 060000 S_IFDIR 040000 S_IFCHR 020000 So 'm&S_IFCHR == S_IFCHR', for example, would succeed for both character and block devices. Go translates the system values to a platform-agnostic bitfield [4], so the previous approach works on Go. But it may be confusing for people used to the native non-bitfield mode, so this commit moves us to an approach that does not rely on Go's using a bitfield. I've also dropped the 07000 portion of the previous 07777 mask in favor of the cross-platform ModePerm mask. This avoids an internal magic number, and the sticky, suid, and sgid bits don't make sense for device nodes. And I'm using some contants from os instead of their syscall analogs. We can't drop the syscall dependency, because we're still using syscall to construct the Mknod arguments, but with this commit we're no longer using it to inspect the source file type. [1]: http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/sys_stat.h.html [2]: https://github.com/opencontainers/runtime-tools/pull/308#discussion_r179799657 [3]: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/include/uapi/linux/stat.h?h=v4.16#n9 [4]: https://github.com/golang/go/blob/b0d437f866eb8987cde7e6550cacd77876f36d4b/src/os/types.go#L45 --- fileutils.go | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/fileutils.go b/fileutils.go index 5a9818a..136bbd9 100644 --- a/fileutils.go +++ b/fileutils.go @@ -22,9 +22,10 @@ func CopyFile(source string, dest string) error { uid := int(st.Uid) gid := int(st.Gid) + modeType := si.Mode()&os.ModeType // Handle symlinks - if si.Mode()&os.ModeSymlink != 0 { + if modeType == os.ModeSymlink { target, err := os.Readlink(source) if err != nil { return err @@ -35,15 +36,14 @@ func CopyFile(source string, dest string) error { } // Handle device files - if st.Mode&syscall.S_IFMT == syscall.S_IFBLK || st.Mode&syscall.S_IFMT == syscall.S_IFCHR { + if modeType == os.ModeDevice { devMajor := int64(major(uint64(st.Rdev))) devMinor := int64(minor(uint64(st.Rdev))) - mode := uint32(si.Mode() & 07777) - if st.Mode&syscall.S_IFMT == syscall.S_IFBLK { - mode |= syscall.S_IFBLK - } - if st.Mode&syscall.S_IFMT == syscall.S_IFCHR { + mode := uint32(si.Mode() & os.ModePerm) + if si.Mode()&os.ModeCharDevice != 0 { mode |= syscall.S_IFCHR + } else { + mode |= syscall.S_IFBLK } if err := syscall.Mknod(dest, mode, int(mkdev(devMajor, devMinor))); err != nil { return err @@ -76,7 +76,7 @@ func CopyFile(source string, dest string) error { } // Chmod the file - if !(si.Mode()&os.ModeSymlink == os.ModeSymlink) { + if !(modeType == os.ModeSymlink) { if err := os.Chmod(dest, si.Mode()); err != nil { return err }