blob: 8b1c3e6086458a4eaaf752d3e0c45966df070e8d [file] [edit]
#include <assert.h>
#include <dirent.h>
#include <fcntl.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <emscripten/console.h>
#include <emscripten/wasmfs.h>
// Define WASMFS_SETUP then WASMFS_RESUME to run the test as two separate
// programs to test persistence. Alternatively, define neither and run the full
// test as a single program.
void cleanup(void);
int main(int argc, char* argv[]) {
int err, fd, nwritten;
const char* msg = "Hello, OPFS!";
const char* msg2 = "Hello, OPFS!Hello, OPFS!";
emscripten_console_log("starting main");
backend_t opfs = wasmfs_create_opfs_backend();
emscripten_console_log("created OPFS backend");
err = wasmfs_create_directory("/opfs", 0777, opfs);
assert(err == 0);
emscripten_console_log("mounted OPFS root directory");
#ifdef WASMFS_RESUME
fd = open("/opfs/working/foo.txt", O_RDWR);
assert(fd > 0);
emscripten_console_log("opened existing OPFS file");
#else // !WASMFS_RESUME
// Remove old files if they exist.
cleanup();
err = mkdir("/opfs/working", 0777);
assert(err == 0);
emscripten_console_log("created OPFS directory");
fd = open("/opfs/working/foo.txt", O_RDWR | O_CREAT | O_EXCL, 0777);
assert(fd > 0);
emscripten_console_log("created OPFS file");
nwritten = write(fd, msg, strlen(msg));
assert(nwritten == strlen(msg));
emscripten_console_logf("wrote message: %s (%d)", msg, nwritten);
int off = lseek(fd, 0, SEEK_SET);
assert(off == 0);
emscripten_console_log("seeked");
#endif // !WASMFS_RESUME
int newfd1 = dup(fd);
assert(newfd1 != -1);
int newfd2 = dup(newfd1);
assert(newfd2 != -1);
err = close(newfd1);
assert(err != -1);
err = close(newfd2);
assert(err != -1);
char buf[100] = {};
int nread = read(fd, buf, 100);
assert(nread == strlen(msg));
assert(strcmp(buf, msg) == 0);
emscripten_console_logf("read message: %s (%d)", buf, nread);
fdatasync(fd);
emscripten_console_log("flushed");
struct stat stat_buf;
err = fstat(fd, &stat_buf);
assert(err == 0);
assert(stat_buf.st_size == strlen(msg));
emscripten_console_log("statted");
#ifndef WASMFS_SETUP
err = ftruncate(fd, 100);
assert(err == 0);
err = fstat(fd, &stat_buf);
assert(err == 0);
assert(stat_buf.st_size == 100);
emscripten_console_log("truncated to 100");
struct dirent** entries;
int nentries = scandir("/opfs/working", &entries, NULL, alphasort);
assert(nentries == 3);
assert(strcmp(entries[0]->d_name, ".") == 0);
assert(strcmp(entries[1]->d_name, "..") == 0);
assert(strcmp(entries[2]->d_name, "foo.txt") == 0);
assert(entries[2]->d_type == DT_REG);
for (int i = 0; i < nentries; i++) {
free(entries[i]);
}
free(entries);
emscripten_console_log("read /opfs/working entries");
nentries = scandir("/opfs", &entries, NULL, alphasort);
assert(nentries == 3);
assert(strcmp(entries[2]->d_name, "working") == 0);
assert(entries[2]->d_type == DT_DIR);
for (int i = 0; i < nentries; i++) {
free(entries[i]);
}
free(entries);
emscripten_console_log("read /opfs entries");
err = close(fd);
assert(err == 0);
emscripten_console_log("closed file");
err = stat("/opfs/working/foo.txt", &stat_buf);
assert(err == 0);
assert(stat_buf.st_size == 100);
emscripten_console_log("statted while closed");
err = truncate("/opfs/working/foo.txt", 42);
assert(err == 0);
emscripten_console_log("resized while closed");
err = stat("/opfs/working/foo.txt", &stat_buf);
assert(err == 0);
assert(stat_buf.st_size == 42);
emscripten_console_log("statted while closed again");
fd = open("/opfs/working/foo.txt", O_RDONLY);
assert(fd > 0);
emscripten_console_log("opened file in read-only mode");
char buf2[100] = {};
nread = read(fd, buf2, 100);
emscripten_console_logf("read message: %s (%d)", buf2, nread);
assert(nread == 42);
assert(strcmp(buf2, msg) == 0);
err = fstat(fd, &stat_buf);
assert(err == 0);
assert(stat_buf.st_size == 42);
emscripten_console_log("statted while open in read-only mode");
int fd2 = open("/opfs/working/foo.txt", O_WRONLY);
assert(fd > 0);
emscripten_console_log("upgraded open state to read-write");
lseek(fd2, strlen(msg), SEEK_SET);
nwritten = write(fd2, msg, strlen(msg));
assert(nwritten == strlen(msg));
emscripten_console_logf("wrote message: %s (%d)", msg, nwritten);
char buf3[100] = {};
lseek(fd, 0, SEEK_SET);
nread = read(fd, buf3, 100);
assert(nread == 42);
assert(strcmp(buf3, msg2) == 0);
emscripten_console_logf("read message: %s (%d)", buf3, nread);
err = close(fd);
assert(err == 0);
err = close(fd2);
assert(err == 0);
fd = open("/opfs/working/foo.txt", O_RDONLY | O_TRUNC);
assert(fd > 0);
emscripten_console_log("truncated while opening read-only");
err = close(fd);
assert(err == 0);
err = stat("/opfs/working/foo.txt", &stat_buf);
assert(err == 0);
assert(stat_buf.st_size == 42);
emscripten_console_log("statted after failed truncation");
fd = open("/opfs/working/foo.txt", O_WRONLY | O_TRUNC);
assert(fd > 0);
emscripten_console_log("truncated while opening write-only");
err = close(fd);
assert(err == 0);
err = stat("/opfs/working/foo.txt", &stat_buf);
assert(err == 0);
assert(stat_buf.st_size == 0);
emscripten_console_log("statted after successful truncation");
err = rename("/opfs/working/foo.txt", "/opfs/foo.txt");
assert(err == 0);
err = access("/opfs/working/foo.txt", F_OK);
assert(err == -1);
err = access("/opfs/foo.txt", F_OK);
assert(err == 0);
emscripten_console_log("moved file");
err = unlink("/opfs/foo.txt");
assert(err == 0);
err = access("/opfs/foo.txt", F_OK);
assert(err == -1);
emscripten_console_log("removed OPFS file");
err = rmdir("/opfs/working");
assert(err == 0);
err = access("/opfs/working", F_OK);
assert(err == -1);
emscripten_console_log("removed OPFS directory");
emscripten_console_log("done");
#endif // !WASMFS_SETUP
}
void cleanup(void) {
printf("cleaning up\n");
unlink("/opfs/working/foo.txt");
rmdir("/opfs/working");
unlink("/opfs/foo.txt");
assert(access("/opfs/working/foo.txt", F_OK) != 0);
assert(access("/opfs/working", F_OK) != 0);
assert(access("/opfs/foo.txt", F_OK) != 0);
}