-/* $Id: js_fd.c,v 1.9 2006/09/15 07:06:58 mmondor Exp $ */
+/* $Id: js_fd.c,v 1.10 2006/09/15 21:04:48 mmondor Exp $ */
/*
* Copyright (c) 2005, Matthew Mondor
* for this (maybe a VFS static class?) Maybe even something calling
* execve(2) and fork(2), those primitives... popen(3) also.
* - Also opendir(3) and friends wrapper...
+ * - fchdir(2) XXX
*/
static JSBool fd_m_open(JSContext *, JSObject *, uintN, jsval *, jsval *);
static JSBool fd_m_set(JSContext *, JSObject *, uintN, jsval *, jsval *);
static JSBool fd_m_close(JSContext *, JSObject *, uintN, jsval *, jsval *);
-static JSBool fd_m_truncate(JSContext *, JSObject *, uintN, jsval *,
+static JSBool fd_m_ftruncate(JSContext *, JSObject *, uintN, jsval *,
jsval *);
static JSBool fd_m_put(JSContext *, JSObject *, uintN, jsval *, jsval *);
static JSBool fd_m_get(JSContext *, JSObject *, uintN, jsval *, jsval *);
static JSBool fd_m_fchmod(JSContext *, JSObject *, uintN, jsval *, jsval *);
static JSBool fd_m_flock(JSContext *, JSObject *, uintN, jsval *, jsval *);
static JSBool fd_m_fstat(JSContext *, JSObject *, uintN, jsval *, jsval *);
-static JSBool fd_m_ftruncate(JSContext *, JSObject *, uintN, jsval *,
- jsval *);
static JSBool fd_sm_poll(JSContext *, JSObject *, uintN, jsval *, jsval *);
static JSBool fd_sm_poll_mkset(JSContext *, jsval *, jsval *, void *);
{ "open", fd_m_open, 0, 0, 0 }, /* Variable 2-3 parameters */
{ "set", fd_m_set, 1, 0, 0 },
{ "close", fd_m_close, 0, 0, 0 },
- { "truncate", fd_m_truncate, 1, 0, 0 },
+ { "ftruncate", fd_m_ftruncate, 1, 0, 0 },
{ "put", fd_m_put, 1, 0, 0 },
{ "get", fd_m_get, 0, 0, 0 },
{ "socket", fd_m_socket, 3, 0, 0 },
{ "fchmod", fd_m_fchmod, 1, 0, 0 },
{ "flock", fd_m_flock, 1, 0, 0 },
{ "fstat", fd_m_fstat, 0, 0, 0 },
- { "ftruncate", fd_m_ftruncate, 1, 0, 0 },
{ NULL, NULL, 0, 0, 0 }
};
}
static JSBool
-fd_m_truncate(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+fd_m_ftruncate(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
jsval *rval)
{
jsfd_t *jsfd;
return JS_FALSE;
}
-static JSBool
-fd_m_ftruncate(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
- jsval *rval)
-{
- /* XXX */
- jsfd_t *jsfd;
- struct stat st;
- JSObject *array = NULL;
- jsval val;
-
- *rval = OBJECT_TO_JSVAL(NULL);
-
- if ((jsfd = fd_methods_args_check(cx, obj, "ftruncate", FDMA_FTRUNCATE,
- argc, argv, JSFD_FILE)) == NULL)
- return JS_FALSE;
-
- if (fstat(jsfd->fd, &st) == -1) {
- jsfd->error = errno;
- QUEUE_EXCEPTION(strerror(errno));
- return JS_FALSE;
- }
-
- /*
- * Note: We immediately link newly created objects to avoid GC
- * problems. For the simplicity of this task we don't need an
- * additional root to be created using JS_AddRoot(), since *rval
- * is already rooted. Moreover, the double objects we create are
- * immediately added as propery as well.
- */
-
- if ((array = JS_NewObject(cx, NULL, NULL, NULL)) == NULL) {
- QUEUE_EXCEPTION("Out of memory");
- goto err;
- }
- *rval = OBJECT_TO_JSVAL(array);
-
-#define DEFINE_INT_PROP(n, i) do { \
- val = INT_TO_JSVAL((int)(i)); \
- if (!JS_DefineProperty(cx, array, (n), val, NULL, NULL, \
- JSPROP_ENUMERATE)) { \
- QUEUE_EXCEPTION("Internal error!"); \
- goto err; \
- } \
-} while (/* CONSTCOND */0)
-
-#define DEFINE_DOUBLE_PROP(n, d) do { \
- if (!JS_NewDoubleValue(cx, (jsdouble)(d), &val)) \
- goto err; \
- if (!JS_DefineProperty(cx, array, (n), val, NULL, NULL, \
- JSPROP_ENUMERATE)) { \
- QUEUE_EXCEPTION("Internal error!"); \
- goto err; \
- } \
-} while (/* CONSTCOND */0)
-
- DEFINE_INT_PROP("st_dev", st.st_dev);
- DEFINE_INT_PROP("st_ino", st.st_ino);
- DEFINE_INT_PROP("st_mode", st.st_mode);
- DEFINE_INT_PROP("st_nlink", st.st_nlink);
- DEFINE_INT_PROP("st_uid", st.st_uid);
- DEFINE_INT_PROP("st_gid", st.st_gid);
- DEFINE_INT_PROP("st_rdev", st.st_rdev);
- DEFINE_DOUBLE_PROP("st_atime", st.st_atime);
- DEFINE_DOUBLE_PROP("st_mtime", st.st_mtime);
- DEFINE_DOUBLE_PROP("st_ctime", st.st_ctime);
- DEFINE_DOUBLE_PROP("st_size", st.st_size);
- DEFINE_DOUBLE_PROP("st_blocks", st.st_blocks);
- DEFINE_INT_PROP("st_blksize", st.st_blksize);
- DEFINE_INT_PROP("st_flags", st.st_flags);
- DEFINE_INT_PROP("st_gen", st.st_gen);
-
-#undef DEFINE_INT_PROP
-#undef DEFINE_DOUBLE_PROP
-
- return JS_TRUE;
-
-err:
- *rval = OBJECT_TO_JSVAL(NULL);
-
- return JS_FALSE;
-}
-
-
/*
* Static methods
--- /dev/null
+/* $Id: js_fs.c,v 1.1 2006/09/15 21:04:48 mmondor Exp $ */
+
+/*
+ * Copyright (c) 2006, Matthew Mondor
+ * ALL RIGHTS RESERVED.
+ */
+
+
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+
+#include <stdint.h>
+
+#include <assert.h>
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <grp.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <jsapi.h>
+
+#include <js_fs.h>
+
+
+
+#define QUEUE_EXCEPTION(s) do { \
+ JS_SetPendingException(cx, \
+ STRING_TO_JSVAL(JS_NewStringCopyZ(cx, (s)))); \
+} while (/* CONSTCOND */0)
+
+
+
+/*
+ * Static prototypes
+ */
+static JSBool fs_constructor(JSContext *, JSObject *, uintN, jsval *,
+ jsval *);
+static void fs_finalize(JSContext *, JSObject *);
+
+static JSBool fs_sm_chdir(JSContext *, JSObject *, uintN, jsval *, jsval *);
+static JSBool fs_sm_getcwd(JSContext *, JSObject *, uintN, jsval *, jsval *);
+static JSBool fs_sm_mkdir(JSContext *, JSObject *, uintN, jsval *, jsval *);
+static JSBool fs_sm_rmdir(JSContext *, JSObject *, uintN, jsval *, jsval *);
+static JSBool fs_sm_stat(JSContext *, JSObject *, uintN, jsval *, jsval *);
+static JSBool fs_sm_lstat(JSContext *, JSObject *, uintN, jsval *, jsval *);
+static JSBool fs_sm_chown(JSContext *, JSObject *, uintN, jsval *, jsval *);
+static JSBool fs_sm_lchown(JSContext *, JSObject *, uintN, jsval *, jsval *);
+static JSBool fs_sm_chmod(JSContext *, JSObject *, uintN, jsval *, jsval *);
+static JSBool fs_sm_rename(JSContext *, JSObject *, uintN, jsval *, jsval *);
+static JSBool fs_sm_unlink(JSContext *, JSObject *, uintN, jsval *,
+ jsval *);
+static JSBool fs_sm_truncate(JSContext *, JSObject *, uintN, jsval *,
+ jsval *);
+static JSBool fs_sm_creat(JSContext *, JSObject *, uintN, jsval *, jsval *);
+static JSBool fs_sm_mknod(JSContext *, JSObject *, uintN, jsval *, jsval *);
+static JSBool fs_sm_mkfifo(JSContext *, JSObject *, uintN, jsval *, jsval *);
+static JSBool fs_sm_symlink(JSContext *, JSObject *, uintN, jsval *,
+ jsval *);
+
+static JSBool fs_sm_stat_i(JSContext *, JSObject *, uintN, jsval *, jsval *,
+ int (*)(const char *, struct stat *));
+
+static int chown_resolve(JSContext *, jsval, jsval, uid_t *, gid_t *);
+
+static mode_t fs_mode_allow(mode_t);
+static int fs_path_allow(const char *);
+
+
+
+/*
+ * Static globals
+ */
+
+/* FS class */
+static JSClass fs_class = {
+ "FS", 0, JS_PropertyStub, JS_PropertyStub,
+ JS_PropertyStub, JS_PropertyStub, JS_EnumerateStub, JS_ResolveStub,
+ JS_ConvertStub, fs_finalize
+};
+
+/* Provided static methods */
+static JSFunctionSpec fs_smethods[] = {
+ { "chdir", fs_sm_chdir, 1, 0, 0 },
+ { "getcwd", fs_sm_getcwd, 0, 0, 0 },
+ { "mkdir", fs_sm_mkdir, 2, 0, 0 },
+ { "rmdir", fs_sm_rmdir, 1, 0, 0 },
+ { "stat", fs_sm_stat, 1, 0, 0 },
+ { "lstat", fs_sm_lstat, 1, 0, 0 },
+ { "chown", fs_sm_chown, 3, 0, 0 },
+ { "lchown", fs_sm_lchown, 3, 0, 0 },
+ { "chmod", fs_sm_chmod, 2, 0, 0 },
+ { "rename", fs_sm_rename, 2, 0, 0 },
+ { "unlink", fs_sm_unlink, 1, 0, 0 },
+ { "truncate", fs_sm_truncate, 2, 0, 0 },
+ { "creat", fs_sm_creat, 2, 0, 0 },
+ { "mknod", fs_sm_mknod, 3, 0, 0 },
+ { "mkfifo", fs_sm_mkfifo, 2, 0, 0 },
+ { "symlink", fs_sm_symlink, 2, 0, 0 }
+};
+
+
+
+/*
+ * FS object control
+ */
+
+JSObject *
+js_InitFSClass(JSContext *cx, JSObject *obj)
+{
+ JSObject *proto;
+
+ if ((proto = JS_InitClass(cx, obj, NULL, &fs_class, fs_constructor,
+ 0, NULL, NULL, NULL, fs_smethods)) == NULL)
+ (void) fprintf(stderr, "Error initializing FS class\n");
+
+ return proto;
+}
+
+static JSBool
+fs_constructor(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+
+ QUEUE_EXCEPTION("FS class non-instanciable");
+
+ return JS_FALSE;
+}
+
+static void
+fs_finalize(JSContext *cx, JSObject *obj)
+{
+
+ /* NOOP */
+}
+
+
+
+/* Static methods */
+static JSBool
+fs_sm_chdir(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ char *path;
+
+ *rval = OBJECT_TO_JSVAL(NULL);
+
+ if (argc != 1) {
+ QUEUE_EXCEPTION("Wrong number of arguments");
+ return JS_FALSE;
+ }
+ if (!JSVAL_IS_STRING(argv[0])) {
+ QUEUE_EXCEPTION("Argument 1 not a String");
+ return JS_FALSE;
+ }
+
+ if ((path = JS_GetStringBytes(JSVAL_TO_STRING(argv[0]))) == NULL) {
+ QUEUE_EXCEPTION("Internal error!");
+ return JS_FALSE;
+ }
+
+ if (fs_path_allow(path) == -1) {
+ QUEUE_EXCEPTION("Path not allowed");
+ return JS_FALSE;
+ }
+
+ if (chdir(path) != 0) {
+ QUEUE_EXCEPTION(strerror(errno));
+ return JS_FALSE;
+ }
+
+ return JS_TRUE;
+}
+
+static JSBool
+fs_sm_getcwd(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+ static char cwd[MAXPATHLEN];
+
+ *rval = OBJECT_TO_JSVAL(NULL);
+
+ if (argc != 0) {
+ QUEUE_EXCEPTION("Wrong number of arguments");
+ return JS_FALSE;
+ }
+
+ if (getcwd(cwd, MAXPATHLEN - 1) == NULL) {
+ QUEUE_EXCEPTION(strerror(errno));
+ return JS_FALSE;
+ }
+
+ *rval = STRING_TO_JSVAL(JS_NewStringCopyZ(cx, cwd));
+
+ return JS_TRUE;
+}
+
+static JSBool
+fs_sm_mkdir(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ char *path;
+ mode_t mode;
+
+ *rval = OBJECT_TO_JSVAL(NULL);
+
+ if (argc != 2) {
+ QUEUE_EXCEPTION("Wrong number of arguments");
+ return JS_FALSE;
+ }
+ if (!JSVAL_IS_STRING(argv[0])) {
+ QUEUE_EXCEPTION("Argument 1 not a String");
+ return JS_FALSE;
+ }
+ if (!JSVAL_IS_INT(argv[0])) {
+ QUEUE_EXCEPTION("Argument 2 not an Integer");
+ return JS_FALSE;
+ }
+
+ if ((path = JS_GetStringBytes(JSVAL_TO_STRING(argv[0]))) == NULL) {
+ QUEUE_EXCEPTION("Internal error!");
+ return JS_FALSE;
+ }
+ if (fs_path_allow(path) != 0) {
+ QUEUE_EXCEPTION("Path not allowed");
+ return JS_FALSE;
+ }
+
+ mode = fs_mode_allow((mode_t)JSVAL_TO_INT(argv[1]));
+
+ if (mkdir(path, mode) == -1) {
+ QUEUE_EXCEPTION(strerror(errno));
+ return JS_FALSE;
+ }
+
+ return JS_TRUE;
+}
+
+static JSBool
+fs_sm_rmdir(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ char *path;
+
+ *rval = OBJECT_TO_JSVAL(NULL);
+
+ if (argc != 1) {
+ QUEUE_EXCEPTION("Wrong number of arguments");
+ return JS_FALSE;
+ }
+ if (!JSVAL_IS_STRING(argv[0])) {
+ QUEUE_EXCEPTION("Argument 1 not a String");
+ return JS_FALSE;
+ }
+
+ if ((path = JS_GetStringBytes(JSVAL_TO_STRING(argv[0]))) == NULL) {
+ QUEUE_EXCEPTION("Internal error!");
+ return JS_FALSE;
+ }
+ if (fs_path_allow(path) != 0) {
+ QUEUE_EXCEPTION("Path not allowed");
+ return JS_FALSE;
+ }
+
+ if (rmdir(path) == -1) {
+ QUEUE_EXCEPTION(strerror(errno));
+ return JS_FALSE;
+ }
+
+ return JS_TRUE;
+}
+
+static JSBool
+fs_sm_stat(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+
+ return fs_sm_stat_i(cx, obj, argc, argv, rval, stat);
+}
+
+static JSBool
+fs_sm_lstat(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+
+ return fs_sm_stat_i(cx, obj, argc, argv, rval, lstat);
+}
+
+static JSBool
+fs_sm_chown(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ char *path;
+ uid_t uid;
+ gid_t gid;
+
+ *rval = OBJECT_TO_JSVAL(NULL);
+
+ if (argc != 3) {
+ QUEUE_EXCEPTION("Wrong number of arguments");
+ return JS_FALSE;
+ }
+ if (!JSVAL_IS_STRING(argv[0])) {
+ QUEUE_EXCEPTION("Argument 1 not a String");
+ return JS_FALSE;
+ }
+
+ if ((path = JS_GetStringBytes(JSVAL_TO_STRING(argv[0]))) == NULL) {
+ QUEUE_EXCEPTION("Internal error!");
+ return JS_FALSE;
+ }
+ if (fs_path_allow(path) != 0) {
+ QUEUE_EXCEPTION("Path not allowed");
+ return JS_FALSE;
+ }
+
+ if (chown_resolve(cx, argv[1], argv[2], &uid, &gid) == -1)
+ return JS_FALSE;
+
+ if (chown(path, uid, gid) == -1) {
+ QUEUE_EXCEPTION(strerror(errno));
+ return JS_FALSE;
+ }
+
+ return JS_TRUE;
+}
+
+static JSBool
+fs_sm_lchown(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+ char *path;
+ uid_t uid;
+ gid_t gid;
+
+ *rval = OBJECT_TO_JSVAL(NULL);
+
+ if (argc != 3) {
+ QUEUE_EXCEPTION("Wrong number of arguments");
+ return JS_FALSE;
+ }
+ if (!JSVAL_IS_STRING(argv[0])) {
+ QUEUE_EXCEPTION("Argument 1 not a String");
+ return JS_FALSE;
+ }
+
+ if ((path = JS_GetStringBytes(JSVAL_TO_STRING(argv[0]))) == NULL) {
+ QUEUE_EXCEPTION("Internal error!");
+ return JS_FALSE;
+ }
+ if (fs_path_allow(path) != 0) {
+ QUEUE_EXCEPTION("Path not allowed");
+ return JS_FALSE;
+ }
+
+ if (chown_resolve(cx, argv[1], argv[2], &uid, &gid) == -1)
+ return JS_FALSE;
+
+ if (lchown(path, uid, gid) == -1) {
+ QUEUE_EXCEPTION(strerror(errno));
+ return JS_FALSE;
+ }
+
+ return JS_TRUE;
+}
+
+static JSBool
+fs_sm_chmod(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ char *path;
+ mode_t mode;
+
+ *rval = OBJECT_TO_JSVAL(NULL);
+
+ if (argc != 2) {
+ QUEUE_EXCEPTION("Wrong number of arguments");
+ return JS_FALSE;
+ }
+ if (!JSVAL_IS_STRING(argv[0])) {
+ QUEUE_EXCEPTION("Argument 1 not a String");
+ return JS_FALSE;
+ }
+ if (!JSVAL_IS_INT(argv[1])) {
+ QUEUE_EXCEPTION("Argument 2 not an Integer");
+ return JS_FALSE;
+ }
+
+ if ((path = JS_GetStringBytes(JSVAL_TO_STRING(argv[0]))) == NULL) {
+ QUEUE_EXCEPTION("Internal error!");
+ return JS_FALSE;
+ }
+ if (fs_path_allow(path) != 0) {
+ QUEUE_EXCEPTION("Path not allowed");
+ return JS_FALSE;
+ }
+
+ mode = fs_mode_allow((mode_t)JSVAL_TO_INT(argv[1]));
+
+ if (chmod(path, mode) == -1) {
+ QUEUE_EXCEPTION(strerror(errno));
+ return JS_FALSE;
+ }
+
+ return JS_TRUE;
+}
+
+static JSBool
+fs_sm_rename(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+ char *path1, *path2;
+
+ *rval = OBJECT_TO_JSVAL(NULL);
+
+ if (argc != 2) {
+ QUEUE_EXCEPTION("Wrong number of arguments");
+ return JS_FALSE;
+ }
+ if (!JSVAL_IS_STRING(argv[0])) {
+ QUEUE_EXCEPTION("Argument 1 not a String");
+ return JS_FALSE;
+ }
+ if (!JSVAL_IS_STRING(argv[1])) {
+ QUEUE_EXCEPTION("Argument 2 not a String");
+ return JS_FALSE;
+ }
+
+ if ((path1 = JS_GetStringBytes(JSVAL_TO_STRING(argv[0]))) == NULL) {
+ QUEUE_EXCEPTION("Internal error!");
+ return JS_FALSE;
+ }
+ if (fs_path_allow(path1) != 0) {
+ QUEUE_EXCEPTION("Path 1 not allowed");
+ return JS_FALSE;
+ }
+
+ if ((path2 = JS_GetStringBytes(JSVAL_TO_STRING(argv[1]))) == NULL) {
+ QUEUE_EXCEPTION("Internal error!");
+ return JS_FALSE;
+ }
+ if (fs_path_allow(path2) != 0) {
+ QUEUE_EXCEPTION("Path 2 not allowed");
+ return JS_FALSE;
+ }
+
+ if (rename(path1, path2) == -1) {
+ QUEUE_EXCEPTION(strerror(errno));
+ return JS_FALSE;
+ }
+
+ return JS_TRUE;
+}
+
+static JSBool
+fs_sm_unlink(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+ char *path;
+
+ *rval = OBJECT_TO_JSVAL(NULL);
+
+ if (argc != 1) {
+ QUEUE_EXCEPTION("Wrong number of arguments");
+ return JS_FALSE;
+ }
+ if (!JSVAL_IS_STRING(argv[0])) {
+ QUEUE_EXCEPTION("Argument 1 not a String");
+ return JS_FALSE;
+ }
+
+ if ((path = JS_GetStringBytes(JSVAL_TO_STRING(argv[0]))) == NULL) {
+ QUEUE_EXCEPTION("Internal error!");
+ return JS_FALSE;
+ }
+ if (fs_path_allow(path) != 0) {
+ QUEUE_EXCEPTION("Path not allowed");
+ return JS_FALSE;
+ }
+
+ if (unlink(path) == -1) {
+ QUEUE_EXCEPTION(strerror(errno));
+ return JS_FALSE;
+ }
+
+ return JS_TRUE;
+}
+
+static JSBool
+fs_sm_truncate(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+ char *path;
+ off_t size;
+ jsdouble dsize;
+
+ *rval = OBJECT_TO_JSVAL(NULL);
+
+ if (argc != 2) {
+ QUEUE_EXCEPTION("Wrong number of arguments");
+ return JS_FALSE;
+ }
+ if (!JSVAL_IS_STRING(argv[0])) {
+ QUEUE_EXCEPTION("Argument 1 not a String");
+ return JS_FALSE;
+ }
+ if (!JSVAL_IS_NUMBER(argv[1])) {
+ QUEUE_EXCEPTION("Argument 2 not a number");
+ return JS_FALSE;
+ }
+
+ if ((path = JS_GetStringBytes(JSVAL_TO_STRING(argv[0]))) == NULL) {
+ QUEUE_EXCEPTION("Internal error!");
+ return JS_FALSE;
+ }
+ if (fs_path_allow(path) != 0) {
+ QUEUE_EXCEPTION("Path not allowed");
+ return JS_FALSE;
+ }
+
+ if (!JS_ValueToNumber(cx, argv[1], &dsize)) {
+ QUEUE_EXCEPTION("Internal error!");
+ return JS_FALSE;
+ }
+ size = (off_t)dsize;
+
+ if (truncate(path, size) == -1) {
+ QUEUE_EXCEPTION(strerror(errno));
+ return JS_FALSE;
+ }
+
+ return JS_TRUE;
+}
+
+static JSBool
+fs_sm_creat(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ char *path;
+ mode_t mode;
+
+ *rval = OBJECT_TO_JSVAL(NULL);
+
+ if (argc != 2) {
+ QUEUE_EXCEPTION("Wrong number of arguments");
+ return JS_FALSE;
+ }
+ if (!JSVAL_IS_STRING(argv[0])) {
+ QUEUE_EXCEPTION("Argument 1 not a String");
+ return JS_FALSE;
+ }
+ if (!JSVAL_IS_INT(argv[1])) {
+ QUEUE_EXCEPTION("Argument 2 not an Integer");
+ return JS_FALSE;
+ }
+
+ if ((path = JS_GetStringBytes(JSVAL_TO_STRING(argv[0]))) == NULL) {
+ QUEUE_EXCEPTION("Internal error!");
+ return JS_FALSE;
+ }
+ if (fs_path_allow(path) != 0) {
+ QUEUE_EXCEPTION("Path not allowed");
+ return JS_FALSE;
+ }
+
+ mode = fs_mode_allow((mode_t)JSVAL_TO_INT(argv[1]));
+
+ if (creat(path, mode) == -1) {
+ QUEUE_EXCEPTION(strerror(errno));
+ return JS_FALSE;
+ }
+
+ return JS_TRUE;
+}
+
+static JSBool
+fs_sm_mknod(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ char *path;
+ mode_t mode;
+ dev_t dev;
+
+ *rval = OBJECT_TO_JSVAL(NULL);
+
+ if (argc != 3) {
+ QUEUE_EXCEPTION("Wrong number of arguments");
+ return JS_FALSE;
+ }
+ if (!JSVAL_IS_STRING(argv[0])) {
+ QUEUE_EXCEPTION("Argument 1 not a String");
+ return JS_FALSE;
+ }
+ if (!JSVAL_IS_INT(argv[1])) {
+ QUEUE_EXCEPTION("Argument 2 not an Integer");
+ return JS_FALSE;
+ }
+ if (!JSVAL_IS_INT(argv[2])) {
+ QUEUE_EXCEPTION("Argument 3 not an Integer");
+ return JS_FALSE;
+ }
+
+ if ((path = JS_GetStringBytes(JSVAL_TO_STRING(argv[0]))) == NULL) {
+ QUEUE_EXCEPTION("Internal error!");
+ return JS_FALSE;
+ }
+ if (fs_path_allow(path) != 0) {
+ QUEUE_EXCEPTION("Path not allowed");
+ return JS_FALSE;
+ }
+
+ mode = fs_mode_allow((mode_t)JSVAL_TO_INT(argv[1]));
+
+ dev = (dev_t)JSVAL_TO_INT(argv[2]);
+
+ if (mknod(path, mode, dev) == -1) {
+ QUEUE_EXCEPTION(strerror(errno));
+ return JS_FALSE;
+ }
+
+ return JS_TRUE;
+}
+
+static JSBool
+fs_sm_mkfifo(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+ char *path;
+ mode_t mode;
+
+ *rval = OBJECT_TO_JSVAL(NULL);
+
+ if (argc != 2) {
+ QUEUE_EXCEPTION("Wrong number of arguments");
+ return JS_FALSE;
+ }
+ if (!JSVAL_IS_STRING(argv[0])) {
+ QUEUE_EXCEPTION("Argument 1 not a String");
+ return JS_FALSE;
+ }
+ if (!JSVAL_IS_INT(argv[1])) {
+ QUEUE_EXCEPTION("Argument 2 not an Integer");
+ return JS_FALSE;
+ }
+
+ if ((path = JS_GetStringBytes(JSVAL_TO_STRING(argv[0]))) == NULL) {
+ QUEUE_EXCEPTION("Internal error!");
+ return JS_FALSE;
+ }
+ if (fs_path_allow(path) != 0) {
+ QUEUE_EXCEPTION("Path not allowed");
+ return JS_FALSE;
+ }
+
+ mode = fs_mode_allow((mode_t)JSVAL_TO_INT(argv[1]));
+
+ if (mkfifo(path, mode) == -1) {
+ QUEUE_EXCEPTION(strerror(errno));
+ return JS_FALSE;
+ }
+
+ return JS_TRUE;
+}
+
+static JSBool
+fs_sm_symlink(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+ char *path1, *path2;
+
+ *rval = OBJECT_TO_JSVAL(NULL);
+
+ if (argc != 2) {
+ QUEUE_EXCEPTION("Wrong number of arguments");
+ return JS_FALSE;
+ }
+ if (!JSVAL_IS_STRING(argv[0])) {
+ QUEUE_EXCEPTION("Argument 1 not a String");
+ return JS_FALSE;
+ }
+ if (!JSVAL_IS_STRING(argv[1])) {
+ QUEUE_EXCEPTION("Argument 2 not a String");
+ return JS_FALSE;
+ }
+
+ if ((path1 = JS_GetStringBytes(JSVAL_TO_STRING(argv[0]))) == NULL) {
+ QUEUE_EXCEPTION("Internal error!");
+ return JS_FALSE;
+ }
+ if (fs_path_allow(path1) != 0) {
+ QUEUE_EXCEPTION("Path 1 not allowed");
+ return JS_FALSE;
+ }
+
+ if ((path2 = JS_GetStringBytes(JSVAL_TO_STRING(argv[1]))) == NULL) {
+ QUEUE_EXCEPTION("Internal error!");
+ return JS_FALSE;
+ }
+ if (fs_path_allow(path2) != 0) {
+ QUEUE_EXCEPTION("Path 2 not allowed");
+ return JS_FALSE;
+ }
+
+ if (symlink(path1, path2) == -1) {
+ QUEUE_EXCEPTION(strerror(errno));
+ return JS_FALSE;
+ }
+
+ return JS_TRUE;
+}
+
+
+static JSBool
+fs_sm_stat_i(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval, int (*stat_i)(const char *, struct stat *))
+{
+ char *path;
+ struct stat st;
+ JSObject *o = NULL;
+ jsval val;
+
+ *rval = OBJECT_TO_JSVAL(NULL);
+
+ if (argc != 1) {
+ QUEUE_EXCEPTION("Wrong number of arguments");
+ return JS_FALSE;
+ }
+ if (!JSVAL_IS_STRING(argv[0])) {
+ QUEUE_EXCEPTION("Argument 1 not a String");
+ return JS_FALSE;
+ }
+
+ if ((path = JS_GetStringBytes(JSVAL_TO_STRING(argv[0]))) == NULL) {
+ QUEUE_EXCEPTION("Internal error!");
+ return JS_FALSE;
+ }
+
+ if (fs_path_allow(path) == -1) {
+ QUEUE_EXCEPTION("Path now allowed");
+ return JS_FALSE;
+ }
+
+ if (stat_i(path, &st) == -1) {
+ QUEUE_EXCEPTION(strerror(errno));
+ return JS_FALSE;
+ }
+
+ /*
+ * Note: We immediately link newly created objects to avoid GC
+ * problems. For the simplicity of this task we don't need an
+ * additional root to be created using JS_AddRoot(), since *rval
+ * is already rooted. Moreover, the double objects we create are
+ * immediately added as propery as well.
+ */
+
+ if ((o = JS_NewObject(cx, NULL, NULL, NULL)) == NULL) {
+ QUEUE_EXCEPTION("Out of memory");
+ goto err;
+ }
+ *rval = OBJECT_TO_JSVAL(o);
+
+#define DEFINE_INT_PROP(n, i) do { \
+ val = INT_TO_JSVAL((int)(i)); \
+ if (!JS_DefineProperty(cx, o, (n), val, NULL, NULL, \
+ JSPROP_ENUMERATE)) { \
+ QUEUE_EXCEPTION("Internal error!"); \
+ goto err; \
+ } \
+} while (/* CONSTCOND */0)
+
+#define DEFINE_DOUBLE_PROP(n, d) do { \
+ if (!JS_NewDoubleValue(cx, (jsdouble)(d), &val)) \
+ goto err; \
+ if (!JS_DefineProperty(cx, o, (n), val, NULL, NULL, \
+ JSPROP_ENUMERATE)) { \
+ QUEUE_EXCEPTION("Internal error!"); \
+ goto err; \
+ } \
+} while (/* CONSTCOND */0)
+
+ DEFINE_INT_PROP("st_dev", st.st_dev);
+ DEFINE_INT_PROP("st_ino", st.st_ino);
+ DEFINE_INT_PROP("st_mode", st.st_mode);
+ DEFINE_INT_PROP("st_nlink", st.st_nlink);
+ DEFINE_INT_PROP("st_uid", st.st_uid);
+ DEFINE_INT_PROP("st_gid", st.st_gid);
+ DEFINE_INT_PROP("st_rdev", st.st_rdev);
+ DEFINE_DOUBLE_PROP("st_atime", st.st_atime);
+ DEFINE_DOUBLE_PROP("st_mtime", st.st_mtime);
+ DEFINE_DOUBLE_PROP("st_ctime", st.st_ctime);
+ DEFINE_DOUBLE_PROP("st_size", st.st_size);
+ DEFINE_DOUBLE_PROP("st_blocks", st.st_blocks);
+ DEFINE_INT_PROP("st_blksize", st.st_blksize);
+ DEFINE_INT_PROP("st_flags", st.st_flags);
+ DEFINE_INT_PROP("st_gen", st.st_gen);
+
+#undef DEFINE_INT_PROP
+#undef DEFINE_DOUBLE_PROP
+
+ return JS_TRUE;
+
+err:
+ *rval = OBJECT_TO_JSVAL(NULL);
+
+ return JS_FALSE;
+}
+
+
+static int
+chown_resolve(JSContext *cx, jsval vuid, jsval vgid, uid_t *uid, gid_t *gid)
+{
+ char *str, e[1024];
+ struct passwd *pwd;
+ struct group *grp;
+
+ if (JSVAL_IS_STRING(vuid)) {
+ if ((str = JS_GetStringBytes(JSVAL_TO_STRING(vuid))) == NULL) {
+ QUEUE_EXCEPTION("Internal error!");
+ return -1;
+ }
+ if ((pwd = getpwnam(str)) == NULL) {
+ (void) snprintf(e, 1023, "Unknown user '%s'", str);
+ QUEUE_EXCEPTION(e);
+ return -1;
+ }
+ *uid = pwd->pw_uid;
+ } else if (JSVAL_IS_INT(vuid))
+ *uid = JSVAL_TO_INT(vuid);
+ else {
+ QUEUE_EXCEPTION("uid argument not String or Integer");
+ return -1;
+ }
+
+ if (JSVAL_IS_STRING(vgid)) {
+ if ((str = JS_GetStringBytes(JSVAL_TO_STRING(vgid))) == NULL) {
+ QUEUE_EXCEPTION("Internal error!");
+ return -1;
+ }
+ if ((grp = getgrnam(str)) == NULL) {
+ (void) snprintf(e, 1023, "Unknown group '%s'", str);
+ QUEUE_EXCEPTION(e);
+ return -1;
+ }
+ *gid = grp->gr_gid;
+ } else if (JSVAL_IS_INT(vgid))
+ *gid = JSVAL_TO_INT(vgid);
+ else {
+ QUEUE_EXCEPTION("gid argument not String or Integer");
+ return -1;
+ }
+
+ return 0;
+}
+
+static mode_t
+fs_mode_allow(mode_t mode)
+{
+ /* XXX */
+
+ return mode;
+}
+
+/* ARGSUSED */
+static int
+fs_path_allow(const char *path)
+{
+ /* XXX */
+
+ return 0;
+}