github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/pkg/fd/fd.go (about)

     1  // Copyright 2018 The gVisor Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  // Package fd provides types for working with file descriptors.
    16  package fd
    17  
    18  import (
    19  	"fmt"
    20  	"io"
    21  	"os"
    22  	"runtime"
    23  	"sync/atomic"
    24  
    25  	"golang.org/x/sys/unix"
    26  )
    27  
    28  // ReadWriter implements io.ReadWriter, io.ReaderAt, and io.WriterAt for fd. It
    29  // does not take ownership of fd.
    30  type ReadWriter struct {
    31  	// fd is accessed atomically so FD.Close/Release can swap it.
    32  	fd int64
    33  }
    34  
    35  var _ io.ReadWriter = (*ReadWriter)(nil)
    36  var _ io.ReaderAt = (*ReadWriter)(nil)
    37  var _ io.WriterAt = (*ReadWriter)(nil)
    38  
    39  // NewReadWriter creates a ReadWriter for fd.
    40  func NewReadWriter(fd int) *ReadWriter {
    41  	return &ReadWriter{int64(fd)}
    42  }
    43  
    44  func fixCount(n int, err error) (int, error) {
    45  	if n < 0 {
    46  		n = 0
    47  	}
    48  	return n, err
    49  }
    50  
    51  // Read implements io.Reader.
    52  func (r *ReadWriter) Read(b []byte) (int, error) {
    53  	c, err := fixCount(unix.Read(r.FD(), b))
    54  	if c == 0 && len(b) > 0 && err == nil {
    55  		return 0, io.EOF
    56  	}
    57  	return c, err
    58  }
    59  
    60  // ReadAt implements io.ReaderAt.
    61  //
    62  // ReadAt always returns a non-nil error when c < len(b).
    63  func (r *ReadWriter) ReadAt(b []byte, off int64) (c int, err error) {
    64  	for len(b) > 0 {
    65  		var m int
    66  		m, err = fixCount(unix.Pread(r.FD(), b, off))
    67  		if m == 0 && err == nil {
    68  			return c, io.EOF
    69  		}
    70  		if err != nil {
    71  			return c, err
    72  		}
    73  		c += m
    74  		b = b[m:]
    75  		off += int64(m)
    76  	}
    77  	return
    78  }
    79  
    80  // Write implements io.Writer.
    81  func (r *ReadWriter) Write(b []byte) (int, error) {
    82  	var err error
    83  	var n, remaining int
    84  	for remaining = len(b); remaining > 0; {
    85  		woff := len(b) - remaining
    86  		n, err = unix.Write(r.FD(), b[woff:])
    87  
    88  		if n > 0 {
    89  			// unix.Write wrote some bytes. This is the common case.
    90  			remaining -= n
    91  		} else {
    92  			if err == nil {
    93  				// unix.Write did not write anything nor did it return an error.
    94  				//
    95  				// There is no way to guarantee that a subsequent unix.Write will
    96  				// make forward progress so just panic.
    97  				panic(fmt.Sprintf("unix.Write returned %d with no error", n))
    98  			}
    99  
   100  			if err != unix.EINTR {
   101  				// If the write failed for anything other than a signal, bail out.
   102  				break
   103  			}
   104  		}
   105  	}
   106  
   107  	return len(b) - remaining, err
   108  }
   109  
   110  // WriteAt implements io.WriterAt.
   111  func (r *ReadWriter) WriteAt(b []byte, off int64) (c int, err error) {
   112  	for len(b) > 0 {
   113  		var m int
   114  		m, err = fixCount(unix.Pwrite(r.FD(), b, off))
   115  		if err != nil {
   116  			break
   117  		}
   118  		c += m
   119  		b = b[m:]
   120  		off += int64(m)
   121  	}
   122  	return
   123  }
   124  
   125  // FD returns the owned file descriptor. Ownership remains unchanged.
   126  func (r *ReadWriter) FD() int {
   127  	return int(atomic.LoadInt64(&r.fd))
   128  }
   129  
   130  // String implements Stringer.String().
   131  func (r *ReadWriter) String() string {
   132  	return fmt.Sprintf("FD: %d", r.FD())
   133  }
   134  
   135  // FD owns a host file descriptor.
   136  //
   137  // It is similar to os.File, with a few important distinctions:
   138  //
   139  // FD provies a Release() method which relinquishes ownership. Like os.File,
   140  // FD adds a finalizer to close the backing FD. However, the finalizer cannot
   141  // be removed from os.File, forever pinning the lifetime of an FD to its
   142  // os.File.
   143  //
   144  // FD supports both blocking and non-blocking operation. os.File only
   145  // supports blocking operation.
   146  type FD struct {
   147  	ReadWriter
   148  }
   149  
   150  // New creates a new FD.
   151  //
   152  // New takes ownership of fd.
   153  func New(fd int) *FD {
   154  	if fd < 0 {
   155  		return &FD{ReadWriter{-1}}
   156  	}
   157  	f := &FD{ReadWriter{int64(fd)}}
   158  	runtime.SetFinalizer(f, (*FD).Close)
   159  	return f
   160  }
   161  
   162  // NewFromFile creates a new FD from an os.File.
   163  //
   164  // NewFromFile does not transfer ownership of the file descriptor (it will be
   165  // duplicated, so both the os.File and FD will eventually need to be closed
   166  // and some (but not all) changes made to the FD will be applied to the
   167  // os.File as well).
   168  //
   169  // The returned FD is always blocking (Go 1.9+).
   170  func NewFromFile(file *os.File) (*FD, error) {
   171  	fd, err := unix.Dup(int(file.Fd()))
   172  	// Technically, the runtime may call the finalizer on file as soon as
   173  	// Fd() returns.
   174  	runtime.KeepAlive(file)
   175  	if err != nil {
   176  		return &FD{ReadWriter{-1}}, err
   177  	}
   178  	return New(fd), nil
   179  }
   180  
   181  // NewFromFiles creates new FDs for each file in the slice.
   182  func NewFromFiles(files []*os.File) ([]*FD, error) {
   183  	rv := make([]*FD, 0, len(files))
   184  	for _, f := range files {
   185  		new, err := NewFromFile(f)
   186  		if err != nil {
   187  			// Cleanup on error.
   188  			for _, fd := range rv {
   189  				fd.Close()
   190  			}
   191  			return nil, err
   192  		}
   193  		rv = append(rv, new)
   194  	}
   195  	return rv, nil
   196  }
   197  
   198  // Open is equivalent to open(2).
   199  func Open(path string, openmode int, perm uint32) (*FD, error) {
   200  	f, err := unix.Open(path, openmode|unix.O_LARGEFILE, perm)
   201  	if err != nil {
   202  		return nil, err
   203  	}
   204  	return New(f), nil
   205  }
   206  
   207  // OpenAt is equivalent to openat(2).
   208  func OpenAt(dir *FD, path string, flags int, mode uint32) (*FD, error) {
   209  	f, err := unix.Openat(dir.FD(), path, flags, mode)
   210  	if err != nil {
   211  		return nil, err
   212  	}
   213  	return New(f), nil
   214  }
   215  
   216  // Close closes the file descriptor contained in the FD.
   217  //
   218  // Close is safe to call multiple times, but will return an error after the
   219  // first call.
   220  //
   221  // Concurrently calling Close and any other method is undefined.
   222  func (f *FD) Close() error {
   223  	runtime.SetFinalizer(f, nil)
   224  	return unix.Close(int(atomic.SwapInt64(&f.fd, -1)))
   225  }
   226  
   227  // Release relinquishes ownership of the contained file descriptor.
   228  //
   229  // Concurrently calling Release and any other method is undefined.
   230  func (f *FD) Release() int {
   231  	runtime.SetFinalizer(f, nil)
   232  	return int(atomic.SwapInt64(&f.fd, -1))
   233  }
   234  
   235  // File converts the FD to an os.File.
   236  //
   237  // FD does not transfer ownership of the file descriptor (it will be
   238  // duplicated, so both the FD and os.File will eventually need to be closed
   239  // and some (but not all) changes made to the os.File will be applied to the
   240  // FD as well).
   241  //
   242  // This operation is somewhat expensive, so care should be taken to minimize
   243  // its use.
   244  func (f *FD) File() (*os.File, error) {
   245  	fd, err := unix.Dup(f.FD())
   246  	if err != nil {
   247  		return nil, err
   248  	}
   249  	return os.NewFile(uintptr(fd), ""), nil
   250  }
   251  
   252  // ReleaseToFile returns an os.File that takes ownership of the FD.
   253  //
   254  // name is passed to os.NewFile.
   255  func (f *FD) ReleaseToFile(name string) *os.File {
   256  	return os.NewFile(uintptr(f.Release()), name)
   257  }