aboutsummaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorAnthony Pesch <inolen@gmail.com>2013-07-16 16:00:10 -0700
committerAnthony Pesch <inolen@gmail.com>2013-07-20 11:19:15 -0700
commit9c52c8a191c553f9c44d25c733b7b4d88aa47bfd (patch)
tree49d3295f87a79b1d284b0746faea99099b01e1f4 /tests
parent475e72dc5539d9c59fc267927441a502c14a178f (diff)
- added lchmod
- fixed up errno values for mknod - split up stat tests into test_stat, test_stat_chmod, test_stat_mknod
Diffstat (limited to 'tests')
-rwxr-xr-xtests/runner.py30
-rw-r--r--tests/stat/output.txt202
-rw-r--r--tests/stat/src.c242
-rw-r--r--tests/stat/test_chmod.c153
-rw-r--r--tests/stat/test_mknod.c96
-rw-r--r--tests/stat/test_stat.c167
6 files changed, 429 insertions, 461 deletions
diff --git a/tests/runner.py b/tests/runner.py
index 9e04c929..932d1eb5 100755
--- a/tests/runner.py
+++ b/tests/runner.py
@@ -6979,23 +6979,19 @@ def process(filename):
self.do_run(src, 'success', force_c=True)
def test_stat(self):
- add_pre_run = '''
-def process(filename):
- src = open(filename, 'r').read().replace(
- '// {{PRE_RUN_ADDITIONS}}',
- \'\'\'
- var f1 = FS.createFolder('/', 'test', true, true);
- var f2 = FS.createDataFile(f1, 'file', 'abcdef', true, true);
- var f3 = FS.createLink(f1, 'link', 'file', true, true);
- var f4 = FS.createDevice(f1, 'device', function(){}, function(){});
- f1.timestamp = f2.timestamp = f3.timestamp = f4.timestamp = new Date(1200000000000);
- \'\'\'
- )
- open(filename, 'w').write(src)
-'''
- src = open(path_from_root('tests', 'stat', 'src.c'), 'r').read()
- expected = open(path_from_root('tests', 'stat', 'output.txt'), 'r').read()
- self.do_run(src, expected, post_build=add_pre_run, extra_emscripten_args=['-H', 'libc/fcntl.h'])
+ Building.COMPILER_TEST_OPTS += ['-DUSE_OLD_FS='+str(Settings.USE_OLD_FS)]
+ src = open(path_from_root('tests', 'stat', 'test_stat.c'), 'r').read()
+ self.do_run(src, 'success', force_c=True)
+
+ def test_stat_chmod(self):
+ Building.COMPILER_TEST_OPTS += ['-DUSE_OLD_FS='+str(Settings.USE_OLD_FS)]
+ src = open(path_from_root('tests', 'stat', 'test_chmod.c'), 'r').read()
+ self.do_run(src, 'success', force_c=True)
+
+ def test_stat_mknod(self):
+ Building.COMPILER_TEST_OPTS += ['-DUSE_OLD_FS='+str(Settings.USE_OLD_FS)]
+ src = open(path_from_root('tests', 'stat', 'test_mknod.c'), 'r').read()
+ self.do_run(src, 'success', force_c=True)
def test_fcntl(self):
add_pre_run = '''
diff --git a/tests/stat/output.txt b/tests/stat/output.txt
deleted file mode 100644
index 1e6ae74e..00000000
--- a/tests/stat/output.txt
+++ /dev/null
@@ -1,202 +0,0 @@
---stat FOLDER--
-ret: 0
-errno: 0
-st_dev: 1
-st_ino: 2
-st_mode: 040777
-st_nlink: 1
-st_rdev: 0
-st_size: 4096
-st_atime: 1200000000
-st_mtime: 1200000000
-st_ctime: 1200000000
-st_blksize: 4096
-st_blocks: 1
-S_ISBLK: 0
-S_ISCHR: 0
-S_ISDIR: 1
-S_ISFIFO: 0
-S_ISREG: 0
-S_ISLNK: 0
-S_ISSOCK: 0
-
---stat FILE--
-ret: 0
-errno: 0
-st_dev: 1
-st_ino: 3
-st_mode: 0100777
-st_nlink: 1
-st_rdev: 0
-st_size: 6
-st_atime: 1200000000
-st_mtime: 1200000000
-st_ctime: 1200000000
-st_blksize: 4096
-st_blocks: 1
-S_ISBLK: 0
-S_ISCHR: 0
-S_ISDIR: 0
-S_ISFIFO: 0
-S_ISREG: 1
-S_ISLNK: 0
-S_ISSOCK: 0
-
---stat DEVICE--
-ret: 0
-errno: 0
-st_dev: 5
-st_ino: 5
-st_mode: 020777
-st_nlink: 1
-st_rdev: 5
-st_size: 0
-st_atime: 1200000000
-st_mtime: 1200000000
-st_ctime: 1200000000
-st_blksize: 4096
-st_blocks: 0
-S_ISBLK: 0
-S_ISCHR: 1
-S_ISDIR: 0
-S_ISFIFO: 0
-S_ISREG: 0
-S_ISLNK: 0
-S_ISSOCK: 0
-
---stat LINK--
-ret: 0
-errno: 0
-st_dev: 1
-st_ino: 3
-st_mode: 0100777
-st_nlink: 1
-st_rdev: 0
-st_size: 6
-st_atime: 1200000000
-st_mtime: 1200000000
-st_ctime: 1200000000
-st_blksize: 4096
-st_blocks: 1
-S_ISBLK: 0
-S_ISCHR: 0
-S_ISDIR: 0
-S_ISFIFO: 0
-S_ISREG: 1
-S_ISLNK: 0
-S_ISSOCK: 0
-
---lstat LINK--
-ret: 0
-errno: 0
-st_dev: 1
-st_ino: 4
-st_mode: 0120777
-st_nlink: 1
-st_rdev: 0
-st_size: 4
-st_atime: 1200000000
-st_mtime: 1200000000
-st_ctime: 1200000000
-st_blksize: 4096
-st_blocks: 1
-S_ISBLK: 0
-S_ISCHR: 0
-S_ISDIR: 0
-S_ISFIFO: 0
-S_ISREG: 0
-S_ISLNK: 1
-S_ISSOCK: 0
-
---fstat FILE--
-ret: 0
-errno: 0
-st_dev: 1
-st_ino: 3
-st_mode: 0100777
-st_nlink: 1
-st_rdev: 0
-st_size: 6
-st_atime: 1200000000
-st_mtime: 1200000000
-st_ctime: 1200000000
-st_blksize: 4096
-st_blocks: 1
-S_ISBLK: 0
-S_ISCHR: 0
-S_ISDIR: 0
-S_ISFIFO: 0
-S_ISREG: 1
-S_ISLNK: 0
-S_ISSOCK: 0
-
---chmod FILE--
-ret: 0
-errno: 0
-st_mode: 0100222
-st_mtime changed: 1
-
---fchmod FILE--
-ret: 0
-errno: 0
-st_mode: 0100777
-st_mtime changed: 1
-
---chmod FOLDER--
-ret: 0
-errno: 0
-st_mode: 040555
-st_mtime changed: 1
-
---chmod LINK--
-ret: 0
-errno: 0
-st_mode: 0100000
-
---mkdir--
-ret: 0
-errno: 0
-st_mode: 040777
-S_ISBLK: 0
-S_ISCHR: 0
-S_ISDIR: 1
-S_ISFIFO: 0
-S_ISREG: 0
-S_ISLNK: 0
-S_ISSOCK: 0
-
---mknod FILE--
-ret: 0
-errno: 0
-st_mode: 0100777
-S_ISBLK: 0
-S_ISCHR: 0
-S_ISDIR: 0
-S_ISFIFO: 0
-S_ISREG: 1
-S_ISLNK: 0
-S_ISSOCK: 0
-
---mknod FOLDER--
-ret: 0
-errno: 0
-st_mode: 040777
-S_ISBLK: 0
-S_ISCHR: 0
-S_ISDIR: 1
-S_ISFIFO: 0
-S_ISREG: 0
-S_ISLNK: 0
-S_ISSOCK: 0
-
---mknod FIFO--
-ret: -1
-errno: 22
-
---mknod DEVICE--
-ret: -1
-errno: 22
-
---mkfifo--
-ret: -1
-errno: 30
diff --git a/tests/stat/src.c b/tests/stat/src.c
deleted file mode 100644
index dc5a0198..00000000
--- a/tests/stat/src.c
+++ /dev/null
@@ -1,242 +0,0 @@
-/*
-Note: Hardcoded st_ino values etc. may change with minor changes to the library impl.
- In such an event, we will need to update output.txt here.
-*/
-
-#include <stdio.h>
-#include <string.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <sys/stat.h>
-
-int main() {
- struct stat s;
-
- printf("--stat FOLDER--\n");
- printf("ret: %d\n", stat("/test", &s));
- printf("errno: %d\n", errno);
- printf("st_dev: %lu\n", s.st_dev);
- printf("st_ino: %lu\n", s.st_ino);
- printf("st_mode: 0%o\n", s.st_mode);
- printf("st_nlink: %d\n", s.st_nlink);
- printf("st_rdev: %lu\n", s.st_rdev);
- printf("st_size: %ld\n", s.st_size);
- printf("st_atime: %ld\n", s.st_atime);
- printf("st_mtime: %ld\n", s.st_mtime);
- printf("st_ctime: %ld\n", s.st_ctime);
- printf("st_blksize: %ld\n", s.st_blksize);
- printf("st_blocks: %ld\n", s.st_blocks);
- printf("S_ISBLK: %d\n", S_ISBLK(s.st_mode));
- printf("S_ISCHR: %d\n", S_ISCHR(s.st_mode));
- printf("S_ISDIR: %d\n", S_ISDIR(s.st_mode));
- printf("S_ISFIFO: %d\n", S_ISFIFO(s.st_mode));
- printf("S_ISREG: %d\n", S_ISREG(s.st_mode));
- printf("S_ISLNK: %d\n", S_ISLNK(s.st_mode));
- printf("S_ISSOCK: %d\n", S_ISSOCK(s.st_mode));
- memset(&s, 0, sizeof s);
-
- printf("\n--stat FILE--\n");
- printf("ret: %d\n", stat("/test/file", &s));
- printf("errno: %d\n", errno);
- printf("st_dev: %lu\n", s.st_dev);
- printf("st_ino: %lu\n", s.st_ino);
- printf("st_mode: 0%o\n", s.st_mode);
- printf("st_nlink: %d\n", s.st_nlink);
- printf("st_rdev: %lu\n", s.st_rdev);
- printf("st_size: %ld\n", s.st_size);
- printf("st_atime: %ld\n", s.st_atime);
- printf("st_mtime: %ld\n", s.st_mtime);
- printf("st_ctime: %ld\n", s.st_ctime);
- printf("st_blksize: %ld\n", s.st_blksize);
- printf("st_blocks: %ld\n", s.st_blocks);
- printf("S_ISBLK: %d\n", S_ISBLK(s.st_mode));
- printf("S_ISCHR: %d\n", S_ISCHR(s.st_mode));
- printf("S_ISDIR: %d\n", S_ISDIR(s.st_mode));
- printf("S_ISFIFO: %d\n", S_ISFIFO(s.st_mode));
- printf("S_ISREG: %d\n", S_ISREG(s.st_mode));
- printf("S_ISLNK: %d\n", S_ISLNK(s.st_mode));
- printf("S_ISSOCK: %d\n", S_ISSOCK(s.st_mode));
- memset(&s, 0, sizeof s);
-
- printf("\n--stat DEVICE--\n");
- printf("ret: %d\n", stat("/test/device", &s));
- printf("errno: %d\n", errno);
- printf("st_dev: %lu\n", s.st_dev);
- printf("st_ino: %lu\n", s.st_ino);
- printf("st_mode: 0%o\n", s.st_mode);
- printf("st_nlink: %d\n", s.st_nlink);
- printf("st_rdev: %lu\n", s.st_rdev);
- printf("st_size: %ld\n", s.st_size);
- printf("st_atime: %ld\n", s.st_atime);
- printf("st_mtime: %ld\n", s.st_mtime);
- printf("st_ctime: %ld\n", s.st_ctime);
- printf("st_blksize: %ld\n", s.st_blksize);
- printf("st_blocks: %ld\n", s.st_blocks);
- printf("S_ISBLK: %d\n", S_ISBLK(s.st_mode));
- printf("S_ISCHR: %d\n", S_ISCHR(s.st_mode));
- printf("S_ISDIR: %d\n", S_ISDIR(s.st_mode));
- printf("S_ISFIFO: %d\n", S_ISFIFO(s.st_mode));
- printf("S_ISREG: %d\n", S_ISREG(s.st_mode));
- printf("S_ISLNK: %d\n", S_ISLNK(s.st_mode));
- printf("S_ISSOCK: %d\n", S_ISSOCK(s.st_mode));
- memset(&s, 0, sizeof s);
-
- printf("\n--stat LINK--\n");
- printf("ret: %d\n", stat("/test/link", &s));
- printf("errno: %d\n", errno);
- printf("st_dev: %lu\n", s.st_dev);
- printf("st_ino: %lu\n", s.st_ino);
- printf("st_mode: 0%o\n", s.st_mode);
- printf("st_nlink: %d\n", s.st_nlink);
- printf("st_rdev: %lu\n", s.st_rdev);
- printf("st_size: %ld\n", s.st_size);
- printf("st_atime: %ld\n", s.st_atime);
- printf("st_mtime: %ld\n", s.st_mtime);
- printf("st_ctime: %ld\n", s.st_ctime);
- printf("st_blksize: %ld\n", s.st_blksize);
- printf("st_blocks: %ld\n", s.st_blocks);
- printf("S_ISBLK: %d\n", S_ISBLK(s.st_mode));
- printf("S_ISCHR: %d\n", S_ISCHR(s.st_mode));
- printf("S_ISDIR: %d\n", S_ISDIR(s.st_mode));
- printf("S_ISFIFO: %d\n", S_ISFIFO(s.st_mode));
- printf("S_ISREG: %d\n", S_ISREG(s.st_mode));
- printf("S_ISLNK: %d\n", S_ISLNK(s.st_mode));
- printf("S_ISSOCK: %d\n", S_ISSOCK(s.st_mode));
- memset(&s, 0, sizeof s);
-
- printf("\n--lstat LINK--\n");
- printf("ret: %d\n", lstat("/test/link", &s));
- printf("errno: %d\n", errno);
- printf("st_dev: %lu\n", s.st_dev);
- printf("st_ino: %lu\n", s.st_ino);
- printf("st_mode: 0%o\n", s.st_mode);
- printf("st_nlink: %d\n", s.st_nlink);
- printf("st_rdev: %lu\n", s.st_rdev);
- printf("st_size: %ld\n", s.st_size);
- printf("st_atime: %ld\n", s.st_atime);
- printf("st_mtime: %ld\n", s.st_mtime);
- printf("st_ctime: %ld\n", s.st_ctime);
- printf("st_blksize: %ld\n", s.st_blksize);
- printf("st_blocks: %ld\n", s.st_blocks);
- printf("S_ISBLK: %d\n", S_ISBLK(s.st_mode));
- printf("S_ISCHR: %d\n", S_ISCHR(s.st_mode));
- printf("S_ISDIR: %d\n", S_ISDIR(s.st_mode));
- printf("S_ISFIFO: %d\n", S_ISFIFO(s.st_mode));
- printf("S_ISREG: %d\n", S_ISREG(s.st_mode));
- printf("S_ISLNK: %d\n", S_ISLNK(s.st_mode));
- printf("S_ISSOCK: %d\n", S_ISSOCK(s.st_mode));
- memset(&s, 0, sizeof s);
-
- printf("\n--fstat FILE--\n");
- printf("ret: %d\n", fstat(open("/test/file", O_RDONLY, 0777), &s));
- printf("errno: %d\n", errno);
- printf("st_dev: %lu\n", s.st_dev);
- printf("st_ino: %lu\n", s.st_ino);
- printf("st_mode: 0%o\n", s.st_mode);
- printf("st_nlink: %d\n", s.st_nlink);
- printf("st_rdev: %lu\n", s.st_rdev);
- printf("st_size: %ld\n", s.st_size);
- printf("st_atime: %ld\n", s.st_atime);
- printf("st_mtime: %ld\n", s.st_mtime);
- printf("st_ctime: %ld\n", s.st_ctime);
- printf("st_blksize: %ld\n", s.st_blksize);
- printf("st_blocks: %ld\n", s.st_blocks);
- printf("S_ISBLK: %d\n", S_ISBLK(s.st_mode));
- printf("S_ISCHR: %d\n", S_ISCHR(s.st_mode));
- printf("S_ISDIR: %d\n", S_ISDIR(s.st_mode));
- printf("S_ISFIFO: %d\n", S_ISFIFO(s.st_mode));
- printf("S_ISREG: %d\n", S_ISREG(s.st_mode));
- printf("S_ISLNK: %d\n", S_ISLNK(s.st_mode));
- printf("S_ISSOCK: %d\n", S_ISSOCK(s.st_mode));
- memset(&s, 0, sizeof s);
-
- printf("\n--chmod FILE--\n");
- printf("ret: %d\n", chmod("/test/file", 0200));
- printf("errno: %d\n", errno);
- stat("/test/file", &s);
- printf("st_mode: 0%o\n", s.st_mode);
- printf("st_mtime changed: %d\n", s.st_mtime != 1200000000l);
- memset(&s, 0, sizeof s);
-
- printf("\n--fchmod FILE--\n");
- printf("ret: %d\n", fchmod(open("/test/file", O_WRONLY, 0777), 0777));
- printf("errno: %d\n", errno);
- stat("/test/file", &s);
- printf("st_mode: 0%o\n", s.st_mode);
- printf("st_mtime changed: %d\n", s.st_mtime != 1200000000l);
- memset(&s, 0, sizeof s);
-
- printf("\n--chmod FOLDER--\n");
- printf("ret: %d\n", chmod("/test", 0400));
- printf("errno: %d\n", errno);
- stat("/test", &s);
- printf("st_mode: 0%o\n", s.st_mode);
- printf("st_mtime changed: %d\n", s.st_mtime != 1200000000l);
- memset(&s, 0, sizeof s);
-
- printf("\n--chmod LINK--\n");
- printf("ret: %d\n", chmod("/test/link", 0000));
- printf("errno: %d\n", errno);
- stat("/test/file", &s);
- printf("st_mode: 0%o\n", s.st_mode);
- memset(&s, 0, sizeof s);
-
- // Make sure we can create stuff in the root.
- chmod("/", 0777);
-
- printf("\n--mkdir--\n");
- printf("ret: %d\n", mkdir("/test-mkdir", 0777));
- printf("errno: %d\n", errno);
- stat("/test-mkdir", &s);
- printf("st_mode: 0%o\n", s.st_mode);
- printf("S_ISBLK: %d\n", S_ISBLK(s.st_mode));
- printf("S_ISCHR: %d\n", S_ISCHR(s.st_mode));
- printf("S_ISDIR: %d\n", S_ISDIR(s.st_mode));
- printf("S_ISFIFO: %d\n", S_ISFIFO(s.st_mode));
- printf("S_ISREG: %d\n", S_ISREG(s.st_mode));
- printf("S_ISLNK: %d\n", S_ISLNK(s.st_mode));
- printf("S_ISSOCK: %d\n", S_ISSOCK(s.st_mode));
- memset(&s, 0, sizeof s);
-
- printf("\n--mknod FILE--\n");
- printf("ret: %d\n", mknod("/test-mknod-file", S_IFREG | 0777, 0));
- printf("errno: %d\n", errno);
- stat("/test-mknod-file", &s);
- printf("st_mode: 0%o\n", s.st_mode);
- printf("S_ISBLK: %d\n", S_ISBLK(s.st_mode));
- printf("S_ISCHR: %d\n", S_ISCHR(s.st_mode));
- printf("S_ISDIR: %d\n", S_ISDIR(s.st_mode));
- printf("S_ISFIFO: %d\n", S_ISFIFO(s.st_mode));
- printf("S_ISREG: %d\n", S_ISREG(s.st_mode));
- printf("S_ISLNK: %d\n", S_ISLNK(s.st_mode));
- printf("S_ISSOCK: %d\n", S_ISSOCK(s.st_mode));
- memset(&s, 0, sizeof s);
-
- printf("\n--mknod FOLDER--\n");
- printf("ret: %d\n", mknod("/test-mknod-dir", S_IFDIR | 0777, 0));
- printf("errno: %d\n", errno);
- stat("/test-mknod-dir", &s);
- printf("st_mode: 0%o\n", s.st_mode);
- printf("S_ISBLK: %d\n", S_ISBLK(s.st_mode));
- printf("S_ISCHR: %d\n", S_ISCHR(s.st_mode));
- printf("S_ISDIR: %d\n", S_ISDIR(s.st_mode));
- printf("S_ISFIFO: %d\n", S_ISFIFO(s.st_mode));
- printf("S_ISREG: %d\n", S_ISREG(s.st_mode));
- printf("S_ISLNK: %d\n", S_ISLNK(s.st_mode));
- printf("S_ISSOCK: %d\n", S_ISSOCK(s.st_mode));
- memset(&s, 0, sizeof s);
-
- printf("\n--mknod FIFO--\n");
- printf("ret: %d\n", mknod("/test-mknod-fifo", S_IFIFO | 0777, 0));
- printf("errno: %d\n", errno);
-
- printf("\n--mknod DEVICE--\n");
- printf("ret: %d\n", mknod("/test-mknod-device", S_IFCHR | 0777, 123));
- printf("errno: %d\n", errno);
-
- printf("\n--mkfifo--\n");
- printf("ret: %d\n", mkfifo("/test-mkfifo", 0777));
- printf("errno: %d\n", errno);
-
- return 0;
-}
diff --git a/tests/stat/test_chmod.c b/tests/stat/test_chmod.c
new file mode 100644
index 00000000..94e6c12b
--- /dev/null
+++ b/tests/stat/test_chmod.c
@@ -0,0 +1,153 @@
+#include <assert.h>
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <utime.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+void create_file(const char *path, const char *buffer, int mode) {
+ int fd = open(path, O_WRONLY | O_CREAT | O_EXCL, mode);
+ assert(fd >= 0);
+
+ int err = write(fd, buffer, sizeof(char) * strlen(buffer));
+ assert(err == (sizeof(char) * strlen(buffer)));
+
+ close(fd);
+}
+
+void setup() {
+ create_file("file", "abcdef", 0777);
+ symlink("file", "file-link");
+ // some platforms use 777, some use 755 by default for symlinks
+ // make sure we're using 777 for the test
+ lchmod("file-link", 0777);
+ mkdir("folder", 0777);
+}
+
+void cleanup() {
+ unlink("file-link");
+ unlink("file");
+ rmdir("folder");
+}
+
+void test() {
+ int err;
+ int lastctime;
+ struct stat s;
+
+ //
+ // chmod a file
+ //
+ // get the current ctime for the file
+ memset(&s, 0, sizeof s);
+ stat("file", &s);
+ lastctime = s.st_ctime;
+ sleep(1);
+
+ // do the actual chmod
+ err = chmod("file", 0200);
+ assert(!err);
+
+ memset(&s, 0, sizeof s);
+ stat("file", &s);
+#if USE_OLD_FS
+ assert(s.st_mode == (0222 | S_IFREG));
+#else
+ assert(s.st_mode == (0200 | S_IFREG));
+#endif
+ assert(s.st_ctime != lastctime);
+
+ //
+ // fchmod a file
+ //
+ lastctime = s.st_ctime;
+ sleep(1);
+
+ err = fchmod(open("file", O_WRONLY), 0100);
+ assert(!err);
+
+ memset(&s, 0, sizeof s);
+ stat("file", &s);
+#if USE_OLD_FS
+ assert(s.st_mode == (0000 | S_IFREG));
+#else
+ assert(s.st_mode == (0100 | S_IFREG));
+#endif
+ assert(s.st_ctime != lastctime);
+
+ //
+ // chmod a folder
+ //
+ // get the current ctime for the folder
+ memset(&s, 0, sizeof s);
+ stat("folder", &s);
+ lastctime = s.st_ctime;
+ sleep(1);
+
+ // do the actual chmod
+ err = chmod("folder", 0300);
+ assert(!err);
+ memset(&s, 0, sizeof s);
+ stat("folder", &s);
+#if USE_OLD_FS
+ assert(s.st_mode == (0222 | S_IFDIR));
+#else
+ assert(s.st_mode == (0300 | S_IFDIR));
+#endif
+ assert(s.st_ctime != lastctime);
+
+ //
+ // chmod a symlink's target
+ //
+ err = chmod("file-link", 0400);
+ assert(!err);
+
+ // make sure the file it references changed
+ stat("file-link", &s);
+#if USE_OLD_FS
+ assert(s.st_mode == (0555 | S_IFREG));
+#else
+ assert(s.st_mode == (0400 | S_IFREG));
+#endif
+
+ // but the link didn't
+ lstat("file-link", &s);
+ assert(s.st_mode == (0777 | S_IFLNK));
+
+ //
+ // chmod the actual symlink
+ //
+ err = lchmod("file-link", 0500);
+ assert(!err);
+
+ // make sure the file it references didn't change
+ stat("file-link", &s);
+#if USE_OLD_FS
+ assert(s.st_mode == (0555 | S_IFREG));
+#else
+ assert(s.st_mode == (0400 | S_IFREG));
+#endif
+
+ // but the link did
+ lstat("file-link", &s);
+#if USE_OLD_FS
+ assert(s.st_mode == (0555 | S_IFLNK));
+#else
+ assert(s.st_mode == (0500 | S_IFLNK));
+#endif
+
+ puts("success");
+}
+
+int main() {
+ atexit(cleanup);
+ signal(SIGABRT, cleanup);
+ setup();
+ test();
+ return EXIT_SUCCESS;
+} \ No newline at end of file
diff --git a/tests/stat/test_mknod.c b/tests/stat/test_mknod.c
new file mode 100644
index 00000000..4cff57d9
--- /dev/null
+++ b/tests/stat/test_mknod.c
@@ -0,0 +1,96 @@
+#include <assert.h>
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <utime.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+void setup() {
+ mkdir("folder-readonly", 0555);
+}
+
+void cleanup() {
+ unlink("mknod-file");
+ unlink("mknod-device");
+ rmdir("folder");
+ rmdir("folder-readonly");
+}
+
+void test() {
+ int err;
+ struct stat s;
+
+ //
+ // mknod
+ // mknod is _extremely_ unportable for anything other
+ // than a FIFO. so, the tests are disabled when running
+ // natively as they'd be utterly inconsistent.
+ //
+#if EMSCRIPTEN
+
+ // mknod a folder
+ err = mknod("mknod-folder", S_IFDIR | 0777, 0);
+ assert(err);
+ assert(errno == EINVAL);
+
+ // mknod fifo
+ err = mknod("mknod-fifo", S_IFIFO | 0777, 0);
+ assert(err);
+ assert(errno == EPERM);
+
+ // mknod a file
+ err = mknod("mknod-file", S_IFREG | 0777, 0);
+ assert(!err);
+ memset(&s, 0, sizeof s);
+ stat("mknod-file", &s);
+ assert(S_ISREG(s.st_mode));
+
+ // mknod a character device
+ err = mknod("mknod-device", S_IFCHR | 0777, 123);
+#if USE_OLD_FS
+ assert(err);
+ assert(errno == EPERM);
+#else
+ assert(!err);
+ memset(&s, 0, sizeof s);
+ stat("mknod-device", &s);
+ assert(S_ISCHR(s.st_mode));
+#endif
+
+#endif
+
+ //
+ // mkdir
+ //
+ // can't mkdir in a readonly dir
+ err = mkdir("folder-readonly/subfolder", 0777);
+ assert(err);
+ assert(errno == EACCES);
+
+ // regular creation
+ err = mkdir("folder", 0777);
+ assert(!err);
+ memset(&s, 0, sizeof s);
+ stat("folder", &s);
+ assert(S_ISDIR(s.st_mode));
+
+ // try to re-create the same folder
+ err = mkdir("folder", 0777);
+ assert(err);
+ assert(errno == EEXIST);
+
+ puts("success");
+}
+
+int main() {
+ atexit(cleanup);
+ signal(SIGABRT, cleanup);
+ setup();
+ test();
+ return EXIT_SUCCESS;
+} \ No newline at end of file
diff --git a/tests/stat/test_stat.c b/tests/stat/test_stat.c
new file mode 100644
index 00000000..14e88370
--- /dev/null
+++ b/tests/stat/test_stat.c
@@ -0,0 +1,167 @@
+#include <assert.h>
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <utime.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+void create_file(const char *path, const char *buffer, int mode) {
+ int fd = open(path, O_WRONLY | O_CREAT | O_EXCL, mode);
+ assert(fd >= 0);
+
+ int err = write(fd, buffer, sizeof(char) * strlen(buffer));
+ assert(err == (sizeof(char) * strlen(buffer)));
+
+ close(fd);
+}
+
+void setup() {
+ struct utimbuf t = {1200000000, 1200000000};
+
+ mkdir("folder", 0777);
+ create_file("folder/file", "abcdef", 0777);
+ symlink("file", "folder/file-link");
+
+ utime("folder/file", &t);
+ utime("folder", &t);
+}
+
+void cleanup() {
+ unlink("folder/file");
+ unlink("folder/file-link");
+ rmdir("folder");
+}
+
+void test() {
+ int err;
+ struct stat s;
+
+ // stat a folder
+ memset(&s, 0, sizeof(s));
+ err = stat("folder", &s);
+ assert(!err);
+ assert(s.st_dev);
+ assert(s.st_ino);
+ assert(S_ISDIR(s.st_mode));
+ assert(s.st_nlink);
+ assert(s.st_rdev == 0);
+ assert(s.st_size);
+ assert(s.st_atime == 1200000000);
+ assert(s.st_mtime == 1200000000);
+ assert(s.st_ctime);
+#ifdef EMSCRIPTEN
+ assert(s.st_blksize == 4096);
+ assert(s.st_blocks == 1);
+#endif
+
+ // stat a file
+ memset(&s, 0, sizeof(s));
+ err = stat("folder/file", &s);
+ assert(!err);
+ assert(s.st_dev);
+ assert(s.st_ino);
+ assert(S_ISREG(s.st_mode));
+ assert(s.st_nlink);
+ assert(s.st_rdev == 0);
+ assert(s.st_size == 6);
+ assert(s.st_atime == 1200000000);
+ assert(s.st_mtime == 1200000000);
+ assert(s.st_ctime);
+#if EMSCRIPTEN
+ assert(s.st_blksize == 4096);
+ assert(s.st_blocks == 1);
+#endif
+
+ // fstat a file (should match file stat from above)
+ memset(&s, 0, sizeof(s));
+ err = fstat(open("folder/file", O_RDONLY), &s);
+ assert(!err);
+ assert(s.st_dev);
+ assert(s.st_ino);
+ assert(S_ISREG(s.st_mode));
+ assert(s.st_nlink);
+ assert(s.st_rdev == 0);
+ assert(s.st_size == 6);
+ assert(s.st_atime == 1200000000);
+ assert(s.st_mtime == 1200000000);
+ assert(s.st_ctime);
+#if EMSCRIPTEN
+ assert(s.st_blksize == 4096);
+ assert(s.st_blocks == 1);
+#endif
+
+ // stat a device
+ memset(&s, 0, sizeof(s));
+ err = stat("/dev/null", &s);
+ assert(!err);
+ assert(s.st_dev);
+ assert(s.st_ino);
+ assert(S_ISCHR(s.st_mode));
+ assert(s.st_nlink);
+#if !USE_OLD_FS
+ // old FS doesn't store proper device ids
+#ifndef __APPLE__
+ // mac uses makedev(3, 2) for /dev/null
+ assert(s.st_rdev == makedev(1, 3));
+#endif
+#endif
+ assert(!s.st_size);
+ assert(s.st_atime);
+ assert(s.st_mtime);
+ assert(s.st_ctime);
+#if EMSCRIPTEN
+ assert(s.st_blksize == 4096);
+ assert(s.st_blocks == 0);
+#endif
+
+ // stat a link (should match the file stat from above)
+ memset(&s, 0, sizeof(s));
+ err = stat("folder/file-link", &s);
+ assert(!err);
+ assert(s.st_dev);
+ assert(s.st_ino);
+ assert(S_ISREG(s.st_mode));
+ assert(s.st_nlink);
+ assert(s.st_rdev == 0);
+ assert(s.st_size == 6);
+ assert(s.st_atime == 1200000000);
+ assert(s.st_mtime == 1200000000);
+ assert(s.st_ctime);
+#if EMSCRIPTEN
+ assert(s.st_blksize == 4096);
+ assert(s.st_blocks == 1);
+#endif
+
+ // lstat a link (should NOT match the file stat from above)
+ memset(&s, 0, sizeof(s));
+ err = lstat("folder/file-link", &s);
+ assert(!err);
+ assert(s.st_dev);
+ assert(s.st_ino);
+ assert(S_ISLNK(s.st_mode));
+ assert(s.st_nlink);
+ assert(s.st_rdev == 0);
+ assert(s.st_size == 4); // strlen("file")
+ assert(s.st_atime != 1200000000); // should NOT match the utime call we did for dir/file
+ assert(s.st_mtime != 1200000000);
+ assert(s.st_ctime);
+#if EMSCRIPTEN
+ assert(s.st_blksize == 4096);
+ assert(s.st_blocks == 1);
+#endif
+
+ puts("success");
+}
+
+int main() {
+ atexit(cleanup);
+ signal(SIGABRT, cleanup);
+ setup();
+ test();
+ return EXIT_SUCCESS;
+} \ No newline at end of file