blob: 94a8de6062cfdcb37e2784800a35a8d30908e871 [file] [log] [blame]
// Copyright 2024 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package os
import (
"internal/poll"
"io"
"runtime"
"syscall"
)
func (f *File) writeTo(w io.Writer) (written int64, handled bool, err error) {
return 0, false, nil
}
// readFrom is basically a refactor of net.sendFile, but adapted to work for the target of *File.
func (f *File) readFrom(r io.Reader) (written int64, handled bool, err error) {
var remain int64 = 0 // 0 indicates sending until EOF
lr, ok := r.(*io.LimitedReader)
if ok {
remain, r = lr.N, lr.R
if remain <= 0 {
return 0, true, nil
}
}
var src *File
switch v := r.(type) {
case *File:
src = v
case fileWithoutWriteTo:
src = v.File
default:
return 0, false, nil
}
if src.checkValid("ReadFrom") != nil {
// Avoid returning the error as we report handled as false,
// leave further error handling as the responsibility of the caller.
return 0, false, nil
}
// If fd_in and fd_out refer to the same file and the source and target ranges overlap,
// sendfile(2) on SunOS will allow this kind of overlapping and work like a memmove,
// in this case the file content remains the same after copying, which is not what we want.
// Thus, we just bail out here and leave it to generic copy when it's a file copying itself.
if f.pfd.Sysfd == src.pfd.Sysfd {
return 0, false, nil
}
// sendfile() on illumos seems to incur intermittent failures when the
// target file is a standard stream (stdout/stderr), we hereby skip any
// anything other than regular files conservatively and leave them to generic copy.
// Check out https://go.dev/issue/68863 for more details.
if runtime.GOOS == "illumos" {
fi, err := f.Stat()
if err != nil {
return 0, false, nil
}
st, ok := fi.Sys().(*syscall.Stat_t)
if !ok {
return 0, false, nil
}
if typ := st.Mode & syscall.S_IFMT; typ != syscall.S_IFREG {
return 0, false, nil
}
}
sc, err := src.SyscallConn()
if err != nil {
return
}
// System call sendfile()s on Solaris and illumos support file-to-file copying.
// Check out https://docs.oracle.com/cd/E86824_01/html/E54768/sendfile-3ext.html and
// https://docs.oracle.com/cd/E88353_01/html/E37843/sendfile-3c.html and
// https://illumos.org/man/3EXT/sendfile for more details.
rerr := sc.Read(func(fd uintptr) bool {
written, err, handled = poll.SendFile(&f.pfd, int(fd), remain)
return true
})
if lr != nil {
lr.N = remain - written
}
if err == nil {
err = rerr
}
return written, handled, wrapSyscallError("sendfile", err)
}