diff --git a/lib/MAST/Ops.nqp b/lib/MAST/Ops.nqp index 19d4f0ceab..7c0fb1b203 100644 --- a/lib/MAST/Ops.nqp +++ b/lib/MAST/Ops.nqp @@ -3533,11 +3533,12 @@ class MAST::Ops { $MVM_operand_read_reg +| $MVM_operand_obj ] ), - 'eof', nqp::hash( + 'stat', nqp::hash( 'code', 49, 'operands', [ $MVM_operand_write_reg +| $MVM_operand_int64, - $MVM_operand_read_reg +| $MVM_operand_obj + $MVM_operand_read_reg +| $MVM_operand_str, + $MVM_operand_read_reg +| $MVM_operand_int64 ] ), 'readline_fh', nqp::hash( diff --git a/nqp-cc/src/QASTOperationsMAST.nqp b/nqp-cc/src/QASTOperationsMAST.nqp index 8e7771fbef..be4e7a1935 100644 --- a/nqp-cc/src/QASTOperationsMAST.nqp +++ b/nqp-cc/src/QASTOperationsMAST.nqp @@ -1283,7 +1283,7 @@ my %open_mode := nqp::hash( ); QAST::MASTOperations.add_core_moarop_mapping('say', 'say', 0); QAST::MASTOperations.add_core_moarop_mapping('print', 'print', 0); -# QAST::MASTOperations.add_core_moarop_mapping('stat', ?); +QAST::MASTOperations.add_core_moarop_mapping('stat', 'stat'); QAST::MASTOperations.add_core_moarop_mapping('open_fh', 'open_fh'); QAST::MASTOperations.add_core_op('open', -> $qastcomp, $op { my @operands := $op.list; @@ -1316,7 +1316,7 @@ QAST::MASTOperations.add_core_moarop_mapping('printfh', 'write_fhs'); QAST::MASTOperations.add_core_moarop_mapping('readlinefh', 'readline_fh'); # QAST::MASTOperations.add_core_moarop_mapping('readlineintfh', ?); QAST::MASTOperations.add_core_moarop_mapping('readallfh', 'readall_fh'); -QAST::MASTOperations.add_core_moarop_mapping('eoffh', 'eof'); +QAST::MASTOperations.add_core_moarop_mapping('eoffh', 'eof_fh'); QAST::MASTOperations.add_core_moarop_mapping('closefh', 'close_fh', 0); QAST::MASTOperations.add_core_moarop_mapping('chmod', 'chmod_f', 0); diff --git a/src/core/interp.c b/src/core/interp.c index a1bbb4e9cf..3cb4052014 100644 --- a/src/core/interp.c +++ b/src/core/interp.c @@ -2775,7 +2775,7 @@ void MVM_interp_run(MVMThreadContext *tc, void (*initial_invoke)(MVMThreadContex GET_REG(cur_op, 0).i64 = MVM_file_tell_fh(tc, GET_REG(cur_op, 2).o); cur_op += 4; break; - case MVM_OP_eof: + case MVM_OP_eof_fh: GET_REG(cur_op, 0).i64 = MVM_file_eof(tc, GET_REG(cur_op, 2).o); cur_op += 4; break; @@ -2804,9 +2804,9 @@ void MVM_interp_run(MVMThreadContext *tc, void (*initial_invoke)(MVMThreadContex MVM_file_truncate(tc, GET_REG(cur_op, 0).o, GET_REG(cur_op, 2).i64); cur_op += 4; break; - case MVM_OP_eof_fh: - GET_REG(cur_op, 0).i64 = MVM_file_eof(tc, GET_REG(cur_op, 2).o); - cur_op += 4; + case MVM_OP_stat: + GET_REG(cur_op, 0).i64 = MVM_file_stat(tc, GET_REG(cur_op, 2).s, GET_REG(cur_op, 4).i64); + cur_op += 6; break; case MVM_OP_getstdin: GET_REG(cur_op, 0).o = MVM_file_get_stdin(tc); diff --git a/src/core/oplist b/src/core/oplist index 8bc1bd4f2e..cb9a958f17 100644 --- a/src/core/oplist +++ b/src/core/oplist @@ -470,7 +470,7 @@ BANK 5 io 0x2E say r(str) 0x2F readlall_fh w(str) r(obj) 0x30 tell_fh w(int64) r(obj) -0x31 eof w(int64) r(obj) +0x31 stat w(int64) r(str) r(int64) 0x32 readline_fh w(str) r(obj) BANK 6 processthread diff --git a/src/core/ops.c b/src/core/ops.c index 6639ee119e..bd737c67dc 100644 --- a/src/core/ops.c +++ b/src/core/ops.c @@ -2784,10 +2784,10 @@ static MVMOpInfo MVM_op_info_io[] = { { MVM_operand_write_reg | MVM_operand_int64, MVM_operand_read_reg | MVM_operand_obj } }, { - MVM_OP_eof, - "eof", - 2, - { MVM_operand_write_reg | MVM_operand_int64, MVM_operand_read_reg | MVM_operand_obj } + MVM_OP_stat, + "stat", + 3, + { MVM_operand_write_reg | MVM_operand_int64, MVM_operand_read_reg | MVM_operand_str, MVM_operand_read_reg | MVM_operand_int64 } }, { MVM_OP_readline_fh, diff --git a/src/core/ops.h b/src/core/ops.h index f90dbdae97..cd895b5953 100644 --- a/src/core/ops.h +++ b/src/core/ops.h @@ -482,7 +482,7 @@ #define MVM_OP_say 46 #define MVM_OP_readall_fh 47 #define MVM_OP_tell_fh 48 -#define MVM_OP_eof 49 +#define MVM_OP_stat 49 #define MVM_OP_readline_fh 50 /* Op name defines for bank processthread. */ diff --git a/src/io/fileops.c b/src/io/fileops.c index 59bf7f1162..778143bb0a 100644 --- a/src/io/fileops.c +++ b/src/io/fileops.c @@ -1,4 +1,5 @@ #include "moarvm.h" +#include #define POOL(tc) (*(tc->interp_cu))->pool @@ -13,6 +14,68 @@ static void verify_filehandle_type(MVMThreadContext *tc, MVMObject *oshandle, MV } } +apr_finfo_t * MVM_file_info(MVMThreadContext *tc, apr_finfo_t *finfo, MVMString *filename, apr_int32_t wanted) { + apr_status_t rv; + apr_pool_t *tmp_pool; + apr_file_t *file_handle; + char *fname = MVM_string_utf8_encode_C_string(tc, filename); + + /* need a temporary pool */ + if ((rv = apr_pool_create(&tmp_pool, POOL(tc))) != APR_SUCCESS) { + free(fname); + MVM_exception_throw_apr_error(tc, rv, "Open file failed to create pool: "); + } + + if ((rv = apr_file_open(&file_handle, (const char *)fname, APR_FOPEN_READ, APR_OS_DEFAULT, tmp_pool)) != APR_SUCCESS) { + free(fname); + apr_pool_destroy(tmp_pool); + MVM_exception_throw_apr_error(tc, rv, "Failed to open file: "); + } + + free(fname); + + if((rv = apr_file_info_get(finfo, wanted, file_handle)) != APR_SUCCESS) { + MVM_exception_throw_apr_error(tc, rv, "Failed to stat file: "); + } + + if ((rv = apr_file_close(file_handle)) != APR_SUCCESS) { + MVM_exception_throw_apr_error(tc, rv, "Failed to close filehandle: "); + } + + return finfo; +} + +MVMint64 MVM_file_stat(MVMThreadContext *tc, MVMString *fn, MVMint64 status) { + MVMint64 r = -1; + apr_finfo_t finfo; + + switch (status) { + case MVM_stat_exists: r = MVM_file_exists(tc, fn); break; + case MVM_stat_filesize: r = MVM_file_info(tc, &finfo, fn, APR_FINFO_SIZE)->size; break; + case MVM_stat_isdir: r = MVM_file_info(tc, &finfo, fn, APR_FINFO_TYPE)->filetype & APR_DIR ? 1 : 0; break; + case MVM_stat_isreg: r = MVM_file_info(tc, &finfo, fn, APR_FINFO_TYPE)->filetype & APR_REG ? 1 : 0; break; + case MVM_stat_isdev: r = MVM_file_info(tc, &finfo, fn, APR_FINFO_TYPE)->filetype & (APR_CHR|APR_BLK) ? 1 : 0; break; + case MVM_stat_createtime: r = MVM_file_info(tc, &finfo, fn, APR_FINFO_CTIME)->ctime; break; + case MVM_stat_accesstime: r = MVM_file_info(tc, &finfo, fn, APR_FINFO_ATIME)->atime; break; + case MVM_stat_modifytime: r = MVM_file_info(tc, &finfo, fn, APR_FINFO_MTIME)->mtime; break; + case MVM_stat_changetime: r = MVM_file_info(tc, &finfo, fn, APR_FINFO_CTIME)->ctime; break; + case MVM_stat_backuptime: r = -1; break; + case MVM_stat_uid: r = MVM_file_info(tc, &finfo, fn, APR_FINFO_USER)->user; break; + case MVM_stat_gid: r = MVM_file_info(tc, &finfo, fn, APR_FINFO_GROUP)->group; break; + case MVM_stat_islnk: r = MVM_file_info(tc, &finfo, fn, APR_FINFO_TYPE)->filetype & APR_LNK ? 1 : 0; break; + case MVM_stat_platform_dev: r = MVM_file_info(tc, &finfo, fn, APR_FINFO_DEV)->device; break; + case MVM_stat_platform_inode: r = MVM_file_info(tc, &finfo, fn, APR_FINFO_INODE)->inode; break; + case MVM_stat_platform_mode: r = MVM_file_info(tc, &finfo, fn, APR_FINFO_PROT)->protection; break; + case MVM_stat_platform_nlinks: r = MVM_file_info(tc, &finfo, fn, APR_FINFO_NLINK)->nlink; break; + case MVM_stat_platform_devtype: r = -1; break; + case MVM_stat_platform_blocksize: r = MVM_file_info(tc, &finfo, fn, APR_FINFO_CSIZE)->csize; break; + case MVM_stat_platform_blocks: r = -1; break; + default: break; + } + + return r; +} + char * MVM_file_get_full_path(MVMThreadContext *tc, apr_pool_t *tmp_pool, char *path) { apr_status_t rv; char *rootpath, *cwd; diff --git a/src/io/fileops.h b/src/io/fileops.h index da46788c86..4811e1cd9a 100644 --- a/src/io/fileops.h +++ b/src/io/fileops.h @@ -1,4 +1,5 @@ char * MVM_file_get_full_path(MVMThreadContext *tc, apr_pool_t *tmp_pool, char *path); +MVMint64 MVM_file_stat(MVMThreadContext *tc, MVMString *filename, MVMint64 status); void MVM_file_copy(MVMThreadContext *tc, MVMString *src, MVMString *dest); void MVM_file_append(MVMThreadContext *tc, MVMString *src, MVMString *dest); void MVM_file_rename(MVMThreadContext *tc, MVMString *src, MVMString *dest); @@ -22,7 +23,6 @@ void MVM_file_flush(MVMThreadContext *tc, MVMObject *oshandle); void MVM_file_sync(MVMThreadContext *tc, MVMObject *oshandle); void MVM_file_pipe(MVMThreadContext *tc, MVMObject *oshandle1, MVMObject *oshandle2); void MVM_file_truncate(MVMThreadContext *tc, MVMObject *oshandle, MVMint64 offset); -MVMint64 MVM_file_eof(MVMThreadContext *tc, MVMObject *oshandle); MVMObject * MVM_file_get_stdin(MVMThreadContext *tc); MVMObject * MVM_file_get_stdout(MVMThreadContext *tc); MVMObject * MVM_file_get_stderr(MVMThreadContext *tc); diff --git a/src/strings/ops.h b/src/strings/ops.h index e7c0e28e3a..ef9dc9c0c6 100644 --- a/src/strings/ops.h +++ b/src/strings/ops.h @@ -17,6 +17,28 @@ default: MVM_exception_throw_adhoc(tc, "invalid mode flag: %d", (mode)); \ } #define MVM_get_apr_perms(p) (apr_fileperms_t)((p & 7) + (((p & 56) >> 3) * 16) + (((p & 448) >> 6) << 8)) + +#define MVM_stat_exists 0 +#define MVM_stat_filesize 1 +#define MVM_stat_isdir 2 +#define MVM_stat_isreg 3 +#define MVM_stat_isdev 4 +#define MVM_stat_createtime 5 +#define MVM_stat_accesstime 6 +#define MVM_stat_modifytime 7 +#define MVM_stat_changetime 8 +#define MVM_stat_backuptime 9 +#define MVM_stat_uid 10 +#define MVM_stat_gid 11 +#define MVM_stat_islnk 12 +#define MVM_stat_platform_dev -1 +#define MVM_stat_platform_inode -2 +#define MVM_stat_platform_mode -3 +#define MVM_stat_platform_nlinks -4 +#define MVM_stat_platform_devtype -5 +#define MVM_stat_platform_blocksize -6 +#define MVM_stat_platform_blocks -7 + /* substring consumer functions accept a state object in *data and consume a substring portion. Utilized by many of the string ops so traversal state can be maintained while applying a function to