151 lines
4.8 KiB
C
151 lines
4.8 KiB
C
#include "ulib.h"
|
|
#include "fs.h"
|
|
|
|
/*
|
|
* Exercises the persistent SFS filesystem (sfs.h/sfs.c) through the exact
|
|
* same syscall path a real userspace program would use: open/write/read/
|
|
* close/mkdir/getdents/unlink on paths under "/mnt", which vfs.c dispatches
|
|
* to sfs.c instead of the kmalloc-based tmpfs tree. Proves the full stack
|
|
* (syscall -> vfs -> sfs -> real block I/O on the same ATA disk /dev/disk0
|
|
* uses) works end to end, not just the in-kernel sfs.c unit tests.
|
|
*/
|
|
|
|
static int bytesEqual(const char* a, const char* b, unsigned long n)
|
|
{
|
|
for (unsigned long i = 0; i < n; i++)
|
|
if (a[i] != b[i])
|
|
return 0;
|
|
return 1;
|
|
}
|
|
|
|
int main(void)
|
|
{
|
|
print("fstest: start, pid=");
|
|
printDec(userGetpid());
|
|
print("\n");
|
|
|
|
/* Nested directory creation. */
|
|
if (userMkdir("/mnt/app") != 0) {
|
|
print("fstest: FAIL mkdir /mnt/app\n");
|
|
return 1;
|
|
}
|
|
if (userMkdir("/mnt/app/logs") != 0) {
|
|
print("fstest: FAIL mkdir /mnt/app/logs\n");
|
|
return 1;
|
|
}
|
|
|
|
/* Create + write + close, then reopen with a fresh fd to prove the data
|
|
lives past the writer's own fd, not just in that fd's local state. */
|
|
const char* payload = "frostbyte fstest payload line one\n";
|
|
unsigned long payloadLen = stringLength(payload);
|
|
|
|
int wfd = (int)userOpen("/mnt/app/logs/boot.log", oReadWrite | oCreate);
|
|
if (wfd < 0) {
|
|
print("fstest: FAIL open for create\n");
|
|
return 1;
|
|
}
|
|
if (userWrite(wfd, payload, payloadLen) != (long)payloadLen) {
|
|
print("fstest: FAIL short write\n");
|
|
return 1;
|
|
}
|
|
userClose(wfd);
|
|
|
|
FbStat st;
|
|
if (userStat("/mnt/app/logs/boot.log", &st) != 0 || st.size != payloadLen) {
|
|
print("fstest: FAIL stat size mismatch\n");
|
|
return 1;
|
|
}
|
|
|
|
int rfd = (int)userOpen("/mnt/app/logs/boot.log", oReadOnly);
|
|
if (rfd < 0) {
|
|
print("fstest: FAIL reopen\n");
|
|
return 1;
|
|
}
|
|
char back[128];
|
|
long got = userRead(rfd, back, sizeof(back));
|
|
if (got != (long)payloadLen || !bytesEqual(back, payload, payloadLen)) {
|
|
print("fstest: FAIL reopen round-trip mismatch\n");
|
|
return 1;
|
|
}
|
|
userClose(rfd);
|
|
print("fstest: create/write/reopen/read round-trip ok\n");
|
|
|
|
/* Append across two separate open() calls: growth must pick up where
|
|
the previous session's data ended. */
|
|
int afd = (int)userOpen("/mnt/app/logs/boot.log", oReadWrite | oAppend);
|
|
if (afd < 0) {
|
|
print("fstest: FAIL open for append\n");
|
|
return 1;
|
|
}
|
|
const char* more = "line two\n";
|
|
unsigned long moreLen = stringLength(more);
|
|
if (userWrite(afd, more, moreLen) != (long)moreLen) {
|
|
print("fstest: FAIL append write\n");
|
|
return 1;
|
|
}
|
|
userClose(afd);
|
|
|
|
if (userStat("/mnt/app/logs/boot.log", &st) != 0 || st.size != payloadLen + moreLen) {
|
|
print("fstest: FAIL stat after append\n");
|
|
return 1;
|
|
}
|
|
print("fstest: append across reopen ok\n");
|
|
|
|
/* A second, unrelated file in the same directory, to exercise readdir
|
|
against more than one entry. */
|
|
int cfd = (int)userOpen("/mnt/app/logs/counters.txt", oReadWrite | oCreate);
|
|
if (cfd < 0) {
|
|
print("fstest: FAIL create second file\n");
|
|
return 1;
|
|
}
|
|
userWrite(cfd, "0", 1);
|
|
userClose(cfd);
|
|
|
|
int dfd = (int)userOpen("/mnt/app/logs", oReadOnly);
|
|
if (dfd < 0) {
|
|
print("fstest: FAIL open dir for listing\n");
|
|
return 1;
|
|
}
|
|
FbDirent entries[8];
|
|
long entCount = userGetdents(dfd, entries, sizeof(entries));
|
|
userClose(dfd);
|
|
if (entCount != 2 * (long)sizeof(FbDirent)) {
|
|
print("fstest: FAIL readdir entry count\n");
|
|
return 1;
|
|
}
|
|
int sawBoot = 0, sawCounters = 0;
|
|
for (int i = 0; i < 2; i++) {
|
|
if (entries[i].type != fsTypeFile) {
|
|
print("fstest: FAIL readdir entry type\n");
|
|
return 1;
|
|
}
|
|
if (bytesEqual(entries[i].name, "boot.log", 9))
|
|
sawBoot = 1;
|
|
if (bytesEqual(entries[i].name, "counters.txt", 13))
|
|
sawCounters = 1;
|
|
}
|
|
if (!sawBoot || !sawCounters) {
|
|
print("fstest: FAIL readdir missing an expected entry\n");
|
|
return 1;
|
|
}
|
|
print("fstest: readdir lists both files ok\n");
|
|
|
|
/* Unlink one, verify it is gone and its sibling survives. */
|
|
if (userUnlink("/mnt/app/logs/counters.txt") != 0) {
|
|
print("fstest: FAIL unlink counters.txt\n");
|
|
return 1;
|
|
}
|
|
if (userStat("/mnt/app/logs/counters.txt", &st) == 0) {
|
|
print("fstest: FAIL unlinked file still stat-able\n");
|
|
return 1;
|
|
}
|
|
if (userStat("/mnt/app/logs/boot.log", &st) != 0) {
|
|
print("fstest: FAIL sibling disappeared after unlink\n");
|
|
return 1;
|
|
}
|
|
print("fstest: unlink ok, sibling survives\n");
|
|
|
|
print("fstest: done\n");
|
|
return 0;
|
|
}
|