//! test/system/services/exfat-test — a client that proves the exFAT mount end to //! end: it waits for the exfat server to mount the volume at /volumes/exfat- //! e0fa0001, reads the seeded HELLO.TXT off it, and exercises mkdir / write / //! read / rename / remove through the VFS (which routes the id-path to the exfat //! backend). Shipped in the initial_ramdisk; the `exfat-volume` QEMU case spawns //! it alongside init with an exFAT data device attached beside the FAT boot volume. const std = @import("std"); const fs = @import("file-system"); const process = @import("process"); const time = @import("time"); const logging = @import("logging"); // The exFAT data device's content id-path — its VolumeSerialNumber is 0xE0FA0001 // (the `exfat-volume` case passes --serial E0FA0001 to make-exfat-image.py). const mount = "/volumes/exfat-e0fa0001"; fn writeLine(comptime fmt: []const u8, arguments: anytype) void { var line: [128]u8 = undefined; _ = logging.write(std.fmt.bufPrint(&line, fmt, arguments) catch return); } pub fn main(init: process.Init) void { _ = init; // Wait for the exfat server to bring up the USB storage chain and mount. var opened: ?fs.Directory = null; var tries: u32 = 0; while (opened == null and tries < 1400) : (tries += 1) { opened = fs.openDirectory(mount); if (opened == null) time.sleepMillis(50); } var dir = opened orelse { _ = logging.write("exfat-test: " ++ mount ++ " never became available\n"); return; }; var count: u32 = 0; var entry: fs.Entry = .{}; while (dir.next(&entry)) { writeLine("exfat-test: entry '{s}' size={d}\n", .{ entry.name(), entry.size }); count += 1; if (count > 32) break; } dir.close(); // Read the seeded HELLO.TXT (make-exfat-image.py writes "exfat hello danos\n"). var read_ok = false; if (fs.open(mount ++ "/HELLO.TXT", .{})) |opened_file| { var file = opened_file; var buf: [32]u8 = undefined; const n = file.read(&buf) orelse 0; file.close(); read_ok = std.mem.startsWith(u8, buf[0..n], "exfat hello danos"); } if (read_ok) _ = logging.write("exfat-test: read HELLO.TXT ok\n"); // Mutation through the mount: mkdir, create + write, rename, read back, remove // — proof the write path reaches the engine over a real device. var mut_ok = false; if (fs.makeDirectory(mount ++ "/TESTDIR")) { var wrote = false; if (fs.open(mount ++ "/TESTDIR/W.TXT", .{ .create = true, .truncate = true })) |created| { var f = created; wrote = (f.writeAll("exfat-mutation-ok") orelse 0) == "exfat-mutation-ok".len; f.close(); } const renamed = fs.rename(mount ++ "/TESTDIR/W.TXT", mount ++ "/TESTDIR/R.TXT"); var readback = false; if (fs.open(mount ++ "/TESTDIR/R.TXT", .{})) |reopened| { var f = reopened; var buf: [32]u8 = undefined; const got = f.read(&buf) orelse 0; f.close(); readback = std.mem.eql(u8, buf[0..got], "exfat-mutation-ok"); } const removed = fs.remove(mount ++ "/TESTDIR/R.TXT"); mut_ok = wrote and renamed and readback and removed; } if (mut_ok) _ = logging.write("exfat-test: mutations ok\n"); if (read_ok and mut_ok) { while (true) { _ = logging.write("exfat-test: ok\n"); time.sleepMillis(1000); } } writeLine("exfat-test: FAILED (read={} mutations={})\n", .{ read_ok, mut_ok }); }