Search code examples
gofile-io

In Go, when is SyscallConn() useful on a regular *os.File?


I am reading some Go code (from https://github.com/KarpelesLab/reflink) which is using SyscallConn() (the func defined on *os.File):

// reflinkInternal performs the actual reflink action without worrying about fallback
func reflinkInternal(d, s *os.File) error {
    ss, err := s.SyscallConn()
    if err != nil {
        return err
    }
    sd, err := d.SyscallConn()
    if err != nil {
        return err
    }
    var err2, err3 error
    err = sd.Control(func(dfd uintptr) {
        err2 = ss.Control(func(sfd uintptr) {
            // int ioctl(int dest_fd, FICLONE, int src_fd);
            err3 = unix.IoctlFileClone(int(dfd), int(sfd))
        })
    })
    if err != nil {
        // sd.Control failed
        return err
    }
    if err2 != nil {
        // ss.Control failed
        return err2
    }
    if err3 != nil && errors.Is(err3, unix.ENOTSUP) {
        return ErrReflinkFailed
    }
    // err3 is ioctl() response
    return err3
}

In this example, are there any advantages to using these Control() funcs instead of just working with d.Fd() and s.Fd() directly? More generally, what is the func func (*os.File) SyscallConn() (syscall.RawConn, error) useful for?


Solution

  • file.Fd() returns a file descriptor AND it makes the file descriptor operate in a blocking mode (tying up a thread for blocking operations). SyscallConn does not do so. It was made in fact explicitly for just getting the file descriptor without making it blocking. See this issue for more information.