#include "common.h"
#include <dirent.h>
#include <sys/stat.h>
#include <sys/mount.h>
#include <fcntl.h>
#include <time.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <limits.h>
#include <xos/io.h>
#define STOP_ON_ERROR 1
#define abs(n) ((n) < 0 ? -(n) : (n))
int main()
{
int fd;
struct stat statbuf;
time_t t;
char buf[256];
int n;
DIR *dir;
struct dirent *dent;
TEST(mount(NULL, "/floppy/empty", "ramfs", 0, NULL), 0);
NEWLINE();
TEST(mkdir("/floppy/empty/dir2", 0), 0);
TEST(mkdir("/floppy/empty/dir1/", 0), 0);
TEST(mkdir("/floppy/empty/dir3", 0), 0);
TEST(mkdir("/floppy/empty/dir1", 0), EEXIST);
TEST(mkdir("/floppy/empty/dir2/dir4", 0), 0);
TEST(rmdir("/floppy/empty/dir2"), ENOTEMPTY);
TEST(rmdir("/floppy/empty/dir2/dir4"), 0);
TEST(rmdir("/floppy/empty/dir2"), 0);
TEST(rmdir("/floppy/empty/dir3"), 0);
TEST(rmdir("/floppy/empty/dir3"), ENOENT);
TEST(mkdir("/floppy/empty/dir1/dir2", 0), 0);
TEST(mkdir("/floppy/empty/dir1/dir2/dir3", 0), 0);
NEWLINE();
fd = TEST(open("/floppy/empty/dir1/dir2/file1", O_WRONLY | O_CREAT, 0), 0);
t = time(NULL);
TEST(write(fd, "Hello world!\n", 13), 0);
TEST(close(fd), 0);
TEST(stat("/floppy/empty/dir1/dir2/file1", &statbuf), 0);
ASSERT(statbuf.st_dev == _XOS_DEV_NONE);
ASSERT(S_ISREG(statbuf.st_mode));
ASSERT(statbuf.st_rdev == _XOS_DEV_NONE);
ASSERT(statbuf.st_size == 13);
ASSERT(abs(statbuf.st_mtime - t) <= time(NULL) - t);
NEWLINE();
fd = TEST(open("/floppy/empty/dir1/dir2/file2", O_CREAT, 0), 0);
TEST(close(fd), 0);
NEWLINE();
sleep(2);
TEST(rename("/floppy/empty/dir1/dir2/file1", "/floppy/empty/dir1/dir2/file1"), 0);
TEST(rename("/floppy/empty/dir1/dir2/file1", "/floppy/empty/dir1/dir2/file3"), 0);
TEST(rename("/floppy/empty/dir1/dir2/file3", "/floppy/empty/dir1/dir2"), EEXIST);
TEST(rename("/floppy/empty/dir1/dir2/file3", "/floppy/empty/dir1/dir2/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"), 0);
TEST(rename("/floppy/empty/dir1/dir2/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "/floppy/empty/dir1/file4"), 0);
fd = TEST(open("/floppy/empty/dir1/file4", O_RDONLY, 0), 0);
n = TEST(read(fd, buf, 256), 0);
ASSERT(n == 13);
ASSERT(!memcmp(buf, "Hello world!\n", n));
TEST(close(fd), 0);
TEST(stat("/floppy/empty/dir1/file4", &statbuf), 0);
ASSERT(statbuf.st_dev == _XOS_DEV_NONE);
ASSERT(S_ISREG(statbuf.st_mode));
ASSERT(statbuf.st_rdev == _XOS_DEV_NONE);
ASSERT(statbuf.st_size == 13);
ASSERT(abs(statbuf.st_mtime - t) <= time(NULL) - t);
TEST(stat("/floppy/empty/dir1/dir2", &statbuf), 0);
ASSERT(statbuf.st_dev == _XOS_DEV_NONE);
ASSERT(S_ISDIR(statbuf.st_mode));
ASSERT(statbuf.st_rdev == _XOS_DEV_NONE);
ASSERT(statbuf.st_size == 0);
ASSERT(abs(statbuf.st_mtime - t) >= 2);
NEWLINE();
fd = TEST(open("/floppy/empty/big_file", O_RDWR | O_CREAT, 0), 0);
TEST(lseek(fd, getpagesize() - 3, SEEK_SET), 0);
n = TEST(write(fd, "Hello world!\n", 13), 0);
ASSERT(n == 13);
TEST(lseek(fd, getpagesize() - 6, SEEK_SET), 0);
n = TEST(read(fd, buf, 256), 0);
ASSERT(n == 16);
ASSERT(!memcmp(buf, "\0\0\0Hello world!\n", n));
close(fd);
TEST(stat("/floppy/empty/big_file", &statbuf), 0);
ASSERT(statbuf.st_size == getpagesize() + 10);
NEWLINE();
fd = TEST(open("/floppy/empty/very_big_file", O_RDWR | O_CREAT, 0), 0);
n = TEST(write(fd, "L'homme et la mer", 17), 0);
ASSERT(n == 17);
TEST(lseek(fd, LONG_MAX - 42, SEEK_SET), 0);
n = TEST(write(fd, "Homme libre, toujours tu cheriras la mer !\n", 43), 0);
ASSERT(n == 42);
TEST(lseek(fd, getpagesize() / sizeof (void *) * getpagesize() - 10, SEEK_SET), 0);
n = TEST(write(fd, "La mer est ton miroir ; tu contemples ton ame", 45), 0);
ASSERT(n == 45);
TEST(lseek(fd, getpagesize() + 3, SEEK_SET), 0);
n = TEST(write(fd, "Dans le deroulement infini de sa lame,", 38), 0);
ASSERT(n == 38);
TEST(lseek(fd, 0, SEEK_SET), 0);
n = TEST(read(fd, buf, 20), 0);
ASSERT(n == 20);
ASSERT(!memcmp(buf, "L'homme et la mer\0\0\0", n));
TEST(lseek(fd, LONG_MAX - 45, SEEK_SET), 0);
n = TEST(read(fd, buf, 256), 0);
ASSERT(n == 45);
ASSERT(!memcmp(buf, "\0\0\0Homme libre, toujours tu cheriras la mer !", n));
TEST(lseek(fd, getpagesize() / sizeof (void *) * getpagesize() - 13, SEEK_SET), 0);
n = TEST(read(fd, buf, 51), 0);
ASSERT(n == 51);
ASSERT(!memcmp(buf, "\0\0\0La mer est ton miroir ; tu contemples ton ame\0\0\0", n));
TEST(lseek(fd, getpagesize() - 3, SEEK_SET), 0);
n = TEST(read(fd, buf, 44), 0);
ASSERT(n == 44);
ASSERT(!memcmp(buf, "\0\0\0\0\0\0Dans le deroulement infini de sa lame,", n));
close(fd);
TEST(stat("/floppy/empty/very_big_file", &statbuf), 0);
ASSERT(statbuf.st_size == LONG_MAX);
NEWLINE();
dir = TEST_PTR(opendir("/floppy/empty"), 0);
errno = 0;
dent = TEST_PTR(readdir(dir), 0);
ASSERT(!strcmp(dent->d_name, "."));
errno = 0;
dent = TEST_PTR(readdir(dir), 0);
ASSERT(!strcmp(dent->d_name, ".."));
errno = 0;
dent = TEST_PTR(readdir(dir), 0);
ASSERT(!strcmp(dent->d_name, "dir1"));
errno = 0;
dent = TEST_PTR(readdir(dir), 0);
ASSERT(!strcmp(dent->d_name, "big_file"));
errno = 0;
dent = TEST_PTR(readdir(dir), 0);
ASSERT(!strcmp(dent->d_name, "very_big_file"));
errno = 0;
dent = TEST_PTR(readdir(dir), 0);
ASSERT(!dent);
TEST(closedir(dir), 0);
NEWLINE();
dir = TEST_PTR(opendir("/floppy/empty/dir1"), 0);
errno = 0;
dent = TEST_PTR(readdir(dir), 0);
ASSERT(!strcmp(dent->d_name, "."));
errno = 0;
dent = TEST_PTR(readdir(dir), 0);
ASSERT(!strcmp(dent->d_name, ".."));
errno = 0;
dent = TEST_PTR(readdir(dir), 0);
ASSERT(!strcmp(dent->d_name, "dir2"));
errno = 0;
dent = TEST_PTR(readdir(dir), 0);
ASSERT(!strcmp(dent->d_name, "file4"));
errno = 0;
dent = TEST_PTR(readdir(dir), 0);
ASSERT(!dent);
TEST(closedir(dir), 0);
NEWLINE();
dir = TEST_PTR(opendir("/floppy/empty/dir1/dir2"), 0);
errno = 0;
dent = TEST_PTR(readdir(dir), 0);
ASSERT(!strcmp(dent->d_name, "."));
errno = 0;
dent = TEST_PTR(readdir(dir), 0);
ASSERT(!strcmp(dent->d_name, ".."));
errno = 0;
dent = TEST_PTR(readdir(dir), 0);
ASSERT(!strcmp(dent->d_name, "dir3"));
errno = 0;
dent = TEST_PTR(readdir(dir), 0);
ASSERT(!strcmp(dent->d_name, "file2"));
errno = 0;
dent = TEST_PTR(readdir(dir), 0);
ASSERT(!dent);
TEST(closedir(dir), 0);
NEWLINE();
TEST(unlink("/floppy/empty/dir1/dir2/file2"), 0);
TEST(rmdir("/floppy/empty/dir1/dir2/dir3"), 0);
TEST(rmdir("/floppy/empty/dir1/dir2"), 0);
TEST(rmdir("/floppy/empty/dir1"), ENOTEMPTY);
TEST(unlink("/floppy/empty/dir1/file4"), 0);
TEST(rmdir("/floppy/empty/dir1"), 0);
NEWLINE();
TEST(umount("/floppy/empty"), 0);
return status ? EXIT_SUCCESS : EXIT_FAILURE;
}