Helpers.cpp 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653
  1. //-------------------------------------------------------------------------------------------------------
  2. // Copyright (C) Microsoft. All rights reserved.
  3. // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
  4. //-------------------------------------------------------------------------------------------------------
  5. #include "stdafx.h"
  6. #include <sys/stat.h>
  7. #if defined(__APPLE__)
  8. #include <mach-o/dyld.h> // _NSGetExecutablePath
  9. #elif defined(__linux__)
  10. #include <unistd.h> // readlink
  11. #elif !defined(_WIN32)
  12. #error "How to get the executable path for this platform?"
  13. #endif // _WIN32 ?
  14. //TODO: x-plat definitions
  15. #ifdef _WIN32
  16. #define MAX_URI_LENGTH 512
  17. #define TTD_HOST_PATH_SEP "\\"
  18. void TTDHostBuildCurrentExeDirectory(char* path, size_t* pathLength, size_t bufferLength)
  19. {
  20. wchar exePath[MAX_PATH];
  21. GetModuleFileName(NULL, exePath, MAX_PATH);
  22. size_t i = wcslen(exePath) - 1;
  23. while(exePath[i] != _u('\\'))
  24. {
  25. --i;
  26. }
  27. if(i * 3 > bufferLength)
  28. {
  29. printf("Don't overflow path buffer during conversion");
  30. exit(1);
  31. }
  32. *pathLength = utf8::EncodeInto((LPUTF8)path, exePath, (charcount_t)(i + 1));
  33. path[*pathLength] = '\0';
  34. }
  35. int TTDHostMKDir(const char* path, size_t pathLength)
  36. {
  37. char16 cpath[MAX_PATH];
  38. LPCUTF8 pathbase = (LPCUTF8)path;
  39. if(MAX_PATH <= pathLength) //<= to account for null terminator
  40. {
  41. printf("Don't overflow path buffer during conversion");
  42. exit(1);
  43. }
  44. utf8::DecodeUnitsIntoAndNullTerminate(cpath, pathbase, pathbase + pathLength);
  45. return _wmkdir(cpath);
  46. }
  47. JsTTDStreamHandle TTDHostOpen(size_t pathLength, const char* path, bool isWrite)
  48. {
  49. char16 wpath[MAX_PATH];
  50. LPCUTF8 pathbase = (LPCUTF8)path;
  51. if(MAX_PATH <= pathLength) //<= to account for null terminator
  52. {
  53. printf("Don't overflow path buffer during conversion");
  54. exit(1);
  55. }
  56. utf8::DecodeUnitsIntoAndNullTerminate(wpath, pathbase, pathbase + pathLength);
  57. FILE* res = nullptr;
  58. _wfopen_s(&res, wpath, isWrite ? _u("w+b") : _u("r+b"));
  59. return (JsTTDStreamHandle)res;
  60. }
  61. #define TTDHostRead(buff, size, handle) fread_s(buff, size, 1, size, (FILE*)handle);
  62. #define TTDHostWrite(buff, size, handle) fwrite(buff, 1, size, (FILE*)handle)
  63. #else
  64. #ifdef __APPLE__
  65. #include <mach-o/dyld.h>
  66. #else
  67. #include <unistd.h>
  68. #endif
  69. #define MAX_URI_LENGTH 512
  70. #define TTD_HOST_PATH_SEP "/"
  71. void TTDHostBuildCurrentExeDirectory(char* path, size_t* pathLength, size_t bufferLength)
  72. {
  73. char exePath[MAX_URI_LENGTH];
  74. //TODO: xplattodo move this logic to PAL
  75. #ifdef __APPLE__
  76. uint32_t tmpPathSize = sizeof(exePath);
  77. _NSGetExecutablePath(exePath, &tmpPathSize);
  78. size_t i = strlen(exePath) - 1;
  79. #else
  80. size_t i = readlink("/proc/self/exe", exePath, MAX_URI_LENGTH) - 1;
  81. #endif
  82. while(exePath[i] != '/')
  83. {
  84. --i;
  85. }
  86. *pathLength = i + 1;
  87. if(*pathLength > bufferLength)
  88. {
  89. printf("Don't overflow path buffer during copy.");
  90. exit(1);
  91. }
  92. memcpy_s(path, bufferLength, exePath, *pathLength);
  93. }
  94. int TTDHostMKDir(const char* path, size_t pathLength)
  95. {
  96. return mkdir(path, 0700);
  97. }
  98. JsTTDStreamHandle TTDHostOpen(size_t pathLength, const char* path, bool isWrite)
  99. {
  100. return (JsTTDStreamHandle)fopen(path, isWrite ? "w+b" : "r+b");
  101. }
  102. #define TTDHostRead(buff, size, handle) fread(buff, 1, size, (FILE*)handle)
  103. #define TTDHostWrite(buff, size, handle) fwrite(buff, 1, size, (FILE*)handle)
  104. #endif
  105. HRESULT Helpers::LoadScriptFromFile(LPCSTR filename, LPCSTR& contents, UINT* lengthBytesOut /*= nullptr*/)
  106. {
  107. HRESULT hr = S_OK;
  108. BYTE * pRawBytes = nullptr;
  109. UINT lengthBytes = 0;
  110. contents = nullptr;
  111. FILE * file = NULL;
  112. //
  113. // Open the file as a binary file to prevent CRT from handling encoding, line-break conversions,
  114. // etc.
  115. //
  116. if (fopen_s(&file, filename, "rb") != 0)
  117. {
  118. if (!HostConfigFlags::flags.MuteHostErrorMsgIsEnabled)
  119. {
  120. #ifdef _WIN32
  121. DWORD lastError = GetLastError();
  122. char16 wszBuff[512];
  123. fprintf(stderr, "Error in opening file '%s' ", filename);
  124. wszBuff[0] = 0;
  125. if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
  126. nullptr,
  127. lastError,
  128. 0,
  129. wszBuff,
  130. _countof(wszBuff),
  131. nullptr))
  132. {
  133. fwprintf(stderr, _u(": %s"), wszBuff);
  134. }
  135. fwprintf(stderr, _u("\n"));
  136. #elif defined(_POSIX_VERSION)
  137. fprintf(stderr, "Error in opening file: ");
  138. perror(filename);
  139. #endif
  140. }
  141. IfFailGo(E_FAIL);
  142. }
  143. if (file != NULL)
  144. {
  145. // Determine the file length, in bytes.
  146. fseek(file, 0, SEEK_END);
  147. lengthBytes = ftell(file);
  148. fseek(file, 0, SEEK_SET);
  149. const size_t bufferLength = lengthBytes + sizeof(BYTE);
  150. pRawBytes = (LPBYTE)malloc(bufferLength);
  151. if (nullptr == pRawBytes)
  152. {
  153. fwprintf(stderr, _u("out of memory"));
  154. IfFailGo(E_OUTOFMEMORY);
  155. }
  156. //
  157. // Read the entire content as a binary block.
  158. //
  159. size_t readBytes = fread(pRawBytes, sizeof(BYTE), lengthBytes, file);
  160. if (readBytes < lengthBytes * sizeof(BYTE))
  161. {
  162. IfFailGo(E_FAIL);
  163. }
  164. pRawBytes[lengthBytes] = 0; // Null terminate it. Could be UTF16
  165. //
  166. // Read encoding to make sure it's supported
  167. //
  168. // Warning: The UNICODE buffer for parsing is supposed to be provided by the host.
  169. // This is not a complete read of the encoding. Some encodings like UTF7, UTF1, EBCDIC, SCSU, BOCU could be
  170. // wrongly classified as ANSI
  171. //
  172. {
  173. C_ASSERT(sizeof(WCHAR) == 2);
  174. if (bufferLength > 2)
  175. {
  176. __analysis_assume(bufferLength > 2);
  177. #pragma prefast(push)
  178. #pragma prefast(disable:6385, "PREfast incorrectly reports this as an out-of-bound access.");
  179. if ((pRawBytes[0] == 0xFE && pRawBytes[1] == 0xFF) ||
  180. (pRawBytes[0] == 0xFF && pRawBytes[1] == 0xFE) ||
  181. (bufferLength > 4 && pRawBytes[0] == 0x00 && pRawBytes[1] == 0x00 &&
  182. ((pRawBytes[2] == 0xFE && pRawBytes[3] == 0xFF) ||
  183. (pRawBytes[2] == 0xFF && pRawBytes[3] == 0xFE))))
  184. {
  185. // unicode unsupported
  186. fwprintf(stderr, _u("unsupported file encoding. Only ANSI and UTF8 supported"));
  187. IfFailGo(E_UNEXPECTED);
  188. }
  189. #pragma prefast(pop)
  190. }
  191. }
  192. }
  193. contents = reinterpret_cast<LPCSTR>(pRawBytes);
  194. Error:
  195. if (SUCCEEDED(hr))
  196. {
  197. if (lengthBytesOut)
  198. {
  199. *lengthBytesOut = lengthBytes;
  200. }
  201. }
  202. if (file != NULL)
  203. {
  204. fclose(file);
  205. }
  206. if (pRawBytes && reinterpret_cast<LPCSTR>(pRawBytes) != contents)
  207. {
  208. free(pRawBytes);
  209. }
  210. return hr;
  211. }
  212. LPCWSTR Helpers::JsErrorCodeToString(JsErrorCode jsErrorCode)
  213. {
  214. bool hasException = false;
  215. ChakraRTInterface::JsHasException(&hasException);
  216. if (hasException)
  217. {
  218. WScriptJsrt::PrintException("", JsErrorScriptException);
  219. }
  220. switch (jsErrorCode)
  221. {
  222. case JsNoError: return _u("JsNoError");
  223. // JsErrorCategoryUsage
  224. case JsErrorCategoryUsage: return _u("JsErrorCategoryUsage");
  225. case JsErrorInvalidArgument: return _u("JsErrorInvalidArgument");
  226. case JsErrorNullArgument: return _u("JsErrorNullArgument");
  227. case JsErrorNoCurrentContext: return _u("JsErrorNoCurrentContext");
  228. case JsErrorInExceptionState: return _u("JsErrorInExceptionState");
  229. case JsErrorNotImplemented: return _u("JsErrorNotImplemented");
  230. case JsErrorWrongThread: return _u("JsErrorWrongThread");
  231. case JsErrorRuntimeInUse: return _u("JsErrorRuntimeInUse");
  232. case JsErrorBadSerializedScript: return _u("JsErrorBadSerializedScript");
  233. case JsErrorInDisabledState: return _u("JsErrorInDisabledState");
  234. case JsErrorCannotDisableExecution: return _u("JsErrorCannotDisableExecution");
  235. case JsErrorHeapEnumInProgress: return _u("JsErrorHeapEnumInProgress");
  236. case JsErrorArgumentNotObject: return _u("JsErrorArgumentNotObject");
  237. case JsErrorInProfileCallback: return _u("JsErrorInProfileCallback");
  238. case JsErrorInThreadServiceCallback: return _u("JsErrorInThreadServiceCallback");
  239. case JsErrorCannotSerializeDebugScript: return _u("JsErrorCannotSerializeDebugScript");
  240. case JsErrorAlreadyDebuggingContext: return _u("JsErrorAlreadyDebuggingContext");
  241. case JsErrorAlreadyProfilingContext: return _u("JsErrorAlreadyProfilingContext");
  242. case JsErrorIdleNotEnabled: return _u("JsErrorIdleNotEnabled");
  243. case JsCannotSetProjectionEnqueueCallback: return _u("JsCannotSetProjectionEnqueueCallback");
  244. case JsErrorCannotStartProjection: return _u("JsErrorCannotStartProjection");
  245. case JsErrorInObjectBeforeCollectCallback: return _u("JsErrorInObjectBeforeCollectCallback");
  246. case JsErrorObjectNotInspectable: return _u("JsErrorObjectNotInspectable");
  247. case JsErrorPropertyNotSymbol: return _u("JsErrorPropertyNotSymbol");
  248. case JsErrorPropertyNotString: return _u("JsErrorPropertyNotString");
  249. case JsErrorInvalidContext: return _u("JsErrorInvalidContext");
  250. case JsInvalidModuleHostInfoKind: return _u("JsInvalidModuleHostInfoKind");
  251. case JsErrorModuleParsed: return _u("JsErrorModuleParsed");
  252. // JsErrorCategoryEngine
  253. case JsErrorCategoryEngine: return _u("JsErrorCategoryEngine");
  254. case JsErrorOutOfMemory: return _u("JsErrorOutOfMemory");
  255. case JsErrorBadFPUState: return _u("JsErrorBadFPUState");
  256. // JsErrorCategoryScript
  257. case JsErrorCategoryScript: return _u("JsErrorCategoryScript");
  258. case JsErrorScriptException: return _u("JsErrorScriptException");
  259. case JsErrorScriptCompile: return _u("JsErrorScriptCompile");
  260. case JsErrorScriptTerminated: return _u("JsErrorScriptTerminated");
  261. case JsErrorScriptEvalDisabled: return _u("JsErrorScriptEvalDisabled");
  262. // JsErrorCategoryFatal
  263. case JsErrorCategoryFatal: return _u("JsErrorCategoryFatal");
  264. case JsErrorFatal: return _u("JsErrorFatal");
  265. case JsErrorWrongRuntime: return _u("JsErrorWrongRuntime");
  266. // JsErrorCategoryDiagError
  267. case JsErrorCategoryDiagError: return _u("JsErrorCategoryDiagError");
  268. case JsErrorDiagAlreadyInDebugMode: return _u("JsErrorDiagAlreadyInDebugMode");
  269. case JsErrorDiagNotInDebugMode: return _u("JsErrorDiagNotInDebugMode");
  270. case JsErrorDiagNotAtBreak: return _u("JsErrorDiagNotAtBreak");
  271. case JsErrorDiagInvalidHandle: return _u("JsErrorDiagInvalidHandle");
  272. case JsErrorDiagObjectNotFound: return _u("JsErrorDiagObjectNotFound");
  273. case JsErrorDiagUnableToPerformAction: return _u("JsErrorDiagUnableToPerformAction");
  274. default:
  275. return _u("<unknown>");
  276. break;
  277. }
  278. }
  279. void Helpers::LogError(__in __nullterminated const char16 *msg, ...)
  280. {
  281. va_list args;
  282. va_start(args, msg);
  283. wprintf(_u("ERROR: "));
  284. vfwprintf(stderr, msg, args);
  285. wprintf(_u("\n"));
  286. fflush(stdout);
  287. va_end(args);
  288. }
  289. HRESULT Helpers::LoadBinaryFile(LPCSTR filename, LPCSTR& contents, UINT& lengthBytes, bool printFileOpenError)
  290. {
  291. HRESULT hr = S_OK;
  292. contents = nullptr;
  293. lengthBytes = 0;
  294. size_t result;
  295. FILE * file;
  296. //
  297. // Open the file as a binary file to prevent CRT from handling encoding, line-break conversions,
  298. // etc.
  299. //
  300. if (fopen_s(&file, filename, "rb") != 0)
  301. {
  302. if (printFileOpenError)
  303. {
  304. #ifdef _WIN32
  305. DWORD lastError = GetLastError();
  306. char16 wszBuff[512];
  307. fprintf(stderr, "Error in opening file '%s' ", filename);
  308. wszBuff[0] = 0;
  309. if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
  310. nullptr,
  311. lastError,
  312. 0,
  313. wszBuff,
  314. _countof(wszBuff),
  315. nullptr))
  316. {
  317. fwprintf(stderr, _u(": %s"), wszBuff);
  318. }
  319. #endif
  320. fprintf(stderr, "\n");
  321. IfFailGo(E_FAIL);
  322. }
  323. else
  324. {
  325. return E_FAIL;
  326. }
  327. }
  328. // file will not be nullptr if _wfopen_s succeeds
  329. __analysis_assume(file != nullptr);
  330. //
  331. // Determine the file length, in bytes.
  332. //
  333. fseek(file, 0, SEEK_END);
  334. lengthBytes = ftell(file);
  335. fseek(file, 0, SEEK_SET);
  336. contents = (LPCSTR)HeapAlloc(GetProcessHeap(), 0, lengthBytes);
  337. if (nullptr == contents)
  338. {
  339. fwprintf(stderr, _u("out of memory"));
  340. IfFailGo(E_OUTOFMEMORY);
  341. }
  342. //
  343. // Read the entire content as a binary block.
  344. //
  345. result = fread((void*)contents, sizeof(char), lengthBytes, file);
  346. if (result != lengthBytes)
  347. {
  348. fwprintf(stderr, _u("Read error"));
  349. IfFailGo(E_FAIL);
  350. }
  351. fclose(file);
  352. Error:
  353. if (contents && FAILED(hr))
  354. {
  355. HeapFree(GetProcessHeap(), 0, (void*)contents);
  356. contents = nullptr;
  357. }
  358. return hr;
  359. }
  360. void Helpers::TTReportLastIOErrorAsNeeded(BOOL ok, const char* msg)
  361. {
  362. if(!ok)
  363. {
  364. #ifdef _WIN32
  365. DWORD lastError = GetLastError();
  366. LPTSTR pTemp = NULL;
  367. FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ARGUMENT_ARRAY, NULL, lastError, 0, (LPTSTR)&pTemp, 0, NULL);
  368. fwprintf(stderr, _u("Error is: %s\n"), pTemp);
  369. #else
  370. fprintf(stderr, "Error is: %i %s\n", errno, strerror(errno));
  371. #endif
  372. fprintf(stderr, "Message is: %s\n", msg);
  373. AssertMsg(false, "IO Error!!!");
  374. exit(1);
  375. }
  376. }
  377. //We assume bounded ascii path length for simplicity
  378. #define MAX_TTD_ASCII_PATH_EXT_LENGTH 64
  379. void Helpers::CreateTTDDirectoryAsNeeded(size_t* uriLength, char* uri, const char* asciiDir1, const wchar* asciiDir2)
  380. {
  381. 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)
  382. {
  383. printf("We assume bounded MAX_URI_LENGTH for simplicity.\n");
  384. printf("%s, %s, %ls\n", uri, asciiDir1, asciiDir2);
  385. exit(1);
  386. }
  387. int success = 0;
  388. int extLength = 0;
  389. extLength = sprintf_s(uri + *uriLength, MAX_TTD_ASCII_PATH_EXT_LENGTH, "%s%s", asciiDir1, TTD_HOST_PATH_SEP);
  390. if(extLength == -1 || MAX_URI_LENGTH < (*uriLength) + extLength)
  391. {
  392. printf("Failed directory extension 1.\n");
  393. printf("%s, %s, %ls\n", uri, asciiDir1, asciiDir2);
  394. exit(1);
  395. }
  396. *uriLength += extLength;
  397. success = TTDHostMKDir(uri, *uriLength);
  398. if(success != 0)
  399. {
  400. //we may fail because someone else created the directory -- that is ok
  401. Helpers::TTReportLastIOErrorAsNeeded(errno != ENOENT, "Failed to create directory");
  402. }
  403. char realAsciiDir2[MAX_TTD_ASCII_PATH_EXT_LENGTH];
  404. size_t asciiDir2Length = wcslen(asciiDir2) + 1;
  405. for(size_t i = 0; i < asciiDir2Length; ++i)
  406. {
  407. if(asciiDir2[i] > CHAR_MAX)
  408. {
  409. printf("Test directory names can only include ascii chars.\n");
  410. exit(1);
  411. }
  412. realAsciiDir2[i] = (char)asciiDir2[i];
  413. }
  414. extLength = sprintf_s(uri + *uriLength, MAX_TTD_ASCII_PATH_EXT_LENGTH, "%s%s", realAsciiDir2, TTD_HOST_PATH_SEP);
  415. if(extLength == -1 || MAX_URI_LENGTH < *uriLength + extLength)
  416. {
  417. printf("Failed directory create 2.\n");
  418. printf("%s, %s, %ls\n", uri, asciiDir1, asciiDir2);
  419. exit(1);
  420. }
  421. *uriLength += extLength;
  422. success = TTDHostMKDir(uri, *uriLength);
  423. if(success != 0)
  424. {
  425. //we may fail because someone else created the directory -- that is ok
  426. Helpers::TTReportLastIOErrorAsNeeded(errno != ENOENT, "Failed to create directory");
  427. }
  428. }
  429. void Helpers::GetTTDDirectory(const wchar* curi, size_t* uriLength, char* uri, size_t bufferLength)
  430. {
  431. TTDHostBuildCurrentExeDirectory(uri, uriLength, bufferLength);
  432. Helpers::CreateTTDDirectoryAsNeeded(uriLength, uri, "_ttdlog", curi);
  433. }
  434. JsTTDStreamHandle CALLBACK Helpers::TTCreateStreamCallback(size_t uriLength, const char* uri, size_t asciiNameLength, const char* asciiName, bool read, bool write)
  435. {
  436. AssertMsg((read | write) & (!read | !write), "Read/Write streams not supported yet -- defaulting to read only");
  437. if(uriLength + asciiNameLength + 1 > MAX_URI_LENGTH)
  438. {
  439. printf("We assume bounded MAX_URI_LENGTH for simplicity.");
  440. exit(1);
  441. }
  442. char path[MAX_URI_LENGTH];
  443. memset(path, 0, MAX_URI_LENGTH);
  444. memcpy_s(path, MAX_URI_LENGTH, uri, uriLength);
  445. memcpy_s(path + uriLength, MAX_URI_LENGTH - uriLength, asciiName, asciiNameLength);
  446. JsTTDStreamHandle res = TTDHostOpen(uriLength + asciiNameLength, path, write);
  447. if(res == nullptr)
  448. {
  449. fprintf(stderr, "Failed to open file: %s\n", path);
  450. }
  451. Helpers::TTReportLastIOErrorAsNeeded(res != nullptr, "Failed File Open");
  452. return res;
  453. }
  454. bool CALLBACK Helpers::TTReadBytesFromStreamCallback(JsTTDStreamHandle handle, byte* buff, size_t size, size_t* readCount)
  455. {
  456. AssertMsg(handle != nullptr, "Bad file handle.");
  457. if(size > MAXDWORD)
  458. {
  459. *readCount = 0;
  460. return false;
  461. }
  462. BOOL ok = FALSE;
  463. *readCount = TTDHostRead(buff, size, (FILE*)handle);
  464. ok = (*readCount != 0);
  465. Helpers::TTReportLastIOErrorAsNeeded(ok, "Failed Read!!!");
  466. return ok ? true : false;
  467. }
  468. bool CALLBACK Helpers::TTWriteBytesToStreamCallback(JsTTDStreamHandle handle, const byte* buff, size_t size, size_t* writtenCount)
  469. {
  470. AssertMsg(handle != nullptr, "Bad file handle.");
  471. if(size > MAXDWORD)
  472. {
  473. *writtenCount = 0;
  474. return false;
  475. }
  476. BOOL ok = FALSE;
  477. *writtenCount = TTDHostWrite(buff, size, (FILE*)handle);
  478. ok = (*writtenCount == size);
  479. Helpers::TTReportLastIOErrorAsNeeded(ok, "Failed Read!!!");
  480. return ok ? true : false;
  481. }
  482. void CALLBACK Helpers::TTFlushAndCloseStreamCallback(JsTTDStreamHandle handle, bool read, bool write)
  483. {
  484. fflush((FILE*)handle);
  485. fclose((FILE*)handle);
  486. }
  487. #define SET_BINARY_PATH_ERROR_MESSAGE(path, msg) \
  488. str_len = (int) strlen(msg); \
  489. memcpy(path, msg, (size_t)str_len); \
  490. path[str_len] = char(0)
  491. void GetBinaryLocation(char *path, const unsigned size)
  492. {
  493. AssertMsg(path != nullptr, "Path can not be nullptr");
  494. AssertMsg(size < INT_MAX, "Isn't it too big for a path buffer?");
  495. #ifdef _WIN32
  496. LPWSTR wpath = (WCHAR*)malloc(sizeof(WCHAR) * size);
  497. int str_len;
  498. if (!wpath)
  499. {
  500. SET_BINARY_PATH_ERROR_MESSAGE(path, "GetBinaryLocation: GetModuleFileName has failed. OutOfMemory!");
  501. return;
  502. }
  503. str_len = GetModuleFileNameW(NULL, wpath, size - 1);
  504. if (str_len <= 0)
  505. {
  506. SET_BINARY_PATH_ERROR_MESSAGE(path, "GetBinaryLocation: GetModuleFileName has failed.");
  507. free(wpath);
  508. return;
  509. }
  510. str_len = WideCharToMultiByte(CP_UTF8, 0, wpath, str_len, path, size, NULL, NULL);
  511. free(wpath);
  512. if (str_len <= 0)
  513. {
  514. SET_BINARY_PATH_ERROR_MESSAGE(path, "GetBinaryLocation: GetModuleFileName (WideCharToMultiByte) has failed.");
  515. return;
  516. }
  517. if ((unsigned)str_len > size - 1)
  518. {
  519. str_len = (int) size - 1;
  520. }
  521. path[str_len] = char(0);
  522. #elif defined(__APPLE__)
  523. uint32_t path_size = (uint32_t)size;
  524. char *tmp = nullptr;
  525. int str_len;
  526. if (_NSGetExecutablePath(path, &path_size))
  527. {
  528. SET_BINARY_PATH_ERROR_MESSAGE(path, "GetBinaryLocation: _NSGetExecutablePath has failed.");
  529. return;
  530. }
  531. tmp = (char*)malloc(size);
  532. char *result = realpath(path, tmp);
  533. str_len = strlen(result);
  534. memcpy(path, result, str_len);
  535. free(tmp);
  536. path[str_len] = char(0);
  537. #elif defined(__linux__)
  538. int str_len = readlink("/proc/self/exe", path, size - 1);
  539. if (str_len <= 0)
  540. {
  541. SET_BINARY_PATH_ERROR_MESSAGE(path, "GetBinaryLocation: /proc/self/exe has failed.");
  542. return;
  543. }
  544. path[str_len] = char(0);
  545. #else
  546. #warning "Implement GetBinaryLocation for this platform"
  547. #endif
  548. }
  549. // xplat-todo: Implement a corresponding solution for GetModuleFileNameW
  550. // and cleanup PAL. [ https://github.com/Microsoft/ChakraCore/pull/2288 should be merged first ]
  551. // GetModuleFileName* PAL is not reliable and forces us to explicitly double initialize PAL
  552. // with argc / argv....
  553. void GetBinaryPathWithFileNameA(char *path, const size_t buffer_size, const char* filename)
  554. {
  555. char fullpath[_MAX_PATH];
  556. char drive[_MAX_DRIVE];
  557. char dir[_MAX_DIR];
  558. char modulename[_MAX_PATH];
  559. GetBinaryLocation(modulename, _MAX_PATH);
  560. _splitpath_s(modulename, drive, _MAX_DRIVE, dir, _MAX_DIR, nullptr, 0, nullptr, 0);
  561. _makepath_s(fullpath, drive, dir, filename, nullptr);
  562. size_t len = strlen(fullpath);
  563. if (len < buffer_size)
  564. {
  565. memcpy(path, fullpath, len * sizeof(char));
  566. }
  567. else
  568. {
  569. len = 0;
  570. }
  571. path[len] = char(0);
  572. }