Files
RedBear-OS/recipes/tests/stdio/renameat.c
T
vasilito b9874d0941 feat: USB storage read/write proof + full Red Bear OS tree sync
Add redbear-usb-storage-check in-guest binary that validates USB mass
storage read and write I/O: discovers /scheme/disk/ devices, writes a
test pattern to sector 2048, reads it back, verifies match, restores
original content. Updates test-usb-storage-qemu.sh with write-proof
verification step.

Includes all accumulated Red Bear OS work: kernel patches, relibc
patches, driver infrastructure, DRM/GPU, KDE recipes, firmware,
validation tooling, build system hardening, and documentation.
2026-05-03 23:03:24 +01:00

226 lines
5.5 KiB
C

#include <fcntl.h>
#include <limits.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
static int temp_file(
const char dir[],
size_t dlen,
char buf[PATH_MAX],
const char name[],
size_t nlen,
bool create
) {
memcpy(buf, dir, dlen);
buf[dlen] = '/';
memcpy(&buf[dlen + 1], name, nlen);
if (create) {
int fd = open(buf, O_CREAT);
if (fd == -1) {
perror("open (file A)");
close(fd);
return -1;
}
close(fd);
}
return 0;
}
int main(void) {
int result = EXIT_FAILURE;
char dir_template[] = "/tmp/mvattest.XXXXXX";
size_t dlen = sizeof(dir_template) - 1;
if (!mkdtemp(dir_template)) {
perror("mkdtemp");
goto bye;
}
int dirfd = open(dir_template, O_DIRECTORY | O_PATH);
if (dirfd == -1) {
perror("open (temp directory)");
goto bye;
}
char dir_template2[] = "/tmp/mvattest2.XXXXXX";
size_t dlen2 = sizeof(dir_template2) - 1;
if (!mkdtemp(dir_template2)) {
perror("mkdtemp");
goto close_dir1;
}
int dirfd2 = open(dir_template2, O_DIRECTORY | O_PATH);
if (dirfd2 == -1) {
perror("open (temp directory)");
goto close_dir1;
}
// File A
const char file_a[] = "power";
char file_a_path[PATH_MAX] = {0};
if (temp_file(dir_template, dlen, file_a_path, file_a, sizeof(file_a), true) == -1) {
goto close_dir2;
}
// File B
const char file_b[] = "nyanko";
char file_b_path[PATH_MAX] = {0};
if (
temp_file(
dir_template,
dlen,
file_b_path,
file_b,
sizeof(file_b),
false
) == -1
) {
goto remove_ab;
}
// File A but in directory 2
char file_a_dir2[PATH_MAX] = {0};
if (
temp_file(
dir_template2,
dlen2,
file_a_dir2,
file_a,
sizeof(file_a),
false
) == -1
) {
goto remove_all;
}
// Move file A to file B normally (same dir)
if (renameat(dirfd, file_a, dirfd, file_b) == -1) {
perror("renameat (A -> B, basic)");
goto remove_all;
}
if (access(file_b_path, F_OK) == -1) {
perror("access (file B, basic)");
goto remove_all;
}
// Move file B to A (absolute path; same dir)
if (renameat(dirfd, file_b_path, dirfd, file_a) == -1) {
perror("renameat (B -> A, absolute path)");
goto remove_all;
}
if (access(file_a_path, F_OK) == -1) {
perror("access (file A, absolute path)");
goto remove_all;
}
// Move A to B (both absolute)
if (renameat(dirfd, file_a_path, dirfd, file_b_path) == -1) {
perror("renameat (A -> B, both absolute)");
goto remove_all;
}
if (access(file_b_path, F_OK) == -1) {
perror("access (file B, both absolute)");
goto remove_all;
}
// Move B to B
if (renameat(dirfd, file_b, dirfd, file_b) == -1) {
perror("renameat (B -> B)");
goto remove_all;
}
if (access(file_b_path, F_OK) == -1) {
perror("access (file B)");
goto remove_all;
}
// Move file B to A (AT_FDCWD)
char cwd[PATH_MAX] = {0};
if (!getcwd(cwd, PATH_MAX)) {
perror("getcwd");
goto remove_all;
}
if (chdir(dir_template) == -1) {
perror("chdir");
goto remove_all;
}
if (renameat(AT_FDCWD, file_b, dirfd, file_a) == -1) {
perror("renameat (B -> A, AT_FDCWD)");
goto remove_all;
}
if (access(file_a_path, F_OK) == -1) {
perror("access (file A, AT_FDCWD)");
goto remove_all;
}
// Reset, though it doesn't really matter.
if (chdir(cwd) == -1) {
perror("chdir");
goto remove_all;
}
// Move to different directory
if (renameat(dirfd, file_a, dirfd2, file_a) == -1) {
perror("renameat (A -> B, different dirs)");
goto remove_all;
}
if (access(file_a_dir2, F_OK) == -1) {
perror("access (file A in dir2)");
goto remove_all;
}
// Move non-existing file
if (renameat(dirfd, "aki", dirfd, "denji") == 0) {
// Wut?
fputs("renameat succeeded at moving a non-existing file\n", stderr);
goto remove_all;
}
// RENAME_NOREPLACE
// Create file B in dir 1 first because we moved it earlier.
int fd = open(file_b_path, O_CREAT);
if (fd == -1) {
perror("open (file B in dir 1)");
close(fd);
goto remove_all;
}
close(fd);
if (renameat2(dirfd, file_b, dirfd2, file_a, RENAME_NOREPLACE) == 0) {
fputs("renameat2 (B -> A, noreplace) succeeded\n", stderr);
goto remove_all;
}
if (access(file_a_dir2, F_OK) == -1) {
fputs("RENAME_NOREPLACE ate file A in dir 2\n", stderr);
goto remove_all;
}
if (access(file_b_path, F_OK) == -1) {
fputs("RENAME_NOREPLACE ate file B in dir 1\n", stderr);
goto remove_all;
}
// TODO: RENAME_EXCHANGE (Needs frename support in Redox)
// Notes for later:
// * Write a message to both files
// * Swap
// * Check if the files swapped correctly by strcmp messages
result = EXIT_SUCCESS;
remove_all:
remove(file_a_dir2);
remove_ab:
remove(file_a_path);
remove(file_b_path);
rmdir(dir_template);
rmdir(dir_template2);
close_dir2:
close(dirfd2);
close_dir1:
close(dirfd);
bye:
return result;
}