#include <errno.h> #include <stdlib.h> #ifdef XP_WIN # include <direct.h> # include <process.h> # include <string.h> # include <wchar.h> # include "util/WindowsWrapper.h" #elif __wasi__ # include <dirent.h> # include <sys/types.h> # include <unistd.h> #else # include <dirent.h> # include <sys/types.h> # include <sys/wait.h> # include <unistd.h> #endif
#include"jsapi.h" // For JSFunctionSpecWithHelp #include"jsfriendapi.h"
#ifdef XP_WIN // On Windows there are various forms of absolute paths (see // http://msdn.microsoft.com/en-us/library/windows/desktop/aa365247%28v=vs.85%29.aspx // for details): // // "\..." // "\\..." // "C:\..." // // The first two cases are handled by the common test below so we only need a // specific test for the last one here.
# ifdef __wasi__ // dirname() seems not to behave properly with wasi-libc; so we do our own // simple thing here. char* p = dirName + strlen(dirName); bool found = false; while (p > dirName) { if (*p == '/') {
found = true;
*p = '\0'; break;
}
p--;
} if (!found) { // There's no '/'. Possible cases are the following: // * "." // * ".." // * filename only // // dirname() returns "." for all cases.
dirName[0] = '.';
dirName[1] = '\0';
} # else // dirname(dirName) might return dirName, or it might return a // statically-allocated string
memmove(dirName, dirname(dirName), strlen(dirName) + 1); # endif
JS::AutoFilename scriptFilename; if (resolveMode == ScriptRelative) { // Get the currently executing script's name.
if (!DescribeScriptedCaller(&scriptFilename, cx) || !scriptFilename.get()) {
JS_ReportErrorASCII(
cx, "cannot resolve path due to hidden or unscripted caller"); return nullptr;
}
if (len > ArrayBufferObject::ByteLengthLimit) {
JS_ReportErrorUTF8(cx, "file %s is too large for a Uint8Array",
pathname.get()); return nullptr;
}
JS::Rooted<JSObject*> obj(cx, JS_NewUint8Array(cx, len)); if (!obj) { return nullptr;
}
js::TypedArrayObject& ta = obj->as<js::TypedArrayObject>(); if (ta.isSharedMemory()) { // Must opt in to use shared memory. For now, don't. // // (It is incorrect to read into the buffer without // synchronization since that can create a race. A // lock here won't fix it - both sides must // participate. So what one must do is to create a // temporary buffer, read into that, and use a // race-safe primitive to copy memory into the // buffer.)
JS_ReportErrorUTF8(cx, "can't read %s: shared memory buffer",
pathname.get()); return nullptr;
}
UniqueChars pathname = JS_EncodeStringToUTF8(cx, str); if (!pathname) {
JS_ReportErrorASCII(cx, "os.file.listDir cannot convert path to UTF8"); returnfalse;
}
RootedValueVector elems(cx); auto append = [&](constchar* name) -> bool { if (!(str = JS_NewStringCopyZ(cx, name))) { returnfalse;
} if (!elems.append(StringValue(str))) {
js::ReportOutOfMemory(cx); returnfalse;
} returntrue;
};
#ifdefined(XP_UNIX)
{
DIR* dir = opendir(pathname.get()); if (!dir) {
JS_ReportErrorUTF8(cx, "os.file.listDir is unable to open: %s",
pathname.get()); returnfalse;
} auto close = mozilla::MakeScopeExit([&] { if (closedir(dir) != 0) {
MOZ_CRASH("Could not close dir");
}
});
WIN32_FIND_DATAA FindFileData;
HANDLE hFind = FindFirstFileA(pattern.begin(), &FindFileData); if (hFind == INVALID_HANDLE_VALUE) {
JS_ReportErrorUTF8(cx, "os.file.listDir is unable to open: %s",
pathname.get()); returnfalse;
} auto close = mozilla::MakeScopeExit([&] { if (!FindClose(hFind)) {
MOZ_CRASH("Could not close Find");
}
}); for (bool found = (hFind != INVALID_HANDLE_VALUE); found;
found = FindNextFileA(hFind, &FindFileData)) { if (!append(FindFileData.cFileName)) { returnfalse;
}
}
} #endif
JSObject* array = JS::NewArrayObject(cx, elems); if (!array) { returnfalse;
}
// Grant the global gOutFile ownership of the new file, release ownership // of its old file, and return a FileObject owning the old file.
file->acquire(); // Global owner of new file
FileObject* fileObj =
FileObject::create(cx, *globalFile); // Newly created owner of old file if (!fileObj) {
file->release(); return nullptr;
}
(*globalFile)->release(); // Release (global) ownership of old file.
*globalFile = file;
if (args.get(0).isUndefined()) {
args.rval().setObject(*oldFileObj); returntrue;
}
if (args[0].isObject()) {
Rooted<FileObject*> fileObj(cx,
args[0].toObject().maybeUnwrapIf<FileObject>()); if (!fileObj) {
JS_ReportErrorNumberASCII(cx, js::shell::my_GetErrorMessage, nullptr,
JSSMSG_INVALID_ARGS, "redirect"); returnfalse;
}
// Passed in a FileObject. Create a FileObject for the previous // global file, and set the global file to the passed-in one.
*outFile = fileObj->rcFile();
(*outFile)->acquire();
oldFile->release();
args.rval().setObject(*oldFileObj); returntrue;
}
RootedString filename(cx); if (!args[0].isNull()) {
filename = JS::ToString(cx, args[0]); if (!filename) { returnfalse;
}
}
if (!redirect(cx, filename, outFile)) { returnfalse;
}
Rooted<FileObject*> fileObj(cx); if (args.get(0).isObject()) {
fileObj = args[0].toObject().maybeUnwrapIf<FileObject>();
}
if (!fileObj) {
JS_ReportErrorNumberASCII(cx, js::shell::my_GetErrorMessage, nullptr,
JSSMSG_INVALID_ARGS, "close"); returnfalse;
}
fileObj->close();
args.rval().setUndefined(); returntrue;
}
// clang-format off staticconst JSFunctionSpecWithHelp osfile_functions[] = {
JS_FN_HELP("readFile", osfile_readFile, 1, 0, "readFile(filename, [\"binary\"])", " Read entire contents of filename. Returns a string, unless \"binary\" is passed\n" " as the second argument, in which case it returns a Uint8Array. Filename is\n" " relative to the current working directory."),
JS_FN_HELP("readRelativeToScript", osfile_readRelativeToScript, 1, 0, "readRelativeToScript(filename, [\"binary\"])", " Read filename into returned string. Filename is relative to the directory\n" " containing the current script."),
JS_FN_HELP("listDir", osfile_listDir, 1, 0, "listDir(dirname)", " Read entire contents of a directory. The \"dirname\" parameter is relate to the\n" " current working directory. Returns a list of filenames within the given directory.\n" " Note that \".\" and \"..\" are also listed."),
JS_FN_HELP("listDirRelativeToScript", osfile_listDirRelativeToScript, 1, 0, "listDirRelativeToScript(dirname)", " Same as \"listDir\" except that the \"dirname\" is relative to the directory\n" " containing the current script."),
JS_FS_HELP_END
}; // clang-format on
// clang-format off staticconst JSFunctionSpecWithHelp osfile_unsafe_functions[] = {
JS_FN_HELP("writeTypedArrayToFile", osfile_writeTypedArrayToFile, 2, 0, "writeTypedArrayToFile(filename, data)", " Write the contents of a typed array to the named file."),
JS_FN_HELP("redirect", osfile_redirectOutput, 1, 0, "redirect([path-or-object])", " Redirect print() output to the named file.\n" " Return an opaque object representing the previous destination, which\n" " may be passed into redirect() later to restore the output."),
JS_FN_HELP("redirectErr", osfile_redirectError, 1, 0, "redirectErr([path-or-object])", " Same as redirect(), but for printErr"),
JS_FN_HELP("close", osfile_close, 1, 0, "close(object)", " Close the file returned by an earlier redirect call."),
// There are two possible definitions of strerror_r floating around. The GNU // one returns a char* which may or may not be the buffer you passed in. The // other one returns an integer status code, and always writes the result into // the provided buffer.
// It is too easy to kill yourself accidentally with os.kill("goose"). if (pid == 0 && !args[0].isInt32()) {
JS_ReportErrorASCII(cx, "os.kill requires numeric pid"); returnfalse;
}
int signal = SIGINT; if (args.length() > 1) { if (!JS::ToInt32(cx, args[1], &signal)) { returnfalse;
}
}
int status = kill(pid, signal); if (status == -1) {
ReportSysError(cx, "kill failed"); returnfalse;
}
// clang-format off staticconst JSFunctionSpecWithHelp os_functions[] = {
JS_FN_HELP("getenv", os_getenv, 1, 0, "getenv(variable)", " Get the value of an environment variable."),
JS_FN_HELP("getpid", os_getpid, 0, 0, "getpid()", " Return the current process id."),
#ifndef __wasi__
JS_FN_HELP("system", os_system, 1, 0, "system(command)", " Execute command on the current host, returning result code or throwing an\n" " exception on failure."),
# ifndef XP_WIN
JS_FN_HELP("spawn", os_spawn, 1, 0, "spawn(command)", " Start up a separate process running the given command. Returns the pid."),
JS_FN_HELP("kill", os_kill, 1, 0, "kill(pid[, signal])", " Send a signal to the given pid. The default signal is SIGINT. The signal\n" " passed in must be numeric, if given."),
JS_FN_HELP("waitpid", os_waitpid, 1, 0, "waitpid(pid[, nohang])", " Calls waitpid(). 'nohang' is a boolean indicating whether to pass WNOHANG.\n" " The return value is an object containing a 'pid' field, if a process was waitable\n" " and an 'exitStatus' field if a pid exited."), # endif #endif// !__wasi__
// For backwards compatibility, expose various os.file.* functions as // direct methods on the global. struct Export { constchar* src; constchar* dst;
};
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.