Source file src/os/zero_copy_solaris.go

     1  // Copyright 2024 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package os
     6  
     7  import (
     8  	"internal/poll"
     9  	"io"
    10  	"runtime"
    11  	"syscall"
    12  )
    13  
    14  func (f *File) writeTo(w io.Writer) (written int64, handled bool, err error) {
    15  	return 0, false, nil
    16  }
    17  
    18  // readFrom is basically a refactor of net.sendFile, but adapted to work for the target of *File.
    19  func (f *File) readFrom(r io.Reader) (written int64, handled bool, err error) {
    20  	var remain int64 = 0 // 0 indicates sending until EOF
    21  	lr, ok := r.(*io.LimitedReader)
    22  	if ok {
    23  		remain, r = lr.N, lr.R
    24  		if remain <= 0 {
    25  			return 0, true, nil
    26  		}
    27  	}
    28  
    29  	var src *File
    30  	switch v := r.(type) {
    31  	case *File:
    32  		src = v
    33  	case fileWithoutWriteTo:
    34  		src = v.File
    35  	default:
    36  		return 0, false, nil
    37  	}
    38  
    39  	if src.checkValid("ReadFrom") != nil {
    40  		// Avoid returning the error as we report handled as false,
    41  		// leave further error handling as the responsibility of the caller.
    42  		return 0, false, nil
    43  	}
    44  
    45  	// If fd_in and fd_out refer to the same file and the source and target ranges overlap,
    46  	// sendfile(2) on SunOS will allow this kind of overlapping and work like a memmove,
    47  	// in this case the file content remains the same after copying, which is not what we want.
    48  	// Thus, we just bail out here and leave it to generic copy when it's a file copying itself.
    49  	if f.pfd.Sysfd == src.pfd.Sysfd {
    50  		return 0, false, nil
    51  	}
    52  
    53  	// sendfile() on illumos seems to incur intermittent failures when the
    54  	// target file is a standard stream (stdout/stderr), we hereby skip any
    55  	// anything other than regular files conservatively and leave them to generic copy.
    56  	// Check out https://go.dev/issue/68863 for more details.
    57  	if runtime.GOOS == "illumos" {
    58  		fi, err := f.Stat()
    59  		if err != nil {
    60  			return 0, false, nil
    61  		}
    62  		st, ok := fi.Sys().(*syscall.Stat_t)
    63  		if !ok {
    64  			return 0, false, nil
    65  		}
    66  		if typ := st.Mode & syscall.S_IFMT; typ != syscall.S_IFREG {
    67  			return 0, false, nil
    68  		}
    69  	}
    70  
    71  	sc, err := src.SyscallConn()
    72  	if err != nil {
    73  		return
    74  	}
    75  
    76  	// System call sendfile()s on Solaris and illumos support file-to-file copying.
    77  	// Check out https://docs.oracle.com/cd/E86824_01/html/E54768/sendfile-3ext.html and
    78  	// https://docs.oracle.com/cd/E88353_01/html/E37843/sendfile-3c.html and
    79  	// https://illumos.org/man/3EXT/sendfile for more details.
    80  	rerr := sc.Read(func(fd uintptr) bool {
    81  		written, err, handled = poll.SendFile(&f.pfd, int(fd), remain)
    82  		return true
    83  	})
    84  	if lr != nil {
    85  		lr.N = remain - written
    86  	}
    87  	if err == nil {
    88  		err = rerr
    89  	}
    90  
    91  	return written, handled, wrapSyscallError("sendfile", err)
    92  }
    93  

View as plain text