vmsys.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942
  1. /*++
  2. Copyright (c) 2015 Minoca Corp.
  3. This file is licensed under the terms of the GNU General Public License
  4. version 3. Alternative licensing terms are available. Contact
  5. info@minocacorp.com for details. See the LICENSE file at the root of this
  6. project for complete licensing information.
  7. Module Name:
  8. vmsys.c
  9. Abstract:
  10. This module implements the default support functions needed to wire a
  11. Chalk interpreter up to the rest of the system in the default configuration.
  12. Author:
  13. Evan Green 28-May-2016
  14. Environment:
  15. C
  16. --*/
  17. //
  18. // ------------------------------------------------------------------- Includes
  19. //
  20. #include <errno.h>
  21. #include <limits.h>
  22. #include <stdio.h>
  23. #include <stdlib.h>
  24. #include <string.h>
  25. #include <sys/stat.h>
  26. #include <unistd.h>
  27. #include "chalkp.h"
  28. #include "vmsys.h"
  29. //
  30. // ---------------------------------------------------------------- Definitions
  31. //
  32. //
  33. // Define some default garbage collection parameters.
  34. //
  35. #define CK_INITIAL_HEAP_DEFAULT (1024 * 1024 * 10)
  36. #define CK_MINIMUM_HEAP_DEFAULT (1024 * 1024)
  37. #define CK_HEAP_GROWTH_DEFAULT 512
  38. //
  39. // ------------------------------------------------------ Data Type Definitions
  40. //
  41. //
  42. // ----------------------------------------------- Internal Function Prototypes
  43. //
  44. PVOID
  45. CkpDefaultReallocate (
  46. PVOID Allocation,
  47. UINTN NewSize
  48. );
  49. CK_LOAD_MODULE_RESULT
  50. CkpDefaultLoadModule (
  51. PCK_VM Vm,
  52. PCSTR ModulePath,
  53. PCK_MODULE_HANDLE ModuleData
  54. );
  55. INT
  56. CkpDefaultSaveModule (
  57. PCK_VM Vm,
  58. PCSTR ModulePath,
  59. PCSTR FrozenData,
  60. UINTN FrozenDataSize
  61. );
  62. VOID
  63. CkpDefaultUnloadForeignModule (
  64. PVOID Data
  65. );
  66. VOID
  67. CkpDefaultWrite (
  68. PCK_VM Vm,
  69. PCSTR String
  70. );
  71. VOID
  72. CkpDefaultError (
  73. PCK_VM Vm,
  74. CK_ERROR_TYPE ErrorType,
  75. PSTR Message
  76. );
  77. VOID
  78. CkpDefaultUnhandledException (
  79. PCK_VM Vm
  80. );
  81. CK_LOAD_MODULE_RESULT
  82. CkpLoadSourceFile (
  83. PCK_VM Vm,
  84. PCSTR Directory,
  85. PCSTR ModulePath,
  86. PCK_MODULE_HANDLE ModuleData
  87. );
  88. CK_LOAD_MODULE_RESULT
  89. CkpReadSource (
  90. PCK_VM Vm,
  91. PCSTR ModulePath,
  92. UINTN PathLength,
  93. FILE *File,
  94. UINTN Size,
  95. PCK_MODULE_HANDLE ModuleData
  96. );
  97. CK_LOAD_MODULE_RESULT
  98. CkpLoadDynamicModule (
  99. PCK_VM Vm,
  100. PCSTR Directory,
  101. PCSTR ModulePath,
  102. PCK_MODULE_HANDLE ModuleData
  103. );
  104. //
  105. // -------------------------------------------------------------------- Globals
  106. //
  107. CK_CONFIGURATION CkDefaultConfiguration = {
  108. CkpDefaultReallocate,
  109. CkpDefaultLoadModule,
  110. CkpDefaultSaveModule,
  111. CkpDefaultUnloadForeignModule,
  112. CkpDefaultWrite,
  113. CkpDefaultError,
  114. CkpDefaultUnhandledException,
  115. CK_INITIAL_HEAP_DEFAULT,
  116. CK_MINIMUM_HEAP_DEFAULT,
  117. CK_HEAP_GROWTH_DEFAULT,
  118. 0
  119. };
  120. //
  121. // ------------------------------------------------------------------ Functions
  122. //
  123. PVOID
  124. CkpDefaultReallocate (
  125. PVOID Allocation,
  126. UINTN NewSize
  127. )
  128. /*++
  129. Routine Description:
  130. This routine contains the default Chalk reallocate routine, which wires up
  131. to the C library realloc function.
  132. Arguments:
  133. Allocation - Supplies an optional pointer to the allocation to resize or
  134. free. If NULL, then this routine will allocate new memory.
  135. NewSize - Supplies the size of the desired allocation. If this is 0 and the
  136. allocation parameter is non-null, the given allocation will be freed.
  137. Otherwise it will be resized to requested size.
  138. Return Value:
  139. Returns a pointer to the allocation on success.
  140. NULL on allocation failure, or in the case the memory is being freed.
  141. --*/
  142. {
  143. return realloc(Allocation, NewSize);
  144. }
  145. CK_LOAD_MODULE_RESULT
  146. CkpDefaultLoadModule (
  147. PCK_VM Vm,
  148. PCSTR ModulePath,
  149. PCK_MODULE_HANDLE ModuleData
  150. )
  151. /*++
  152. Routine Description:
  153. This routine is called to load a new Chalk module.
  154. Arguments:
  155. Vm - Supplies a pointer to the virtual machine.
  156. ModulePath - Supplies a pointer to the module path to load. Directories
  157. will be separated with dots. If this contains a slash, then it is an
  158. absolute path that should be loaded directly.
  159. ModuleData - Supplies a pointer where the loaded module information will
  160. be returned on success.
  161. Return Value:
  162. Returns a load module error code.
  163. --*/
  164. {
  165. PSTR Character;
  166. PCSTR Directory;
  167. PSTR ModuleCopy;
  168. UINTN PathCount;
  169. UINTN PathIndex;
  170. CK_LOAD_MODULE_RESULT Result;
  171. if (!CkEnsureStack(Vm, 2)) {
  172. return CkLoadModuleNoMemory;
  173. }
  174. //
  175. // If the module path contains a slash, just try to load it directly.
  176. //
  177. if (strchr(ModulePath, '/') != NULL) {
  178. Result = CkpLoadDynamicModule(Vm, NULL, ModulePath, ModuleData);
  179. if (Result != CkLoadModuleForeign) {
  180. Result = CkpLoadSourceFile(Vm, NULL, ModulePath, ModuleData);
  181. }
  182. return Result;
  183. }
  184. //
  185. // Copy the module path, and convert mydir.mymod into mydir/mymod.
  186. //
  187. ModuleCopy = strdup(ModulePath);
  188. if (ModuleCopy == NULL) {
  189. return CkLoadModuleNoMemory;
  190. }
  191. Character = ModuleCopy;
  192. while (*Character != '\0') {
  193. if (*Character == '.') {
  194. *Character = '/';
  195. }
  196. Character += 1;
  197. }
  198. CkPushModulePath(Vm);
  199. PathCount = CkListSize(Vm, -1);
  200. Result = CkLoadModuleNotFound;
  201. if (PathCount == 0) {
  202. CkStackPop(Vm);
  203. free(ModuleCopy);
  204. return Result;
  205. }
  206. for (PathIndex = 0; PathIndex < PathCount; PathIndex += 1) {
  207. CkListGet(Vm, -1, PathIndex);
  208. Directory = CkGetString(Vm, -1, NULL);
  209. if (Directory == NULL) {
  210. Directory = "";
  211. }
  212. Result = CkpLoadSourceFile(Vm, Directory, ModuleCopy, ModuleData);
  213. if (Result != CkLoadModuleNotFound) {
  214. break;
  215. }
  216. Result = CkpLoadDynamicModule(Vm, Directory, ModuleCopy, ModuleData);
  217. if (Result != CkLoadModuleNotFound) {
  218. break;
  219. }
  220. CkStackPop(Vm);
  221. }
  222. //
  223. // Pop the last list entry and the module path list.
  224. //
  225. CkStackPop(Vm);
  226. CkStackPop(Vm);
  227. free(ModuleCopy);
  228. return Result;
  229. }
  230. INT
  231. CkpDefaultSaveModule (
  232. PCK_VM Vm,
  233. PCSTR ModulePath,
  234. PCSTR FrozenData,
  235. UINTN FrozenDataSize
  236. )
  237. /*++
  238. Routine Description:
  239. This routine is called after a module is compiled, so that the caller can
  240. save the compilation object.
  241. Arguments:
  242. Vm - Supplies a pointer to the virtual machine.
  243. ModulePath - Supplies a pointer to the source file path that was just
  244. loaded.
  245. FrozenData - Supplies an opaque binary representation of the compiled
  246. module. The format of this data is unspecified and may change between
  247. revisions of the language.
  248. FrozenDataSize - Supplies the number of bytes in the frozen module data.
  249. Return Value:
  250. 0 always, since failure is non-fatal.
  251. --*/
  252. {
  253. PSTR Dot;
  254. FILE *File;
  255. size_t Length;
  256. CHAR Path[PATH_MAX];
  257. ssize_t Written;
  258. //
  259. // Use the same path as the source file, but replace the extension with
  260. // the object extension.
  261. //
  262. Length = strlen(ModulePath);
  263. if (Length + 2 > PATH_MAX) {
  264. return 0;
  265. }
  266. memcpy(Path, ModulePath, Length + 1);
  267. Dot = strrchr(Path, '.');
  268. if (Dot == NULL) {
  269. return 0;
  270. }
  271. if (Dot + 1 + strlen(CK_OBJECT_EXTENSION) >= Path + PATH_MAX) {
  272. return 0;
  273. }
  274. strcpy(Dot + 1, CK_OBJECT_EXTENSION);
  275. //
  276. // Attempt to save the file.
  277. //
  278. File = fopen(Path, "wb");
  279. if (File == NULL) {
  280. return 0;
  281. }
  282. Written = fwrite(FrozenData, 1, FrozenDataSize, File);
  283. fclose(File);
  284. //
  285. // If not everything was written, delete the file so as not to have half
  286. // baked objects.
  287. //
  288. if (Written != FrozenDataSize) {
  289. unlink(Path);
  290. }
  291. return 0;
  292. }
  293. VOID
  294. CkpDefaultUnloadForeignModule (
  295. PVOID Data
  296. )
  297. /*++
  298. Routine Description:
  299. This routine is called when a foreign module is being destroyed.
  300. Arguments:
  301. Data - Supplies a pointer to the handle returned when the foreign module
  302. was loaded. This is usually a dynamic library handle.
  303. Return Value:
  304. None.
  305. --*/
  306. {
  307. CK_ASSERT(Data != NULL);
  308. CkpFreeLibrary(Data);
  309. return;
  310. }
  311. VOID
  312. CkpDefaultWrite (
  313. PCK_VM Vm,
  314. PCSTR String
  315. )
  316. /*++
  317. Routine Description:
  318. This routine is called to print text in Chalk.
  319. Arguments:
  320. Vm - Supplies a pointer to the virtual machine.
  321. String - Supplies a pointer to the string to print. This routine should not
  322. modify or free this string.
  323. Return Value:
  324. None.
  325. --*/
  326. {
  327. printf("%s", String);
  328. return;
  329. }
  330. VOID
  331. CkpDefaultError (
  332. PCK_VM Vm,
  333. CK_ERROR_TYPE ErrorType,
  334. PSTR Message
  335. )
  336. /*++
  337. Routine Description:
  338. This routine when the Chalk interpreter experiences an error.
  339. Arguments:
  340. Vm - Supplies a pointer to the virtual machine.
  341. ErrorType - Supplies the type of error occurring.
  342. Message - Supplies a pointer to a string describing the error.
  343. Return Value:
  344. None.
  345. --*/
  346. {
  347. if (Message == NULL) {
  348. Message = "";
  349. }
  350. switch (ErrorType) {
  351. case CkErrorNoMemory:
  352. fprintf(stderr, "Allocation failure\n");
  353. break;
  354. case CkErrorRuntime:
  355. fprintf(stderr, "Error: %s.\n", Message);
  356. break;
  357. case CkErrorCompile:
  358. default:
  359. fprintf(stderr, "Compile Error: %s.\n", Message);
  360. break;
  361. }
  362. return;
  363. }
  364. VOID
  365. CkpDefaultUnhandledException (
  366. PCK_VM Vm
  367. )
  368. /*++
  369. Routine Description:
  370. This routine implements the default handling of an unhandled exception. It
  371. takes one argument, the exception, and prints the exception and stack trace
  372. to stderr.
  373. Arguments:
  374. Vm - Supplies a pointer to the virtual machine.
  375. Return Value:
  376. None.
  377. --*/
  378. {
  379. UINTN Length;
  380. PCSTR String;
  381. fprintf(stderr, "Unhandled Exception:\n");
  382. CkPushValue(Vm, 1);
  383. CkCallMethod(Vm, "__str", 0);
  384. String = CkGetString(Vm, -1, &Length);
  385. fprintf(stderr, "%s\n", String);
  386. CkStackPop(Vm);
  387. //
  388. // Set the exception as the return value.
  389. //
  390. CkStackReplace(Vm, 0);
  391. return;
  392. }
  393. //
  394. // --------------------------------------------------------- Internal Functions
  395. //
  396. CK_LOAD_MODULE_RESULT
  397. CkpLoadSourceFile (
  398. PCK_VM Vm,
  399. PCSTR Directory,
  400. PCSTR ModulePath,
  401. PCK_MODULE_HANDLE ModuleData
  402. )
  403. /*++
  404. Routine Description:
  405. This routine is called to load a new Chalk source file.
  406. Arguments:
  407. Vm - Supplies a pointer to the virtual machine.
  408. Directory - Supplies a pointer to the directory to find the module in.
  409. ModulePath - Supplies a pointer to the module path to load.
  410. ModuleData - Supplies a pointer where the loaded module information will
  411. be returned on success.
  412. Return Value:
  413. Returns a load module error code.
  414. --*/
  415. {
  416. FILE *File;
  417. off_t FileSize;
  418. CK_LOAD_MODULE_RESULT LoadStatus;
  419. CHAR ObjectPath[PATH_MAX];
  420. INT ObjectPathLength;
  421. struct stat ObjectStat;
  422. INT ObjectStatus;
  423. CHAR Path[PATH_MAX];
  424. INT PathLength;
  425. INT SourceStatus;
  426. struct stat Stat;
  427. File = NULL;
  428. LoadStatus = CkLoadModuleStaticError;
  429. //
  430. // Get the full path to the source file.
  431. //
  432. if (Directory == NULL) {
  433. PathLength = snprintf(Path, PATH_MAX, "%s", ModulePath);
  434. } else if (*Directory == '\0') {
  435. PathLength = snprintf(Path,
  436. PATH_MAX,
  437. "%s.%s",
  438. ModulePath,
  439. CK_SOURCE_EXTENSION);
  440. } else {
  441. PathLength = snprintf(Path,
  442. PATH_MAX,
  443. "%s/%s.%s",
  444. Directory,
  445. ModulePath,
  446. CK_SOURCE_EXTENSION);
  447. }
  448. if ((PathLength < 0) || (PathLength > PATH_MAX)) {
  449. ModuleData->Error = "Max path length exceeded";
  450. return CkLoadModuleStaticError;
  451. }
  452. Path[PATH_MAX - 1] = '\0';
  453. //
  454. // Get the path to the pre-compiled object.
  455. //
  456. if (Directory == NULL) {
  457. ObjectPathLength = -1;
  458. } else if (*Directory == '\0') {
  459. ObjectPathLength = snprintf(ObjectPath,
  460. PATH_MAX,
  461. "%s.%s",
  462. ModulePath,
  463. CK_OBJECT_EXTENSION);
  464. } else {
  465. ObjectPathLength = snprintf(ObjectPath,
  466. PATH_MAX,
  467. "%s/%s.%s",
  468. Directory,
  469. ModulePath,
  470. CK_OBJECT_EXTENSION);
  471. }
  472. if ((ObjectPathLength < 0) || (ObjectPathLength > PATH_MAX)) {
  473. ObjectPath[0] = '\0';
  474. ObjectPathLength = 0;
  475. }
  476. //
  477. // Stat both the source and the object. Both must be files, and the object
  478. // must have a non-zero size.
  479. //
  480. SourceStatus = stat(Path, &Stat);
  481. if ((SourceStatus == 0) && (!S_ISREG(Stat.st_mode))) {
  482. SourceStatus = -1;
  483. }
  484. ObjectStatus = -1;
  485. if (ObjectPathLength != 0) {
  486. ObjectStatus = stat(ObjectPath, &ObjectStat);
  487. if ((ObjectStatus == 0) &&
  488. ((!S_ISREG(ObjectStat.st_mode)) || (ObjectStat.st_size == 0))) {
  489. ObjectStatus = -1;
  490. }
  491. }
  492. //
  493. // If neither exists, the the module can't be found.
  494. //
  495. if ((SourceStatus != 0) && (ObjectStatus != 0)) {
  496. LoadStatus = CkLoadModuleNotFound;
  497. goto LoadSourceFileEnd;
  498. }
  499. //
  500. // If the object path exists and is either 1) the only thing that exists or
  501. // 2) is newer than the source, then try to open the object file.
  502. //
  503. FileSize = Stat.st_size;
  504. if ((ObjectStatus == 0) &&
  505. ((SourceStatus != 0) || (ObjectStat.st_mtime >= Stat.st_mtime))) {
  506. File = fopen(ObjectPath, "rb");
  507. if (File != NULL) {
  508. FileSize = ObjectStat.st_size;
  509. PathLength = ObjectPathLength;
  510. }
  511. }
  512. //
  513. // Try to open the source if opening the object file was not an option or
  514. // failed.
  515. //
  516. if ((File == NULL) && (SourceStatus == 0)) {
  517. File = fopen(Path, "rb");
  518. }
  519. if (File == NULL) {
  520. LoadStatus = CkLoadModuleStaticError;
  521. goto LoadSourceFileEnd;
  522. }
  523. LoadStatus = CkpReadSource(Vm,
  524. Path,
  525. PathLength,
  526. File,
  527. FileSize,
  528. ModuleData);
  529. LoadSourceFileEnd:
  530. if (LoadStatus == CkLoadModuleStaticError) {
  531. if ((errno == ENOENT) || (errno == EACCES) || (errno == EPERM)) {
  532. return CkLoadModuleNotFound;
  533. }
  534. ModuleData->Error = strerror(errno);
  535. }
  536. if (File != NULL) {
  537. fclose(File);
  538. }
  539. return LoadStatus;
  540. }
  541. CK_LOAD_MODULE_RESULT
  542. CkpReadSource (
  543. PCK_VM Vm,
  544. PCSTR ModulePath,
  545. UINTN PathLength,
  546. FILE *File,
  547. UINTN Size,
  548. PCK_MODULE_HANDLE ModuleData
  549. )
  550. /*++
  551. Routine Description:
  552. This routine is called to read in the contents of a Chalk source file.
  553. Arguments:
  554. Vm - Supplies a pointer to the virtual machine.
  555. ModulePath - Supplies a pointer to the opened path.
  556. PathLength - Supplies the length of the opened path in bytes, not including
  557. the null terminator.
  558. File - Supplies a pointer to the open file.
  559. Size - Supplies the size of the file in bytes.
  560. ModuleData - Supplies a pointer where the loaded module information will
  561. be returned on success.
  562. Return Value:
  563. Returns a load module error code.
  564. --*/
  565. {
  566. CK_LOAD_MODULE_RESULT LoadStatus;
  567. PSTR Source;
  568. LoadStatus = CkLoadModuleStaticError;
  569. Source = CkAllocate(Vm, Size + 1);
  570. if (Source == NULL) {
  571. LoadStatus = CkLoadModuleNoMemory;
  572. goto ReadSourceEnd;
  573. }
  574. if (fread(Source, 1, Size, File) != Size) {
  575. LoadStatus = CkLoadModuleStaticError;
  576. goto ReadSourceEnd;
  577. }
  578. Source[Size] = '\0';
  579. ModuleData->Source.Path = CkAllocate(Vm, PathLength + 1);
  580. if (ModuleData->Source.Path == NULL) {
  581. LoadStatus = CkLoadModuleNoMemory;
  582. goto ReadSourceEnd;
  583. }
  584. CkCopy(ModuleData->Source.Path, ModulePath, PathLength + 1);
  585. ModuleData->Source.PathLength = PathLength;
  586. ModuleData->Source.Text = Source;
  587. Source = NULL;
  588. ModuleData->Source.Length = Size;
  589. LoadStatus = CkLoadModuleSource;
  590. ReadSourceEnd:
  591. if (Source != NULL) {
  592. CkFree(Vm, Source);
  593. }
  594. return LoadStatus;
  595. }
  596. CK_LOAD_MODULE_RESULT
  597. CkpLoadDynamicModule (
  598. PCK_VM Vm,
  599. PCSTR Directory,
  600. PCSTR ModulePath,
  601. PCK_MODULE_HANDLE ModuleData
  602. )
  603. /*++
  604. Routine Description:
  605. This routine is called to load a new Chalk dynamic library module.
  606. Arguments:
  607. Vm - Supplies a pointer to the virtual machine.
  608. Directory - Supplies a pointer to the directory to find the module in. If
  609. this is NULL, then the module path will be used without modification.
  610. ModulePath - Supplies a pointer to the module path to load.
  611. ModuleData - Supplies a pointer where the loaded module information will
  612. be returned on success.
  613. Return Value:
  614. Returns a load module error code.
  615. --*/
  616. {
  617. PCK_FOREIGN_FUNCTION EntryPoint;
  618. PVOID Handle;
  619. CK_LOAD_MODULE_RESULT LoadStatus;
  620. CHAR Path[PATH_MAX];
  621. INT PathLength;
  622. struct stat Stat;
  623. Handle = NULL;
  624. LoadStatus = CkLoadModuleStaticError;
  625. ModuleData->Error = NULL;
  626. if (Directory == NULL) {
  627. PathLength = snprintf(Path, PATH_MAX, "%s", ModulePath);
  628. } else if (*Directory == '\0') {
  629. PathLength = snprintf(Path,
  630. PATH_MAX,
  631. "%s%s",
  632. ModulePath,
  633. CkSharedLibraryExtension);
  634. } else {
  635. PathLength = snprintf(Path,
  636. PATH_MAX,
  637. "%s/%s%s",
  638. Directory,
  639. ModulePath,
  640. CkSharedLibraryExtension);
  641. }
  642. if ((PathLength < 0) || (PathLength > PATH_MAX)) {
  643. ModuleData->Error = "Max path length exceeded";
  644. return CkLoadModuleStaticError;
  645. }
  646. Path[PATH_MAX - 1] = '\0';
  647. //
  648. // Validate that this path points to a regular file before trying to open
  649. // a dynamic library.
  650. //
  651. if (stat(Path, &Stat) != 0) {
  652. if ((errno == ENOENT) || (errno == EACCES) || (errno == EPERM)) {
  653. LoadStatus = CkLoadModuleNotFound;
  654. } else {
  655. ModuleData->Error = strerror(errno);
  656. }
  657. goto LoadDynamicModuleEnd;
  658. }
  659. if (!S_ISREG(Stat.st_mode)) {
  660. return CkLoadModuleNotFound;
  661. }
  662. //
  663. // Open up the dynamic library.
  664. //
  665. Handle = CkpLoadLibrary(Path);
  666. if (Handle == NULL) {
  667. return CkLoadModuleNotFound;
  668. }
  669. EntryPoint = CkpGetLibrarySymbol(Handle, CK_MODULE_ENTRY_NAME);
  670. if (EntryPoint == NULL) {
  671. LoadStatus = CkLoadModuleNotFound;
  672. goto LoadDynamicModuleEnd;
  673. }
  674. ModuleData->Foreign.Path = CkAllocate(Vm, PathLength + 1);
  675. if (ModuleData->Source.Path == NULL) {
  676. LoadStatus = CkLoadModuleNoMemory;
  677. goto LoadDynamicModuleEnd;
  678. }
  679. CkCopy(ModuleData->Foreign.Path, Path, PathLength + 1);
  680. ModuleData->Foreign.PathLength = PathLength;
  681. ModuleData->Foreign.Handle = Handle;
  682. Handle = NULL;
  683. ModuleData->Foreign.Entry = EntryPoint;
  684. LoadStatus = CkLoadModuleForeign;
  685. LoadDynamicModuleEnd:
  686. if (Handle != NULL) {
  687. CkpFreeLibrary(Handle);
  688. }
  689. return LoadStatus;
  690. }