github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/pkg/sentry/fs/gofer/handles.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 gofer
    16  
    17  import (
    18  	"io"
    19  
    20  	"github.com/SagerNet/gvisor/pkg/context"
    21  	"github.com/SagerNet/gvisor/pkg/fd"
    22  	"github.com/SagerNet/gvisor/pkg/log"
    23  	"github.com/SagerNet/gvisor/pkg/p9"
    24  	"github.com/SagerNet/gvisor/pkg/refs"
    25  	"github.com/SagerNet/gvisor/pkg/safemem"
    26  	"github.com/SagerNet/gvisor/pkg/secio"
    27  	"github.com/SagerNet/gvisor/pkg/sentry/fs"
    28  )
    29  
    30  // handles are the open handles of a gofer file. They are reference counted to
    31  // support open handle sharing between files for read only filesystems.
    32  //
    33  // If Host != nil then it will be used exclusively over File.
    34  type handles struct {
    35  	refs.AtomicRefCount
    36  
    37  	// File is a p9.File handle. Must not be nil.
    38  	File contextFile
    39  
    40  	// Host is an *fd.FD handle. May be nil.
    41  	Host *fd.FD
    42  
    43  	// isHostBorrowed tells whether 'Host' is owned or borrowed. If owned, it's
    44  	// closed on destruction, otherwise it's released.
    45  	isHostBorrowed bool
    46  }
    47  
    48  // DecRef drops a reference on handles.
    49  func (h *handles) DecRef() {
    50  	ctx := context.Background()
    51  	h.DecRefWithDestructor(ctx, func(context.Context) {
    52  		if h.Host != nil {
    53  			if h.isHostBorrowed {
    54  				h.Host.Release()
    55  			} else {
    56  				if err := h.Host.Close(); err != nil {
    57  					log.Warningf("error closing host file: %v", err)
    58  				}
    59  			}
    60  		}
    61  		if err := h.File.close(ctx); err != nil {
    62  			log.Warningf("error closing p9 file: %v", err)
    63  		}
    64  	})
    65  }
    66  
    67  func newHandles(ctx context.Context, client *p9.Client, file contextFile, flags fs.FileFlags) (*handles, error) {
    68  	_, newFile, err := file.walk(ctx, nil)
    69  	if err != nil {
    70  		return nil, err
    71  	}
    72  
    73  	var p9flags p9.OpenFlags
    74  	switch {
    75  	case flags.Read && flags.Write:
    76  		p9flags = p9.ReadWrite
    77  	case flags.Read && !flags.Write:
    78  		p9flags = p9.ReadOnly
    79  	case !flags.Read && flags.Write:
    80  		p9flags = p9.WriteOnly
    81  	default:
    82  		panic("impossible fs.FileFlags")
    83  	}
    84  	if flags.Truncate && p9.VersionSupportsOpenTruncateFlag(client.Version()) {
    85  		p9flags |= p9.OpenTruncate
    86  	}
    87  
    88  	hostFile, _, _, err := newFile.open(ctx, p9flags)
    89  	if err != nil {
    90  		newFile.close(ctx)
    91  		return nil, err
    92  	}
    93  	h := handles{
    94  		File: newFile,
    95  		Host: hostFile,
    96  	}
    97  	h.EnableLeakCheck("gofer.handles")
    98  	return &h, nil
    99  }
   100  
   101  type handleReadWriter struct {
   102  	ctx context.Context
   103  	h   *handles
   104  	off int64
   105  }
   106  
   107  func (h *handles) readWriterAt(ctx context.Context, offset int64) *handleReadWriter {
   108  	return &handleReadWriter{ctx, h, offset}
   109  }
   110  
   111  // ReadToBlocks implements safemem.Reader.ReadToBlocks.
   112  func (rw *handleReadWriter) ReadToBlocks(dsts safemem.BlockSeq) (uint64, error) {
   113  	var r io.Reader
   114  	if rw.h.Host != nil {
   115  		r = secio.NewOffsetReader(rw.h.Host, rw.off)
   116  	} else {
   117  		r = &p9.ReadWriterFile{File: rw.h.File.file, Offset: uint64(rw.off)}
   118  	}
   119  
   120  	rw.ctx.UninterruptibleSleepStart(false)
   121  	defer rw.ctx.UninterruptibleSleepFinish(false)
   122  	n, err := safemem.FromIOReader{r}.ReadToBlocks(dsts)
   123  	rw.off += int64(n)
   124  	return n, err
   125  }
   126  
   127  // WriteFromBlocks implements safemem.Writer.WriteFromBlocks.
   128  func (rw *handleReadWriter) WriteFromBlocks(srcs safemem.BlockSeq) (uint64, error) {
   129  	var w io.Writer
   130  	if rw.h.Host != nil {
   131  		w = secio.NewOffsetWriter(rw.h.Host, rw.off)
   132  	} else {
   133  		w = &p9.ReadWriterFile{File: rw.h.File.file, Offset: uint64(rw.off)}
   134  	}
   135  
   136  	rw.ctx.UninterruptibleSleepStart(false)
   137  	defer rw.ctx.UninterruptibleSleepFinish(false)
   138  	n, err := safemem.FromIOWriter{w}.WriteFromBlocks(srcs)
   139  	rw.off += int64(n)
   140  	return n, err
   141  }