github.com/ttpreport/gvisor-ligolo@v0.0.0-20240123134145-a858404967ba/pkg/lisafs/client_file.go (about)

     1  // Copyright 2021 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 lisafs
    16  
    17  import (
    18  	"fmt"
    19  	"io"
    20  
    21  	"github.com/ttpreport/gvisor-ligolo/pkg/abi/linux"
    22  	"github.com/ttpreport/gvisor-ligolo/pkg/context"
    23  	"github.com/ttpreport/gvisor-ligolo/pkg/log"
    24  	"github.com/ttpreport/gvisor-ligolo/pkg/marshal/primitive"
    25  	"golang.org/x/sys/unix"
    26  )
    27  
    28  // ClientFD is a wrapper around FDID that provides client-side utilities
    29  // so that RPC making is easier.
    30  type ClientFD struct {
    31  	fd     FDID
    32  	client *Client
    33  }
    34  
    35  // ID returns the underlying FDID.
    36  func (f *ClientFD) ID() FDID {
    37  	return f.fd
    38  }
    39  
    40  // Client returns the backing Client.
    41  func (f *ClientFD) Client() *Client {
    42  	return f.client
    43  }
    44  
    45  // NewFD initializes a new ClientFD.
    46  func (c *Client) NewFD(fd FDID) ClientFD {
    47  	return ClientFD{
    48  		client: c,
    49  		fd:     fd,
    50  	}
    51  }
    52  
    53  // Ok returns true if the underlying FD is ok.
    54  func (f *ClientFD) Ok() bool {
    55  	return f.fd.Ok()
    56  }
    57  
    58  // Close queues this FD to be closed on the server and resets f.fd.
    59  // This maybe invoke the Close RPC if the queue is full. If flush is true, then
    60  // the Close RPC is made immediately. Consider setting flush to false if
    61  // closing this FD on remote right away is not critical.
    62  func (f *ClientFD) Close(ctx context.Context, flush bool) {
    63  	f.client.CloseFD(ctx, f.fd, flush)
    64  	f.fd = InvalidFDID
    65  }
    66  
    67  // OpenAt makes the OpenAt RPC.
    68  func (f *ClientFD) OpenAt(ctx context.Context, flags uint32) (FDID, int, error) {
    69  	req := OpenAtReq{
    70  		FD:    f.fd,
    71  		Flags: flags,
    72  	}
    73  	var respFD [1]int
    74  	var resp OpenAtResp
    75  	ctx.UninterruptibleSleepStart(false)
    76  	err := f.client.SndRcvMessage(OpenAt, uint32(req.SizeBytes()), req.MarshalUnsafe, resp.CheckedUnmarshal, respFD[:], req.String, resp.String)
    77  	ctx.UninterruptibleSleepFinish(false)
    78  	return resp.OpenFD, respFD[0], err
    79  }
    80  
    81  // OpenCreateAt makes the OpenCreateAt RPC.
    82  func (f *ClientFD) OpenCreateAt(ctx context.Context, name string, flags uint32, mode linux.FileMode, uid UID, gid GID) (Inode, FDID, int, error) {
    83  	var req OpenCreateAtReq
    84  	req.DirFD = f.fd
    85  	req.Name = SizedString(name)
    86  	req.Flags = primitive.Uint32(flags)
    87  	req.Mode = mode
    88  	req.UID = uid
    89  	req.GID = gid
    90  
    91  	var respFD [1]int
    92  	var resp OpenCreateAtResp
    93  	ctx.UninterruptibleSleepStart(false)
    94  	err := f.client.SndRcvMessage(OpenCreateAt, uint32(req.SizeBytes()), req.MarshalBytes, resp.CheckedUnmarshal, respFD[:], req.String, resp.String)
    95  	ctx.UninterruptibleSleepFinish(false)
    96  	return resp.Child, resp.NewFD, respFD[0], err
    97  }
    98  
    99  // StatTo makes the Fstat RPC and populates stat with the result.
   100  func (f *ClientFD) StatTo(ctx context.Context, stat *linux.Statx) error {
   101  	req := StatReq{FD: f.fd}
   102  	ctx.UninterruptibleSleepStart(false)
   103  	err := f.client.SndRcvMessage(FStat, uint32(req.SizeBytes()), req.MarshalUnsafe, stat.CheckedUnmarshal, nil, req.String, stat.String)
   104  	ctx.UninterruptibleSleepFinish(false)
   105  	return err
   106  }
   107  
   108  // Sync makes the Fsync RPC.
   109  func (f *ClientFD) Sync(ctx context.Context) error {
   110  	req := FsyncReq{FDs: []FDID{f.fd}}
   111  	var resp FsyncResp
   112  	ctx.UninterruptibleSleepStart(false)
   113  	err := f.client.SndRcvMessage(FSync, uint32(req.SizeBytes()), req.MarshalBytes, resp.CheckedUnmarshal, nil, req.String, resp.String)
   114  	ctx.UninterruptibleSleepFinish(false)
   115  	return err
   116  }
   117  
   118  // chunkify applies fn to buf in chunks based on chunkSize.
   119  func chunkify(chunkSize uint64, buf []byte, fn func([]byte, uint64) (uint64, error)) (uint64, error) {
   120  	toProcess := uint64(len(buf))
   121  	var (
   122  		totalProcessed uint64
   123  		curProcessed   uint64
   124  		off            uint64
   125  		err            error
   126  	)
   127  	for {
   128  		if totalProcessed == toProcess {
   129  			return totalProcessed, nil
   130  		}
   131  
   132  		if totalProcessed+chunkSize > toProcess {
   133  			curProcessed, err = fn(buf[totalProcessed:], off)
   134  		} else {
   135  			curProcessed, err = fn(buf[totalProcessed:totalProcessed+chunkSize], off)
   136  		}
   137  		totalProcessed += curProcessed
   138  		off += curProcessed
   139  
   140  		if err != nil {
   141  			return totalProcessed, err
   142  		}
   143  
   144  		// Return partial result immediately.
   145  		if curProcessed < chunkSize {
   146  			return totalProcessed, nil
   147  		}
   148  
   149  		// If we received more bytes than we ever requested, this is a problem.
   150  		if totalProcessed > toProcess {
   151  			panic(fmt.Sprintf("bytes completed (%d)) > requested (%d)", totalProcessed, toProcess))
   152  		}
   153  	}
   154  }
   155  
   156  // Read makes the PRead RPC.
   157  func (f *ClientFD) Read(ctx context.Context, dst []byte, offset uint64) (uint64, error) {
   158  	var resp PReadResp
   159  	// maxDataReadSize represents the maximum amount of data we can read at once
   160  	// (maximum message size - metadata size present in resp). Uninitialized
   161  	// resp.SizeBytes() correctly returns the metadata size only (since the read
   162  	// buffer is empty).
   163  	maxDataReadSize := uint64(f.client.maxMessageSize) - uint64(resp.SizeBytes())
   164  	return chunkify(maxDataReadSize, dst, func(buf []byte, curOff uint64) (uint64, error) {
   165  		req := PReadReq{
   166  			Offset: offset + curOff,
   167  			FD:     f.fd,
   168  			Count:  uint32(len(buf)),
   169  		}
   170  
   171  		// This will be unmarshalled into. Already set Buf so that we don't need to
   172  		// allocate a temporary buffer during unmarshalling.
   173  		// PReadResp.CheckedUnmarshal expects this to be set.
   174  		resp.Buf = buf
   175  		ctx.UninterruptibleSleepStart(false)
   176  		err := f.client.SndRcvMessage(PRead, uint32(req.SizeBytes()), req.MarshalUnsafe, resp.CheckedUnmarshal, nil, req.String, resp.String)
   177  		ctx.UninterruptibleSleepFinish(false)
   178  		if err != nil {
   179  			return 0, err
   180  		}
   181  
   182  		// io.EOF is not an error that a lisafs server can return. Use POSIX
   183  		// semantics to return io.EOF manually: zero bytes were returned and a
   184  		// non-zero buffer was used.
   185  		// NOTE(b/237442794): Some callers like splice really depend on a non-nil
   186  		// error being returned in such a case. This is consistent with P9.
   187  		if resp.NumBytes == 0 && len(buf) > 0 {
   188  			return 0, io.EOF
   189  		}
   190  		return uint64(resp.NumBytes), nil
   191  	})
   192  }
   193  
   194  // Write makes the PWrite RPC.
   195  func (f *ClientFD) Write(ctx context.Context, src []byte, offset uint64) (uint64, error) {
   196  	var req PWriteReq
   197  	// maxDataWriteSize represents the maximum amount of data we can write at
   198  	// once (maximum message size - metadata size present in req). Uninitialized
   199  	// req.SizeBytes() correctly returns the metadata size only (since the write
   200  	// buffer is empty).
   201  	maxDataWriteSize := uint64(f.client.maxMessageSize) - uint64(req.SizeBytes())
   202  	return chunkify(maxDataWriteSize, src, func(buf []byte, curOff uint64) (uint64, error) {
   203  		req = PWriteReq{
   204  			Offset:   primitive.Uint64(offset + curOff),
   205  			FD:       f.fd,
   206  			NumBytes: primitive.Uint32(len(buf)),
   207  			Buf:      buf,
   208  		}
   209  
   210  		var resp PWriteResp
   211  		ctx.UninterruptibleSleepStart(false)
   212  		err := f.client.SndRcvMessage(PWrite, uint32(req.SizeBytes()), req.MarshalBytes, resp.CheckedUnmarshal, nil, req.String, resp.String)
   213  		ctx.UninterruptibleSleepFinish(false)
   214  		return resp.Count, err
   215  	})
   216  }
   217  
   218  // MkdirAt makes the MkdirAt RPC.
   219  func (f *ClientFD) MkdirAt(ctx context.Context, name string, mode linux.FileMode, uid UID, gid GID) (Inode, error) {
   220  	var req MkdirAtReq
   221  	req.DirFD = f.fd
   222  	req.Name = SizedString(name)
   223  	req.Mode = mode
   224  	req.UID = uid
   225  	req.GID = gid
   226  
   227  	var resp MkdirAtResp
   228  	ctx.UninterruptibleSleepStart(false)
   229  	err := f.client.SndRcvMessage(MkdirAt, uint32(req.SizeBytes()), req.MarshalBytes, resp.CheckedUnmarshal, nil, req.String, resp.String)
   230  	ctx.UninterruptibleSleepFinish(false)
   231  	return resp.ChildDir, err
   232  }
   233  
   234  // SymlinkAt makes the SymlinkAt RPC.
   235  func (f *ClientFD) SymlinkAt(ctx context.Context, name, target string, uid UID, gid GID) (Inode, error) {
   236  	req := SymlinkAtReq{
   237  		DirFD:  f.fd,
   238  		Name:   SizedString(name),
   239  		Target: SizedString(target),
   240  		UID:    uid,
   241  		GID:    gid,
   242  	}
   243  
   244  	var resp SymlinkAtResp
   245  	ctx.UninterruptibleSleepStart(false)
   246  	err := f.client.SndRcvMessage(SymlinkAt, uint32(req.SizeBytes()), req.MarshalBytes, resp.CheckedUnmarshal, nil, req.String, resp.String)
   247  	ctx.UninterruptibleSleepFinish(false)
   248  	return resp.Symlink, err
   249  }
   250  
   251  // LinkAt makes the LinkAt RPC.
   252  func (f *ClientFD) LinkAt(ctx context.Context, targetFD FDID, name string) (Inode, error) {
   253  	req := LinkAtReq{
   254  		DirFD:  f.fd,
   255  		Target: targetFD,
   256  		Name:   SizedString(name),
   257  	}
   258  
   259  	var resp LinkAtResp
   260  	ctx.UninterruptibleSleepStart(false)
   261  	err := f.client.SndRcvMessage(LinkAt, uint32(req.SizeBytes()), req.MarshalBytes, resp.CheckedUnmarshal, nil, req.String, resp.String)
   262  	ctx.UninterruptibleSleepFinish(false)
   263  	return resp.Link, err
   264  }
   265  
   266  // MknodAt makes the MknodAt RPC.
   267  func (f *ClientFD) MknodAt(ctx context.Context, name string, mode linux.FileMode, uid UID, gid GID, minor, major uint32) (Inode, error) {
   268  	var req MknodAtReq
   269  	req.DirFD = f.fd
   270  	req.Name = SizedString(name)
   271  	req.Mode = mode
   272  	req.UID = uid
   273  	req.GID = gid
   274  	req.Minor = primitive.Uint32(minor)
   275  	req.Major = primitive.Uint32(major)
   276  
   277  	var resp MknodAtResp
   278  	ctx.UninterruptibleSleepStart(false)
   279  	err := f.client.SndRcvMessage(MknodAt, uint32(req.SizeBytes()), req.MarshalBytes, resp.CheckedUnmarshal, nil, req.String, resp.String)
   280  	ctx.UninterruptibleSleepFinish(false)
   281  	return resp.Child, err
   282  }
   283  
   284  // SetStat makes the SetStat RPC.
   285  func (f *ClientFD) SetStat(ctx context.Context, stat *linux.Statx) (uint32, error, error) {
   286  	req := SetStatReq{
   287  		FD:   f.fd,
   288  		Mask: stat.Mask,
   289  		Mode: uint32(stat.Mode),
   290  		UID:  UID(stat.UID),
   291  		GID:  GID(stat.GID),
   292  		Size: stat.Size,
   293  		Atime: linux.Timespec{
   294  			Sec:  stat.Atime.Sec,
   295  			Nsec: int64(stat.Atime.Nsec),
   296  		},
   297  		Mtime: linux.Timespec{
   298  			Sec:  stat.Mtime.Sec,
   299  			Nsec: int64(stat.Mtime.Nsec),
   300  		},
   301  	}
   302  
   303  	var resp SetStatResp
   304  	ctx.UninterruptibleSleepStart(false)
   305  	err := f.client.SndRcvMessage(SetStat, uint32(req.SizeBytes()), req.MarshalUnsafe, resp.CheckedUnmarshal, nil, req.String, resp.String)
   306  	ctx.UninterruptibleSleepFinish(false)
   307  	if err != nil {
   308  		return 0, nil, err
   309  	}
   310  	if resp.FailureMask == 0 {
   311  		return 0, nil, nil
   312  	}
   313  	return resp.FailureMask, unix.Errno(resp.FailureErrNo), nil
   314  }
   315  
   316  // WalkMultiple makes the Walk RPC with multiple path components.
   317  func (f *ClientFD) WalkMultiple(ctx context.Context, names []string) (WalkStatus, []Inode, error) {
   318  	req := WalkReq{
   319  		DirFD: f.fd,
   320  		Path:  StringArray(names),
   321  	}
   322  
   323  	var resp WalkResp
   324  	ctx.UninterruptibleSleepStart(false)
   325  	err := f.client.SndRcvMessage(Walk, uint32(req.SizeBytes()), req.MarshalBytes, resp.CheckedUnmarshal, nil, req.String, resp.String)
   326  	ctx.UninterruptibleSleepFinish(false)
   327  	return resp.Status, resp.Inodes, err
   328  }
   329  
   330  // Walk makes the Walk RPC with just one path component to walk.
   331  func (f *ClientFD) Walk(ctx context.Context, name string) (Inode, error) {
   332  	req := WalkReq{
   333  		DirFD: f.fd,
   334  		Path:  []string{name},
   335  	}
   336  
   337  	var inode [1]Inode
   338  	resp := WalkResp{Inodes: inode[:]}
   339  	ctx.UninterruptibleSleepStart(false)
   340  	err := f.client.SndRcvMessage(Walk, uint32(req.SizeBytes()), req.MarshalBytes, resp.CheckedUnmarshal, nil, req.String, resp.String)
   341  	ctx.UninterruptibleSleepFinish(false)
   342  	if err != nil {
   343  		return Inode{}, err
   344  	}
   345  
   346  	switch resp.Status {
   347  	case WalkComponentDoesNotExist:
   348  		return Inode{}, unix.ENOENT
   349  	case WalkComponentSymlink:
   350  		// f is not a directory which can be walked on.
   351  		return Inode{}, unix.ENOTDIR
   352  	}
   353  
   354  	if n := len(resp.Inodes); n > 1 {
   355  		for i := range resp.Inodes {
   356  			f.client.CloseFD(ctx, resp.Inodes[i].ControlFD, false /* flush */)
   357  		}
   358  		log.Warningf("requested to walk one component, but got %d results", n)
   359  		return Inode{}, unix.EIO
   360  	} else if n == 0 {
   361  		log.Warningf("walk has success status but no results returned")
   362  		return Inode{}, unix.ENOENT
   363  	}
   364  	return inode[0], err
   365  }
   366  
   367  // WalkStat makes the WalkStat RPC with multiple path components to walk.
   368  func (f *ClientFD) WalkStat(ctx context.Context, names []string) ([]linux.Statx, error) {
   369  	req := WalkReq{
   370  		DirFD: f.fd,
   371  		Path:  StringArray(names),
   372  	}
   373  
   374  	var resp WalkStatResp
   375  	ctx.UninterruptibleSleepStart(false)
   376  	err := f.client.SndRcvMessage(WalkStat, uint32(req.SizeBytes()), req.MarshalBytes, resp.CheckedUnmarshal, nil, req.String, resp.String)
   377  	ctx.UninterruptibleSleepFinish(false)
   378  	return resp.Stats, err
   379  }
   380  
   381  // StatFSTo makes the FStatFS RPC and populates statFS with the result.
   382  func (f *ClientFD) StatFSTo(ctx context.Context, statFS *StatFS) error {
   383  	req := FStatFSReq{FD: f.fd}
   384  	ctx.UninterruptibleSleepStart(false)
   385  	err := f.client.SndRcvMessage(FStatFS, uint32(req.SizeBytes()), req.MarshalUnsafe, statFS.CheckedUnmarshal, nil, req.String, statFS.String)
   386  	ctx.UninterruptibleSleepFinish(false)
   387  	return err
   388  }
   389  
   390  // Allocate makes the FAllocate RPC.
   391  func (f *ClientFD) Allocate(ctx context.Context, mode, offset, length uint64) error {
   392  	req := FAllocateReq{
   393  		FD:     f.fd,
   394  		Mode:   mode,
   395  		Offset: offset,
   396  		Length: length,
   397  	}
   398  	var resp FAllocateResp
   399  	ctx.UninterruptibleSleepStart(false)
   400  	err := f.client.SndRcvMessage(FAllocate, uint32(req.SizeBytes()), req.MarshalUnsafe, resp.CheckedUnmarshal, nil, req.String, resp.String)
   401  	ctx.UninterruptibleSleepFinish(false)
   402  	return err
   403  }
   404  
   405  // ReadLinkAt makes the ReadLinkAt RPC.
   406  func (f *ClientFD) ReadLinkAt(ctx context.Context) (string, error) {
   407  	req := ReadLinkAtReq{FD: f.fd}
   408  	var resp ReadLinkAtResp
   409  	ctx.UninterruptibleSleepStart(false)
   410  	err := f.client.SndRcvMessage(ReadLinkAt, uint32(req.SizeBytes()), req.MarshalUnsafe, resp.CheckedUnmarshal, nil, req.String, resp.String)
   411  	ctx.UninterruptibleSleepFinish(false)
   412  	return string(resp.Target), err
   413  }
   414  
   415  // Flush makes the Flush RPC.
   416  func (f *ClientFD) Flush(ctx context.Context) error {
   417  	if !f.client.IsSupported(Flush) {
   418  		// If Flush is not supported, it probably means that it would be a noop.
   419  		return nil
   420  	}
   421  	req := FlushReq{FD: f.fd}
   422  	var resp FlushResp
   423  	ctx.UninterruptibleSleepStart(false)
   424  	err := f.client.SndRcvMessage(Flush, uint32(req.SizeBytes()), req.MarshalUnsafe, resp.CheckedUnmarshal, nil, req.String, resp.String)
   425  	ctx.UninterruptibleSleepFinish(false)
   426  	return err
   427  }
   428  
   429  // BindAt makes the BindAt RPC.
   430  func (f *ClientFD) BindAt(ctx context.Context, sockType linux.SockType, name string, mode linux.FileMode, uid UID, gid GID) (Inode, *ClientBoundSocketFD, error) {
   431  	var (
   432  		req          BindAtReq
   433  		resp         BindAtResp
   434  		hostSocketFD [1]int
   435  	)
   436  	req.DirFD = f.fd
   437  	req.SockType = primitive.Uint32(sockType)
   438  	req.Name = SizedString(name)
   439  	req.Mode = mode
   440  	req.UID = uid
   441  	req.GID = gid
   442  	ctx.UninterruptibleSleepStart(false)
   443  	err := f.client.SndRcvMessage(BindAt, uint32(req.SizeBytes()), req.MarshalBytes, resp.CheckedUnmarshal, hostSocketFD[:], req.String, resp.String)
   444  	ctx.UninterruptibleSleepFinish(false)
   445  	if err == nil && hostSocketFD[0] < 0 {
   446  		// No host socket fd? We can't proceed.
   447  		// Clean up any resources the gofer sent to us.
   448  		if resp.Child.ControlFD.Ok() {
   449  			f.client.CloseFD(ctx, resp.Child.ControlFD, false /* flush */)
   450  		}
   451  		if resp.BoundSocketFD.Ok() {
   452  			f.client.CloseFD(ctx, resp.BoundSocketFD, false /* flush */)
   453  		}
   454  		err = unix.EBADF
   455  	}
   456  	if err != nil {
   457  		return Inode{}, nil, err
   458  	}
   459  
   460  	cbsFD := &ClientBoundSocketFD{
   461  		fd:             resp.BoundSocketFD,
   462  		notificationFD: int32(hostSocketFD[0]),
   463  		client:         f.client,
   464  	}
   465  
   466  	return resp.Child, cbsFD, err
   467  }
   468  
   469  // Connect makes the Connect RPC.
   470  func (f *ClientFD) Connect(ctx context.Context, sockType linux.SockType) (int, error) {
   471  	req := ConnectReq{FD: f.fd, SockType: uint32(sockType)}
   472  	var resp ConnectResp
   473  	var sockFD [1]int
   474  	ctx.UninterruptibleSleepStart(false)
   475  	err := f.client.SndRcvMessage(Connect, uint32(req.SizeBytes()), req.MarshalUnsafe, resp.CheckedUnmarshal, sockFD[:], req.String, resp.String)
   476  	ctx.UninterruptibleSleepFinish(false)
   477  	if err == nil && sockFD[0] < 0 {
   478  		err = unix.EBADF
   479  	}
   480  	return sockFD[0], err
   481  }
   482  
   483  // UnlinkAt makes the UnlinkAt RPC.
   484  func (f *ClientFD) UnlinkAt(ctx context.Context, name string, flags uint32) error {
   485  	req := UnlinkAtReq{
   486  		DirFD: f.fd,
   487  		Name:  SizedString(name),
   488  		Flags: primitive.Uint32(flags),
   489  	}
   490  	var resp UnlinkAtResp
   491  	ctx.UninterruptibleSleepStart(false)
   492  	err := f.client.SndRcvMessage(UnlinkAt, uint32(req.SizeBytes()), req.MarshalBytes, resp.CheckedUnmarshal, nil, req.String, resp.String)
   493  	ctx.UninterruptibleSleepFinish(false)
   494  	return err
   495  }
   496  
   497  // RenameAt makes the RenameAt RPC which renames oldName inside directory f to
   498  // newDirFD directory with name newName.
   499  func (f *ClientFD) RenameAt(ctx context.Context, oldName string, newDirFD FDID, newName string) error {
   500  	req := RenameAtReq{
   501  		OldDir:  f.fd,
   502  		OldName: SizedString(oldName),
   503  		NewDir:  newDirFD,
   504  		NewName: SizedString(newName),
   505  	}
   506  	var resp RenameAtResp
   507  	ctx.UninterruptibleSleepStart(false)
   508  	err := f.client.SndRcvMessage(RenameAt, uint32(req.SizeBytes()), req.MarshalBytes, resp.CheckedUnmarshal, nil, req.String, resp.String)
   509  	ctx.UninterruptibleSleepFinish(false)
   510  	return err
   511  }
   512  
   513  // Getdents64 makes the Getdents64 RPC.
   514  func (f *ClientFD) Getdents64(ctx context.Context, count int32) ([]Dirent64, error) {
   515  	req := Getdents64Req{
   516  		DirFD: f.fd,
   517  		Count: count,
   518  	}
   519  
   520  	var resp Getdents64Resp
   521  	ctx.UninterruptibleSleepStart(false)
   522  	err := f.client.SndRcvMessage(Getdents64, uint32(req.SizeBytes()), req.MarshalUnsafe, resp.CheckedUnmarshal, nil, req.String, resp.String)
   523  	ctx.UninterruptibleSleepFinish(false)
   524  	return resp.Dirents, err
   525  }
   526  
   527  // ListXattr makes the FListXattr RPC.
   528  func (f *ClientFD) ListXattr(ctx context.Context, size uint64) ([]string, error) {
   529  	req := FListXattrReq{
   530  		FD:   f.fd,
   531  		Size: size,
   532  	}
   533  
   534  	var resp FListXattrResp
   535  	ctx.UninterruptibleSleepStart(false)
   536  	err := f.client.SndRcvMessage(FListXattr, uint32(req.SizeBytes()), req.MarshalUnsafe, resp.CheckedUnmarshal, nil, req.String, resp.String)
   537  	ctx.UninterruptibleSleepFinish(false)
   538  	return resp.Xattrs, err
   539  }
   540  
   541  // GetXattr makes the FGetXattr RPC.
   542  func (f *ClientFD) GetXattr(ctx context.Context, name string, size uint64) (string, error) {
   543  	req := FGetXattrReq{
   544  		FD:      f.fd,
   545  		Name:    SizedString(name),
   546  		BufSize: primitive.Uint32(size),
   547  	}
   548  
   549  	var resp FGetXattrResp
   550  	ctx.UninterruptibleSleepStart(false)
   551  	err := f.client.SndRcvMessage(FGetXattr, uint32(req.SizeBytes()), req.MarshalBytes, resp.CheckedUnmarshal, nil, req.String, resp.String)
   552  	ctx.UninterruptibleSleepFinish(false)
   553  	return string(resp.Value), err
   554  }
   555  
   556  // SetXattr makes the FSetXattr RPC.
   557  func (f *ClientFD) SetXattr(ctx context.Context, name string, value string, flags uint32) error {
   558  	req := FSetXattrReq{
   559  		FD:    f.fd,
   560  		Name:  SizedString(name),
   561  		Value: SizedString(value),
   562  		Flags: primitive.Uint32(flags),
   563  	}
   564  	var resp FSetXattrResp
   565  	ctx.UninterruptibleSleepStart(false)
   566  	err := f.client.SndRcvMessage(FSetXattr, uint32(req.SizeBytes()), req.MarshalBytes, resp.CheckedUnmarshal, nil, req.String, resp.String)
   567  	ctx.UninterruptibleSleepFinish(false)
   568  	return err
   569  }
   570  
   571  // RemoveXattr makes the FRemoveXattr RPC.
   572  func (f *ClientFD) RemoveXattr(ctx context.Context, name string) error {
   573  	req := FRemoveXattrReq{
   574  		FD:   f.fd,
   575  		Name: SizedString(name),
   576  	}
   577  	var resp FRemoveXattrResp
   578  	ctx.UninterruptibleSleepStart(false)
   579  	err := f.client.SndRcvMessage(FRemoveXattr, uint32(req.SizeBytes()), req.MarshalBytes, resp.CheckedUnmarshal, nil, req.String, resp.String)
   580  	ctx.UninterruptibleSleepFinish(false)
   581  	return err
   582  }
   583  
   584  // ClientBoundSocketFD corresponds to a bound socket on the server. It
   585  // implements transport.BoundSocketFD.
   586  //
   587  // All fields are immutable.
   588  type ClientBoundSocketFD struct {
   589  	// fd is the FDID of the bound socket on the server.
   590  	fd FDID
   591  
   592  	// notificationFD is the host FD that can be used to notify when new
   593  	// clients connect to the socket.
   594  	notificationFD int32
   595  
   596  	client *Client
   597  }
   598  
   599  // Close implements transport.BoundSocketFD.Close.
   600  func (f *ClientBoundSocketFD) Close(ctx context.Context) {
   601  	_ = unix.Close(int(f.notificationFD))
   602  	// flush is true because the socket FD must be closed immediately on the
   603  	// server. close(2) on socket FD impacts application behavior.
   604  	f.client.CloseFD(ctx, f.fd, true /* flush */)
   605  }
   606  
   607  // NotificationFD implements transport.BoundSocketFD.NotificationFD.
   608  func (f *ClientBoundSocketFD) NotificationFD() int32 {
   609  	return f.notificationFD
   610  }
   611  
   612  // Listen implements transport.BoundSocketFD.Listen.
   613  func (f *ClientBoundSocketFD) Listen(ctx context.Context, backlog int32) error {
   614  	req := ListenReq{
   615  		FD:      f.fd,
   616  		Backlog: backlog,
   617  	}
   618  	var resp ListenResp
   619  	ctx.UninterruptibleSleepStart(false)
   620  	err := f.client.SndRcvMessage(Listen, uint32(req.SizeBytes()), req.MarshalBytes, resp.CheckedUnmarshal, nil, req.String, resp.String)
   621  	ctx.UninterruptibleSleepFinish(false)
   622  	return err
   623  }
   624  
   625  // Accept implements transport.BoundSocketFD.Accept.
   626  func (f *ClientBoundSocketFD) Accept(ctx context.Context) (int, error) {
   627  	req := AcceptReq{
   628  		FD: f.fd,
   629  	}
   630  	var resp AcceptResp
   631  	var hostSocketFD [1]int
   632  	ctx.UninterruptibleSleepStart(false)
   633  	err := f.client.SndRcvMessage(Accept, uint32(req.SizeBytes()), req.MarshalBytes, resp.CheckedUnmarshal, hostSocketFD[:], req.String, resp.String)
   634  	ctx.UninterruptibleSleepFinish(false)
   635  	if err == nil && hostSocketFD[0] < 0 {
   636  		err = unix.EBADF
   637  	}
   638  	return hostSocketFD[0], err
   639  }