| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661 |
- //-------------------------------------------------------------------------------------------------------
- // Copyright (C) Microsoft. All rights reserved.
- // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
- //-------------------------------------------------------------------------------------------------------
- #include "stdafx.h"
- #include <sys/stat.h>
- #if defined(__APPLE__)
- #include <mach-o/dyld.h> // _NSGetExecutablePath
- #elif defined(__linux__)
- #include <unistd.h> // readlink
- #elif !defined(_WIN32)
- #error "How to get the executable path for this platform?"
- #endif // _WIN32 ?
- //TODO: x-plat definitions
- #ifdef _WIN32
- #define MAX_URI_LENGTH 512
- #define TTD_HOST_PATH_SEP "\\"
- void TTDHostBuildCurrentExeDirectory(char* path, size_t* pathLength, size_t bufferLength)
- {
- wchar exePath[MAX_PATH];
- GetModuleFileName(NULL, exePath, MAX_PATH);
- size_t i = wcslen(exePath) - 1;
- while(exePath[i] != _u('\\'))
- {
- --i;
- }
- if(i * 3 > bufferLength)
- {
- printf("Don't overflow path buffer during conversion");
- exit(1);
- }
- *pathLength = utf8::EncodeInto((LPUTF8)path, exePath, (charcount_t)(i + 1));
- path[*pathLength] = '\0';
- }
- int TTDHostMKDir(const char* path, size_t pathLength)
- {
- char16 cpath[MAX_PATH];
- LPCUTF8 pathbase = (LPCUTF8)path;
- if(MAX_PATH <= pathLength) //<= to account for null terminator
- {
- printf("Don't overflow path buffer during conversion");
- exit(1);
- }
- utf8::DecodeUnitsIntoAndNullTerminate(cpath, pathbase, pathbase + pathLength);
- return _wmkdir(cpath);
- }
- JsTTDStreamHandle TTDHostOpen(size_t pathLength, const char* path, bool isWrite)
- {
- char16 wpath[MAX_PATH];
- LPCUTF8 pathbase = (LPCUTF8)path;
- if(MAX_PATH <= pathLength) //<= to account for null terminator
- {
- printf("Don't overflow path buffer during conversion");
- exit(1);
- }
- utf8::DecodeUnitsIntoAndNullTerminate(wpath, pathbase, pathbase + pathLength);
- FILE* res = nullptr;
- _wfopen_s(&res, wpath, isWrite ? _u("w+b") : _u("r+b"));
- return (JsTTDStreamHandle)res;
- }
- #define TTDHostRead(buff, size, handle) fread_s(buff, size, 1, size, (FILE*)handle);
- #define TTDHostWrite(buff, size, handle) fwrite(buff, 1, size, (FILE*)handle)
- #else
- #ifdef __APPLE__
- #include <mach-o/dyld.h>
- #else
- #include <unistd.h>
- #endif
- #define MAX_URI_LENGTH 512
- #define TTD_HOST_PATH_SEP "/"
- void TTDHostBuildCurrentExeDirectory(char* path, size_t* pathLength, size_t bufferLength)
- {
- char exePath[MAX_URI_LENGTH];
- //TODO: xplattodo move this logic to PAL
- #ifdef __APPLE__
- uint32_t tmpPathSize = sizeof(exePath);
- _NSGetExecutablePath(exePath, &tmpPathSize);
- size_t i = strlen(exePath) - 1;
- #else
- size_t i = readlink("/proc/self/exe", exePath, MAX_URI_LENGTH) - 1;
- #endif
- while(exePath[i] != '/')
- {
- --i;
- }
- *pathLength = i + 1;
- if(*pathLength > bufferLength)
- {
- printf("Don't overflow path buffer during copy.");
- exit(1);
- }
- memcpy_s(path, bufferLength, exePath, *pathLength);
- }
- int TTDHostMKDir(const char* path, size_t pathLength)
- {
- return mkdir(path, 0700);
- }
- JsTTDStreamHandle TTDHostOpen(size_t pathLength, const char* path, bool isWrite)
- {
- return (JsTTDStreamHandle)fopen(path, isWrite ? "w+b" : "r+b");
- }
- #define TTDHostRead(buff, size, handle) fread(buff, 1, size, (FILE*)handle)
- #define TTDHostWrite(buff, size, handle) fwrite(buff, 1, size, (FILE*)handle)
- #endif
- HRESULT Helpers::LoadScriptFromFile(LPCSTR filename, LPCSTR& contents, UINT* lengthBytesOut /*= nullptr*/)
- {
- HRESULT hr = S_OK;
- BYTE * pRawBytes = nullptr;
- UINT lengthBytes = 0;
- contents = nullptr;
- FILE * file = NULL;
- //
- // Open the file as a binary file to prevent CRT from handling encoding, line-break conversions,
- // etc.
- //
- if (fopen_s(&file, filename, "rb") != 0)
- {
- #ifdef _WIN32
- DWORD lastError = GetLastError();
- char16 wszBuff[512];
- fprintf(stderr, "Error in opening file '%s' ", filename);
- wszBuff[0] = 0;
- if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
- nullptr,
- lastError,
- 0,
- wszBuff,
- _countof(wszBuff),
- nullptr))
- {
- fwprintf(stderr, _u(": %s"), wszBuff);
- }
- fwprintf(stderr, _u("\n"));
- #elif defined(_POSIX_VERSION)
- fprintf(stderr, "Error in opening file: ");
- perror(filename);
- #endif
- IfFailGo(E_FAIL);
- }
- if (file != NULL)
- {
- // Determine the file length, in bytes.
- fseek(file, 0, SEEK_END);
- lengthBytes = ftell(file);
- fseek(file, 0, SEEK_SET);
- const size_t bufferLength = lengthBytes + sizeof(BYTE);
- pRawBytes = (LPBYTE)malloc(bufferLength);
- if (nullptr == pRawBytes)
- {
- fwprintf(stderr, _u("out of memory"));
- IfFailGo(E_OUTOFMEMORY);
- }
- //
- // Read the entire content as a binary block.
- //
- size_t readBytes = fread(pRawBytes, sizeof(BYTE), lengthBytes, file);
- if (readBytes < lengthBytes * sizeof(BYTE))
- {
- IfFailGo(E_FAIL);
- }
- pRawBytes[lengthBytes] = 0; // Null terminate it. Could be UTF16
- //
- // Read encoding to make sure it's supported
- //
- // Warning: The UNICODE buffer for parsing is supposed to be provided by the host.
- // This is not a complete read of the encoding. Some encodings like UTF7, UTF1, EBCDIC, SCSU, BOCU could be
- // wrongly classified as ANSI
- //
- {
- C_ASSERT(sizeof(WCHAR) == 2);
- if (bufferLength > 2)
- {
- if ((pRawBytes[0] == 0xFE && pRawBytes[1] == 0xFF) ||
- (pRawBytes[0] == 0xFF && pRawBytes[1] == 0xFE) ||
- (bufferLength > 4 && pRawBytes[0] == 0x00 && pRawBytes[1] == 0x00 &&
- ((pRawBytes[2] == 0xFE && pRawBytes[3] == 0xFF) ||
- (pRawBytes[2] == 0xFF && pRawBytes[3] == 0xFE))))
- {
- // unicode unsupported
- fwprintf(stderr, _u("unsupported file encoding. Only ANSI and UTF8 supported"));
- IfFailGo(E_UNEXPECTED);
- }
- }
- }
- }
- contents = reinterpret_cast<LPCSTR>(pRawBytes);
- Error:
- if (SUCCEEDED(hr))
- {
- if (lengthBytesOut)
- {
- *lengthBytesOut = lengthBytes;
- }
- }
- if (file != NULL)
- {
- fclose(file);
- }
- if (pRawBytes && reinterpret_cast<LPCSTR>(pRawBytes) != contents)
- {
- free(pRawBytes);
- }
- return hr;
- }
- LPCWSTR Helpers::JsErrorCodeToString(JsErrorCode jsErrorCode)
- {
- bool hasException = false;
- ChakraRTInterface::JsHasException(&hasException);
- if (hasException)
- {
- WScriptJsrt::PrintException("", JsErrorScriptException);
- }
- switch (jsErrorCode)
- {
- case JsNoError:
- return _u("JsNoError");
- break;
- case JsErrorInvalidArgument:
- return _u("JsErrorInvalidArgument");
- break;
- case JsErrorNullArgument:
- return _u("JsErrorNullArgument");
- break;
- case JsErrorNoCurrentContext:
- return _u("JsErrorNoCurrentContext");
- break;
- case JsErrorInExceptionState:
- return _u("JsErrorInExceptionState");
- break;
- case JsErrorNotImplemented:
- return _u("JsErrorNotImplemented");
- break;
- case JsErrorWrongThread:
- return _u("JsErrorWrongThread");
- break;
- case JsErrorRuntimeInUse:
- return _u("JsErrorRuntimeInUse");
- break;
- case JsErrorBadSerializedScript:
- return _u("JsErrorBadSerializedScript");
- break;
- case JsErrorInDisabledState:
- return _u("JsErrorInDisabledState");
- break;
- case JsErrorCannotDisableExecution:
- return _u("JsErrorCannotDisableExecution");
- break;
- case JsErrorHeapEnumInProgress:
- return _u("JsErrorHeapEnumInProgress");
- break;
- case JsErrorOutOfMemory:
- return _u("JsErrorOutOfMemory");
- break;
- case JsErrorScriptException:
- return _u("JsErrorScriptException");
- break;
- case JsErrorScriptCompile:
- return _u("JsErrorScriptCompile");
- break;
- case JsErrorScriptTerminated:
- return _u("JsErrorScriptTerminated");
- break;
- case JsErrorFatal:
- return _u("JsErrorFatal");
- break;
- default:
- return _u("<unknown>");
- break;
- }
- }
- void Helpers::LogError(__in __nullterminated const char16 *msg, ...)
- {
- va_list args;
- va_start(args, msg);
- wprintf(_u("ERROR: "));
- vfwprintf(stderr, msg, args);
- wprintf(_u("\n"));
- fflush(stdout);
- va_end(args);
- }
- HRESULT Helpers::LoadBinaryFile(LPCSTR filename, LPCSTR& contents, UINT& lengthBytes, bool printFileOpenError)
- {
- HRESULT hr = S_OK;
- contents = nullptr;
- lengthBytes = 0;
- size_t result;
- FILE * file;
- //
- // Open the file as a binary file to prevent CRT from handling encoding, line-break conversions,
- // etc.
- //
- if (fopen_s(&file, filename, "rb") != 0)
- {
- if (printFileOpenError)
- {
- #ifdef _WIN32
- DWORD lastError = GetLastError();
- char16 wszBuff[512];
- fprintf(stderr, "Error in opening file '%s' ", filename);
- wszBuff[0] = 0;
- if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
- nullptr,
- lastError,
- 0,
- wszBuff,
- _countof(wszBuff),
- nullptr))
- {
- fwprintf(stderr, _u(": %s"), wszBuff);
- }
- #endif
- fprintf(stderr, "\n");
- IfFailGo(E_FAIL);
- }
- else
- {
- return E_FAIL;
- }
- }
- // file will not be nullptr if _wfopen_s succeeds
- __analysis_assume(file != nullptr);
- //
- // Determine the file length, in bytes.
- //
- fseek(file, 0, SEEK_END);
- lengthBytes = ftell(file);
- fseek(file, 0, SEEK_SET);
- contents = (LPCSTR)HeapAlloc(GetProcessHeap(), 0, lengthBytes);
- if (nullptr == contents)
- {
- fwprintf(stderr, _u("out of memory"));
- IfFailGo(E_OUTOFMEMORY);
- }
- //
- // Read the entire content as a binary block.
- //
- result = fread((void*)contents, sizeof(char), lengthBytes, file);
- if (result != lengthBytes)
- {
- fwprintf(stderr, _u("Read error"));
- IfFailGo(E_FAIL);
- }
- fclose(file);
- Error:
- if (contents && FAILED(hr))
- {
- HeapFree(GetProcessHeap(), 0, (void*)contents);
- contents = nullptr;
- }
- return hr;
- }
- void Helpers::TTReportLastIOErrorAsNeeded(BOOL ok, const char* msg)
- {
- if(!ok)
- {
- #ifdef _WIN32
- DWORD lastError = GetLastError();
- LPTSTR pTemp = NULL;
- FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ARGUMENT_ARRAY, NULL, lastError, 0, (LPTSTR)&pTemp, 0, NULL);
- fwprintf(stderr, _u("Error is: %s\n"), pTemp);
- #else
- fprintf(stderr, "Error is: %i %s\n", errno, strerror(errno));
- #endif
- fprintf(stderr, "Message is: %s\n", msg);
- AssertMsg(false, "IO Error!!!");
- exit(1);
- }
- }
- //We assume bounded ascii path length for simplicity
- #define MAX_TTD_ASCII_PATH_EXT_LENGTH 64
- void Helpers::CreateTTDDirectoryAsNeeded(size_t* uriLength, char* uri, const char* asciiDir1, const wchar* asciiDir2)
- {
- if(*uriLength + strlen(asciiDir1) + wcslen(asciiDir2) + 2 > MAX_URI_LENGTH || strlen(asciiDir1) >= MAX_TTD_ASCII_PATH_EXT_LENGTH || wcslen(asciiDir2) >= MAX_TTD_ASCII_PATH_EXT_LENGTH)
- {
- printf("We assume bounded MAX_URI_LENGTH for simplicity.\n");
- printf("%s, %s, %ls\n", uri, asciiDir1, asciiDir2);
- exit(1);
- }
- int success = 0;
- int extLength = 0;
- extLength = sprintf_s(uri + *uriLength, MAX_TTD_ASCII_PATH_EXT_LENGTH, "%s%s", asciiDir1, TTD_HOST_PATH_SEP);
- if(extLength == -1 || MAX_URI_LENGTH < (*uriLength) + extLength)
- {
- printf("Failed directory extension 1.\n");
- printf("%s, %s, %ls\n", uri, asciiDir1, asciiDir2);
- exit(1);
- }
- *uriLength += extLength;
- success = TTDHostMKDir(uri, *uriLength);
- if(success != 0)
- {
- //we may fail because someone else created the directory -- that is ok
- Helpers::TTReportLastIOErrorAsNeeded(errno != ENOENT, "Failed to create directory");
- }
- char realAsciiDir2[MAX_TTD_ASCII_PATH_EXT_LENGTH];
- size_t asciiDir2Length = wcslen(asciiDir2) + 1;
- for(size_t i = 0; i < asciiDir2Length; ++i)
- {
- if(asciiDir2[i] > CHAR_MAX)
- {
- printf("Test directory names can only include ascii chars.\n");
- exit(1);
- }
- realAsciiDir2[i] = (char)asciiDir2[i];
- }
- extLength = sprintf_s(uri + *uriLength, MAX_TTD_ASCII_PATH_EXT_LENGTH, "%s%s", realAsciiDir2, TTD_HOST_PATH_SEP);
- if(extLength == -1 || MAX_URI_LENGTH < *uriLength + extLength)
- {
- printf("Failed directory create 2.\n");
- printf("%s, %s, %ls\n", uri, asciiDir1, asciiDir2);
- exit(1);
- }
- *uriLength += extLength;
- success = TTDHostMKDir(uri, *uriLength);
- if(success != 0)
- {
- //we may fail because someone else created the directory -- that is ok
- Helpers::TTReportLastIOErrorAsNeeded(errno != ENOENT, "Failed to create directory");
- }
- }
- void Helpers::GetTTDDirectory(const wchar* curi, size_t* uriLength, char* uri, size_t bufferLength)
- {
- TTDHostBuildCurrentExeDirectory(uri, uriLength, bufferLength);
- Helpers::CreateTTDDirectoryAsNeeded(uriLength, uri, "_ttdlog", curi);
- }
- JsTTDStreamHandle CALLBACK Helpers::TTCreateStreamCallback(size_t uriLength, const char* uri, size_t asciiNameLength, const char* asciiName, bool read, bool write)
- {
- AssertMsg((read | write) & (!read | !write), "Read/Write streams not supported yet -- defaulting to read only");
- if(uriLength + asciiNameLength + 1 > MAX_URI_LENGTH)
- {
- printf("We assume bounded MAX_URI_LENGTH for simplicity.");
- exit(1);
- }
- char path[MAX_URI_LENGTH];
- memset(path, 0, MAX_URI_LENGTH);
- memcpy_s(path, MAX_URI_LENGTH, uri, uriLength);
- memcpy_s(path + uriLength, MAX_URI_LENGTH - uriLength, asciiName, asciiNameLength);
- JsTTDStreamHandle res = TTDHostOpen(uriLength + asciiNameLength, path, write);
- if(res == nullptr)
- {
- fprintf(stderr, "Failed to open file: %s\n", path);
- }
- Helpers::TTReportLastIOErrorAsNeeded(res != nullptr, "Failed File Open");
- return res;
- }
- bool CALLBACK Helpers::TTReadBytesFromStreamCallback(JsTTDStreamHandle handle, byte* buff, size_t size, size_t* readCount)
- {
- AssertMsg(handle != nullptr, "Bad file handle.");
- if(size > MAXDWORD)
- {
- *readCount = 0;
- return false;
- }
- BOOL ok = FALSE;
- *readCount = TTDHostRead(buff, size, (FILE*)handle);
- ok = (*readCount != 0);
- Helpers::TTReportLastIOErrorAsNeeded(ok, "Failed Read!!!");
- return ok ? true : false;
- }
- bool CALLBACK Helpers::TTWriteBytesToStreamCallback(JsTTDStreamHandle handle, const byte* buff, size_t size, size_t* writtenCount)
- {
- AssertMsg(handle != nullptr, "Bad file handle.");
- if(size > MAXDWORD)
- {
- *writtenCount = 0;
- return false;
- }
- BOOL ok = FALSE;
- *writtenCount = TTDHostWrite(buff, size, (FILE*)handle);
- ok = (*writtenCount == size);
- Helpers::TTReportLastIOErrorAsNeeded(ok, "Failed Read!!!");
- return ok ? true : false;
- }
- void CALLBACK Helpers::TTFlushAndCloseStreamCallback(JsTTDStreamHandle handle, bool read, bool write)
- {
- fflush((FILE*)handle);
- fclose((FILE*)handle);
- }
- #define SET_BINARY_PATH_ERROR_MESSAGE(path, msg) \
- str_len = (int) strlen(msg); \
- memcpy(path, msg, (size_t)str_len); \
- path[str_len] = char(0)
- void GetBinaryLocation(char *path, const unsigned size)
- {
- AssertMsg(path != nullptr, "Path can not be nullptr");
- AssertMsg(size < INT_MAX, "Isn't it too big for a path buffer?");
- #ifdef _WIN32
- LPWSTR wpath = (WCHAR*)malloc(sizeof(WCHAR) * size);
- int str_len;
- if (!wpath)
- {
- SET_BINARY_PATH_ERROR_MESSAGE(path, "GetBinaryLocation: GetModuleFileName has failed. OutOfMemory!");
- return;
- }
- str_len = GetModuleFileNameW(NULL, wpath, size - 1);
- if (str_len <= 0)
- {
- SET_BINARY_PATH_ERROR_MESSAGE(path, "GetBinaryLocation: GetModuleFileName has failed.");
- free(wpath);
- return;
- }
- str_len = WideCharToMultiByte(CP_UTF8, 0, wpath, str_len, path, size, NULL, NULL);
- free(wpath);
- if (str_len <= 0)
- {
- SET_BINARY_PATH_ERROR_MESSAGE(path, "GetBinaryLocation: GetModuleFileName (WideCharToMultiByte) has failed.");
- return;
- }
- if ((unsigned)str_len > size - 1)
- {
- str_len = (int) size - 1;
- }
- path[str_len] = char(0);
- #elif defined(__APPLE__)
- uint32_t path_size = (uint32_t)size;
- char *tmp = nullptr;
- int str_len;
- if (_NSGetExecutablePath(path, &path_size))
- {
- SET_BINARY_PATH_ERROR_MESSAGE(path, "GetBinaryLocation: _NSGetExecutablePath has failed.");
- return;
- }
- tmp = (char*)malloc(size);
- char *result = realpath(path, tmp);
- str_len = strlen(result);
- memcpy(path, result, str_len);
- free(tmp);
- path[str_len] = char(0);
- #elif defined(__linux__)
- int str_len = readlink("/proc/self/exe", path, size - 1);
- if (str_len <= 0)
- {
- SET_BINARY_PATH_ERROR_MESSAGE(path, "GetBinaryLocation: /proc/self/exe has failed.");
- return;
- }
- path[str_len] = char(0);
- #else
- #warning "Implement GetBinaryLocation for this platform"
- #endif
- }
- // xplat-todo: Implement a corresponding solution for GetModuleFileNameW
- // and cleanup PAL. [ https://github.com/Microsoft/ChakraCore/pull/2288 should be merged first ]
- // GetModuleFileName* PAL is not reliable and forces us to explicitly double initialize PAL
- // with argc / argv....
- void GetBinaryPathWithFileNameA(char *path, const size_t buffer_size, const char* filename)
- {
- char fullpath[_MAX_PATH];
- char drive[_MAX_DRIVE];
- char dir[_MAX_DIR];
- char modulename[_MAX_PATH];
- GetBinaryLocation(modulename, _MAX_PATH);
- _splitpath_s(modulename, drive, _MAX_DRIVE, dir, _MAX_DIR, nullptr, 0, nullptr, 0);
- _makepath_s(fullpath, drive, dir, filename, nullptr);
- size_t len = strlen(fullpath);
- if (len < buffer_size)
- {
- memcpy(path, fullpath, len * sizeof(char));
- }
- else
- {
- len = 0;
- }
- path[len] = char(0);
- }
|