| ... | @@ -779,6 +779,21 @@ pub const IO_Uring = struct { | ... | @@ -779,6 +779,21 @@ pub const IO_Uring = struct { |
| 779 | return sqe; | 779 | return sqe; |
| 780 | } | 780 | } |
| 781 | | 781 | |
| | 782 | /// Queues (but does not submit) an SQE to perform a `mkdirat(2)`. |
| | 783 | /// Returns a pointer to the SQE. |
| | 784 | pub fn mkdirat( |
| | 785 | self: *IO_Uring, |
| | 786 | user_data: u64, |
| | 787 | dir_fd: os.fd_t, |
| | 788 | path: [*:0]const u8, |
| | 789 | mode: os.mode_t, |
| | 790 | ) !*io_uring_sqe { |
| | 791 | const sqe = try self.get_sqe(); |
| | 792 | io_uring_prep_mkdirat(sqe, dir_fd, path, mode); |
| | 793 | sqe.user_data = user_data; |
| | 794 | return sqe; |
| | 795 | } |
| | 796 | |
| 782 | /// Registers an array of file descriptors. | 797 | /// Registers an array of file descriptors. |
| 783 | /// Every time a file descriptor is put in an SQE and submitted to the kernel, the kernel must | 798 | /// Every time a file descriptor is put in an SQE and submitted to the kernel, the kernel must |
| 784 | /// retrieve a reference to the file, and once I/O has completed the file reference must be | 799 | /// retrieve a reference to the file, and once I/O has completed the file reference must be |
| ... | @@ -1365,6 +1380,15 @@ pub fn io_uring_prep_unlinkat( | ... | @@ -1365,6 +1380,15 @@ pub fn io_uring_prep_unlinkat( |
| 1365 | sqe.rw_flags = flags; | 1380 | sqe.rw_flags = flags; |
| 1366 | } | 1381 | } |
| 1367 | | 1382 | |
| | 1383 | pub fn io_uring_prep_mkdirat( |
| | 1384 | sqe: *io_uring_sqe, |
| | 1385 | dir_fd: os.fd_t, |
| | 1386 | path: [*:0]const u8, |
| | 1387 | mode: os.mode_t, |
| | 1388 | ) void { |
| | 1389 | io_uring_prep_rw(.MKDIRAT, sqe, dir_fd, @ptrToInt(path), mode, 0); |
| | 1390 | } |
| | 1391 | |
| 1368 | test "structs/offsets/entries" { | 1392 | test "structs/offsets/entries" { |
| 1369 | if (builtin.os.tag != .linux) return error.SkipZigTest; | 1393 | if (builtin.os.tag != .linux) return error.SkipZigTest; |
| 1370 | | 1394 | |
| ... | @@ -2456,3 +2480,46 @@ test "unlinkat" { | ... | @@ -2456,3 +2480,46 @@ test "unlinkat" { |
| 2456 | else => std.debug.panic("unexpected error: {}", .{err}), | 2480 | else => std.debug.panic("unexpected error: {}", .{err}), |
| 2457 | }; | 2481 | }; |
| 2458 | } | 2482 | } |
| | 2483 | |
| | 2484 | test "mkdirat" { |
| | 2485 | if (builtin.os.tag != .linux) return error.SkipZigTest; |
| | 2486 | |
| | 2487 | var ring = IO_Uring.init(1, 0) catch |err| switch (err) { |
| | 2488 | error.SystemOutdated => return error.SkipZigTest, |
| | 2489 | error.PermissionDenied => return error.SkipZigTest, |
| | 2490 | else => return err, |
| | 2491 | }; |
| | 2492 | defer ring.deinit(); |
| | 2493 | |
| | 2494 | const path = "test_io_uring_mkdirat"; |
| | 2495 | |
| | 2496 | defer std.fs.cwd().deleteDir(path) catch {}; |
| | 2497 | |
| | 2498 | // Submit mkdirat |
| | 2499 | |
| | 2500 | var sqe = try ring.mkdirat( |
| | 2501 | 0x12121212, |
| | 2502 | linux.AT.FDCWD, |
| | 2503 | path, |
| | 2504 | 0o0755, |
| | 2505 | ); |
| | 2506 | try testing.expectEqual(linux.IORING_OP.MKDIRAT, sqe.opcode); |
| | 2507 | try testing.expectEqual(@as(i32, linux.AT.FDCWD), sqe.fd); |
| | 2508 | try testing.expectEqual(@as(u32, 1), try ring.submit()); |
| | 2509 | |
| | 2510 | const cqe = try ring.copy_cqe(); |
| | 2511 | switch (cqe.err()) { |
| | 2512 | .SUCCESS => {}, |
| | 2513 | // This kernel's io_uring does not yet implement mkdirat (kernel version < 5.15) |
| | 2514 | .INVAL => return error.SkipZigTest, |
| | 2515 | else => |errno| std.debug.panic("unhandled errno: {}", .{errno}), |
| | 2516 | } |
| | 2517 | try testing.expectEqual(linux.io_uring_cqe{ |
| | 2518 | .user_data = 0x12121212, |
| | 2519 | .res = 0, |
| | 2520 | .flags = 0, |
| | 2521 | }, cqe); |
| | 2522 | |
| | 2523 | // Validate that the directory exist |
| | 2524 | _ = try std.fs.cwd().openDir(path, .{}); |
| | 2525 | } |