github.com/iceber/iouring-go@v0.0.0-20230403020409-002cfd2e2a90/prep_request.go (about)

     1  //go:build linux
     2  // +build linux
     3  
     4  package iouring
     5  
     6  import (
     7  	"errors"
     8  	"os"
     9  	"syscall"
    10  	"unsafe"
    11  
    12  	"golang.org/x/sys/unix"
    13  
    14  	iouring_syscall "github.com/iceber/iouring-go/syscall"
    15  )
    16  
    17  type PrepRequest func(sqe iouring_syscall.SubmissionQueueEntry, userData *UserData)
    18  
    19  // WithInfo request with extra info
    20  func (prepReq PrepRequest) WithInfo(info interface{}) PrepRequest {
    21  	return func(sqe iouring_syscall.SubmissionQueueEntry, userData *UserData) {
    22  		prepReq(sqe, userData)
    23  		userData.SetRequestInfo(info)
    24  	}
    25  }
    26  
    27  func (prepReq PrepRequest) WithDrain() PrepRequest {
    28  	return func(sqe iouring_syscall.SubmissionQueueEntry, userData *UserData) {
    29  		prepReq(sqe, userData)
    30  		sqe.SetFlags(iouring_syscall.IOSQE_FLAGS_IO_DRAIN)
    31  	}
    32  }
    33  
    34  func (prepReq PrepRequest) WithCallback(callback RequestCallback) PrepRequest {
    35  	return func(sqe iouring_syscall.SubmissionQueueEntry, userData *UserData) {
    36  		prepReq(sqe, userData)
    37  		userData.SetRequestCallback(callback)
    38  	}
    39  }
    40  
    41  func (iour *IOURing) Read(file *os.File, b []byte, ch chan<- Result) (Request, error) {
    42  	fd := int(file.Fd())
    43  	if fd < 0 {
    44  		return nil, errors.New("invalid file")
    45  	}
    46  
    47  	return iour.SubmitRequest(Read(fd, b), ch)
    48  }
    49  
    50  func (iour *IOURing) Write(file *os.File, b []byte, ch chan<- Result) (Request, error) {
    51  	fd := int(file.Fd())
    52  	if fd < 0 {
    53  		return nil, errors.New("invalid file")
    54  	}
    55  
    56  	return iour.SubmitRequest(Write(fd, b), ch)
    57  }
    58  
    59  func (iour *IOURing) Pread(file *os.File, b []byte, offset uint64, ch chan<- Result) (Request, error) {
    60  	fd := int(file.Fd())
    61  	if fd < 0 {
    62  		return nil, errors.New("invalid file")
    63  	}
    64  
    65  	return iour.SubmitRequest(Pread(fd, b, offset), ch)
    66  }
    67  
    68  func (iour *IOURing) Pwrite(file *os.File, b []byte, offset uint64, ch chan<- Result) (Request, error) {
    69  	fd := int(file.Fd())
    70  	if fd < 0 {
    71  		return nil, errors.New("invalid file")
    72  	}
    73  
    74  	return iour.SubmitRequest(Pwrite(fd, b, offset), ch)
    75  }
    76  
    77  func Nop() PrepRequest {
    78  	return func(sqe iouring_syscall.SubmissionQueueEntry, userData *UserData) {
    79  		sqe.PrepOperation(iouring_syscall.IORING_OP_NOP, -1, 0, 0, 0)
    80  	}
    81  }
    82  
    83  func Read(fd int, b []byte) PrepRequest {
    84  	var bp unsafe.Pointer
    85  	if len(b) > 0 {
    86  		bp = unsafe.Pointer(&b[0])
    87  	} else {
    88  		bp = unsafe.Pointer(&_zero)
    89  	}
    90  
    91  	return func(sqe iouring_syscall.SubmissionQueueEntry, userData *UserData) {
    92  		userData.request.resolver = fdResolver
    93  		userData.SetRequestBuffer(b, nil)
    94  
    95  		sqe.PrepOperation(
    96  			iouring_syscall.IORING_OP_READ,
    97  			int32(fd),
    98  			uint64(uintptr(bp)),
    99  			uint32(len(b)),
   100  			0,
   101  		)
   102  	}
   103  }
   104  
   105  func Pread(fd int, b []byte, offset uint64) PrepRequest {
   106  	var bp unsafe.Pointer
   107  	if len(b) > 0 {
   108  		bp = unsafe.Pointer(&b[0])
   109  	} else {
   110  		bp = unsafe.Pointer(&_zero)
   111  	}
   112  
   113  	return func(sqe iouring_syscall.SubmissionQueueEntry, userData *UserData) {
   114  		userData.request.resolver = fdResolver
   115  		userData.SetRequestBuffer(b, nil)
   116  
   117  		sqe.PrepOperation(
   118  			iouring_syscall.IORING_OP_READ,
   119  			int32(fd),
   120  			uint64(uintptr(bp)),
   121  			uint32(len(b)),
   122  			uint64(offset),
   123  		)
   124  	}
   125  }
   126  
   127  func Write(fd int, b []byte) PrepRequest {
   128  	var bp unsafe.Pointer
   129  	if len(b) > 0 {
   130  		bp = unsafe.Pointer(&b[0])
   131  	} else {
   132  		bp = unsafe.Pointer(&_zero)
   133  	}
   134  
   135  	return func(sqe iouring_syscall.SubmissionQueueEntry, userData *UserData) {
   136  		userData.request.resolver = fdResolver
   137  		userData.SetRequestBuffer(b, nil)
   138  
   139  		sqe.PrepOperation(
   140  			iouring_syscall.IORING_OP_WRITE,
   141  			int32(fd),
   142  			uint64(uintptr(bp)),
   143  			uint32(len(b)),
   144  			0,
   145  		)
   146  	}
   147  }
   148  
   149  func Pwrite(fd int, b []byte, offset uint64) PrepRequest {
   150  	var bp unsafe.Pointer
   151  	if len(b) > 0 {
   152  		bp = unsafe.Pointer(&b[0])
   153  	} else {
   154  		bp = unsafe.Pointer(&_zero)
   155  	}
   156  
   157  	return func(sqe iouring_syscall.SubmissionQueueEntry, userData *UserData) {
   158  		userData.request.resolver = fdResolver
   159  		userData.SetRequestBuffer(b, nil)
   160  
   161  		sqe.PrepOperation(
   162  			iouring_syscall.IORING_OP_WRITE,
   163  			int32(fd),
   164  			uint64(uintptr(bp)),
   165  			uint32(len(b)),
   166  			uint64(offset),
   167  		)
   168  	}
   169  }
   170  
   171  func Readv(fd int, bs [][]byte) PrepRequest {
   172  	iovecs := bytes2iovec(bs)
   173  
   174  	var bp unsafe.Pointer
   175  	if len(iovecs) > 0 {
   176  		bp = unsafe.Pointer(&iovecs[0])
   177  	} else {
   178  		bp = unsafe.Pointer(&_zero)
   179  	}
   180  
   181  	return func(sqe iouring_syscall.SubmissionQueueEntry, userData *UserData) {
   182  		userData.request.resolver = fdResolver
   183  		userData.SetRequestBuffers(bs)
   184  
   185  		sqe.PrepOperation(
   186  			iouring_syscall.IORING_OP_READV,
   187  			int32(fd),
   188  			uint64(uintptr(bp)),
   189  			uint32(len(iovecs)),
   190  			0,
   191  		)
   192  	}
   193  }
   194  
   195  func Preadv(fd int, bs [][]byte, offset uint64) PrepRequest {
   196  	iovecs := bytes2iovec(bs)
   197  
   198  	var bp unsafe.Pointer
   199  	if len(iovecs) > 0 {
   200  		bp = unsafe.Pointer(&iovecs[0])
   201  	} else {
   202  		bp = unsafe.Pointer(&_zero)
   203  	}
   204  
   205  	return func(sqe iouring_syscall.SubmissionQueueEntry, userData *UserData) {
   206  		userData.request.resolver = fdResolver
   207  		userData.SetRequestBuffers(bs)
   208  
   209  		sqe.PrepOperation(iouring_syscall.IORING_OP_READV,
   210  			int32(fd),
   211  			uint64(uintptr(bp)),
   212  			uint32(len(iovecs)),
   213  			offset,
   214  		)
   215  	}
   216  }
   217  
   218  func Writev(fd int, bs [][]byte) PrepRequest {
   219  	iovecs := bytes2iovec(bs)
   220  
   221  	var bp unsafe.Pointer
   222  	if len(iovecs) > 0 {
   223  		bp = unsafe.Pointer(&iovecs[0])
   224  	} else {
   225  		bp = unsafe.Pointer(&_zero)
   226  	}
   227  
   228  	return func(sqe iouring_syscall.SubmissionQueueEntry, userData *UserData) {
   229  		userData.request.resolver = fdResolver
   230  		userData.SetRequestBuffers(bs)
   231  
   232  		sqe.PrepOperation(
   233  			iouring_syscall.IORING_OP_WRITEV,
   234  			int32(fd),
   235  			uint64(uintptr(bp)),
   236  			uint32(len(iovecs)),
   237  			0,
   238  		)
   239  	}
   240  }
   241  
   242  func Pwritev(fd int, bs [][]byte, offset int64) PrepRequest {
   243  	iovecs := bytes2iovec(bs)
   244  
   245  	var bp unsafe.Pointer
   246  	if len(iovecs) > 0 {
   247  		bp = unsafe.Pointer(&iovecs[0])
   248  	} else {
   249  		bp = unsafe.Pointer(&_zero)
   250  	}
   251  
   252  	return func(sqe iouring_syscall.SubmissionQueueEntry, userData *UserData) {
   253  		userData.request.resolver = fdResolver
   254  		userData.SetRequestBuffers(bs)
   255  
   256  		sqe.PrepOperation(
   257  			iouring_syscall.IORING_OP_WRITEV,
   258  			int32(fd),
   259  			uint64(uintptr(bp)),
   260  			uint32(len(iovecs)),
   261  			uint64(offset),
   262  		)
   263  	}
   264  }
   265  
   266  func Send(sockfd int, b []byte, flags int) PrepRequest {
   267  	var bp unsafe.Pointer
   268  	if len(b) > 0 {
   269  		bp = unsafe.Pointer(&b[0])
   270  	} else {
   271  		bp = unsafe.Pointer(&_zero)
   272  	}
   273  
   274  	return func(sqe iouring_syscall.SubmissionQueueEntry, userData *UserData) {
   275  		userData.SetRequestBuffer(b, nil)
   276  
   277  		sqe.PrepOperation(
   278  			iouring_syscall.IORING_OP_SEND,
   279  			int32(sockfd),
   280  			uint64(uintptr(bp)),
   281  			uint32(len(b)),
   282  			0,
   283  		)
   284  		sqe.SetOpFlags(uint32(flags))
   285  	}
   286  }
   287  
   288  func Recv(sockfd int, b []byte, flags int) PrepRequest {
   289  	var bp unsafe.Pointer
   290  	if len(b) > 0 {
   291  		bp = unsafe.Pointer(&b[0])
   292  	} else {
   293  		bp = unsafe.Pointer(&_zero)
   294  	}
   295  
   296  	return func(sqe iouring_syscall.SubmissionQueueEntry, userData *UserData) {
   297  		userData.SetRequestBuffer(b, nil)
   298  
   299  		sqe.PrepOperation(
   300  			iouring_syscall.IORING_OP_RECV,
   301  			int32(sockfd),
   302  			uint64(uintptr(bp)),
   303  			uint32(len(b)),
   304  			0,
   305  		)
   306  		sqe.SetOpFlags(uint32(flags))
   307  	}
   308  }
   309  
   310  func Sendmsg(sockfd int, p, oob []byte, to syscall.Sockaddr, flags int) (PrepRequest, error) {
   311  	var ptr unsafe.Pointer
   312  	var salen uint32
   313  	if to != nil {
   314  		var err error
   315  		ptr, salen, err = sockaddr(to)
   316  		if err != nil {
   317  			return nil, err
   318  		}
   319  	}
   320  
   321  	msg := &syscall.Msghdr{}
   322  	msg.Name = (*byte)(ptr)
   323  	msg.Namelen = uint32(salen)
   324  	var iov syscall.Iovec
   325  	if len(p) > 0 {
   326  		iov.Base = &p[0]
   327  		iov.SetLen(len(p))
   328  	}
   329  	var dummy byte
   330  	if len(oob) > 0 {
   331  		if len(p) == 0 {
   332  			var sockType int
   333  			sockType, err := syscall.GetsockoptInt(sockfd, syscall.SOL_SOCKET, syscall.SO_TYPE)
   334  			if err != nil {
   335  				return nil, err
   336  			}
   337  			// send at least one normal byte
   338  			if sockType != syscall.SOCK_DGRAM {
   339  				iov.Base = &dummy
   340  				iov.SetLen(1)
   341  			}
   342  		}
   343  		msg.Control = &oob[0]
   344  		msg.SetControllen(len(oob))
   345  	}
   346  	msg.Iov = &iov
   347  	msg.Iovlen = 1
   348  
   349  	resolver := func(req Request) {
   350  		result := req.(*request)
   351  		result.r0 = int(result.res)
   352  		errResolver(result)
   353  		if result.err != nil {
   354  			return
   355  		}
   356  
   357  		if len(oob) > 0 && len(p) == 0 {
   358  			result.r0 = 0
   359  		}
   360  	}
   361  
   362  	msgptr := unsafe.Pointer(msg)
   363  	return func(sqe iouring_syscall.SubmissionQueueEntry, userData *UserData) {
   364  		userData.hold(msg, to)
   365  		userData.request.resolver = resolver
   366  		userData.SetRequestBuffer(p, oob)
   367  
   368  		sqe.PrepOperation(iouring_syscall.IORING_OP_SENDMSG, int32(sockfd), uint64(uintptr(msgptr)), 1, 0)
   369  		sqe.SetOpFlags(uint32(flags))
   370  	}, nil
   371  }
   372  
   373  func Recvmsg(sockfd int, p, oob []byte, to syscall.Sockaddr, flags int) (PrepRequest, error) {
   374  	var msg syscall.Msghdr
   375  	var rsa syscall.RawSockaddrAny
   376  	msg.Name = (*byte)(unsafe.Pointer(&rsa))
   377  	msg.Namelen = uint32(syscall.SizeofSockaddrAny)
   378  	var iov syscall.Iovec
   379  	if len(p) > 0 {
   380  		iov.Base = &p[0]
   381  		iov.SetLen(len(p))
   382  	}
   383  	var dummy byte
   384  	if len(oob) > 0 {
   385  		if len(p) == 0 {
   386  			var sockType int
   387  			sockType, err := syscall.GetsockoptInt(sockfd, syscall.SOL_SOCKET, syscall.SO_TYPE)
   388  			if err != nil {
   389  				return nil, err
   390  			}
   391  			// receive at least one normal byte
   392  			if sockType != syscall.SOCK_DGRAM {
   393  				iov.Base = &dummy
   394  				iov.SetLen(1)
   395  			}
   396  		}
   397  		msg.Control = &oob[0]
   398  		msg.SetControllen(len(oob))
   399  	}
   400  	msg.Iov = &iov
   401  	msg.Iovlen = 1
   402  
   403  	resolver := func(req Request) {
   404  		result := req.(*request)
   405  		result.r0 = int(result.res)
   406  		errResolver(result)
   407  		if result.err != nil {
   408  			return
   409  		}
   410  
   411  		if len(oob) > 0 && len(p) == 0 {
   412  			result.r0 = 0
   413  		}
   414  	}
   415  
   416  	return func(sqe iouring_syscall.SubmissionQueueEntry, userData *UserData) {
   417  		userData.hold(&msg, &rsa)
   418  		userData.request.resolver = resolver
   419  		userData.SetRequestBuffer(p, oob)
   420  
   421  		sqe.PrepOperation(
   422  			iouring_syscall.IORING_OP_RECVMSG,
   423  			int32(sockfd),
   424  			uint64(uintptr(unsafe.Pointer(&msg))),
   425  			1,
   426  			0,
   427  		)
   428  		sqe.SetOpFlags(uint32(flags))
   429  	}, nil
   430  }
   431  
   432  func Accept(sockfd int) PrepRequest {
   433  	var rsa syscall.RawSockaddrAny
   434  	var len uint32 = syscall.SizeofSockaddrAny
   435  
   436  	resolver := func(req Request) {
   437  		result := req.(*request)
   438  		fd := int(result.res)
   439  		errResolver(result)
   440  		if result.err != nil {
   441  			return
   442  		}
   443  
   444  		result.r0 = fd
   445  		result.r1, result.err = anyToSockaddr(&rsa)
   446  		if result.err != nil {
   447  			syscall.Close(fd)
   448  			result.r0 = 0
   449  		}
   450  	}
   451  
   452  	return func(sqe iouring_syscall.SubmissionQueueEntry, userData *UserData) {
   453  		userData.hold(&len)
   454  		userData.request.resolver = resolver
   455  		sqe.PrepOperation(iouring_syscall.IORING_OP_ACCEPT, int32(sockfd), uint64(uintptr(unsafe.Pointer(&rsa))), 0, uint64(uintptr(unsafe.Pointer(&len))))
   456  	}
   457  }
   458  
   459  func Accept4(sockfd int, flags int) PrepRequest {
   460  	var rsa syscall.RawSockaddrAny
   461  	var len uint32 = syscall.SizeofSockaddrAny
   462  
   463  	resolver := func(req Request) {
   464  		result := req.(*request)
   465  		fd := int(result.res)
   466  		errResolver(result)
   467  		if result.err != nil {
   468  			return
   469  		}
   470  
   471  		if len > syscall.SizeofSockaddrAny {
   472  			panic("RawSockaddrAny too small")
   473  		}
   474  
   475  		result.r0 = fd
   476  		result.r1, result.err = anyToSockaddr(&rsa)
   477  		if result.err != nil {
   478  			syscall.Close(fd)
   479  			result.r0 = 0
   480  		}
   481  	}
   482  	return func(sqe iouring_syscall.SubmissionQueueEntry, userData *UserData) {
   483  		userData.hold(&rsa, &len)
   484  		userData.request.resolver = resolver
   485  
   486  		sqe.PrepOperation(
   487  			iouring_syscall.IORING_OP_ACCEPT,
   488  			int32(sockfd),
   489  			uint64(uintptr(unsafe.Pointer(&rsa))),
   490  			0,
   491  			uint64(uintptr(unsafe.Pointer(&len))),
   492  		)
   493  		sqe.SetOpFlags(uint32(flags))
   494  	}
   495  }
   496  
   497  func Connect(sockfd int, sa syscall.Sockaddr) (PrepRequest, error) {
   498  	ptr, n, err := sockaddr(sa)
   499  	if err != nil {
   500  		return nil, err
   501  	}
   502  
   503  	return func(sqe iouring_syscall.SubmissionQueueEntry, userData *UserData) {
   504  		userData.hold(sa)
   505  		userData.request.resolver = errResolver
   506  
   507  		sqe.PrepOperation(
   508  			iouring_syscall.IORING_OP_CONNECT,
   509  			int32(sockfd),
   510  			uint64(uintptr(ptr)),
   511  			0,
   512  			uint64(n),
   513  		)
   514  	}, nil
   515  }
   516  
   517  func Openat(dirfd int, path string, flags uint32, mode uint32) (PrepRequest, error) {
   518  	flags |= syscall.O_LARGEFILE
   519  	b, err := syscall.ByteSliceFromString(path)
   520  	if err != nil {
   521  		return nil, err
   522  	}
   523  
   524  	bp := unsafe.Pointer(&b[0])
   525  	return func(sqe iouring_syscall.SubmissionQueueEntry, userData *UserData) {
   526  		userData.hold(&b)
   527  		userData.request.resolver = fdResolver
   528  
   529  		sqe.PrepOperation(
   530  			iouring_syscall.IORING_OP_OPENAT,
   531  			int32(dirfd),
   532  			uint64(uintptr(bp)),
   533  			mode,
   534  			0,
   535  		)
   536  		sqe.SetOpFlags(flags)
   537  	}, nil
   538  }
   539  
   540  func Openat2(dirfd int, path string, how *unix.OpenHow) (PrepRequest, error) {
   541  	b, err := syscall.ByteSliceFromString(path)
   542  	if err != nil {
   543  		return nil, err
   544  	}
   545  
   546  	bp := unsafe.Pointer(&b[0])
   547  	return func(sqe iouring_syscall.SubmissionQueueEntry, userData *UserData) {
   548  		userData.hold(&b)
   549  		userData.request.resolver = fdResolver
   550  
   551  		sqe.PrepOperation(
   552  			iouring_syscall.IORING_OP_OPENAT2,
   553  			int32(dirfd),
   554  			uint64(uintptr(bp)),
   555  			unix.SizeofOpenHow,
   556  			uint64(uintptr(unsafe.Pointer(how))),
   557  		)
   558  	}, nil
   559  }
   560  
   561  func Statx(dirfd int, path string, flags uint32, mask int, stat *unix.Statx_t) (PrepRequest, error) {
   562  	b, err := syscall.ByteSliceFromString(path)
   563  	if err != nil {
   564  		return nil, err
   565  	}
   566  
   567  	bp := unsafe.Pointer(&b[0])
   568  	return func(sqe iouring_syscall.SubmissionQueueEntry, userData *UserData) {
   569  		userData.request.resolver = errResolver
   570  		userData.hold(&b, stat)
   571  
   572  		sqe.PrepOperation(
   573  			iouring_syscall.IORING_OP_STATX,
   574  			int32(dirfd),
   575  			uint64(uintptr(bp)),
   576  			uint32(mask),
   577  			uint64(uintptr(unsafe.Pointer(stat))),
   578  		)
   579  		sqe.SetOpFlags(flags)
   580  	}, nil
   581  }
   582  
   583  func Fsync(fd int) PrepRequest {
   584  	return func(sqe iouring_syscall.SubmissionQueueEntry, userData *UserData) {
   585  		userData.request.resolver = errResolver
   586  		sqe.PrepOperation(iouring_syscall.IORING_OP_FSYNC, int32(fd), 0, 0, 0)
   587  	}
   588  }
   589  
   590  func Fdatasync(fd int) PrepRequest {
   591  	return func(sqe iouring_syscall.SubmissionQueueEntry, userData *UserData) {
   592  		userData.request.resolver = errResolver
   593  		sqe.PrepOperation(iouring_syscall.IORING_OP_FSYNC, int32(fd), 0, 0, 0)
   594  		sqe.SetOpFlags(iouring_syscall.IORING_FSYNC_DATASYNC)
   595  	}
   596  }
   597  
   598  func Fallocate(fd int, mode uint32, off int64, length int64) PrepRequest {
   599  	return func(sqe iouring_syscall.SubmissionQueueEntry, userData *UserData) {
   600  		userData.request.resolver = errResolver
   601  
   602  		sqe.PrepOperation(
   603  			iouring_syscall.IORING_OP_FALLOCATE,
   604  			int32(fd),
   605  			uint64(length),
   606  			uint32(mode),
   607  			uint64(off),
   608  		)
   609  	}
   610  }
   611  
   612  func Close(fd int) PrepRequest {
   613  	return func(sqe iouring_syscall.SubmissionQueueEntry, userData *UserData) {
   614  		userData.request.resolver = errResolver
   615  		sqe.PrepOperation(iouring_syscall.IORING_OP_CLOSE, int32(fd), 0, 0, 0)
   616  	}
   617  }
   618  
   619  func Madvise(b []byte, advice int) PrepRequest {
   620  	var bp unsafe.Pointer
   621  	if len(b) > 0 {
   622  		bp = unsafe.Pointer(&b[0])
   623  	} else {
   624  		bp = unsafe.Pointer(&_zero)
   625  	}
   626  	return func(sqe iouring_syscall.SubmissionQueueEntry, userData *UserData) {
   627  		userData.request.resolver = errResolver
   628  		userData.SetRequestBuffer(b, nil)
   629  
   630  		sqe.PrepOperation(
   631  			iouring_syscall.IORING_OP_MADVISE,
   632  			-1,
   633  			uint64(uintptr(bp)),
   634  			uint32(len(b)),
   635  			0,
   636  		)
   637  		sqe.SetOpFlags(uint32(advice))
   638  	}
   639  }
   640  
   641  func EpollCtl(epfd int, op int, fd int, event *syscall.EpollEvent) PrepRequest {
   642  	return func(sqe iouring_syscall.SubmissionQueueEntry, userData *UserData) {
   643  		userData.request.resolver = errResolver
   644  
   645  		sqe.PrepOperation(
   646  			iouring_syscall.IORING_OP_EPOLL_CTL,
   647  			int32(epfd),
   648  			uint64(uintptr(unsafe.Pointer(event))),
   649  			uint32(op),
   650  			uint64(fd),
   651  		)
   652  	}
   653  }
   654  
   655  func Mkdirat(dirFd int, path string, mode uint32) (PrepRequest, error) {
   656  	b, err := syscall.ByteSliceFromString(path)
   657  	if err != nil {
   658  		return nil, err
   659  	}
   660  
   661  	bp := unsafe.Pointer(&b[0])
   662  	return func(sqe iouring_syscall.SubmissionQueueEntry, userData *UserData) {
   663  		userData.hold(&b)
   664  		userData.request.resolver = fdResolver
   665  
   666  		sqe.PrepOperation(
   667  			iouring_syscall.IORING_OP_MKDIRAT,
   668  			int32(dirFd),
   669  			uint64(uintptr(bp)),
   670  			mode,
   671  			0,
   672  		)
   673  	}, nil
   674  }
   675  
   676  func Unlinkat(fd int, path string, flags int32) (PrepRequest, error) {
   677  	b, err := syscall.ByteSliceFromString(path)
   678  	if err != nil {
   679  		return nil, err
   680  	}
   681  
   682  	bp := unsafe.Pointer(&b[0])
   683  	return func(sqe iouring_syscall.SubmissionQueueEntry, userData *UserData) {
   684  		userData.hold(&b)
   685  		userData.request.resolver = fdResolver
   686  
   687  		sqe.PrepOperation(
   688  			iouring_syscall.IORING_OP_UNLINKAT,
   689  			int32(fd),
   690  			uint64(uintptr(bp)),
   691  			0,
   692  			0,
   693  		)
   694  		sqe.SetOpFlags(uint32(flags))
   695  	}, nil
   696  }
   697  
   698  func Symlinkat(target string, newDirFd int, linkPath string) (PrepRequest, error) {
   699  	bTarget, err := syscall.ByteSliceFromString(target)
   700  	if err != nil {
   701  		return nil, err
   702  	}
   703  	bLink, err := syscall.ByteSliceFromString(linkPath)
   704  	if err != nil {
   705  		return nil, err
   706  	}
   707  
   708  	bpTarget := unsafe.Pointer(&bTarget[0])
   709  	bpLink := unsafe.Pointer(&bLink[0])
   710  	return func(sqe iouring_syscall.SubmissionQueueEntry, userData *UserData) {
   711  		userData.hold(&bTarget, &bLink)
   712  		userData.request.resolver = fdResolver
   713  
   714  		sqe.PrepOperation(
   715  			iouring_syscall.IORING_OP_SYMLINKAT,
   716  			int32(newDirFd),
   717  			uint64(uintptr(bpTarget)),
   718  			0,
   719  			uint64(uintptr(bpLink)),
   720  		)
   721  	}, nil
   722  }
   723  
   724  func Renameat2(oldDirFd int, oldPath string, newDirFd int, newPath string, flags int) (PrepRequest, error) {
   725  	bOldPath, err := syscall.ByteSliceFromString(oldPath)
   726  	if err != nil {
   727  		return nil, err
   728  	}
   729  	bNewPath, err := syscall.ByteSliceFromString(newPath)
   730  	if err != nil {
   731  		return nil, err
   732  	}
   733  
   734  	bpOldPath := unsafe.Pointer(&bOldPath[0])
   735  	bpNewPath := unsafe.Pointer(&bNewPath[0])
   736  	return func(sqe iouring_syscall.SubmissionQueueEntry, userData *UserData) {
   737  		userData.hold(&bOldPath, &bNewPath)
   738  		userData.request.resolver = fdResolver
   739  
   740  		sqe.PrepOperation(
   741  			iouring_syscall.IORING_OP_RENAMEAT,
   742  			int32(oldDirFd), uint64(uintptr(bpOldPath)),
   743  			uint32(newDirFd), uint64(uintptr(bpNewPath)),
   744  		)
   745  		sqe.SetOpFlags(uint32(flags))
   746  	}, nil
   747  }
   748  
   749  func Renameat(oldDirFd int, oldPath string, newDirFd int, newPath string) (PrepRequest, error) {
   750  	return Renameat2(oldDirFd, oldPath, newDirFd, newPath, 0)
   751  }
   752  
   753  func Linkat(targetDirFd int, targetPath string, linkDirFd int, linkPath string, flags int) (PrepRequest, error) {
   754  	bTargetPath, err := syscall.ByteSliceFromString(targetPath)
   755  	if err != nil {
   756  		return nil, err
   757  	}
   758  	bLinkPath, err := syscall.ByteSliceFromString(linkPath)
   759  	if err != nil {
   760  		return nil, err
   761  	}
   762  
   763  	bpTargetPath := unsafe.Pointer(&bTargetPath[0])
   764  	bpLinkPath := unsafe.Pointer(&bLinkPath[0])
   765  	return func(sqe iouring_syscall.SubmissionQueueEntry, userData *UserData) {
   766  		userData.hold(&bpTargetPath, &bpLinkPath)
   767  		userData.request.resolver = fdResolver
   768  
   769  		sqe.PrepOperation(
   770  			iouring_syscall.IORING_OP_LINKAT,
   771  			int32(targetDirFd),
   772  			uint64(uintptr(bpTargetPath)),
   773  			uint32(linkDirFd),
   774  			uint64(uintptr(bpLinkPath)),
   775  		)
   776  		sqe.SetOpFlags(uint32(flags))
   777  	}, nil
   778  }