diff --git a/docs/ops.markdown b/docs/ops.markdown index ab0364f1a0..d65a38d8a2 100755 --- a/docs/ops.markdown +++ b/docs/ops.markdown @@ -175,6 +175,7 @@ * [getstderr](#getstderr) * [getstdin](#getstdin) * [getstdout](#getstdout) + * [fdopen](#fdopen) * [open](#open) * [openasync `jvm`](#openasync-jvm) * [print](#print) @@ -208,6 +209,8 @@ * [lstat_time](#lstat_time) * [symlink](#symlink) * [unlink](#unlink) + * [fstat](#fstat) + * [fstat_time](#fstat_time) - [Type/Conversion Opcodes](#-typeconversion-opcodes) * [bool](#bool) * [bootarray `jvm` `moar`](#bootarray-jvm-moar) @@ -1632,6 +1635,11 @@ Return the filehandle for standard input. Return the filehandle for standard output. +## fdopen +* fdopen(int $fd) + +Return the filehandle for the given file descriptor. + ## open * `open(str $filename, str $mode)` @@ -1872,13 +1880,13 @@ a num, using the OS's stat() function. ## lstat * `lstat(str $path, int $code --> int)` -Same as stat, but internally uses the OS's lstat() function, which does *not* +Same as stat, but internally uses the OS' lstat() function, which does *not* follow symlinks. ## lstat_time -* `stat_time(str $path, int $code --> num)` +* `lstat_time(str $path, int $code --> num)` -Same as stat_time, but internally uses the OS's lstat() function, which does +Same as stat_time, but internally uses the OS' lstat() function, which does *not* follow symlinks. ## symlink @@ -1892,6 +1900,18 @@ Create a symbolic link from `$after` to `$before` Delete the given file $path. Returns 0 on success, -2 if the file didn't exist. May throw an exception. +## fstat +* fstat(int $fd, int $code --> int) + +Same as stat, but internally uses the OS' fstat() function, which takes a file +descriptor instead of a path. + +## fstat_time +* fstat_time(int $fd, int $code --> int) + +Same as stat_time, but internally uses the OS' fstat() function, which takes a +file descriptor instead of a path. + # Type/Conversion Opcodes ## bool diff --git a/src/vm/js/Operations.nqp b/src/vm/js/Operations.nqp index a790931027..4092370cbd 100644 --- a/src/vm/js/Operations.nqp +++ b/src/vm/js/Operations.nqp @@ -534,6 +534,7 @@ class QAST::OperationsJS { add_simple_op('getstdout', $T_OBJ, [], :side_effects); add_simple_op('getstdin', $T_OBJ, [], :side_effects); + add_simple_op('fdopen', $T_OBJ, [$T_INT], :side_effects); add_simple_op('open', $T_OBJ, [$T_STR, $T_STR], :side_effects); add_simple_op('opendir', $T_OBJ, [$T_STR], :side_effects); @@ -1029,6 +1030,9 @@ class QAST::OperationsJS { add_simple_op('lstat', $T_INT, [$T_STR, $T_INT], :side_effects); add_simple_op('lstat_time', $T_NUM, [$T_STR, $T_INT], :side_effects); + add_simple_op('fstat', $T_INT, [$T_INT, $T_INT], :side_effects); + add_simple_op('fstat_time', $T_NUM, [$T_INT, $T_INT], :side_effects); + add_simple_op('fileislink', $T_INT, [$T_STR], :side_effects); add_simple_op('filewritable', $T_INT, [$T_STR], :side_effects); diff --git a/src/vm/js/nqp-runtime/browser.js b/src/vm/js/nqp-runtime/browser.js index aa98ea0398..fb5434ebbd 100644 --- a/src/vm/js/nqp-runtime/browser.js +++ b/src/vm/js/nqp-runtime/browser.js @@ -170,6 +170,39 @@ op.stat = function(file, code) { } }; +op.stat_time = function(file, code) { + throw new NQPException('nqp::stat_time is not supported in the browser'); +}; + +op.lstat = function(file, code) { + const EXISTS = 0; + if (code == EXISTS && (file === '/etc/os-release' || file === '/bin/uname' || file === '/usr/bin/uname')) { + return 0; + } else { + throw new NQPException('nqp::lstat is not supported in the browser'); + } +}; + +op.lstat_time = function(file, code) { + throw new NQPException('nqp::lstat_time is not supported in the browser'); +}; + +op.fstat = function(fd, code) { + throw new NQPException('nqp::fstat is not supported in the browser'); +}; + +op.fstat_time = function(fd, code) { + throw new NQPException('nqp::fstat_time is not supported in the browser'); +}; + +op.fdopen = function(fd) { + throw new NQPException('nqp::fdopen is not supported in the browser'); +}; + +op.open = function(file, mode) { + throw new NQPException('nqp::open is not supported in the browser'); +}; + class Exit { constructor(code) { this.code = code; diff --git a/src/vm/js/nqp-runtime/io.js b/src/vm/js/nqp-runtime/io.js index fe3eb62899..0e0b41ea25 100644 --- a/src/vm/js/nqp-runtime/io.js +++ b/src/vm/js/nqp-runtime/io.js @@ -66,33 +66,35 @@ op.filereadable = function(path) { return isFile(path, fs.constants.R_OK); }; -function stat(file, code, lstat) { - const EXISTS = 0; - const FILESIZE = 1; - const ISDIR = 2; - const ISREG = 3; - const ISDEV = 4; - const CREATETIME = 5; - const ACCESSTIME = 6; - const MODIFYTIME = 7; - const CHANGETIME = 8; - const BACKUPTIME = 9; - const UID = 10; - const GID = 11; - const ISLNK = 12; - const PLATFORM_DEV = -1; - const PLATFORM_INODE = -2; - const PLATFORM_MODE = -3; - const PLATFORM_NLINKS = -4; - const PLATFORM_DEVTYPE = -5; +function stat(file, code, lstat, fstat) { + const EXISTS = 0; + const FILESIZE = 1; + const ISDIR = 2; + const ISREG = 3; + const ISDEV = 4; + const CREATETIME = 5; + const ACCESSTIME = 6; + const MODIFYTIME = 7; + const CHANGETIME = 8; + const BACKUPTIME = 9; + const UID = 10; + const GID = 11; + const ISLNK = 12; + const PLATFORM_DEV = -1; + const PLATFORM_INODE = -2; + const PLATFORM_MODE = -3; + const PLATFORM_NLINKS = -4; + const PLATFORM_DEVTYPE = -5; const PLATFORM_BLOCKSIZE = -6; - const PLATFORM_BLOCKS = -7; + const PLATFORM_BLOCKS = -7; // we can't use fs.existsSync(file) as it follows symlinks let stats; try { if (lstat || code == ISLNK) { stats = fs.lstatSync(file); + } else if (fstat) { + stmts = fs.fstatSync(file); } else { stats = fs.statSync(file); } @@ -134,19 +136,27 @@ op.fileislink = function(file) { }; op.stat = function(file, code) { - return stat(file, code, false) | 0; + return stat(file, code, false, false) | 0; }; op.stat_time = function(file, code) { - return stat(file, code, false); + return stat(file, code, false, false); }; op.lstat = function(file, code) { - return stat(file, code, true) | 0; + return stat(file, code, true, false) | 0; }; op.lstat_time = function(file, code) { - return stat(file, code, true); + return stat(file, code, true, false); +}; + +op.fstat = function(fd, code) { + return stat(fd, code, false, true) | 0; +}; + +op.fstat_time = function(fd, code) { + return stat(fd, code, false, true); }; class IOHandle extends NQPObject { @@ -273,13 +283,18 @@ function modeToFlags(mode) { return flags; } +op.fdopen = function(fd) { + const fh = new FileHandle(fd); + return fh; +}; + op.open = function(name, mode) { try { const fh = new FileHandle(fs.openSync(name, modeToFlags(mode))); return fh; } catch (e) { if (e.code === 'ENOENT') { - throw new NQPException(`Failed to open file ${name}: No such file or director`); + throw new NQPException(`Failed to open file ${name}: No such file or directory`); } else { throw e; } diff --git a/src/vm/js/nqp-runtime/moar.core b/src/vm/js/nqp-runtime/moar.core new file mode 100644 index 0000000000..64d2d73d58 Binary files /dev/null and b/src/vm/js/nqp-runtime/moar.core differ diff --git a/src/vm/js/nqp-runtime/node.core b/src/vm/js/nqp-runtime/node.core new file mode 100644 index 0000000000..ca39e8622c Binary files /dev/null and b/src/vm/js/nqp-runtime/node.core differ diff --git a/src/vm/js/nqp-runtime/shared-io.js b/src/vm/js/nqp-runtime/shared-io.js index 4bb58eec4c..03040a0413 100644 --- a/src/vm/js/nqp-runtime/shared-io.js +++ b/src/vm/js/nqp-runtime/shared-io.js @@ -1,30 +1,32 @@ -function stat(fs, file, code, lstat) { - const EXISTS = 0; - const FILESIZE = 1; - const ISDIR = 2; - const ISREG = 3; - const ISDEV = 4; - const CREATETIME = 5; - const ACCESSTIME = 6; - const MODIFYTIME = 7; - const CHANGETIME = 8; - const BACKUPTIME = 9; - const UID = 10; - const GID = 11; - const ISLNK = 12; - const PLATFORM_DEV = -1; - const PLATFORM_INODE = -2; - const PLATFORM_MODE = -3; - const PLATFORM_NLINKS = -4; - const PLATFORM_DEVTYPE = -5; +function stat(fs, file, code, lstat, fstat) { + const EXISTS = 0; + const FILESIZE = 1; + const ISDIR = 2; + const ISREG = 3; + const ISDEV = 4; + const CREATETIME = 5; + const ACCESSTIME = 6; + const MODIFYTIME = 7; + const CHANGETIME = 8; + const BACKUPTIME = 9; + const UID = 10; + const GID = 11; + const ISLNK = 12; + const PLATFORM_DEV = -1; + const PLATFORM_INODE = -2; + const PLATFORM_MODE = -3; + const PLATFORM_NLINKS = -4; + const PLATFORM_DEVTYPE = -5; const PLATFORM_BLOCKSIZE = -6; - const PLATFORM_BLOCKS = -7; + const PLATFORM_BLOCKS = -7; // we can't use fs.existsSync(file) as it follows symlinks let stats; try { if (lstat || code == ISLNK) { stats = fs.lstatSync(file); + } else if (fstat) { + stmts = fs.fstatSync(file); } else { stats = fs.statSync(file); } diff --git a/src/vm/jvm/QAST/Compiler.nqp b/src/vm/jvm/QAST/Compiler.nqp index ef7bc671cb..2426beaefa 100644 --- a/src/vm/jvm/QAST/Compiler.nqp +++ b/src/vm/jvm/QAST/Compiler.nqp @@ -2159,8 +2159,11 @@ QAST::OperationsJAST.map_classlib_core_op('print', $TYPE_OPS, 'print', [$RT_STR] QAST::OperationsJAST.map_classlib_core_op('say', $TYPE_OPS, 'say', [$RT_STR], $RT_STR, :tc); QAST::OperationsJAST.map_classlib_core_op('stat', $TYPE_OPS, 'stat', [$RT_STR, $RT_INT], $RT_INT); QAST::OperationsJAST.map_classlib_core_op('lstat', $TYPE_OPS, 'lstat', [$RT_STR, $RT_INT], $RT_INT); +QAST::OperationsJAST.map_classlib_core_op('fstat', $TYPE_OPS, 'fstat', [$RT_INT, $RT_INT], $RT_INT); QAST::OperationsJAST.map_classlib_core_op('stat_time', $TYPE_OPS, 'stat_time', [$RT_STR, $RT_INT], $RT_NUM); QAST::OperationsJAST.map_classlib_core_op('lstat_time', $TYPE_OPS, 'lstat_time', [$RT_STR, $RT_INT], $RT_NUM); +QAST::OperationsJAST.map_classlib_core_op('fstat_time', $TYPE_OPS, 'fstat_time', [$RT_INT, $RT_INT], $RT_NUM); +QAST::OperationsJAST.map_classlib_core_op('fdopen', $TYPE_OPS, 'fdopen', [$RT_INT], $RT_OBJ, :tc); QAST::OperationsJAST.map_classlib_core_op('open', $TYPE_OPS, 'open', [$RT_STR, $RT_STR], $RT_OBJ, :tc); QAST::OperationsJAST.map_classlib_core_op('readlink', $TYPE_OPS, 'readlink', [$RT_STR], $RT_STR, :tc); QAST::OperationsJAST.map_classlib_core_op('filereadable', $TYPE_OPS, 'filereadable', [$RT_STR], $RT_INT, :tc); diff --git a/src/vm/jvm/runtime/org/perl6/nqp/runtime/Ops.java b/src/vm/jvm/runtime/org/perl6/nqp/runtime/Ops.java index 9aa1944bf2..eb316f5b3e 100644 --- a/src/vm/jvm/runtime/org/perl6/nqp/runtime/Ops.java +++ b/src/vm/jvm/runtime/org/perl6/nqp/runtime/Ops.java @@ -212,6 +212,10 @@ public static long lstat(String filename, long status) { return stat_internal(filename, status, LinkOption.NOFOLLOW_LINKS); } + public static long fstat(long fd, long status) { + throw new UnsupportedOperationException("nqp::fstat is not supported on the JVM"); + } + public static long stat_internal(String filename, long status, LinkOption ... linkOption) { long rval = -1; @@ -381,6 +385,10 @@ public static double lstat_time(String filename, long status) { return stat_time_internal(filename, status, LinkOption.NOFOLLOW_LINKS); } + public static double fstat_time(long fd, long status) { + throw new UnsupportedOperationException("nqp::fstat_time is not supported on the JVM"); + } + protected static double stat_time_internal(String filename, long status, LinkOption... linkOption) { String attrName; switch ((int) status) { @@ -408,6 +416,10 @@ protected static double stat_time_internal(String filename, long status, LinkOpt } } + public static SixModelObject fdopen(long fd, ThreadContext tc) { + throw new UnsupportedOperationException("nqp::fdopen is not supported on the JVM"); + } + public static SixModelObject open(String path, String mode, ThreadContext tc) { SixModelObject IOType = tc.curFrame.codeRef.staticInfo.compUnit.hllConfig.ioType; IOHandleInstance h = (IOHandleInstance)IOType.st.REPR.allocate(tc, IOType.st); diff --git a/src/vm/moar/QAST/QASTOperationsMAST.nqp b/src/vm/moar/QAST/QASTOperationsMAST.nqp index 008b4c03bb..2c22fa0fad 100644 --- a/src/vm/moar/QAST/QASTOperationsMAST.nqp +++ b/src/vm/moar/QAST/QASTOperationsMAST.nqp @@ -2274,7 +2274,10 @@ QAST::MASTOperations.add_core_moarop_mapping('stat', 'stat'); QAST::MASTOperations.add_core_moarop_mapping('stat_time', 'stat_time'); QAST::MASTOperations.add_core_moarop_mapping('lstat', 'lstat'); QAST::MASTOperations.add_core_moarop_mapping('lstat_time', 'lstat_time'); +QAST::MASTOperations.add_core_moarop_mapping('fstat', 'fstat'); +QAST::MASTOperations.add_core_moarop_mapping('fstat_time', 'fstat_time'); QAST::MASTOperations.add_core_moarop_mapping('open', 'open_fh'); +QAST::MASTOperations.add_core_moarop_mapping('fdopen', 'fdopen_fh'); QAST::MASTOperations.add_core_moarop_mapping('filereadable', 'filereadable'); QAST::MASTOperations.add_core_moarop_mapping('filewritable', 'filewritable'); QAST::MASTOperations.add_core_moarop_mapping('fileexecutable', 'fileexecutable');