8e389c03f8
Реализовать двухпанельный Commander от платформенного PoC до этапов P6-P20: EMM-каталог, сортировку и выбор, операции с файлами и деревьями, транзакционное копирование, метаданные, политику конфликтов и предварительную проверку свободного места. Добавить проектную документацию, HDD/MAME-сценарии и проверенные артефакты. Расширить libc операцией bank_write_page, исправлением режима O_RDONLY и связанными регрессионными проверками.
174 lines
5.1 KiB
C
174 lines
5.1 KiB
C
/*
|
|
* p1_dir.c — наблюдаемая проверка CURDIR/CHDIR/F_FIRST/F_NEXT.
|
|
*
|
|
* Тест не меняет файлы. chdir(".") используется только для проверки
|
|
* сохранения текущего каталога.
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdint.h>
|
|
#include <string.h>
|
|
#include <errno.h>
|
|
#include <unistd.h>
|
|
#include <dir.h>
|
|
#include "p1_platform.h"
|
|
|
|
#define P1_FIND_ATTRS (FA_RDONLY | FA_HIDDEN | FA_SYSTEM | FA_DIREC | FA_ARCH)
|
|
#define P1_FIND_LIMIT 4096u
|
|
|
|
static char cwd_before[256];
|
|
static char cwd_after[256];
|
|
static ffblk_t find_buf;
|
|
|
|
static int scan_pattern(const char *pattern, uint16_t *out_count,
|
|
uint8_t *out_dot, uint8_t *out_dotdot)
|
|
{
|
|
uint16_t count = 0;
|
|
uint8_t dot = 0;
|
|
uint8_t dotdot = 0;
|
|
int rc;
|
|
int end_errno;
|
|
|
|
errno = 0;
|
|
rc = ffirst(pattern, &find_buf, P1_FIND_ATTRS);
|
|
if (rc != 0) {
|
|
if (errno == ENOENT) {
|
|
printf("Pattern %-4s: empty (ffirst errno=%d)\n", pattern, errno);
|
|
*out_count = 0;
|
|
*out_dot = 0;
|
|
*out_dotdot = 0;
|
|
return 0;
|
|
}
|
|
printf("ffirst(%s) failed: errno=%d\n", pattern, errno);
|
|
return -1;
|
|
}
|
|
|
|
for (;;) {
|
|
if (strcmp(find_buf.found_name, ".") == 0) dot = 1;
|
|
if (strcmp(find_buf.found_name, "..") == 0) dotdot = 1;
|
|
|
|
if (count < 20) {
|
|
printf(" %02X %10lu %04X/%04X %s\n",
|
|
(unsigned)find_buf.found_attr,
|
|
(unsigned long)find_buf.size,
|
|
(unsigned)find_buf.date,
|
|
(unsigned)find_buf.time,
|
|
find_buf.found_name);
|
|
}
|
|
|
|
count++;
|
|
if (count >= P1_FIND_LIMIT) {
|
|
puts("Enumeration limit reached: possible F_NEXT loop.");
|
|
return -1;
|
|
}
|
|
|
|
errno = 0;
|
|
if (fnext(&find_buf) != 0) break;
|
|
}
|
|
|
|
end_errno = errno;
|
|
printf("Pattern %-4s: count=%u dot=%u dotdot=%u end_errno=%d\n",
|
|
pattern, (unsigned)count, (unsigned)dot, (unsigned)dotdot,
|
|
end_errno);
|
|
|
|
/* MAME 0.287 / BIOS 3.06 подтвердил ENOENT (3) для конца F_NEXT.
|
|
* Код 0x0F из старого описания DSS здесь не является штатным. */
|
|
if (end_errno != ENOENT) {
|
|
puts("Unexpected F_NEXT termination code.");
|
|
return -1;
|
|
}
|
|
|
|
*out_count = count;
|
|
*out_dot = dot;
|
|
*out_dotdot = dotdot;
|
|
return 0;
|
|
}
|
|
|
|
int p1_test_directory(void)
|
|
{
|
|
uint16_t count_star_dot;
|
|
uint16_t count_star;
|
|
uint8_t dot1, dotdot1, dot2, dotdot2;
|
|
int failed = 0;
|
|
|
|
p1_heading("Directory: CURDIR, CHDIR, F_FIRST/F_NEXT");
|
|
|
|
errno = 0;
|
|
if (getcwd(cwd_before, sizeof(cwd_before)) == 0) {
|
|
printf("getcwd failed: errno=%d\n", errno);
|
|
return -1;
|
|
}
|
|
printf("CWD before: %s\n", cwd_before);
|
|
|
|
if (chdir(".") != 0) {
|
|
printf("chdir(.) failed: errno=%d\n", errno);
|
|
failed++;
|
|
}
|
|
|
|
if (getcwd(cwd_after, sizeof(cwd_after)) == 0) {
|
|
printf("second getcwd failed: errno=%d\n", errno);
|
|
return -1;
|
|
}
|
|
printf("CWD after : %s\n", cwd_after);
|
|
if (strcmp(cwd_before, cwd_after) != 0) {
|
|
puts("CWD changed after chdir(.).");
|
|
failed++;
|
|
}
|
|
|
|
puts("\nFirst entries for *.*:");
|
|
if (scan_pattern("*.*", &count_star_dot, &dot1, &dotdot1) != 0) {
|
|
failed++;
|
|
}
|
|
|
|
puts("\nFirst entries for *:");
|
|
if (scan_pattern("*", &count_star, &dot2, &dotdot2) != 0) {
|
|
failed++;
|
|
}
|
|
|
|
if (count_star != count_star_dot) {
|
|
printf("NOTE: * count (%u) differs from *.* count (%u).\n",
|
|
(unsigned)count_star, (unsigned)count_star_dot);
|
|
}
|
|
if (dot1 != dot2 || dotdot1 != dotdot2) {
|
|
puts("NOTE: dot entries differ between patterns.");
|
|
}
|
|
|
|
printf("Directory checks failed: %u\n", (unsigned)failed);
|
|
return failed ? -1 : 0;
|
|
}
|
|
|
|
int p1_test_disk_info(void)
|
|
{
|
|
P1DiskInfo info;
|
|
uint32_t cluster_bytes;
|
|
uint32_t total_bytes;
|
|
uint32_t free_bytes;
|
|
|
|
p1_heading("DSKINFO: current disk");
|
|
errno = 0;
|
|
if (p1_disk_info(0xFF, &info) != 0) {
|
|
printf("DSKINFO failed: errno=%d\n", errno);
|
|
return -1;
|
|
}
|
|
|
|
cluster_bytes = (uint32_t)info.sectors_per_cluster *
|
|
(uint32_t)info.bytes_per_sector;
|
|
total_bytes = cluster_bytes * (uint32_t)info.total_clusters;
|
|
free_bytes = cluster_bytes * (uint32_t)info.free_clusters;
|
|
|
|
printf("Sectors/cluster : %u\n", (unsigned)info.sectors_per_cluster);
|
|
printf("Bytes/sector : %u\n", (unsigned)info.bytes_per_sector);
|
|
printf("Total clusters : %u\n", (unsigned)info.total_clusters);
|
|
printf("Free clusters : %u\n", (unsigned)info.free_clusters);
|
|
printf("Cluster bytes : %lu\n", (unsigned long)cluster_bytes);
|
|
printf("Total bytes : %lu\n", (unsigned long)total_bytes);
|
|
printf("Free bytes : %lu\n", (unsigned long)free_bytes);
|
|
|
|
if (info.sectors_per_cluster == 0 || info.bytes_per_sector == 0 ||
|
|
info.total_clusters == 0 || info.free_clusters > info.total_clusters) {
|
|
puts("DSKINFO returned inconsistent values.");
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|