package misc import ( "os" "errors" "strings" "syscall" "path" ) type Dir_t struct { fd int name string } var ( Err_illegal_filename = errors.New("illegal filename") Err_invalid_file_descriptor = errors.New("invalid file descriptor") ) // Open a file at exactly the given directory. func Open_file_at(dir Dir_t, filename string, flags int, perms os.FileMode) (*os.File, error) { if strings.IndexByte(filename, '/') != -1 { return nil, Err_illegal_filename } return Open_file_beneath(dir, filename, flags, perms) } // Open a file at or beneath the given directory. func Open_file_beneath(dir Dir_t, filename string, flags int, perms os.FileMode) (*os.File, error) { fd, err := Openat2(dir.fd, filename, &Open_how_t{ Flags: uint64(flags), Mode: uint64(syscallMode(perms)), Resolve: RESOLVE_BENEATH|RESOLVE_NO_SYMLINKS, }) if err != nil { return nil, err } file := os.NewFile(uintptr(fd), path.Join(dir.name, filename)) if file == nil { return nil, Err_invalid_file_descriptor } else { return file, nil } } // Open a directory as read-only and return a Dir_t to it. The caller is // responsible for closing the directory with [[Close_directory]]. func Open_directory_readonly(path string) (Dir_t, error) { _fd, err := syscall.Open(path, os.O_RDONLY|syscall.O_DIRECTORY, 0) return Dir_t{fd: _fd, name: path}, err } // Close a directory returned by [[Open_directory_readonly]]. func Close_directory(dir Dir_t) error { return syscall.Close(dir.fd) } // syscallMode returns the syscall-specific mode flags from Go's portable mode flags. func syscallMode(i os.FileMode) (o uint32) { // This part actually came from Go's os/file_posix.go but IMO it's too // small and should fall under fair use. o |= uint32(i.Perm()) if i&os.ModeSetuid != 0 { o |= syscall.S_ISUID } if i&os.ModeSetgid != 0 { o |= syscall.S_ISGID } if i&os.ModeSticky != 0 { o |= syscall.S_ISVTX } // No mapping for Go's ModeTemporary (plan9 only). return }