aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormax99x <max99x@gmail.com>2011-07-20 10:20:09 +0300
committermax99x <max99x@gmail.com>2011-07-21 02:48:24 +0300
commit10ca04685b6e0ec0e8089fbe859e0085d8020622 (patch)
treee256b40bfbf8324e73c977b82c36cc4a227f7be5
parent278416d5426493959216d46279d3c40f91f33f81 (diff)
Implemented <fcntl.h>.
-rw-r--r--src/library.js191
-rw-r--r--tests/fcntl-misc/output.txt10
-rw-r--r--tests/fcntl-misc/src.c31
-rw-r--r--tests/fcntl-open/output.txt723
-rw-r--r--tests/fcntl-open/src.c56
-rw-r--r--tests/fcntl/output.txt42
-rw-r--r--tests/fcntl/src.c80
-rw-r--r--tests/runner.py37
8 files changed, 1157 insertions, 13 deletions
diff --git a/src/library.js b/src/library.js
index 46c396cb..793454de 100644
--- a/src/library.js
+++ b/src/library.js
@@ -679,6 +679,184 @@ LibraryManager.library = {
},
// ==========================================================================
+ // fcntl.h
+ // ==========================================================================
+
+ __flock_struct_layout: Types.structDefinitions.flock,
+ open__deps: ['$FS', '__setErrNo', '$ERRNO_CODES',
+ 'strlen', 'strcpy', 'dirname', 'basename'],
+ open: function(path, oflag, mode) {
+ // int open(const char *path, int oflag, ...);
+ // http://pubs.opengroup.org/onlinepubs/009695399/functions/open.html
+ // NOTE: This implementation tries to mimic glibc rather that strictly
+ // following the POSIX standard.
+
+ // Simplify flags.
+ var accessMode = oflag & 0x3; // O_ACCMODE.
+ var isWrite = accessMode != 0x0; // O_RDONLY.
+ var isRead = accessMode != 0x1; // O_WRONLY.
+ var isCreate = Boolean(oflag & 0x40); // O_CREAT.
+ var isExistCheck = Boolean(oflag & 0x80); // O_EXCL.
+ var isTruncate = Boolean(oflag & 0x200); // O_TRUNC.
+ var isAppend = Boolean(oflag & 0x400); // O_APPEND.
+
+ // Verify path.
+ var pathStr = Pointer_stringify(path);
+ if (!pathStr) {
+ ___setErrNo(ERRNO_CODES.ENOENT);
+ return -1;
+ }
+ var absolutePath = FS.absolutePath(pathStr);
+ if (absolutePath === null) {
+ ___setErrNo(ERRNO_CODES.ENOENT);
+ return -1;
+ }
+ var buffer = _malloc(_strlen(path) + 1);
+ var parentPath = Pointer_stringify(_dirname(_strcpy(buffer, path)));
+ var name = Pointer_stringify(_basename(_strcpy(buffer, path)));
+ _free(buffer);
+ var parent = FS.findObject(parentPath);
+ if (parent === null) return -1;
+ if (!parent.isFolder || !parent.read) {
+ ___setErrNo(ERRNO_CODES.EACCES);
+ return -1;
+ }
+ var target = parent.contents[name] || null;
+
+ // Verify the file exists, create if needed and allowed.
+ if (target) {
+ if (isCreate && isExistCheck) {
+ ___setErrNo(ERRNO_CODES.EEXIST);
+ return -1;
+ }
+ if ((isWrite || isCreate || isTruncate) && target.isFolder) {
+ ___setErrNo(ERRNO_CODES.EISDIR);
+ return -1;
+ }
+ if (isRead && !target.read || isWrite && !target.write) {
+ ___setErrNo(ERRNO_CODES.EACCES);
+ return -1;
+ }
+ if (isTruncate && !target.isDevice) {
+ target.contents = [];
+ } else {
+ if (!FS.forceLoadFile(target)) {
+ ___setErrNo(ERRNO_CODES.EIO);
+ return -1;
+ }
+ }
+ } else {
+ if (!isCreate) {
+ ___setErrNo(ERRNO_CODES.ENOENT);
+ return -1;
+ }
+ if (!parent.write) {
+ ___setErrNo(ERRNO_CODES.EACCES);
+ return -1;
+ }
+ target = FS.createDataFile(parent, name, [], mode & 0x100, mode & 0x80); // S_IRUSR, S_IWUSR.
+ }
+
+ // Actually create an open stream.
+ var id = FS.streams.length;
+ FS.streams[id] = {
+ isFolder: false,
+ path: absolutePath,
+ object: target,
+ position: 0,
+ isRead: isRead,
+ isWrite: isWrite,
+ isAppend: isAppend
+ };
+ return id;
+ },
+ creat__deps: ['open'],
+ creat: function(path, mode) {
+ // int creat(const char *path, mode_t mode);
+ // http://pubs.opengroup.org/onlinepubs/009695399/functions/creat.html
+ return _open(path, 0x241, mode); // O_WRONLY | O_CREAT | O_TRUNC.
+ },
+ fcntl__deps: ['$FS', '__setErrNo', '$ERRNO_CODES', '__flock_struct_layout'],
+ fcntl: function(fildes, cmd, arg) {
+ // int fcntl(int fildes, int cmd, ...);
+ // http://pubs.opengroup.org/onlinepubs/009695399/functions/fcntl.html
+ if (!(fildes in FS.streams)) {
+ ___setErrNo(ERRNO_CODES.EBADF);
+ return -1;
+ }
+ var stream = FS.streams[fildes];
+ switch (cmd) {
+ case 0: // F_DUPFD.
+ if (arg < 0) {
+ ___setErrNo(ERRNO_CODES.EINVAL);
+ return -1;
+ }
+ var newStream = {};
+ for (var member in stream) {
+ newStream[member] = stream[member];
+ }
+ if (arg in FS.streams) arg = FS.streams.length;
+ FS.streams[arg] = newStream;
+ return arg;
+ case 1: // F_GETFD.
+ case 2: // F_SETFD.
+ return 0; // FD_CLOEXEC makes no sense for a single process.
+ case 3: // F_GETFL.
+ var flags = 0;
+ if (stream.isRead && stream.isWrite) flags = 0x2; // O_RDWR.
+ else if (!stream.isRead && stream.isWrite) flags = 0x1; // O_WRONLY.
+ else if (stream.isRead && !stream.isWrite) flags = 0x0; // O_RDONLY.
+ if (stream.isAppend) flags |= 0x400; // O_APPEND.
+ // Synchronization and blocking flags are irrelevant to us.
+ return flags;
+ case 4: // F_SETFL.
+ stream.isAppend = Boolean(arg | 0x400); // O_APPEND.
+ // Synchronization and blocking flags are irrelevant to us.
+ return 0;
+ case 5: // F_GETLK.
+ var offset = ___flock_struct_layout.members.l_type.offset;
+ // We're always unlocked.
+ {{{ makeSetValue('arg', 'offset', '2', 'i16') }}} // F_UNLCK.
+ return 0;
+ case 6: // F_SETLK.
+ case 7: // F_SETLKW.
+ // Pretend that the locking is successful.
+ return 0;
+ case 8: // F_SETOWN.
+ case 9: // F_GETOWN.
+ // These are for sockets. We don't have them implemented (yet?).
+ ___setErrNo(ERRNO_CODES.EINVAL);
+ return -1;
+ default:
+ ___setErrNo(ERRNO_CODES.EINVAL);
+ return -1;
+ }
+ // Should never be reached. Only to silence strict warnings.
+ return -1;
+ },
+ posix_fadvise: function(fd, offset, len, advice) {
+ // int posix_fadvise(int fd, off_t offset, off_t len, int advice);
+ // http://pubs.opengroup.org/onlinepubs/009695399/functions/posix_fadvise.html
+ // Advise as much as you wish. We don't care.
+ return 0;
+ },
+ posix_madvise: 'posix_fadvise',
+ posix_fallocate__deps: ['$FS', '__setErrNo', '$ERRNO_CODES'],
+ posix_fallocate: function(fd, offset, len) {
+ // int posix_fallocate(int fd, off_t offset, off_t len);
+ // http://pubs.opengroup.org/onlinepubs/009695399/functions/posix_fallocate.html
+ if (!(fd in FS.streams) || FS.streams[fd].link ||
+ FS.streams[fd].isFolder || FS.streams[fd].isDevice) {
+ ___setErrNo(ERRNO_CODES.EBADF);
+ return -1;
+ }
+ var contents = FS.streams[fd].object.contents;
+ var limit = offset + len;
+ while (limit > contents.length) contents.push(0);
+ return 0;
+ },
+
+ // ==========================================================================
_scanString: function() {
// Supports %x, %4x, %d.%d, %s
@@ -1446,17 +1624,6 @@ LibraryManager.library = {
// unix file IO, see http://rabbit.eng.miami.edu/info/functions/unixio.html
- open: function(filename, flags, mode) {
- filename = Pointer_stringify(filename);
- if (flags === 0) { // RDONLY
- return STDIO.open(filename);
- } else if (flags === 1) { // WRONLY
- return STDIO.prepare(filename);
- } else {
- return assert(false, 'open with odd params: ' + [flags, mode]);
- }
- },
-
__01open64___deps: ['open'],
__01open64_: function(filename, mode, flags) {
// open(), but with flags and mode switched.
@@ -1472,8 +1639,6 @@ LibraryManager.library = {
return STDIO.read(stream, ptr, numbytes);
},
- fcntl: function() { }, // TODO...
-
mmap: function(start, num, prot, flags, stream, offset) {
// Leaky and non-shared... FIXME
var info = STDIO.streams[stream];
diff --git a/tests/fcntl-misc/output.txt b/tests/fcntl-misc/output.txt
new file mode 100644
index 00000000..73eae541
--- /dev/null
+++ b/tests/fcntl-misc/output.txt
@@ -0,0 +1,10 @@
+posix_fadvise: 0
+errno: 0
+
+posix_fallocate: 0
+errno: 0
+st_size: 6
+
+posix_fallocate2: 0
+errno: 0
+st_size: 10
diff --git a/tests/fcntl-misc/src.c b/tests/fcntl-misc/src.c
new file mode 100644
index 00000000..73734969
--- /dev/null
+++ b/tests/fcntl-misc/src.c
@@ -0,0 +1,31 @@
+#include <stdio.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <string.h>
+
+int main() {
+ struct stat s;
+ int f = open("/test", O_RDONLY, 0777);
+
+ printf("posix_fadvise: %d\n", posix_fadvise(f, 3, 2, POSIX_FADV_DONTNEED));
+ printf("errno: %d\n", errno);
+ printf("\n");
+ errno = 0;
+
+ printf("posix_fallocate: %d\n", posix_fallocate(f, 3, 2));
+ printf("errno: %d\n", errno);
+ stat("/test", &s);
+ printf("st_size: %d\n", s.st_size);
+ memset(&s, 0, sizeof s);
+ printf("\n");
+ errno = 0;
+
+ printf("posix_fallocate2: %d\n", posix_fallocate(f, 3, 7));
+ printf("errno: %d\n", errno);
+ stat("/test", &s);
+ printf("st_size: %d\n", s.st_size);
+ memset(&s, 0, sizeof s);
+
+ return 0;
+}
diff --git a/tests/fcntl-open/output.txt b/tests/fcntl-open/output.txt
new file mode 100644
index 00000000..314ae880
--- /dev/null
+++ b/tests/fcntl-open/output.txt
@@ -0,0 +1,723 @@
+EXISTING FILE 0,0
+success: 1
+errno: 0
+st_mode: 0100000
+
+EXISTING FOLDER 0,0
+success: 1
+errno: 0
+st_mode: 040000
+
+NON-EXISTING 0,0
+success: 0
+errno: 2
+st_mode: 00
+
+EXISTING FILE 0,1
+success: 1
+errno: 0
+st_mode: 0100000
+
+EXISTING FOLDER 0,1
+success: 0
+errno: 21
+st_mode: 040000
+
+NON-EXISTING 0,1
+success: 1
+errno: 0
+st_mode: 0100000
+
+EXISTING FILE 0,2
+success: 1
+errno: 0
+st_mode: 0100000
+
+EXISTING FOLDER 0,2
+success: 1
+errno: 0
+st_mode: 040000
+
+NON-EXISTING 0,2
+success: 0
+errno: 2
+st_mode: 00
+
+EXISTING FILE 0,3
+success: 0
+errno: 17
+st_mode: 0100000
+
+EXISTING FOLDER 0,3
+success: 0
+errno: 17
+st_mode: 040000
+
+NON-EXISTING 0,3
+success: 1
+errno: 0
+st_mode: 0100000
+
+EXISTING FILE 0,4
+success: 1
+errno: 0
+st_mode: 0100000
+
+EXISTING FOLDER 0,4
+success: 0
+errno: 21
+st_mode: 040000
+
+NON-EXISTING 0,4
+success: 0
+errno: 2
+st_mode: 00
+
+EXISTING FILE 0,5
+success: 1
+errno: 0
+st_mode: 0100000
+
+EXISTING FOLDER 0,5
+success: 0
+errno: 21
+st_mode: 040000
+
+NON-EXISTING 0,5
+success: 1
+errno: 0
+st_mode: 0100000
+
+EXISTING FILE 0,6
+success: 1
+errno: 0
+st_mode: 0100000
+
+EXISTING FOLDER 0,6
+success: 0
+errno: 21
+st_mode: 040000
+
+NON-EXISTING 0,6
+success: 0
+errno: 2
+st_mode: 00
+
+EXISTING FILE 0,7
+success: 0
+errno: 17
+st_mode: 0100000
+
+EXISTING FOLDER 0,7
+success: 0
+errno: 17
+st_mode: 040000
+
+NON-EXISTING 0,7
+success: 1
+errno: 0
+st_mode: 0100000
+
+EXISTING FILE 0,8
+success: 1
+errno: 0
+st_mode: 0100000
+
+EXISTING FOLDER 0,8
+success: 1
+errno: 0
+st_mode: 040000
+
+NON-EXISTING 0,8
+success: 0
+errno: 2
+st_mode: 00
+
+EXISTING FILE 0,9
+success: 1
+errno: 0
+st_mode: 0100000
+
+EXISTING FOLDER 0,9
+success: 0
+errno: 21
+st_mode: 040000
+
+NON-EXISTING 0,9
+success: 1
+errno: 0
+st_mode: 0100000
+
+EXISTING FILE 0,10
+success: 1
+errno: 0
+st_mode: 0100000
+
+EXISTING FOLDER 0,10
+success: 1
+errno: 0
+st_mode: 040000
+
+NON-EXISTING 0,10
+success: 0
+errno: 2
+st_mode: 00
+
+EXISTING FILE 0,11
+success: 0
+errno: 17
+st_mode: 0100000
+
+EXISTING FOLDER 0,11
+success: 0
+errno: 17
+st_mode: 040000
+
+NON-EXISTING 0,11
+success: 1
+errno: 0
+st_mode: 0100000
+
+EXISTING FILE 0,12
+success: 1
+errno: 0
+st_mode: 0100000
+
+EXISTING FOLDER 0,12
+success: 0
+errno: 21
+st_mode: 040000
+
+NON-EXISTING 0,12
+success: 0
+errno: 2
+st_mode: 00
+
+EXISTING FILE 0,13
+success: 1
+errno: 0
+st_mode: 0100000
+
+EXISTING FOLDER 0,13
+success: 0
+errno: 21
+st_mode: 040000
+
+NON-EXISTING 0,13
+success: 1
+errno: 0
+st_mode: 0100000
+
+EXISTING FILE 0,14
+success: 1
+errno: 0
+st_mode: 0100000
+
+EXISTING FOLDER 0,14
+success: 0
+errno: 21
+st_mode: 040000
+
+NON-EXISTING 0,14
+success: 0
+errno: 2
+st_mode: 00
+
+EXISTING FILE 0,15
+success: 0
+errno: 17
+st_mode: 0100000
+
+EXISTING FOLDER 0,15
+success: 0
+errno: 17
+st_mode: 040000
+
+NON-EXISTING 0,15
+success: 1
+errno: 0
+st_mode: 0100000
+
+EXISTING FILE 1,0
+success: 1
+errno: 0
+st_mode: 0100000
+
+EXISTING FOLDER 1,0
+success: 0
+errno: 21
+st_mode: 040000
+
+NON-EXISTING 1,0
+success: 0
+errno: 2
+st_mode: 00
+
+EXISTING FILE 1,1
+success: 1
+errno: 0
+st_mode: 0100000
+
+EXISTING FOLDER 1,1
+success: 0
+errno: 21
+st_mode: 040000
+
+NON-EXISTING 1,1
+success: 1
+errno: 0
+st_mode: 0100000
+
+EXISTING FILE 1,2
+success: 1
+errno: 0
+st_mode: 0100000
+
+EXISTING FOLDER 1,2
+success: 0
+errno: 21
+st_mode: 040000
+
+NON-EXISTING 1,2
+success: 0
+errno: 2
+st_mode: 00
+
+EXISTING FILE 1,3
+success: 0
+errno: 17
+st_mode: 0100000
+
+EXISTING FOLDER 1,3
+success: 0
+errno: 17
+st_mode: 040000
+
+NON-EXISTING 1,3
+success: 1
+errno: 0
+st_mode: 0100000
+
+EXISTING FILE 1,4
+success: 1
+errno: 0
+st_mode: 0100000
+
+EXISTING FOLDER 1,4
+success: 0
+errno: 21
+st_mode: 040000
+
+NON-EXISTING 1,4
+success: 0
+errno: 2
+st_mode: 00
+
+EXISTING FILE 1,5
+success: 1
+errno: 0
+st_mode: 0100000
+
+EXISTING FOLDER 1,5
+success: 0
+errno: 21
+st_mode: 040000
+
+NON-EXISTING 1,5
+success: 1
+errno: 0
+st_mode: 0100000
+
+EXISTING FILE 1,6
+success: 1
+errno: 0
+st_mode: 0100000
+
+EXISTING FOLDER 1,6
+success: 0
+errno: 21
+st_mode: 040000
+
+NON-EXISTING 1,6
+success: 0
+errno: 2
+st_mode: 00
+
+EXISTING FILE 1,7
+success: 0
+errno: 17
+st_mode: 0100000
+
+EXISTING FOLDER 1,7
+success: 0
+errno: 17
+st_mode: 040000
+
+NON-EXISTING 1,7
+success: 1
+errno: 0
+st_mode: 0100000
+
+EXISTING FILE 1,8
+success: 1
+errno: 0
+st_mode: 0100000
+
+EXISTING FOLDER 1,8
+success: 0
+errno: 21
+st_mode: 040000
+
+NON-EXISTING 1,8
+success: 0
+errno: 2
+st_mode: 00
+
+EXISTING FILE 1,9
+success: 1
+errno: 0
+st_mode: 0100000
+
+EXISTING FOLDER 1,9
+success: 0
+errno: 21
+st_mode: 040000
+
+NON-EXISTING 1,9
+success: 1
+errno: 0
+st_mode: 0100000
+
+EXISTING FILE 1,10
+success: 1
+errno: 0
+st_mode: 0100000
+
+EXISTING FOLDER 1,10
+success: 0
+errno: 21
+st_mode: 040000
+
+NON-EXISTING 1,10
+success: 0
+errno: 2
+st_mode: 00
+
+EXISTING FILE 1,11
+success: 0
+errno: 17
+st_mode: 0100000
+
+EXISTING FOLDER 1,11
+success: 0
+errno: 17
+st_mode: 040000
+
+NON-EXISTING 1,11
+success: 1
+errno: 0
+st_mode: 0100000
+
+EXISTING FILE 1,12
+success: 1
+errno: 0
+st_mode: 0100000
+
+EXISTING FOLDER 1,12
+success: 0
+errno: 21
+st_mode: 040000
+
+NON-EXISTING 1,12
+success: 0
+errno: 2
+st_mode: 00
+
+EXISTING FILE 1,13
+success: 1
+errno: 0
+st_mode: 0100000
+
+EXISTING FOLDER 1,13
+success: 0
+errno: 21
+st_mode: 040000
+
+NON-EXISTING 1,13
+success: 1
+errno: 0
+st_mode: 0100000
+
+EXISTING FILE 1,14
+success: 1
+errno: 0
+st_mode: 0100000
+
+EXISTING FOLDER 1,14
+success: 0
+errno: 21
+st_mode: 040000
+
+NON-EXISTING 1,14
+success: 0
+errno: 2
+st_mode: 00
+
+EXISTING FILE 1,15
+success: 0
+errno: 17
+st_mode: 0100000
+
+EXISTING FOLDER 1,15
+success: 0
+errno: 17
+st_mode: 040000
+
+NON-EXISTING 1,15
+success: 1
+errno: 0
+st_mode: 0100000
+
+EXISTING FILE 2,0
+success: 1
+errno: 0
+st_mode: 0100000
+
+EXISTING FOLDER 2,0
+success: 0
+errno: 21
+st_mode: 040000
+
+NON-EXISTING 2,0
+success: 0
+errno: 2
+st_mode: 00
+
+EXISTING FILE 2,1
+success: 1
+errno: 0
+st_mode: 0100000
+
+EXISTING FOLDER 2,1
+success: 0
+errno: 21
+st_mode: 040000
+
+NON-EXISTING 2,1
+success: 1
+errno: 0
+st_mode: 0100000
+
+EXISTING FILE 2,2
+success: 1
+errno: 0
+st_mode: 0100000
+
+EXISTING FOLDER 2,2
+success: 0
+errno: 21
+st_mode: 040000
+
+NON-EXISTING 2,2
+success: 0
+errno: 2
+st_mode: 00
+
+EXISTING FILE 2,3
+success: 0
+errno: 17
+st_mode: 0100000
+
+EXISTING FOLDER 2,3
+success: 0
+errno: 17
+st_mode: 040000
+
+NON-EXISTING 2,3
+success: 1
+errno: 0
+st_mode: 0100000
+
+EXISTING FILE 2,4
+success: 1
+errno: 0
+st_mode: 0100000
+
+EXISTING FOLDER 2,4
+success: 0
+errno: 21
+st_mode: 040000
+
+NON-EXISTING 2,4
+success: 0
+errno: 2
+st_mode: 00
+
+EXISTING FILE 2,5
+success: 1
+errno: 0
+st_mode: 0100000
+
+EXISTING FOLDER 2,5
+success: 0
+errno: 21
+st_mode: 040000
+
+NON-EXISTING 2,5
+success: 1
+errno: 0
+st_mode: 0100000
+
+EXISTING FILE 2,6
+success: 1
+errno: 0
+st_mode: 0100000
+
+EXISTING FOLDER 2,6
+success: 0
+errno: 21
+st_mode: 040000
+
+NON-EXISTING 2,6
+success: 0
+errno: 2
+st_mode: 00
+
+EXISTING FILE 2,7
+success: 0
+errno: 17
+st_mode: 0100000
+
+EXISTING FOLDER 2,7
+success: 0
+errno: 17
+st_mode: 040000
+
+NON-EXISTING 2,7
+success: 1
+errno: 0
+st_mode: 0100000
+
+EXISTING FILE 2,8
+success: 1
+errno: 0
+st_mode: 0100000
+
+EXISTING FOLDER 2,8
+success: 0
+errno: 21
+st_mode: 040000
+
+NON-EXISTING 2,8
+success: 0
+errno: 2
+st_mode: 00
+
+EXISTING FILE 2,9
+success: 1
+errno: 0
+st_mode: 0100000
+
+EXISTING FOLDER 2,9
+success: 0
+errno: 21
+st_mode: 040000
+
+NON-EXISTING 2,9
+success: 1
+errno: 0
+st_mode: 0100000
+
+EXISTING FILE 2,10
+success: 1
+errno: 0
+st_mode: 0100000
+
+EXISTING FOLDER 2,10
+success: 0
+errno: 21
+st_mode: 040000
+
+NON-EXISTING 2,10
+success: 0
+errno: 2
+st_mode: 00
+
+EXISTING FILE 2,11
+success: 0
+errno: 17
+st_mode: 0100000
+
+EXISTING FOLDER 2,11
+success: 0
+errno: 17
+st_mode: 040000
+
+NON-EXISTING 2,11
+success: 1
+errno: 0
+st_mode: 0100000
+
+EXISTING FILE 2,12
+success: 1
+errno: 0
+st_mode: 0100000
+
+EXISTING FOLDER 2,12
+success: 0
+errno: 21
+st_mode: 040000
+
+NON-EXISTING 2,12
+success: 0
+errno: 2
+st_mode: 00
+
+EXISTING FILE 2,13
+success: 1
+errno: 0
+st_mode: 0100000
+
+EXISTING FOLDER 2,13
+success: 0
+errno: 21
+st_mode: 040000
+
+NON-EXISTING 2,13
+success: 1
+errno: 0
+st_mode: 0100000
+
+EXISTING FILE 2,14
+success: 1
+errno: 0
+st_mode: 0100000
+
+EXISTING FOLDER 2,14
+success: 0
+errno: 21
+st_mode: 040000
+
+NON-EXISTING 2,14
+success: 0
+errno: 2
+st_mode: 00
+
+EXISTING FILE 2,15
+success: 0
+errno: 17
+st_mode: 0100000
+
+EXISTING FOLDER 2,15
+success: 0
+errno: 17
+st_mode: 040000
+
+NON-EXISTING 2,15
+success: 1
+errno: 0
+st_mode: 0100000
+
+CREAT
+success: 1
+errno: 0
diff --git a/tests/fcntl-open/src.c b/tests/fcntl-open/src.c
new file mode 100644
index 00000000..52d2e7e4
--- /dev/null
+++ b/tests/fcntl-open/src.c
@@ -0,0 +1,56 @@
+#include <stdio.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <string.h>
+
+int main() {
+ struct stat s;
+ int modes[] = {O_RDONLY, O_WRONLY, O_RDWR};
+ char nonexistent_name[] = "/noexist-##";
+
+ for (int i = 0; i < 3; i++) {
+ for (int j = 0; j < 16; j++) {
+ int flags = modes[i];
+ if (j & 0x1) flags |= O_CREAT;
+ if (j & 0x2) flags |= O_EXCL;
+ if (j & 0x4) flags |= O_TRUNC;
+ if (j & 0x8) flags |= O_APPEND;
+
+ printf("EXISTING FILE %d,%d\n", i, j);
+ printf("success: %d\n", open("/test-file", flags, 0777) != -1);
+ printf("errno: %d\n", errno);
+ stat("/test-file", &s);
+ printf("st_mode: 0%o\n", s.st_mode & 037777777000);
+ memset(&s, 0, sizeof s);
+ printf("\n");
+ errno = 0;
+
+ printf("EXISTING FOLDER %d,%d\n", i, j);
+ printf("success: %d\n", open("/test-folder", flags, 0777) != -1);
+ printf("errno: %d\n", errno);
+ stat("/test-folder", &s);
+ printf("st_mode: 0%o\n", s.st_mode & 037777777000);
+ memset(&s, 0, sizeof s);
+ printf("\n");
+ errno = 0;
+
+ nonexistent_name[9] = 'a' + i;
+ nonexistent_name[10] = 'a' + j;
+ printf("NON-EXISTING %d,%d\n", i, j);
+ printf("success: %d\n", open(nonexistent_name, flags, 0777) != -1);
+ printf("errno: %d\n", errno);
+ stat(nonexistent_name, &s);
+ printf("st_mode: 0%o\n", s.st_mode & 037777777000);
+ memset(&s, 0, sizeof s);
+ printf("\n");
+ errno = 0;
+ }
+ }
+
+ printf("CREAT\n");
+ printf("success: %d\n", creat("/creat-me", 0777) != -1);
+ printf("errno: %d\n", errno);
+
+ return 0;
+}
diff --git a/tests/fcntl/output.txt b/tests/fcntl/output.txt
new file mode 100644
index 00000000..1077e89b
--- /dev/null
+++ b/tests/fcntl/output.txt
@@ -0,0 +1,42 @@
+F_DUPFD: 100
+errno: 0
+
+F_DUPFD/error1: -1
+errno: 9
+
+F_DUPFD/error2: -1
+errno: 22
+
+F_GETFD: 0
+errno: 0
+
+F_SETFD: 0
+errno: 0
+
+F_GETFL: 2
+errno: 0
+
+F_SETFL: 0
+errno: 0
+
+F_GETFL/2: 0x402
+errno: 0
+
+F_GETLK: 0
+errno: 0
+lk.l_type == F_UNLCK: 1
+
+F_SETLK: 0
+errno: 0
+
+F_SETLKW: 0
+errno: 0
+
+F_SETOWN: -1
+errno: 22
+
+F_GETOWN: -1
+errno: 22
+
+INVALID: -1
+errno: 22
diff --git a/tests/fcntl/src.c b/tests/fcntl/src.c
new file mode 100644
index 00000000..1e9a1536
--- /dev/null
+++ b/tests/fcntl/src.c
@@ -0,0 +1,80 @@
+#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+
+int main() {
+ int f = open("/test", O_RDWR, 0777);
+
+ printf("F_DUPFD: %d\n", fcntl(f, F_DUPFD, 100));
+ printf("errno: %d\n", errno);
+ printf("\n");
+ errno = 0;
+
+ printf("F_DUPFD/error1: %d\n", fcntl(50, F_DUPFD, 200));
+ printf("errno: %d\n", errno);
+ printf("\n");
+ errno = 0;
+
+ printf("F_DUPFD/error2: %d\n", fcntl(f, F_DUPFD, -1));
+ printf("errno: %d\n", errno);
+ printf("\n");
+ errno = 0;
+
+ printf("F_GETFD: %d\n", fcntl(f, F_GETFD));
+ printf("errno: %d\n", errno);
+ printf("\n");
+ errno = 0;
+
+ printf("F_SETFD: %d\n", fcntl(f, F_SETFD));
+ printf("errno: %d\n", errno);
+ printf("\n");
+ errno = 0;
+
+ printf("F_GETFL: %d\n", fcntl(f, F_GETFL));
+ printf("errno: %d\n", errno);
+ printf("\n");
+ errno = 0;
+
+ printf("F_SETFL: %d\n", fcntl(f, F_SETFL, O_APPEND));
+ printf("errno: %d\n", errno);
+ printf("\n");
+ errno = 0;
+
+ printf("F_GETFL/2: %#x\n", fcntl(f, F_GETFL));
+ printf("errno: %d\n", errno);
+ printf("\n");
+ errno = 0;
+
+ flock lk;
+ lk.l_type = 42;
+ printf("F_GETLK: %d\n", fcntl(f, F_GETLK, &lk));
+ printf("errno: %d\n", errno);
+ printf("lk.l_type == F_UNLCK: %d\n", lk.l_type == F_UNLCK);
+ printf("\n");
+ errno = 0;
+
+ printf("F_SETLK: %d\n", fcntl(f, F_SETLK, &lk));
+ printf("errno: %d\n", errno);
+ printf("\n");
+ errno = 0;
+
+ printf("F_SETLKW: %d\n", fcntl(f, F_SETLK, &lk));
+ printf("errno: %d\n", errno);
+ printf("\n");
+ errno = 0;
+
+ printf("F_SETOWN: %d\n", fcntl(f, F_SETOWN, 123));
+ printf("errno: %d\n", errno);
+ printf("\n");
+ errno = 0;
+
+ printf("F_GETOWN: %d\n", fcntl(f, F_GETOWN));
+ printf("errno: %d\n", errno);
+ printf("\n");
+ errno = 0;
+
+ printf("INVALID: %d\n", fcntl(f, 123));
+ printf("errno: %d\n", errno);
+
+ return 0;
+}
diff --git a/tests/runner.py b/tests/runner.py
index 27c19867..4a91f59e 100644
--- a/tests/runner.py
+++ b/tests/runner.py
@@ -2173,6 +2173,43 @@ if 'benchmark' not in sys.argv:
expected = open(path_from_root('tests', 'stat', 'output.txt'), 'r').read()
self.do_test(src, expected, post_build=addPreRun)
+ def test_fcntl(self):
+ def addPreRun(filename):
+ src = open(filename, 'r').read().replace(
+ '// {{PRE_RUN_ADDITIONS}}',
+ "FS.createDataFile('/', 'test', 'abcdef', true, true);"
+ )
+ open(filename, 'w').write(src)
+ src = open(path_from_root('tests', 'fcntl', 'src.c'), 'r').read()
+ expected = open(path_from_root('tests', 'fcntl', 'output.txt'), 'r').read()
+ self.do_test(src, expected, post_build=addPreRun)
+
+ def test_fcntl_open(self):
+ def addPreRun(filename):
+ src = open(filename, 'r').read().replace(
+ '// {{PRE_RUN_ADDITIONS}}',
+ '''
+ FS.createDataFile('/', 'test-file', 'abcdef', true, true);
+ FS.createFolder('/', 'test-folder', true, true);
+ FS.root.write = true;
+ '''
+ )
+ open(filename, 'w').write(src)
+ src = open(path_from_root('tests', 'fcntl-open', 'src.c'), 'r').read()
+ expected = open(path_from_root('tests', 'fcntl-open', 'output.txt'), 'r').read()
+ self.do_test(src, expected, post_build=addPreRun)
+
+ def test_fcntl_misc(self):
+ def addPreRun(filename):
+ src = open(filename, 'r').read().replace(
+ '// {{PRE_RUN_ADDITIONS}}',
+ "FS.createDataFile('/', 'test', 'abcdef', true, true);"
+ )
+ open(filename, 'w').write(src)
+ src = open(path_from_root('tests', 'fcntl-misc', 'src.c'), 'r').read()
+ expected = open(path_from_root('tests', 'fcntl-misc', 'output.txt'), 'r').read()
+ self.do_test(src, expected, post_build=addPreRun)
+
def test_statvfs(self):
src = r'''
#include <stdio.h>