Helpers.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661
  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. #ifdef _WIN32
  119. DWORD lastError = GetLastError();
  120. char16 wszBuff[512];
  121. fprintf(stderr, "Error in opening file '%s' ", filename);
  122. wszBuff[0] = 0;
  123. if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
  124. nullptr,
  125. lastError,
  126. 0,
  127. wszBuff,
  128. _countof(wszBuff),
  129. nullptr))
  130. {
  131. fwprintf(stderr, _u(": %s"), wszBuff);
  132. }
  133. fwprintf(stderr, _u("\n"));
  134. #elif defined(_POSIX_VERSION)
  135. fprintf(stderr, "Error in opening file: ");
  136. perror(filename);
  137. #endif
  138. IfFailGo(E_FAIL);
  139. }
  140. if (file != NULL)
  141. {
  142. // Determine the file length, in bytes.
  143. fseek(file, 0, SEEK_END);
  144. lengthBytes = ftell(file);
  145. fseek(file, 0, SEEK_SET);
  146. const size_t bufferLength = lengthBytes + sizeof(BYTE);
  147. pRawBytes = (LPBYTE)malloc(bufferLength);
  148. if (nullptr == pRawBytes)
  149. {
  150. fwprintf(stderr, _u("out of memory"));
  151. IfFailGo(E_OUTOFMEMORY);
  152. }
  153. //
  154. // Read the entire content as a binary block.
  155. //
  156. size_t readBytes = fread(pRawBytes, sizeof(BYTE), lengthBytes, file);
  157. if (readBytes < lengthBytes * sizeof(BYTE))
  158. {
  159. IfFailGo(E_FAIL);
  160. }
  161. pRawBytes[lengthBytes] = 0; // Null terminate it. Could be UTF16
  162. //
  163. // Read encoding to make sure it's supported
  164. //
  165. // Warning: The UNICODE buffer for parsing is supposed to be provided by the host.
  166. // This is not a complete read of the encoding. Some encodings like UTF7, UTF1, EBCDIC, SCSU, BOCU could be
  167. // wrongly classified as ANSI
  168. //
  169. {
  170. C_ASSERT(sizeof(WCHAR) == 2);
  171. if (bufferLength > 2)
  172. {
  173. if ((pRawBytes[0] == 0xFE && pRawBytes[1] == 0xFF) ||
  174. (pRawBytes[0] == 0xFF && pRawBytes[1] == 0xFE) ||
  175. (bufferLength > 4 && pRawBytes[0] == 0x00 && pRawBytes[1] == 0x00 &&
  176. ((pRawBytes[2] == 0xFE && pRawBytes[3] == 0xFF) ||
  177. (pRawBytes[2] == 0xFF && pRawBytes[3] == 0xFE))))
  178. {
  179. // unicode unsupported
  180. fwprintf(stderr, _u("unsupported file encoding. Only ANSI and UTF8 supported"));
  181. IfFailGo(E_UNEXPECTED);
  182. }
  183. }
  184. }
  185. }
  186. contents = reinterpret_cast<LPCSTR>(pRawBytes);
  187. Error:
  188. if (SUCCEEDED(hr))
  189. {
  190. if (lengthBytesOut)
  191. {
  192. *lengthBytesOut = lengthBytes;
  193. }
  194. }
  195. if (file != NULL)
  196. {
  197. fclose(file);
  198. }
  199. if (pRawBytes && reinterpret_cast<LPCSTR>(pRawBytes) != contents)
  200. {
  201. free(pRawBytes);
  202. }
  203. return hr;
  204. }
  205. LPCWSTR Helpers::JsErrorCodeToString(JsErrorCode jsErrorCode)
  206. {
  207. bool hasException = false;
  208. ChakraRTInterface::JsHasException(&hasException);
  209. if (hasException)
  210. {
  211. WScriptJsrt::PrintException("", JsErrorScriptException);
  212. }
  213. switch (jsErrorCode)
  214. {
  215. case JsNoError:
  216. return _u("JsNoError");
  217. break;
  218. case JsErrorInvalidArgument:
  219. return _u("JsErrorInvalidArgument");
  220. break;
  221. case JsErrorNullArgument:
  222. return _u("JsErrorNullArgument");
  223. break;
  224. case JsErrorNoCurrentContext:
  225. return _u("JsErrorNoCurrentContext");
  226. break;
  227. case JsErrorInExceptionState:
  228. return _u("JsErrorInExceptionState");
  229. break;
  230. case JsErrorNotImplemented:
  231. return _u("JsErrorNotImplemented");
  232. break;
  233. case JsErrorWrongThread:
  234. return _u("JsErrorWrongThread");
  235. break;
  236. case JsErrorRuntimeInUse:
  237. return _u("JsErrorRuntimeInUse");
  238. break;
  239. case JsErrorBadSerializedScript:
  240. return _u("JsErrorBadSerializedScript");
  241. break;
  242. case JsErrorInDisabledState:
  243. return _u("JsErrorInDisabledState");
  244. break;
  245. case JsErrorCannotDisableExecution:
  246. return _u("JsErrorCannotDisableExecution");
  247. break;
  248. case JsErrorHeapEnumInProgress:
  249. return _u("JsErrorHeapEnumInProgress");
  250. break;
  251. case JsErrorOutOfMemory:
  252. return _u("JsErrorOutOfMemory");
  253. break;
  254. case JsErrorScriptException:
  255. return _u("JsErrorScriptException");
  256. break;
  257. case JsErrorScriptCompile:
  258. return _u("JsErrorScriptCompile");
  259. break;
  260. case JsErrorScriptTerminated:
  261. return _u("JsErrorScriptTerminated");
  262. break;
  263. case JsErrorFatal:
  264. return _u("JsErrorFatal");
  265. break;
  266. default:
  267. return _u("<unknown>");
  268. break;
  269. }
  270. }
  271. void Helpers::LogError(__in __nullterminated const char16 *msg, ...)
  272. {
  273. va_list args;
  274. va_start(args, msg);
  275. wprintf(_u("ERROR: "));
  276. vfwprintf(stderr, msg, args);
  277. wprintf(_u("\n"));
  278. fflush(stdout);
  279. va_end(args);
  280. }
  281. HRESULT Helpers::LoadBinaryFile(LPCSTR filename, LPCSTR& contents, UINT& lengthBytes, bool printFileOpenError)
  282. {
  283. HRESULT hr = S_OK;
  284. contents = nullptr;
  285. lengthBytes = 0;
  286. size_t result;
  287. FILE * file;
  288. //
  289. // Open the file as a binary file to prevent CRT from handling encoding, line-break conversions,
  290. // etc.
  291. //
  292. if (fopen_s(&file, filename, "rb") != 0)
  293. {
  294. if (printFileOpenError)
  295. {
  296. #ifdef _WIN32
  297. DWORD lastError = GetLastError();
  298. char16 wszBuff[512];
  299. fprintf(stderr, "Error in opening file '%s' ", filename);
  300. wszBuff[0] = 0;
  301. if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
  302. nullptr,
  303. lastError,
  304. 0,
  305. wszBuff,
  306. _countof(wszBuff),
  307. nullptr))
  308. {
  309. fwprintf(stderr, _u(": %s"), wszBuff);
  310. }
  311. #endif
  312. fprintf(stderr, "\n");
  313. IfFailGo(E_FAIL);
  314. }
  315. else
  316. {
  317. return E_FAIL;
  318. }
  319. }
  320. // file will not be nullptr if _wfopen_s succeeds
  321. __analysis_assume(file != nullptr);
  322. //
  323. // Determine the file length, in bytes.
  324. //
  325. fseek(file, 0, SEEK_END);
  326. lengthBytes = ftell(file);
  327. fseek(file, 0, SEEK_SET);
  328. contents = (LPCSTR)HeapAlloc(GetProcessHeap(), 0, lengthBytes);
  329. if (nullptr == contents)
  330. {
  331. fwprintf(stderr, _u("out of memory"));
  332. IfFailGo(E_OUTOFMEMORY);
  333. }
  334. //
  335. // Read the entire content as a binary block.
  336. //
  337. result = fread((void*)contents, sizeof(char), lengthBytes, file);
  338. if (result != lengthBytes)
  339. {
  340. fwprintf(stderr, _u("Read error"));
  341. IfFailGo(E_FAIL);
  342. }
  343. fclose(file);
  344. Error:
  345. if (contents && FAILED(hr))
  346. {
  347. HeapFree(GetProcessHeap(), 0, (void*)contents);
  348. contents = nullptr;
  349. }
  350. return hr;
  351. }
  352. void Helpers::TTReportLastIOErrorAsNeeded(BOOL ok, const char* msg)
  353. {
  354. if(!ok)
  355. {
  356. #ifdef _WIN32
  357. DWORD lastError = GetLastError();
  358. LPTSTR pTemp = NULL;
  359. FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ARGUMENT_ARRAY, NULL, lastError, 0, (LPTSTR)&pTemp, 0, NULL);
  360. fwprintf(stderr, _u("Error is: %s\n"), pTemp);
  361. #else
  362. fprintf(stderr, "Error is: %i %s\n", errno, strerror(errno));
  363. #endif
  364. fprintf(stderr, "Message is: %s\n", msg);
  365. AssertMsg(false, "IO Error!!!");
  366. exit(1);
  367. }
  368. }
  369. //We assume bounded ascii path length for simplicity
  370. #define MAX_TTD_ASCII_PATH_EXT_LENGTH 64
  371. void Helpers::CreateTTDDirectoryAsNeeded(size_t* uriLength, char* uri, const char* asciiDir1, const wchar* asciiDir2)
  372. {
  373. 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)
  374. {
  375. printf("We assume bounded MAX_URI_LENGTH for simplicity.\n");
  376. printf("%s, %s, %ls\n", uri, asciiDir1, asciiDir2);
  377. exit(1);
  378. }
  379. int success = 0;
  380. int extLength = 0;
  381. extLength = sprintf_s(uri + *uriLength, MAX_TTD_ASCII_PATH_EXT_LENGTH, "%s%s", asciiDir1, TTD_HOST_PATH_SEP);
  382. if(extLength == -1 || MAX_URI_LENGTH < (*uriLength) + extLength)
  383. {
  384. printf("Failed directory extension 1.\n");
  385. printf("%s, %s, %ls\n", uri, asciiDir1, asciiDir2);
  386. exit(1);
  387. }
  388. *uriLength += extLength;
  389. success = TTDHostMKDir(uri, *uriLength);
  390. if(success != 0)
  391. {
  392. //we may fail because someone else created the directory -- that is ok
  393. Helpers::TTReportLastIOErrorAsNeeded(errno != ENOENT, "Failed to create directory");
  394. }
  395. char realAsciiDir2[MAX_TTD_ASCII_PATH_EXT_LENGTH];
  396. size_t asciiDir2Length = wcslen(asciiDir2) + 1;
  397. for(size_t i = 0; i < asciiDir2Length; ++i)
  398. {
  399. if(asciiDir2[i] > CHAR_MAX)
  400. {
  401. printf("Test directory names can only include ascii chars.\n");
  402. exit(1);
  403. }
  404. realAsciiDir2[i] = (char)asciiDir2[i];
  405. }
  406. extLength = sprintf_s(uri + *uriLength, MAX_TTD_ASCII_PATH_EXT_LENGTH, "%s%s", realAsciiDir2, TTD_HOST_PATH_SEP);
  407. if(extLength == -1 || MAX_URI_LENGTH < *uriLength + extLength)
  408. {
  409. printf("Failed directory create 2.\n");
  410. printf("%s, %s, %ls\n", uri, asciiDir1, asciiDir2);
  411. exit(1);
  412. }
  413. *uriLength += extLength;
  414. success = TTDHostMKDir(uri, *uriLength);
  415. if(success != 0)
  416. {
  417. //we may fail because someone else created the directory -- that is ok
  418. Helpers::TTReportLastIOErrorAsNeeded(errno != ENOENT, "Failed to create directory");
  419. }
  420. }
  421. void Helpers::GetTTDDirectory(const wchar* curi, size_t* uriLength, char* uri, size_t bufferLength)
  422. {
  423. TTDHostBuildCurrentExeDirectory(uri, uriLength, bufferLength);
  424. Helpers::CreateTTDDirectoryAsNeeded(uriLength, uri, "_ttdlog", curi);
  425. }
  426. JsTTDStreamHandle CALLBACK Helpers::TTCreateStreamCallback(size_t uriLength, const char* uri, size_t asciiNameLength, const char* asciiName, bool read, bool write)
  427. {
  428. AssertMsg((read | write) & (!read | !write), "Read/Write streams not supported yet -- defaulting to read only");
  429. if(uriLength + asciiNameLength + 1 > MAX_URI_LENGTH)
  430. {
  431. printf("We assume bounded MAX_URI_LENGTH for simplicity.");
  432. exit(1);
  433. }
  434. char path[MAX_URI_LENGTH];
  435. memset(path, 0, MAX_URI_LENGTH);
  436. memcpy_s(path, MAX_URI_LENGTH, uri, uriLength);
  437. memcpy_s(path + uriLength, MAX_URI_LENGTH - uriLength, asciiName, asciiNameLength);
  438. JsTTDStreamHandle res = TTDHostOpen(uriLength + asciiNameLength, path, write);
  439. if(res == nullptr)
  440. {
  441. fprintf(stderr, "Failed to open file: %s\n", path);
  442. }
  443. Helpers::TTReportLastIOErrorAsNeeded(res != nullptr, "Failed File Open");
  444. return res;
  445. }
  446. bool CALLBACK Helpers::TTReadBytesFromStreamCallback(JsTTDStreamHandle handle, byte* buff, size_t size, size_t* readCount)
  447. {
  448. AssertMsg(handle != nullptr, "Bad file handle.");
  449. if(size > MAXDWORD)
  450. {
  451. *readCount = 0;
  452. return false;
  453. }
  454. BOOL ok = FALSE;
  455. *readCount = TTDHostRead(buff, size, (FILE*)handle);
  456. ok = (*readCount != 0);
  457. Helpers::TTReportLastIOErrorAsNeeded(ok, "Failed Read!!!");
  458. return ok ? true : false;
  459. }
  460. bool CALLBACK Helpers::TTWriteBytesToStreamCallback(JsTTDStreamHandle handle, const byte* buff, size_t size, size_t* writtenCount)
  461. {
  462. AssertMsg(handle != nullptr, "Bad file handle.");
  463. if(size > MAXDWORD)
  464. {
  465. *writtenCount = 0;
  466. return false;
  467. }
  468. BOOL ok = FALSE;
  469. *writtenCount = TTDHostWrite(buff, size, (FILE*)handle);
  470. ok = (*writtenCount == size);
  471. Helpers::TTReportLastIOErrorAsNeeded(ok, "Failed Read!!!");
  472. return ok ? true : false;
  473. }
  474. void CALLBACK Helpers::TTFlushAndCloseStreamCallback(JsTTDStreamHandle handle, bool read, bool write)
  475. {
  476. fflush((FILE*)handle);
  477. fclose((FILE*)handle);
  478. }
  479. #define SET_BINARY_PATH_ERROR_MESSAGE(path, msg) \
  480. str_len = (int) strlen(msg); \
  481. memcpy(path, msg, (size_t)str_len); \
  482. path[str_len] = char(0)
  483. void GetBinaryLocation(char *path, const unsigned size)
  484. {
  485. AssertMsg(path != nullptr, "Path can not be nullptr");
  486. AssertMsg(size < INT_MAX, "Isn't it too big for a path buffer?");
  487. #ifdef _WIN32
  488. LPWSTR wpath = (WCHAR*)malloc(sizeof(WCHAR) * size);
  489. int str_len;
  490. if (!wpath)
  491. {
  492. SET_BINARY_PATH_ERROR_MESSAGE(path, "GetBinaryLocation: GetModuleFileName has failed. OutOfMemory!");
  493. return;
  494. }
  495. str_len = GetModuleFileNameW(NULL, wpath, size - 1);
  496. if (str_len <= 0)
  497. {
  498. SET_BINARY_PATH_ERROR_MESSAGE(path, "GetBinaryLocation: GetModuleFileName has failed.");
  499. free(wpath);
  500. return;
  501. }
  502. str_len = WideCharToMultiByte(CP_UTF8, 0, wpath, str_len, path, size, NULL, NULL);
  503. free(wpath);
  504. if (str_len <= 0)
  505. {
  506. SET_BINARY_PATH_ERROR_MESSAGE(path, "GetBinaryLocation: GetModuleFileName (WideCharToMultiByte) has failed.");
  507. return;
  508. }
  509. if ((unsigned)str_len > size - 1)
  510. {
  511. str_len = (int) size - 1;
  512. }
  513. path[str_len] = char(0);
  514. #elif defined(__APPLE__)
  515. uint32_t path_size = (uint32_t)size;
  516. char *tmp = nullptr;
  517. int str_len;
  518. if (_NSGetExecutablePath(path, &path_size))
  519. {
  520. SET_BINARY_PATH_ERROR_MESSAGE(path, "GetBinaryLocation: _NSGetExecutablePath has failed.");
  521. return;
  522. }
  523. tmp = (char*)malloc(size);
  524. char *result = realpath(path, tmp);
  525. str_len = strlen(result);
  526. memcpy(path, result, str_len);
  527. free(tmp);
  528. path[str_len] = char(0);
  529. #elif defined(__linux__)
  530. int str_len = readlink("/proc/self/exe", path, size - 1);
  531. if (str_len <= 0)
  532. {
  533. SET_BINARY_PATH_ERROR_MESSAGE(path, "GetBinaryLocation: /proc/self/exe has failed.");
  534. return;
  535. }
  536. path[str_len] = char(0);
  537. #else
  538. #warning "Implement GetBinaryLocation for this platform"
  539. #endif
  540. }
  541. // xplat-todo: Implement a corresponding solution for GetModuleFileNameW
  542. // and cleanup PAL. [ https://github.com/Microsoft/ChakraCore/pull/2288 should be merged first ]
  543. // GetModuleFileName* PAL is not reliable and forces us to explicitly double initialize PAL
  544. // with argc / argv....
  545. void GetBinaryPathWithFileNameA(char *path, const size_t buffer_size, const char* filename)
  546. {
  547. char fullpath[_MAX_PATH];
  548. char drive[_MAX_DRIVE];
  549. char dir[_MAX_DIR];
  550. char modulename[_MAX_PATH];
  551. GetBinaryLocation(modulename, _MAX_PATH);
  552. _splitpath_s(modulename, drive, _MAX_DRIVE, dir, _MAX_DIR, nullptr, 0, nullptr, 0);
  553. _makepath_s(fullpath, drive, dir, filename, nullptr);
  554. size_t len = strlen(fullpath);
  555. if (len < buffer_size)
  556. {
  557. memcpy(path, fullpath, len * sizeof(char));
  558. }
  559. else
  560. {
  561. len = 0;
  562. }
  563. path[len] = char(0);
  564. }