#include #include #include #include #include #include #include #include #include #include #include #include #include "js_util_functions.h" #include "file.h" //You must include the .0 on the constant 1000.0 so the calculation is done as a double, not as an integer. #define SEC_TO_MSEC(sec) (sec*1000.0) static JSBool checkForPermission(FileInformation *info, int perm); static JSBool File_ctor(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval); static JSBool File_exists(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval); static JSBool File_create(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval); static JSBool File_touch(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval); static JSBool File_getPermissions(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval); static JSBool File_isReadable(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval); static JSBool File_isWritable(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval); static JSBool File_isExecutable(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval); static JSBool File_isLink(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval); static JSBool File_isPipe(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval); static JSBool File_isSocket(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval); static JSBool File_isDirectory(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval); static JSBool File_getLastModified(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval); static JSBool File_getLastAccess(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval); static JSBool File_getCreationTime(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval); static JSBool File_getSize(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval); static JSBool File_truncate(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval); static JSObject *FilePrototype = NULL; static JSClass js_File_class = { "File", JSCLASS_HAS_PRIVATE, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub, JSCLASS_NO_OPTIONAL_MEMBERS }; static JSFunctionSpec File_methods[] = { {"create", File_create, 0, 0 ,0}, {"touch", File_touch, 0, 0, 0}, {"exists", File_exists, 0, 0 ,0}, {"getPermissions", File_getPermissions, 0, 0 ,0}, {"isReadable", File_isReadable, 0, 0 ,0}, {"isWritable", File_isWritable, 0, 0 ,0}, {"isExecutable", File_isExecutable, 0, 0 ,0}, {"isLink", File_isLink, 0, 0 ,0}, {"isPipe", File_isPipe, 0, 0 ,0}, {"isSocket", File_isSocket, 0, 0 ,0}, {"isDirectory", File_isDirectory, 0, 0 ,0}, {"getLastModified", File_getLastModified, 0, 0 ,0}, {"getLastAccess", File_getLastAccess, 0, 0 ,0}, {"getCreationTime", File_getCreationTime, 0, 0 ,0}, {"getSize", File_getSize, 0, 0 ,0}, {"truncate", File_truncate, 0, 0 ,0}, {NULL} }; static char *staterrorstr(int e){ char *msg = NULL; switch (e){ case ENOENT: msg = strdup("File does not exist."); break; case EACCES: msg = strdup("Permission denied to check file."); break; case EBADF: msg = strdup("Bad file descriptor"); break; case ELOOP: msg = strdup("Symbolic link loop encountered."); break; case ENAMETOOLONG: msg = strdup("File name too long, not supported."); break; case ENOMEM: msg = strdup("Out of memory."); break; case ENOTDIR: msg = strdup("Path component not a directory."); break; default: msg = strdup("Unknown error occured."); } return msg; } JSBool register_class_File(JSContext *cx){ JSObject *globalObj = JS_GetGlobalObject(cx); /* Define the file object. */ FilePrototype = JS_InitClass(cx, globalObj, NULL, &js_File_class, File_ctor, 1, NULL, File_methods, NULL, NULL); if (!FilePrototype){ return JS_FALSE; } return JS_TRUE; } JSObject *File_getPrototypeObject(){ return FilePrototype; } static JSBool File_ctor(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval){ if (argc < 1){ char *str = strdup("Not enough parameters to File constructor."); JSString *exceptionDescription = JS_NewString(cx, str, strlen(str)); JS_SetPendingException(cx, STRING_TO_JSVAL(exceptionDescription)); return JS_FALSE; } else { char *file=NULL; size_t fileNameLength=0; FileInformation *info = malloc(sizeof(*info)); info->fp = NULL; info->filename = NULL; fileNameLength = JSString_to_CString(JS_ValueToString(cx, argv[0]), &file); info->filename = strdup(file); JS_SetPrivate(cx, obj, info); } return JS_TRUE; } static JSBool File_create(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval){ /* First see if the file already exists. If it does, throw an exception. */ struct stat existsCheck; FileInformation *info = (FileInformation*)JS_GetPrivate(cx, obj); if (stat(info->filename, &existsCheck) == 0){ jsval exception = printf_exception(cx, "Cannot create file '%s'. A file by that name already exists.", info->filename); JS_SetPendingException(cx, exception); return JS_FALSE; } else if (errno == ENOENT){ FILE *fp = NULL; fp = fopen(info->filename, "w"); if (fp){ fclose(fp); *rval = BOOLEAN_TO_JSVAL(JS_TRUE); } else { *rval = BOOLEAN_TO_JSVAL(JS_FALSE); } return JS_TRUE; } else { char *msg = staterrorstr(errno); jsval exception = printf_exception(cx, "Creation failed. (%d) %s", errno, msg); free(msg); JS_SetPendingException(cx, exception); return JS_FALSE; } return JS_TRUE; } static JSBool File_touch(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval){ struct stat existsCheck; FileInformation *info = (FileInformation*)JS_GetPrivate(cx, obj); if (stat(info->filename, &existsCheck) == 0){ struct utimbuf times; times.actime = time(NULL); times.modtime = time(NULL); if (utime(info->filename, ×) == 0){ *rval = BOOLEAN_TO_JSVAL(JS_TRUE); } else { char *msg = staterrorstr(errno); jsval exception = printf_exception(cx, "touch failed. (%d) %s", errno, msg); free(msg); JS_SetPendingException(cx, exception); return JS_FALSE; } } else if (errno == ENOENT){ FILE *fp = fopen(info->filename, "w"); if (fp){ fclose(fp); *rval = BOOLEAN_TO_JSVAL(JS_TRUE); } else { char *msg = staterrorstr(errno); jsval exception = printf_exception(cx, "touch failed, could not create file. (%d) %s", errno, msg); free(msg); JS_SetPendingException(cx, exception); return JS_FALSE; } } else { char *msg = staterrorstr(errno); jsval exception = printf_exception(cx, "Existance check failed (%d) %s", errno, msg); free(msg); JS_SetPendingException(cx, exception); return JS_FALSE; } return JS_TRUE; } static JSBool File_exists(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval){ /* First see if the file already exists. If it does, throw an exception. */ struct stat existsCheck; FileInformation *info = (FileInformation*)JS_GetPrivate(cx, obj); if (stat(info->filename, &existsCheck) == 0){ *rval = BOOLEAN_TO_JSVAL(JS_TRUE); } else if (errno == ENOENT){ *rval = BOOLEAN_TO_JSVAL(JS_FALSE); } else { char *msg = staterrorstr(errno); jsval exception = printf_exception(cx, "Existance check failed. (%d) %s", errno, msg); free(msg); JS_SetPendingException(cx, exception); return JS_FALSE; } return JS_TRUE; } static JSBool File_getPermissions(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval){ struct stat fileInfo; FileInformation *info = (FileInformation*)JS_GetPrivate(cx, obj); if (stat(info->filename, &fileInfo) == 0){ *rval = INT_TO_JSVAL(fileInfo.st_mode); return JS_TRUE; } else { char *msg = staterrorstr(errno); jsval exception = printf_exception(cx, "stat failed on file (%d) %s", errno, msg); free(msg); JS_SetPendingException(cx, exception); return JS_FALSE; } } static JSBool File_isReadable(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval){ FileInformation *info = (FileInformation*)JS_GetPrivate(cx, obj); errno = 0; if (checkForPermission(info, S_IRUSR|S_IRGRP|S_IROTH)){ *rval = BOOLEAN_TO_JSVAL(JS_TRUE); return JS_TRUE; } else { if (errno == 0){ *rval = BOOLEAN_TO_JSVAL(JS_FALSE); return JS_TRUE; } else { char *msg = staterrorstr(errno); jsval exception = printf_exception(cx, "stat failed on file (%d) %s", errno, msg); free(msg); JS_SetPendingException(cx, exception); return JS_FALSE; } } } static JSBool File_isWritable(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval){ FileInformation *info = (FileInformation*)JS_GetPrivate(cx, obj); errno = 0; if (checkForPermission(info, S_IWUSR|S_IWGRP|S_IWOTH)){ *rval = BOOLEAN_TO_JSVAL(JS_TRUE); return JS_TRUE; } else { if (errno == 0){ *rval = BOOLEAN_TO_JSVAL(JS_FALSE); return JS_TRUE; } else { char *msg = staterrorstr(errno); jsval exception = printf_exception(cx, "stat failed on file (%d) %s", errno, msg); free(msg); JS_SetPendingException(cx, exception); return JS_FALSE; } } } static JSBool File_isExecutable(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval){ FileInformation *info = (FileInformation*)JS_GetPrivate(cx, obj); errno = 0; if (checkForPermission(info, S_IXUSR|S_IXGRP|S_IXOTH)){ *rval = BOOLEAN_TO_JSVAL(JS_TRUE); return JS_TRUE; } else { if (errno == 0){ *rval = BOOLEAN_TO_JSVAL(JS_FALSE); return JS_TRUE; } else { char *msg = staterrorstr(errno); jsval exception = printf_exception(cx, "stat failed on file (%d) %s", errno, msg); free(msg); JS_SetPendingException(cx, exception); return JS_FALSE; } } } static JSBool File_isLink(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval){ struct stat fileInfo; FileInformation *info = (FileInformation*)JS_GetPrivate(cx, obj); if (lstat(info->filename, &fileInfo) == 0){ if (S_ISLNK(fileInfo.st_mode)){ *rval = BOOLEAN_TO_JSVAL(JS_TRUE); } else { *rval = BOOLEAN_TO_JSVAL(JS_FALSE); } return JS_TRUE; } else { char *msg = staterrorstr(errno); jsval exception = printf_exception(cx, "stat failed on file (%d) %s", errno, msg); free(msg); JS_SetPendingException(cx, exception); return JS_FALSE; } } static JSBool File_isPipe(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval){ struct stat fileInfo; FileInformation *info = (FileInformation*)JS_GetPrivate(cx, obj); if (stat(info->filename, &fileInfo) == 0){ if (S_ISFIFO(fileInfo.st_mode)){ *rval = BOOLEAN_TO_JSVAL(JS_TRUE); } else { *rval = BOOLEAN_TO_JSVAL(JS_FALSE); } return JS_TRUE; } else { char *msg = staterrorstr(errno); jsval exception = printf_exception(cx, "stat failed on file (%d) %s", errno, msg); free(msg); JS_SetPendingException(cx, exception); return JS_FALSE; } } static JSBool File_isSocket(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval){ struct stat fileInfo; FileInformation *info = (FileInformation*)JS_GetPrivate(cx, obj); if (stat(info->filename, &fileInfo) == 0){ if (S_ISSOCK(fileInfo.st_mode)){ *rval = BOOLEAN_TO_JSVAL(JS_TRUE); } else { *rval = BOOLEAN_TO_JSVAL(JS_FALSE); } return JS_TRUE; } else { char *msg = staterrorstr(errno); jsval exception = printf_exception(cx, "stat failed on file (%d) %s", errno, msg); free(msg); JS_SetPendingException(cx, exception); return JS_FALSE; } } static JSBool File_isDirectory(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval){ struct stat fileInfo; FileInformation *info = (FileInformation*)JS_GetPrivate(cx, obj); if (stat(info->filename, &fileInfo) == 0){ if (S_ISDIR(fileInfo.st_mode)){ *rval = BOOLEAN_TO_JSVAL(JS_TRUE); } else { *rval = BOOLEAN_TO_JSVAL(JS_FALSE); } return JS_TRUE; } else { char *msg = staterrorstr(errno); jsval exception = printf_exception(cx, "stat failed on file (%d) %s", errno, msg); free(msg); JS_SetPendingException(cx, exception); return JS_FALSE; } } static JSBool File_getLastModified(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval){ struct stat fileInfo; FileInformation *info = (FileInformation*)JS_GetPrivate(cx, obj); if (stat(info->filename, &fileInfo) == 0){ JSObject *dateObj = js_NewDateObjectMsec(cx, SEC_TO_MSEC(fileInfo.st_mtime)); if (!dateObj){ jsval exception = printf_exception(cx, "Unable to construct date object to hold time."); JS_SetPendingException(cx, exception); return JS_FALSE; } *rval = OBJECT_TO_JSVAL(dateObj); return JS_TRUE; } else { char *msg = staterrorstr(errno); jsval exception = printf_exception(cx, "stat failed on file (%d) %s", errno, msg); free(msg); JS_SetPendingException(cx, exception); return JS_FALSE; } } static JSBool File_getLastAccess(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval){ struct stat fileInfo; FileInformation *info = (FileInformation*)JS_GetPrivate(cx, obj); if (stat(info->filename, &fileInfo) == 0){ JSObject *dateObj = js_NewDateObjectMsec(cx, SEC_TO_MSEC(fileInfo.st_atime)); if (!dateObj){ jsval exception = printf_exception(cx, "Unable to construct date object to hold time."); JS_SetPendingException(cx, exception); return JS_FALSE; } *rval = OBJECT_TO_JSVAL(dateObj); return JS_TRUE; } else { char *msg = staterrorstr(errno); jsval exception = printf_exception(cx, "stat failed on file (%d) %s", errno, msg); free(msg); JS_SetPendingException(cx, exception); return JS_FALSE; } } static JSBool File_getCreationTime(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval){ struct stat fileInfo; FileInformation *info = (FileInformation*)JS_GetPrivate(cx, obj); if (stat(info->filename, &fileInfo) == 0){ JSObject *dateObj = js_NewDateObjectMsec(cx, SEC_TO_MSEC(fileInfo.st_ctime)); if (!dateObj){ jsval exception = printf_exception(cx, "Unable to construct date object to hold time."); JS_SetPendingException(cx, exception); return JS_FALSE; } *rval = OBJECT_TO_JSVAL(dateObj); return JS_TRUE; } else { char *msg = staterrorstr(errno); jsval exception = printf_exception(cx, "stat failed on file (%d) %s", errno, msg); free(msg); JS_SetPendingException(cx, exception); return JS_FALSE; } } static JSBool File_getSize(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval){ struct stat fileInfo; FileInformation *info = (FileInformation*)JS_GetPrivate(cx, obj); if (stat(info->filename, &fileInfo) == 0){ *rval = INT_TO_JSVAL(fileInfo.st_size); return JS_TRUE; } else { char *msg = staterrorstr(errno); jsval exception = printf_exception(cx, "stat failed on file (%d) %s", errno, msg); free(msg); JS_SetPendingException(cx, exception); return JS_FALSE; } } static JSBool File_truncate(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval){ FileInformation *info = (FileInformation*)JS_GetPrivate(cx, obj); if (argc >= 1){ off_t len = JSVAL_TO_INT(argv[0]); if (truncate(info->filename, len) == 0){ *rval = BOOLEAN_TO_JSVAL(JS_TRUE); return JS_TRUE; } else { char *msg = staterrorstr(errno); jsval exception = printf_exception(cx, "Truncate failed on file. (%d) %s", errno, msg); free(msg); JS_SetPendingException(cx, exception); return JS_FALSE; } } else { jsval exception = printf_exception(cx, "Not enough arguments"); JS_SetPendingException(cx, exception); return JS_FALSE; } } static JSBool checkForPermission(FileInformation *info, int perm){ struct stat fileInfo; if (stat(info->filename, &fileInfo) == 0){ uid_t uid=-1; gid_t gid=-1; uid = geteuid(); gid = getegid(); if (uid == fileInfo.st_uid){ if (fileInfo.st_mode & (perm & S_IRWXU)){ return JS_TRUE; } else { return JS_FALSE; } } else if (gid == fileInfo.st_gid){ if (fileInfo.st_mode & (perm & S_IRWXG)){ return JS_TRUE; } else { return JS_FALSE; } } else { if (fileInfo.st_mode & (perm & S_IRWXO)){ return JS_TRUE; } else { return JS_FALSE; } } } else { return JS_FALSE; } }