8e389c03f8
Реализовать двухпанельный Commander от платформенного PoC до этапов P6-P20: EMM-каталог, сортировку и выбор, операции с файлами и деревьями, транзакционное копирование, метаданные, политику конфликтов и предварительную проверку свободного места. Добавить проектную документацию, HDD/MAME-сценарии и проверенные артефакты. Расширить libc операцией bank_write_page, исправлением режима O_RDONLY и связанными регрессионными проверками.
111 lines
3.4 KiB
C
111 lines
3.4 KiB
C
/*
|
|
* p10_rename_probe.c — target-регрессия локального F6/RENAME.
|
|
*
|
|
* Проверяет файл, каталог, запрет overwrite и восстановление CWD через тот
|
|
* же низкоуровневый helper, который вызывает Commander.
|
|
*/
|
|
|
|
#include <stdint.h>
|
|
#include <string.h>
|
|
#include <errno.h>
|
|
#include <fcntl.h>
|
|
#include <unistd.h>
|
|
#include "sc_file_ops.h"
|
|
|
|
static int result_fd = -1;
|
|
static uint8_t failures;
|
|
static char cwd_before[256];
|
|
static char cwd_after[256];
|
|
static char cwd_scratch[256];
|
|
|
|
static void log_text(const char *text)
|
|
{
|
|
const char *end = text;
|
|
while (*end != '\0') end++;
|
|
if (result_fd >= 0) {
|
|
(void)write(result_fd, text, (uint16_t)(end - text));
|
|
}
|
|
}
|
|
|
|
static void check(uint8_t condition, const char *name)
|
|
{
|
|
log_text(condition ? "PASS " : "FAIL ");
|
|
if (!condition) failures++;
|
|
log_text(name);
|
|
log_text("\r\n");
|
|
}
|
|
|
|
static uint8_t file_has(const char *path, const char *expected)
|
|
{
|
|
char data[24];
|
|
int fd = open(path, O_RDONLY);
|
|
int got;
|
|
uint16_t length = 0u;
|
|
|
|
if (fd < 0) return 0u;
|
|
while (expected[length] != '\0') length++;
|
|
got = read(fd, data, sizeof(data));
|
|
(void)close(fd);
|
|
return got == (int)length && memcmp(data, expected, length) == 0;
|
|
}
|
|
|
|
static uint8_t file_absent(const char *path)
|
|
{
|
|
int fd;
|
|
errno = 0;
|
|
fd = open(path, O_RDONLY);
|
|
if (fd >= 0) {
|
|
(void)close(fd);
|
|
return 0u;
|
|
}
|
|
return errno == ENOENT || errno == ENOPATH;
|
|
}
|
|
|
|
int main(void)
|
|
{
|
|
int rc;
|
|
int collision_errno;
|
|
int entered;
|
|
|
|
result_fd = open("D:\\RENRES.TXT", O_WRONLY | O_CREAT | O_TRUNC);
|
|
check(getcwd(cwd_before, sizeof(cwd_before)) != 0,
|
|
"CWD captured before rename matrix");
|
|
|
|
rc = sc_rename_local("D:\\RENTEST", "OLD.TXT", "NEW.TXT",
|
|
cwd_scratch, sizeof(cwd_scratch));
|
|
check(rc == 0 && file_absent("D:\\RENTEST\\OLD.TXT") &&
|
|
file_has("D:\\RENTEST\\NEW.TXT", "old payload\r\n"),
|
|
"file renamed without data change");
|
|
|
|
errno = 0;
|
|
rc = sc_rename_local("D:\\RENTEST", "NEW.TXT", "EXIST.TXT",
|
|
cwd_scratch, sizeof(cwd_scratch));
|
|
collision_errno = errno;
|
|
check(rc != 0 && collision_errno == EEXIST &&
|
|
file_has("D:\\RENTEST\\NEW.TXT", "old payload\r\n") &&
|
|
file_has("D:\\RENTEST\\EXIST.TXT", "existing payload\r\n"),
|
|
"existing target blocks rename and stays intact");
|
|
|
|
rc = sc_rename_local("D:\\RENTEST", "OLDDIR", "NEWDIR",
|
|
cwd_scratch, sizeof(cwd_scratch));
|
|
entered = chdir("D:\\RENTEST\\NEWDIR");
|
|
if (entered == 0) entered = chdir(cwd_before);
|
|
check(rc == 0 && entered == 0 &&
|
|
file_has("D:\\RENTEST\\NEWDIR\\KEEP.BIN", "dir payload\r\n"),
|
|
"directory renamed with contents intact");
|
|
|
|
errno = 0;
|
|
rc = sc_rename_local("D:\\MISSING", "A.TXT", "B.TXT",
|
|
cwd_scratch, sizeof(cwd_scratch));
|
|
check(rc != 0 && getcwd(cwd_after, sizeof(cwd_after)) != 0 &&
|
|
strcmp(cwd_before, cwd_after) == 0,
|
|
"failed directory change preserves CWD");
|
|
check(getcwd(cwd_after, sizeof(cwd_after)) != 0 &&
|
|
strcmp(cwd_before, cwd_after) == 0,
|
|
"successful and rejected renames restore CWD");
|
|
|
|
if (failures == 0u) log_text("ALL PASS\r\n");
|
|
if (result_fd >= 0) (void)close(result_fd);
|
|
return failures;
|
|
}
|