| ... | ... | @@ -764,6 +764,21 @@ pub const IO_Uring = struct { |
| 764 | 764 | return sqe; |
| 765 | 765 | } |
| 766 | 766 | |
| 767 | /// Queues (but does not submit) an SQE to perform a `unlinkat(2)`. |
| 768 | /// Returns a pointer to the SQE. |
| 769 | pub fn unlinkat( |
| 770 | self: *IO_Uring, |
| 771 | user_data: u64, |
| 772 | dir_fd: os.fd_t, |
| 773 | path: [*:0]const u8, |
| 774 | flags: u32, |
| 775 | ) !*io_uring_sqe { |
| 776 | const sqe = try self.get_sqe(); |
| 777 | io_uring_prep_unlinkat(sqe, dir_fd, path, flags); |
| 778 | sqe.user_data = user_data; |
| 779 | return sqe; |
| 780 | } |
| 781 | |
| 767 | 782 | /// Registers an array of file descriptors. |
| 768 | 783 | /// Every time a file descriptor is put in an SQE and submitted to the kernel, the kernel must |
| 769 | 784 | /// retrieve a reference to the file, and once I/O has completed the file reference must be |
| ... | ... | @@ -1340,6 +1355,16 @@ pub fn io_uring_prep_renameat( |
| 1340 | 1355 | sqe.rw_flags = flags; |
| 1341 | 1356 | } |
| 1342 | 1357 | |
| 1358 | pub fn io_uring_prep_unlinkat( |
| 1359 | sqe: *io_uring_sqe, |
| 1360 | dir_fd: os.fd_t, |
| 1361 | path: [*:0]const u8, |
| 1362 | flags: u32, |
| 1363 | ) void { |
| 1364 | io_uring_prep_rw(.UNLINKAT, sqe, dir_fd, @ptrToInt(path), 0, 0); |
| 1365 | sqe.rw_flags = flags; |
| 1366 | } |
| 1367 | |
| 1343 | 1368 | test "structs/offsets/entries" { |
| 1344 | 1369 | if (builtin.os.tag != .linux) return error.SkipZigTest; |
| 1345 | 1370 | |
| ... | ... | @@ -2381,3 +2406,53 @@ test "renameat" { |
| 2381 | 2406 | try testing.expectEqualStrings("hello", new_file_data[0..read]); |
| 2382 | 2407 | } |
| 2383 | 2408 | } |
| 2409 | |
| 2410 | test "unlinkat" { |
| 2411 | if (builtin.os.tag != .linux) return error.SkipZigTest; |
| 2412 | |
| 2413 | var ring = IO_Uring.init(1, 0) catch |err| switch (err) { |
| 2414 | error.SystemOutdated => return error.SkipZigTest, |
| 2415 | error.PermissionDenied => return error.SkipZigTest, |
| 2416 | else => return err, |
| 2417 | }; |
| 2418 | defer ring.deinit(); |
| 2419 | |
| 2420 | const path = "test_io_uring_unlinkat"; |
| 2421 | |
| 2422 | // Write old file with data |
| 2423 | |
| 2424 | const file = try std.fs.cwd().createFile(path, .{ .truncate = true, .mode = 0o666 }); |
| 2425 | defer file.close(); |
| 2426 | defer std.fs.cwd().deleteFile(path) catch {}; |
| 2427 | |
| 2428 | // Submit unlinkat |
| 2429 | |
| 2430 | var sqe = try ring.unlinkat( |
| 2431 | 0x12121212, |
| 2432 | linux.AT.FDCWD, |
| 2433 | path, |
| 2434 | 0, |
| 2435 | ); |
| 2436 | try testing.expectEqual(linux.IORING_OP.UNLINKAT, sqe.opcode); |
| 2437 | try testing.expectEqual(@as(i32, linux.AT.FDCWD), sqe.fd); |
| 2438 | try testing.expectEqual(@as(u32, 1), try ring.submit()); |
| 2439 | |
| 2440 | const cqe = try ring.copy_cqe(); |
| 2441 | switch (cqe.err()) { |
| 2442 | .SUCCESS => {}, |
| 2443 | // This kernel's io_uring does not yet implement unlinkat (kernel version < 5.11) |
| 2444 | .INVAL => return error.SkipZigTest, |
| 2445 | else => |errno| std.debug.panic("unhandled errno: {}", .{errno}), |
| 2446 | } |
| 2447 | try testing.expectEqual(linux.io_uring_cqe{ |
| 2448 | .user_data = 0x12121212, |
| 2449 | .res = 0, |
| 2450 | .flags = 0, |
| 2451 | }, cqe); |
| 2452 | |
| 2453 | // Validate that the file doesn't exist anymore |
| 2454 | _ = std.fs.cwd().openFile(path, .{}) catch |err| switch (err) { |
| 2455 | error.FileNotFound => {}, |
| 2456 | else => std.debug.panic("unexpected error: {}", .{err}), |
| 2457 | }; |
| 2458 | } |