github.com/nicocha30/gvisor-ligolo@v0.0.0-20230726075806-989fa2c0a413/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 "golang.org/x/sys/unix" 22 "github.com/nicocha30/gvisor-ligolo/pkg/abi/linux" 23 "github.com/nicocha30/gvisor-ligolo/pkg/context" 24 "github.com/nicocha30/gvisor-ligolo/pkg/log" 25 "github.com/nicocha30/gvisor-ligolo/pkg/marshal/primitive" 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 }