github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/pkg/sentry/fs/host/descriptor.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 host 16 17 import ( 18 "fmt" 19 20 "golang.org/x/sys/unix" 21 "github.com/SagerNet/gvisor/pkg/fdnotifier" 22 "github.com/SagerNet/gvisor/pkg/log" 23 "github.com/SagerNet/gvisor/pkg/waiter" 24 ) 25 26 // descriptor wraps a host fd. 27 // 28 // +stateify savable 29 type descriptor struct { 30 // If origFD >= 0, it is the host fd that this file was originally created 31 // from, which must be available at time of restore. The FD can be closed 32 // after descriptor is created. 33 origFD int 34 35 // wouldBlock is true if value (below) points to a file that can 36 // return EWOULDBLOCK for operations that would block. 37 wouldBlock bool 38 39 // value is the wrapped host fd. It is never saved or restored 40 // directly. 41 value int `state:"nosave"` 42 } 43 44 // newDescriptor returns a wrapped host file descriptor. On success, 45 // the descriptor is registered for event notifications with queue. 46 func newDescriptor(fd int, saveable bool, wouldBlock bool, queue *waiter.Queue) (*descriptor, error) { 47 ownedFD := fd 48 origFD := -1 49 if saveable { 50 var err error 51 ownedFD, err = unix.Dup(fd) 52 if err != nil { 53 return nil, err 54 } 55 origFD = fd 56 } 57 if wouldBlock { 58 if err := unix.SetNonblock(ownedFD, true); err != nil { 59 return nil, err 60 } 61 if err := fdnotifier.AddFD(int32(ownedFD), queue); err != nil { 62 return nil, err 63 } 64 } 65 return &descriptor{ 66 origFD: origFD, 67 wouldBlock: wouldBlock, 68 value: ownedFD, 69 }, nil 70 } 71 72 // initAfterLoad initializes the value of the descriptor after Load. 73 func (d *descriptor) initAfterLoad(id uint64, queue *waiter.Queue) error { 74 var err error 75 d.value, err = unix.Dup(d.origFD) 76 if err != nil { 77 return fmt.Errorf("failed to dup restored fd %d: %v", d.origFD, err) 78 } 79 if d.wouldBlock { 80 if err := unix.SetNonblock(d.value, true); err != nil { 81 return err 82 } 83 if err := fdnotifier.AddFD(int32(d.value), queue); err != nil { 84 return err 85 } 86 } 87 return nil 88 } 89 90 // Release releases all resources held by descriptor. 91 func (d *descriptor) Release() { 92 if d.wouldBlock { 93 fdnotifier.RemoveFD(int32(d.value)) 94 } 95 if err := unix.Close(d.value); err != nil { 96 log.Warningf("error closing fd %d: %v", d.value, err) 97 } 98 d.value = -1 99 }