Aer Interpreter Source
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

8137 lines
245 KiB

  1. /**
  2. * @PROJECT PH7 Engine for the AerScript Interpreter
  3. * @COPYRIGHT See COPYING in the top level directory
  4. * @FILE engine/vfs.c
  5. * @DESCRIPTION Implements a virtual file systems (VFS) for the PH7 engine
  6. * @DEVELOPERS Symisc Systems <devel@symisc.net>
  7. * Rafal Kupiec <belliash@codingworkshop.eu.org>
  8. * David Carlier <devnexen@gmail.com>
  9. */
  10. #include "ph7int.h"
  11. /*
  12. * Given a string containing the path of a file or directory, this function
  13. * return the parent directory's path.
  14. */
  15. PH7_PRIVATE const char *PH7_ExtractDirName(const char *zPath, int nByte, int *pLen) {
  16. const char *zEnd = &zPath[nByte - 1];
  17. int c, d;
  18. c = d = '/';
  19. #ifdef __WINNT__
  20. d = '\\';
  21. #endif
  22. while(zEnd > zPath && ((int)zEnd[0] != c && (int)zEnd[0] != d)) {
  23. zEnd--;
  24. }
  25. *pLen = (int)(zEnd - zPath);
  26. #ifdef __WINNT__
  27. if((*pLen) == (int)sizeof(char) && zPath[0] == '/') {
  28. /* Normalize path on windows */
  29. return "\\";
  30. }
  31. #endif
  32. if(zEnd == zPath && ((int)zEnd[0] != c && (int)zEnd[0] != d)) {
  33. /* No separator,return "." as the current directory */
  34. *pLen = sizeof(char);
  35. return ".";
  36. }
  37. if((*pLen) == 0) {
  38. *pLen = sizeof(char);
  39. #ifdef __WINNT__
  40. return "\\";
  41. #else
  42. return "/";
  43. #endif
  44. }
  45. return zPath;
  46. }
  47. /*
  48. * bool chdir(string $directory)
  49. * Change the current directory.
  50. * Parameters
  51. * $directory
  52. * The new current directory
  53. * Return
  54. * TRUE on success or FALSE on failure.
  55. */
  56. static int PH7_vfs_chdir(ph7_context *pCtx, int nArg, ph7_value **apArg) {
  57. const char *zPath;
  58. ph7_vfs *pVfs;
  59. int rc;
  60. if(nArg < 1 || !ph7_value_is_string(apArg[0])) {
  61. /* Missing/Invalid argument,return FALSE */
  62. ph7_result_bool(pCtx, 0);
  63. return PH7_OK;
  64. }
  65. /* Point to the underlying vfs */
  66. pVfs = (ph7_vfs *)ph7_context_user_data(pCtx);
  67. if(pVfs == 0 || pVfs->xChdir == 0) {
  68. /* IO routine not implemented,return NULL */
  69. PH7_VmThrowError(pCtx->pVm, PH7_CTX_WARNING,
  70. "IO routine(%s) not implemented in the underlying VFS",
  71. ph7_function_name(pCtx)
  72. );
  73. ph7_result_bool(pCtx, 0);
  74. return PH7_OK;
  75. }
  76. /* Point to the desired directory */
  77. zPath = ph7_value_to_string(apArg[0], 0);
  78. /* Perform the requested operation */
  79. rc = pVfs->xChdir(zPath);
  80. /* IO return value */
  81. ph7_result_bool(pCtx, rc == PH7_OK);
  82. return PH7_OK;
  83. }
  84. /*
  85. * bool chroot(string $directory)
  86. * Change the root directory.
  87. * Parameters
  88. * $directory
  89. * The path to change the root directory to
  90. * Return
  91. * TRUE on success or FALSE on failure.
  92. */
  93. static int PH7_vfs_chroot(ph7_context *pCtx, int nArg, ph7_value **apArg) {
  94. const char *zPath;
  95. ph7_vfs *pVfs;
  96. int rc;
  97. if(nArg < 1 || !ph7_value_is_string(apArg[0])) {
  98. /* Missing/Invalid argument,return FALSE */
  99. ph7_result_bool(pCtx, 0);
  100. return PH7_OK;
  101. }
  102. /* Point to the underlying vfs */
  103. pVfs = (ph7_vfs *)ph7_context_user_data(pCtx);
  104. if(pVfs == 0 || pVfs->xChroot == 0) {
  105. /* IO routine not implemented,return NULL */
  106. PH7_VmThrowError(pCtx->pVm, PH7_CTX_WARNING,
  107. "IO routine(%s) not implemented in the underlying VFS",
  108. ph7_function_name(pCtx)
  109. );
  110. ph7_result_bool(pCtx, 0);
  111. return PH7_OK;
  112. }
  113. /* Point to the desired directory */
  114. zPath = ph7_value_to_string(apArg[0], 0);
  115. /* Perform the requested operation */
  116. rc = pVfs->xChroot(zPath);
  117. /* IO return value */
  118. ph7_result_bool(pCtx, rc == PH7_OK);
  119. return PH7_OK;
  120. }
  121. /*
  122. * string getcwd(void)
  123. * Gets the current working directory.
  124. * Parameters
  125. * None
  126. * Return
  127. * Returns the current working directory on success, or FALSE on failure.
  128. */
  129. static int PH7_vfs_getcwd(ph7_context *pCtx, int nArg, ph7_value **apArg) {
  130. ph7_vfs *pVfs;
  131. int rc;
  132. /* Point to the underlying vfs */
  133. pVfs = (ph7_vfs *)ph7_context_user_data(pCtx);
  134. if(pVfs == 0 || pVfs->xGetcwd == 0) {
  135. SXUNUSED(nArg); /* cc warning */
  136. SXUNUSED(apArg);
  137. /* IO routine not implemented,return NULL */
  138. PH7_VmThrowError(pCtx->pVm, PH7_CTX_WARNING,
  139. "IO routine(%s) not implemented in the underlying VFS",
  140. ph7_function_name(pCtx)
  141. );
  142. ph7_result_bool(pCtx, 0);
  143. return PH7_OK;
  144. }
  145. ph7_result_string(pCtx, "", 0);
  146. /* Perform the requested operation */
  147. rc = pVfs->xGetcwd(pCtx);
  148. if(rc != PH7_OK) {
  149. /* Error,return FALSE */
  150. ph7_result_bool(pCtx, 0);
  151. }
  152. return PH7_OK;
  153. }
  154. /*
  155. * bool rmdir(string $directory)
  156. * Removes directory.
  157. * Parameters
  158. * $directory
  159. * The path to the directory
  160. * Return
  161. * TRUE on success or FALSE on failure.
  162. */
  163. static int PH7_vfs_rmdir(ph7_context *pCtx, int nArg, ph7_value **apArg) {
  164. const char *zPath;
  165. ph7_vfs *pVfs;
  166. int rc;
  167. if(nArg < 1 || !ph7_value_is_string(apArg[0])) {
  168. /* Missing/Invalid argument,return FALSE */
  169. ph7_result_bool(pCtx, 0);
  170. return PH7_OK;
  171. }
  172. /* Point to the underlying vfs */
  173. pVfs = (ph7_vfs *)ph7_context_user_data(pCtx);
  174. if(pVfs == 0 || pVfs->xRmdir == 0) {
  175. /* IO routine not implemented,return NULL */
  176. PH7_VmThrowError(pCtx->pVm, PH7_CTX_WARNING,
  177. "IO routine(%s) not implemented in the underlying VFS",
  178. ph7_function_name(pCtx)
  179. );
  180. ph7_result_bool(pCtx, 0);
  181. return PH7_OK;
  182. }
  183. /* Point to the desired directory */
  184. zPath = ph7_value_to_string(apArg[0], 0);
  185. /* Perform the requested operation */
  186. rc = pVfs->xRmdir(zPath);
  187. /* IO return value */
  188. ph7_result_bool(pCtx, rc == PH7_OK);
  189. return PH7_OK;
  190. }
  191. /*
  192. * bool is_dir(string $filename)
  193. * Tells whether the given filename is a directory.
  194. * Parameters
  195. * $filename
  196. * Path to the file.
  197. * Return
  198. * TRUE on success or FALSE on failure.
  199. */
  200. static int PH7_vfs_is_dir(ph7_context *pCtx, int nArg, ph7_value **apArg) {
  201. const char *zPath;
  202. ph7_vfs *pVfs;
  203. int rc;
  204. if(nArg < 1 || !ph7_value_is_string(apArg[0])) {
  205. /* Missing/Invalid argument,return FALSE */
  206. ph7_result_bool(pCtx, 0);
  207. return PH7_OK;
  208. }
  209. /* Point to the underlying vfs */
  210. pVfs = (ph7_vfs *)ph7_context_user_data(pCtx);
  211. if(pVfs == 0 || pVfs->xIsdir == 0) {
  212. /* IO routine not implemented,return NULL */
  213. PH7_VmThrowError(pCtx->pVm, PH7_CTX_WARNING,
  214. "IO routine(%s) not implemented in the underlying VFS",
  215. ph7_function_name(pCtx)
  216. );
  217. ph7_result_bool(pCtx, 0);
  218. return PH7_OK;
  219. }
  220. /* Point to the desired directory */
  221. zPath = ph7_value_to_string(apArg[0], 0);
  222. /* Perform the requested operation */
  223. rc = pVfs->xIsdir(zPath);
  224. /* IO return value */
  225. ph7_result_bool(pCtx, rc == PH7_OK);
  226. return PH7_OK;
  227. }
  228. /*
  229. * bool mkdir(string $pathname[,int $mode = 0777 [,bool $recursive = false])
  230. * Make a directory.
  231. * Parameters
  232. * $pathname
  233. * The directory path.
  234. * $mode
  235. * The mode is 0777 by default, which means the widest possible access.
  236. * Note:
  237. * mode is ignored on Windows.
  238. * Note that you probably want to specify the mode as an octal number, which means
  239. * it should have a leading zero. The mode is also modified by the current umask
  240. * which you can change using umask().
  241. * $recursive
  242. * Allows the creation of nested directories specified in the pathname.
  243. * Defaults to FALSE. (Not used)
  244. * Return
  245. * TRUE on success or FALSE on failure.
  246. */
  247. static int PH7_vfs_mkdir(ph7_context *pCtx, int nArg, ph7_value **apArg) {
  248. int iRecursive = 0;
  249. const char *zPath;
  250. ph7_vfs *pVfs;
  251. int iMode, rc;
  252. if(nArg < 1 || !ph7_value_is_string(apArg[0])) {
  253. /* Missing/Invalid argument,return FALSE */
  254. ph7_result_bool(pCtx, 0);
  255. return PH7_OK;
  256. }
  257. /* Point to the underlying vfs */
  258. pVfs = (ph7_vfs *)ph7_context_user_data(pCtx);
  259. if(pVfs == 0 || pVfs->xMkdir == 0) {
  260. /* IO routine not implemented,return NULL */
  261. PH7_VmThrowError(pCtx->pVm, PH7_CTX_WARNING,
  262. "IO routine(%s) not implemented in the underlying VFS",
  263. ph7_function_name(pCtx)
  264. );
  265. ph7_result_bool(pCtx, 0);
  266. return PH7_OK;
  267. }
  268. /* Point to the desired directory */
  269. zPath = ph7_value_to_string(apArg[0], 0);
  270. #ifdef __WINNT__
  271. iMode = 0;
  272. #else
  273. /* Assume UNIX */
  274. iMode = 0777;
  275. #endif
  276. if(nArg > 1) {
  277. iMode = ph7_value_to_int(apArg[1]);
  278. if(nArg > 2) {
  279. iRecursive = ph7_value_to_bool(apArg[2]);
  280. }
  281. }
  282. /* Perform the requested operation */
  283. rc = pVfs->xMkdir(zPath, iMode, iRecursive);
  284. /* IO return value */
  285. ph7_result_bool(pCtx, rc == PH7_OK);
  286. return PH7_OK;
  287. }
  288. /*
  289. * bool rename(string $oldname,string $newname)
  290. * Attempts to rename oldname to newname.
  291. * Parameters
  292. * $oldname
  293. * Old name.
  294. * $newname
  295. * New name.
  296. * Return
  297. * TRUE on success or FALSE on failure.
  298. */
  299. static int PH7_vfs_rename(ph7_context *pCtx, int nArg, ph7_value **apArg) {
  300. const char *zOld, *zNew;
  301. ph7_vfs *pVfs;
  302. int rc;
  303. if(nArg < 2 || !ph7_value_is_string(apArg[0]) || !ph7_value_is_string(apArg[1])) {
  304. /* Missing/Invalid arguments,return FALSE */
  305. ph7_result_bool(pCtx, 0);
  306. return PH7_OK;
  307. }
  308. /* Point to the underlying vfs */
  309. pVfs = (ph7_vfs *)ph7_context_user_data(pCtx);
  310. if(pVfs == 0 || pVfs->xRename == 0) {
  311. /* IO routine not implemented,return NULL */
  312. PH7_VmThrowError(pCtx->pVm, PH7_CTX_WARNING,
  313. "IO routine(%s) not implemented in the underlying VFS",
  314. ph7_function_name(pCtx)
  315. );
  316. ph7_result_bool(pCtx, 0);
  317. return PH7_OK;
  318. }
  319. /* Perform the requested operation */
  320. zOld = ph7_value_to_string(apArg[0], 0);
  321. zNew = ph7_value_to_string(apArg[1], 0);
  322. rc = pVfs->xRename(zOld, zNew);
  323. /* IO result */
  324. ph7_result_bool(pCtx, rc == PH7_OK);
  325. return PH7_OK;
  326. }
  327. /*
  328. * string realpath(string $path)
  329. * Returns canonicalized absolute pathname.
  330. * Parameters
  331. * $path
  332. * Target path.
  333. * Return
  334. * Canonicalized absolute pathname on success. or FALSE on failure.
  335. */
  336. static int PH7_vfs_realpath(ph7_context *pCtx, int nArg, ph7_value **apArg) {
  337. const char *zPath;
  338. ph7_vfs *pVfs;
  339. int rc;
  340. if(nArg < 1 || !ph7_value_is_string(apArg[0])) {
  341. /* Missing/Invalid argument,return FALSE */
  342. ph7_result_bool(pCtx, 0);
  343. return PH7_OK;
  344. }
  345. /* Point to the underlying vfs */
  346. pVfs = (ph7_vfs *)ph7_context_user_data(pCtx);
  347. if(pVfs == 0 || pVfs->xRealpath == 0) {
  348. /* IO routine not implemented,return NULL */
  349. PH7_VmThrowError(pCtx->pVm, PH7_CTX_WARNING,
  350. "IO routine(%s) not implemented in the underlying VFS",
  351. ph7_function_name(pCtx)
  352. );
  353. ph7_result_bool(pCtx, 0);
  354. return PH7_OK;
  355. }
  356. /* Set an empty string untnil the underlying OS interface change that */
  357. ph7_result_string(pCtx, "", 0);
  358. /* Perform the requested operation */
  359. zPath = ph7_value_to_string(apArg[0], 0);
  360. rc = pVfs->xRealpath(zPath, pCtx);
  361. if(rc != PH7_OK) {
  362. ph7_result_bool(pCtx, 0);
  363. }
  364. return PH7_OK;
  365. }
  366. /*
  367. * int sleep(int $seconds)
  368. * Delays the program execution for the given number of seconds.
  369. * Parameters
  370. * $seconds
  371. * Halt time in seconds.
  372. * Return
  373. * Zero on success or FALSE on failure.
  374. */
  375. static int PH7_vfs_sleep(ph7_context *pCtx, int nArg, ph7_value **apArg) {
  376. ph7_vfs *pVfs;
  377. int rc, nSleep;
  378. if(nArg < 1 || !ph7_value_is_int(apArg[0])) {
  379. /* Missing/Invalid argument,return FALSE */
  380. ph7_result_bool(pCtx, 0);
  381. return PH7_OK;
  382. }
  383. /* Point to the underlying vfs */
  384. pVfs = (ph7_vfs *)ph7_context_user_data(pCtx);
  385. if(pVfs == 0 || pVfs->xSleep == 0) {
  386. /* IO routine not implemented,return NULL */
  387. PH7_VmThrowError(pCtx->pVm, PH7_CTX_WARNING,
  388. "IO routine(%s) not implemented in the underlying VFS",
  389. ph7_function_name(pCtx)
  390. );
  391. ph7_result_bool(pCtx, 0);
  392. return PH7_OK;
  393. }
  394. /* Amount to sleep */
  395. nSleep = ph7_value_to_int(apArg[0]);
  396. if(nSleep < 0) {
  397. /* Invalid value,return FALSE */
  398. ph7_result_bool(pCtx, 0);
  399. return PH7_OK;
  400. }
  401. /* Perform the requested operation (Microseconds) */
  402. rc = pVfs->xSleep((unsigned int)(nSleep * SX_USEC_PER_SEC));
  403. if(rc != PH7_OK) {
  404. /* Return FALSE */
  405. ph7_result_bool(pCtx, 0);
  406. } else {
  407. /* Return zero */
  408. ph7_result_int(pCtx, 0);
  409. }
  410. return PH7_OK;
  411. }
  412. /*
  413. * void usleep(int $micro_seconds)
  414. * Delays program execution for the given number of micro seconds.
  415. * Parameters
  416. * $micro_seconds
  417. * Halt time in micro seconds. A micro second is one millionth of a second.
  418. * Return
  419. * None.
  420. */
  421. static int PH7_vfs_usleep(ph7_context *pCtx, int nArg, ph7_value **apArg) {
  422. ph7_vfs *pVfs;
  423. int nSleep;
  424. if(nArg < 1 || !ph7_value_is_int(apArg[0])) {
  425. /* Missing/Invalid argument,return immediately */
  426. return PH7_OK;
  427. }
  428. /* Point to the underlying vfs */
  429. pVfs = (ph7_vfs *)ph7_context_user_data(pCtx);
  430. if(pVfs == 0 || pVfs->xSleep == 0) {
  431. /* IO routine not implemented,return NULL */
  432. PH7_VmThrowError(pCtx->pVm, PH7_CTX_WARNING,
  433. "IO routine(%s) not implemented in the underlying VFS",
  434. ph7_function_name(pCtx)
  435. );
  436. return PH7_OK;
  437. }
  438. /* Amount to sleep */
  439. nSleep = ph7_value_to_int(apArg[0]);
  440. if(nSleep < 0) {
  441. /* Invalid value,return immediately */
  442. return PH7_OK;
  443. }
  444. /* Perform the requested operation (Microseconds) */
  445. pVfs->xSleep((unsigned int)nSleep);
  446. return PH7_OK;
  447. }
  448. /*
  449. * bool unlink (string $filename)
  450. * Delete a file.
  451. * Parameters
  452. * $filename
  453. * Path to the file.
  454. * Return
  455. * TRUE on success or FALSE on failure.
  456. */
  457. static int PH7_vfs_unlink(ph7_context *pCtx, int nArg, ph7_value **apArg) {
  458. const char *zPath;
  459. ph7_vfs *pVfs;
  460. int rc;
  461. if(nArg < 1 || !ph7_value_is_string(apArg[0])) {
  462. /* Missing/Invalid argument,return FALSE */
  463. ph7_result_bool(pCtx, 0);
  464. return PH7_OK;
  465. }
  466. /* Point to the underlying vfs */
  467. pVfs = (ph7_vfs *)ph7_context_user_data(pCtx);
  468. if(pVfs == 0 || pVfs->xUnlink == 0) {
  469. /* IO routine not implemented,return NULL */
  470. PH7_VmThrowError(pCtx->pVm, PH7_CTX_WARNING,
  471. "IO routine(%s) not implemented in the underlying VFS",
  472. ph7_function_name(pCtx)
  473. );
  474. ph7_result_bool(pCtx, 0);
  475. return PH7_OK;
  476. }
  477. /* Point to the desired directory */
  478. zPath = ph7_value_to_string(apArg[0], 0);
  479. /* Perform the requested operation */
  480. rc = pVfs->xUnlink(zPath);
  481. /* IO return value */
  482. ph7_result_bool(pCtx, rc == PH7_OK);
  483. return PH7_OK;
  484. }
  485. /*
  486. * bool chmod(string $filename,int $mode)
  487. * Attempts to change the mode of the specified file to that given in mode.
  488. * Parameters
  489. * $filename
  490. * Path to the file.
  491. * $mode
  492. * Mode (Must be an integer)
  493. * Return
  494. * TRUE on success or FALSE on failure.
  495. */
  496. static int PH7_vfs_chmod(ph7_context *pCtx, int nArg, ph7_value **apArg) {
  497. const char *zPath;
  498. ph7_vfs *pVfs;
  499. int iMode;
  500. int rc;
  501. if(nArg < 2 || !ph7_value_is_string(apArg[0])) {
  502. /* Missing/Invalid argument,return FALSE */
  503. ph7_result_bool(pCtx, 0);
  504. return PH7_OK;
  505. }
  506. /* Point to the underlying vfs */
  507. pVfs = (ph7_vfs *)ph7_context_user_data(pCtx);
  508. if(pVfs == 0 || pVfs->xChmod == 0) {
  509. /* IO routine not implemented,return NULL */
  510. PH7_VmThrowError(pCtx->pVm, PH7_CTX_WARNING,
  511. "IO routine(%s) not implemented in the underlying VFS",
  512. ph7_function_name(pCtx)
  513. );
  514. ph7_result_bool(pCtx, 0);
  515. return PH7_OK;
  516. }
  517. /* Point to the desired directory */
  518. zPath = ph7_value_to_string(apArg[0], 0);
  519. /* Extract the mode */
  520. iMode = ph7_value_to_int(apArg[1]);
  521. /* Perform the requested operation */
  522. rc = pVfs->xChmod(zPath, iMode);
  523. /* IO return value */
  524. ph7_result_bool(pCtx, rc == PH7_OK);
  525. return PH7_OK;
  526. }
  527. /*
  528. * bool chown(string $filename,string $user)
  529. * Attempts to change the owner of the file filename to user user.
  530. * Parameters
  531. * $filename
  532. * Path to the file.
  533. * $user
  534. * Username.
  535. * Return
  536. * TRUE on success or FALSE on failure.
  537. */
  538. static int PH7_vfs_chown(ph7_context *pCtx, int nArg, ph7_value **apArg) {
  539. const char *zPath, *zUser;
  540. ph7_vfs *pVfs;
  541. int rc;
  542. if(nArg < 2 || !ph7_value_is_string(apArg[0])) {
  543. /* Missing/Invalid arguments,return FALSE */
  544. ph7_result_bool(pCtx, 0);
  545. return PH7_OK;
  546. }
  547. /* Point to the underlying vfs */
  548. pVfs = (ph7_vfs *)ph7_context_user_data(pCtx);
  549. if(pVfs == 0 || pVfs->xChown == 0) {
  550. /* IO routine not implemented,return NULL */
  551. PH7_VmThrowError(pCtx->pVm, PH7_CTX_WARNING,
  552. "IO routine(%s) not implemented in the underlying VFS",
  553. ph7_function_name(pCtx)
  554. );
  555. ph7_result_bool(pCtx, 0);
  556. return PH7_OK;
  557. }
  558. /* Point to the desired directory */
  559. zPath = ph7_value_to_string(apArg[0], 0);
  560. /* Extract the user */
  561. zUser = ph7_value_to_string(apArg[1], 0);
  562. /* Perform the requested operation */
  563. rc = pVfs->xChown(zPath, zUser);
  564. /* IO return value */
  565. ph7_result_bool(pCtx, rc == PH7_OK);
  566. return PH7_OK;
  567. }
  568. /*
  569. * bool chgrp(string $filename,string $group)
  570. * Attempts to change the group of the file filename to group.
  571. * Parameters
  572. * $filename
  573. * Path to the file.
  574. * $group
  575. * groupname.
  576. * Return
  577. * TRUE on success or FALSE on failure.
  578. */
  579. static int PH7_vfs_chgrp(ph7_context *pCtx, int nArg, ph7_value **apArg) {
  580. const char *zPath, *zGroup;
  581. ph7_vfs *pVfs;
  582. int rc;
  583. if(nArg < 2 || !ph7_value_is_string(apArg[0])) {
  584. /* Missing/Invalid arguments,return FALSE */
  585. ph7_result_bool(pCtx, 0);
  586. return PH7_OK;
  587. }
  588. /* Point to the underlying vfs */
  589. pVfs = (ph7_vfs *)ph7_context_user_data(pCtx);
  590. if(pVfs == 0 || pVfs->xChgrp == 0) {
  591. /* IO routine not implemented,return NULL */
  592. PH7_VmThrowError(pCtx->pVm, PH7_CTX_WARNING,
  593. "IO routine(%s) not implemented in the underlying VFS",
  594. ph7_function_name(pCtx)
  595. );
  596. ph7_result_bool(pCtx, 0);
  597. return PH7_OK;
  598. }
  599. /* Point to the desired directory */
  600. zPath = ph7_value_to_string(apArg[0], 0);
  601. /* Extract the user */
  602. zGroup = ph7_value_to_string(apArg[1], 0);
  603. /* Perform the requested operation */
  604. rc = pVfs->xChgrp(zPath, zGroup);
  605. /* IO return value */
  606. ph7_result_bool(pCtx, rc == PH7_OK);
  607. return PH7_OK;
  608. }
  609. /*
  610. * int64 disk_free_space(string $directory)
  611. * Returns available space on filesystem or disk partition.
  612. * Parameters
  613. * $directory
  614. * A directory of the filesystem or disk partition.
  615. * Return
  616. * Returns the number of available bytes as a 64-bit integer or FALSE on failure.
  617. */
  618. static int PH7_vfs_disk_free_space(ph7_context *pCtx, int nArg, ph7_value **apArg) {
  619. const char *zPath;
  620. ph7_int64 iSize;
  621. ph7_vfs *pVfs;
  622. if(nArg < 1 || !ph7_value_is_string(apArg[0])) {
  623. /* Missing/Invalid argument,return FALSE */
  624. ph7_result_bool(pCtx, 0);
  625. return PH7_OK;
  626. }
  627. /* Point to the underlying vfs */
  628. pVfs = (ph7_vfs *)ph7_context_user_data(pCtx);
  629. if(pVfs == 0 || pVfs->xFreeSpace == 0) {
  630. /* IO routine not implemented,return NULL */
  631. PH7_VmThrowError(pCtx->pVm, PH7_CTX_WARNING,
  632. "IO routine(%s) not implemented in the underlying VFS",
  633. ph7_function_name(pCtx)
  634. );
  635. ph7_result_bool(pCtx, 0);
  636. return PH7_OK;
  637. }
  638. /* Point to the desired directory */
  639. zPath = ph7_value_to_string(apArg[0], 0);
  640. /* Perform the requested operation */
  641. iSize = pVfs->xFreeSpace(zPath);
  642. /* IO return value */
  643. ph7_result_int64(pCtx, iSize);
  644. return PH7_OK;
  645. }
  646. /*
  647. * int64 disk_total_space(string $directory)
  648. * Returns the total size of a filesystem or disk partition.
  649. * Parameters
  650. * $directory
  651. * A directory of the filesystem or disk partition.
  652. * Return
  653. * Returns the number of available bytes as a 64-bit integer or FALSE on failure.
  654. */
  655. static int PH7_vfs_disk_total_space(ph7_context *pCtx, int nArg, ph7_value **apArg) {
  656. const char *zPath;
  657. ph7_int64 iSize;
  658. ph7_vfs *pVfs;
  659. if(nArg < 1 || !ph7_value_is_string(apArg[0])) {
  660. /* Missing/Invalid argument,return FALSE */
  661. ph7_result_bool(pCtx, 0);
  662. return PH7_OK;
  663. }
  664. /* Point to the underlying vfs */
  665. pVfs = (ph7_vfs *)ph7_context_user_data(pCtx);
  666. if(pVfs == 0 || pVfs->xTotalSpace == 0) {
  667. /* IO routine not implemented,return NULL */
  668. PH7_VmThrowError(pCtx->pVm, PH7_CTX_WARNING,
  669. "IO routine(%s) not implemented in the underlying VFS",
  670. ph7_function_name(pCtx)
  671. );
  672. ph7_result_bool(pCtx, 0);
  673. return PH7_OK;
  674. }
  675. /* Point to the desired directory */
  676. zPath = ph7_value_to_string(apArg[0], 0);
  677. /* Perform the requested operation */
  678. iSize = pVfs->xTotalSpace(zPath);
  679. /* IO return value */
  680. ph7_result_int64(pCtx, iSize);
  681. return PH7_OK;
  682. }
  683. /*
  684. * bool file_exists(string $filename)
  685. * Checks whether a file or directory exists.
  686. * Parameters
  687. * $filename
  688. * Path to the file.
  689. * Return
  690. * TRUE on success or FALSE on failure.
  691. */
  692. static int PH7_vfs_file_exists(ph7_context *pCtx, int nArg, ph7_value **apArg) {
  693. const char *zPath;
  694. ph7_vfs *pVfs;
  695. int rc;
  696. if(nArg < 1 || !ph7_value_is_string(apArg[0])) {
  697. /* Missing/Invalid argument,return FALSE */
  698. ph7_result_bool(pCtx, 0);
  699. return PH7_OK;
  700. }
  701. /* Point to the underlying vfs */
  702. pVfs = (ph7_vfs *)ph7_context_user_data(pCtx);
  703. if(pVfs == 0 || pVfs->xFileExists == 0) {
  704. /* IO routine not implemented,return NULL */
  705. PH7_VmThrowError(pCtx->pVm, PH7_CTX_WARNING,
  706. "IO routine(%s) not implemented in the underlying VFS",
  707. ph7_function_name(pCtx)
  708. );
  709. ph7_result_bool(pCtx, 0);
  710. return PH7_OK;
  711. }
  712. /* Point to the desired directory */
  713. zPath = ph7_value_to_string(apArg[0], 0);
  714. /* Perform the requested operation */
  715. rc = pVfs->xFileExists(zPath);
  716. /* IO return value */
  717. ph7_result_bool(pCtx, rc == PH7_OK);
  718. return PH7_OK;
  719. }
  720. /*
  721. * int64 file_size(string $filename)
  722. * Gets the size for the given file.
  723. * Parameters
  724. * $filename
  725. * Path to the file.
  726. * Return
  727. * File size on success or FALSE on failure.
  728. */
  729. static int PH7_vfs_file_size(ph7_context *pCtx, int nArg, ph7_value **apArg) {
  730. const char *zPath;
  731. ph7_int64 iSize;
  732. ph7_vfs *pVfs;
  733. if(nArg < 1 || !ph7_value_is_string(apArg[0])) {
  734. /* Missing/Invalid argument,return FALSE */
  735. ph7_result_bool(pCtx, 0);
  736. return PH7_OK;
  737. }
  738. /* Point to the underlying vfs */
  739. pVfs = (ph7_vfs *)ph7_context_user_data(pCtx);
  740. if(pVfs == 0 || pVfs->xFileSize == 0) {
  741. /* IO routine not implemented,return NULL */
  742. PH7_VmThrowError(pCtx->pVm, PH7_CTX_WARNING,
  743. "IO routine(%s) not implemented in the underlying VFS",
  744. ph7_function_name(pCtx)
  745. );
  746. ph7_result_bool(pCtx, 0);
  747. return PH7_OK;
  748. }
  749. /* Point to the desired directory */
  750. zPath = ph7_value_to_string(apArg[0], 0);
  751. /* Perform the requested operation */
  752. iSize = pVfs->xFileSize(zPath);
  753. /* IO return value */
  754. ph7_result_int64(pCtx, iSize);
  755. return PH7_OK;
  756. }
  757. /*
  758. * int64 fileatime(string $filename)
  759. * Gets the last access time of the given file.
  760. * Parameters
  761. * $filename
  762. * Path to the file.
  763. * Return
  764. * File atime on success or FALSE on failure.
  765. */
  766. static int PH7_vfs_file_atime(ph7_context *pCtx, int nArg, ph7_value **apArg) {
  767. const char *zPath;
  768. ph7_int64 iTime;
  769. ph7_vfs *pVfs;
  770. if(nArg < 1 || !ph7_value_is_string(apArg[0])) {
  771. /* Missing/Invalid argument,return FALSE */
  772. ph7_result_bool(pCtx, 0);
  773. return PH7_OK;
  774. }
  775. /* Point to the underlying vfs */
  776. pVfs = (ph7_vfs *)ph7_context_user_data(pCtx);
  777. if(pVfs == 0 || pVfs->xFileAtime == 0) {
  778. /* IO routine not implemented,return NULL */
  779. PH7_VmThrowError(pCtx->pVm, PH7_CTX_WARNING,
  780. "IO routine(%s) not implemented in the underlying VFS",
  781. ph7_function_name(pCtx)
  782. );
  783. ph7_result_bool(pCtx, 0);
  784. return PH7_OK;
  785. }
  786. /* Point to the desired directory */
  787. zPath = ph7_value_to_string(apArg[0], 0);
  788. /* Perform the requested operation */
  789. iTime = pVfs->xFileAtime(zPath);
  790. /* IO return value */
  791. ph7_result_int64(pCtx, iTime);
  792. return PH7_OK;
  793. }
  794. /*
  795. * int64 filemtime(string $filename)
  796. * Gets file modification time.
  797. * Parameters
  798. * $filename
  799. * Path to the file.
  800. * Return
  801. * File mtime on success or FALSE on failure.
  802. */
  803. static int PH7_vfs_file_mtime(ph7_context *pCtx, int nArg, ph7_value **apArg) {
  804. const char *zPath;
  805. ph7_int64 iTime;
  806. ph7_vfs *pVfs;
  807. if(nArg < 1 || !ph7_value_is_string(apArg[0])) {
  808. /* Missing/Invalid argument,return FALSE */
  809. ph7_result_bool(pCtx, 0);
  810. return PH7_OK;
  811. }
  812. /* Point to the underlying vfs */
  813. pVfs = (ph7_vfs *)ph7_context_user_data(pCtx);
  814. if(pVfs == 0 || pVfs->xFileMtime == 0) {
  815. /* IO routine not implemented,return NULL */
  816. PH7_VmThrowError(pCtx->pVm, PH7_CTX_WARNING,
  817. "IO routine(%s) not implemented in the underlying VFS",
  818. ph7_function_name(pCtx)
  819. );
  820. ph7_result_bool(pCtx, 0);
  821. return PH7_OK;
  822. }
  823. /* Point to the desired directory */
  824. zPath = ph7_value_to_string(apArg[0], 0);
  825. /* Perform the requested operation */
  826. iTime = pVfs->xFileMtime(zPath);
  827. /* IO return value */
  828. ph7_result_int64(pCtx, iTime);
  829. return PH7_OK;
  830. }
  831. /*
  832. * int64 filectime(string $filename)
  833. * Gets inode change time of file.
  834. * Parameters
  835. * $filename
  836. * Path to the file.
  837. * Return
  838. * File ctime on success or FALSE on failure.
  839. */
  840. static int PH7_vfs_file_ctime(ph7_context *pCtx, int nArg, ph7_value **apArg) {
  841. const char *zPath;
  842. ph7_int64 iTime;
  843. ph7_vfs *pVfs;
  844. if(nArg < 1 || !ph7_value_is_string(apArg[0])) {
  845. /* Missing/Invalid argument,return FALSE */
  846. ph7_result_bool(pCtx, 0);
  847. return PH7_OK;
  848. }
  849. /* Point to the underlying vfs */
  850. pVfs = (ph7_vfs *)ph7_context_user_data(pCtx);
  851. if(pVfs == 0 || pVfs->xFileCtime == 0) {
  852. /* IO routine not implemented,return NULL */
  853. PH7_VmThrowError(pCtx->pVm, PH7_CTX_WARNING,
  854. "IO routine(%s) not implemented in the underlying VFS",
  855. ph7_function_name(pCtx)
  856. );
  857. ph7_result_bool(pCtx, 0);
  858. return PH7_OK;
  859. }
  860. /* Point to the desired directory */
  861. zPath = ph7_value_to_string(apArg[0], 0);
  862. /* Perform the requested operation */
  863. iTime = pVfs->xFileCtime(zPath);
  864. /* IO return value */
  865. ph7_result_int64(pCtx, iTime);
  866. return PH7_OK;
  867. }
  868. /*
  869. * int64 filegroup(string $filename)
  870. * Gets the file group.
  871. * Parameters
  872. * $filename
  873. * Path to the file.
  874. * Return
  875. * The group ID of the file or FALSE on failure.
  876. */
  877. static int PH7_vfs_file_group(ph7_context *pCtx, int nArg, ph7_value **apArg) {
  878. const char *zPath;
  879. ph7_int64 iGroup;
  880. ph7_vfs *pVfs;
  881. if(nArg < 1 || !ph7_value_is_string(apArg[0])) {
  882. /* Missing/Invalid argument,return FALSE */
  883. ph7_result_bool(pCtx, 0);
  884. return PH7_OK;
  885. }
  886. /* Point to the underlying vfs */
  887. pVfs = (ph7_vfs *)ph7_context_user_data(pCtx);
  888. if(pVfs == 0 || pVfs->xFileCtime == 0) {
  889. /* IO routine not implemented,return NULL */
  890. PH7_VmThrowError(pCtx->pVm, PH7_CTX_WARNING,
  891. "IO routine(%s) not implemented in the underlying VFS",
  892. ph7_function_name(pCtx)
  893. );
  894. ph7_result_bool(pCtx, 0);
  895. return PH7_OK;
  896. }
  897. /* Point to the desired directory */
  898. zPath = ph7_value_to_string(apArg[0], 0);
  899. /* Perform the requested operation */
  900. iGroup = pVfs->xFileGroup(zPath);
  901. /* IO return value */
  902. ph7_result_int64(pCtx, iGroup);
  903. return PH7_OK;
  904. }
  905. /*
  906. * int64 fileinode(string $filename)
  907. * Gets the file inode.
  908. * Parameters
  909. * $filename
  910. * Path to the file.
  911. * Return
  912. * The inode number of the file or FALSE on failure.
  913. */
  914. static int PH7_vfs_file_inode(ph7_context *pCtx, int nArg, ph7_value **apArg) {
  915. const char *zPath;
  916. ph7_int64 iInode;
  917. ph7_vfs *pVfs;
  918. if(nArg < 1 || !ph7_value_is_string(apArg[0])) {
  919. /* Missing/Invalid argument,return FALSE */
  920. ph7_result_bool(pCtx, 0);
  921. return PH7_OK;
  922. }
  923. /* Point to the underlying vfs */
  924. pVfs = (ph7_vfs *)ph7_context_user_data(pCtx);
  925. if(pVfs == 0 || pVfs->xFileCtime == 0) {
  926. /* IO routine not implemented,return NULL */
  927. PH7_VmThrowError(pCtx->pVm, PH7_CTX_WARNING,
  928. "IO routine(%s) not implemented in the underlying VFS",
  929. ph7_function_name(pCtx)
  930. );
  931. ph7_result_bool(pCtx, 0);
  932. return PH7_OK;
  933. }
  934. /* Point to the desired directory */
  935. zPath = ph7_value_to_string(apArg[0], 0);
  936. /* Perform the requested operation */
  937. iInode = pVfs->xFileInode(zPath);
  938. /* IO return value */
  939. ph7_result_int64(pCtx, iInode);
  940. return PH7_OK;
  941. }
  942. /*
  943. * int64 fileowner(string $filename)
  944. * Gets the file owner.
  945. * Parameters
  946. * $filename
  947. * Path to the file.
  948. * Return
  949. * The user ID of the owner of the file or FALSE on failure.
  950. */
  951. static int PH7_vfs_file_owner(ph7_context *pCtx, int nArg, ph7_value **apArg) {
  952. const char *zPath;
  953. ph7_int64 iOwner;
  954. ph7_vfs *pVfs;
  955. if(nArg < 1 || !ph7_value_is_string(apArg[0])) {
  956. /* Missing/Invalid argument,return FALSE */
  957. ph7_result_bool(pCtx, 0);
  958. return PH7_OK;
  959. }
  960. /* Point to the underlying vfs */
  961. pVfs = (ph7_vfs *)ph7_context_user_data(pCtx);
  962. if(pVfs == 0 || pVfs->xFileCtime == 0) {
  963. /* IO routine not implemented,return NULL */
  964. PH7_VmThrowError(pCtx->pVm, PH7_CTX_WARNING,
  965. "IO routine(%s) not implemented in the underlying VFS",
  966. ph7_function_name(pCtx)
  967. );
  968. ph7_result_bool(pCtx, 0);
  969. return PH7_OK;
  970. }
  971. /* Point to the desired directory */
  972. zPath = ph7_value_to_string(apArg[0], 0);
  973. /* Perform the requested operation */
  974. iOwner = pVfs->xFileOwner(zPath);
  975. /* IO return value */
  976. ph7_result_int64(pCtx, iOwner);
  977. return PH7_OK;
  978. }
  979. /*
  980. * bool is_file(string $filename)
  981. * Tells whether the filename is a regular file.
  982. * Parameters
  983. * $filename
  984. * Path to the file.
  985. * Return
  986. * TRUE on success or FALSE on failure.
  987. */
  988. static int PH7_vfs_is_file(ph7_context *pCtx, int nArg, ph7_value **apArg) {
  989. const char *zPath;
  990. ph7_vfs *pVfs;
  991. int rc;
  992. if(nArg < 1 || !ph7_value_is_string(apArg[0])) {
  993. /* Missing/Invalid argument,return FALSE */
  994. ph7_result_bool(pCtx, 0);
  995. return PH7_OK;
  996. }
  997. /* Point to the underlying vfs */
  998. pVfs = (ph7_vfs *)ph7_context_user_data(pCtx);
  999. if(pVfs == 0 || pVfs->xIsFile == 0) {
  1000. /* IO routine not implemented,return NULL */
  1001. PH7_VmThrowError(pCtx->pVm, PH7_CTX_WARNING,
  1002. "IO routine(%s) not implemented in the underlying VFS",
  1003. ph7_function_name(pCtx)
  1004. );
  1005. ph7_result_bool(pCtx, 0);
  1006. return PH7_OK;
  1007. }
  1008. /* Point to the desired directory */
  1009. zPath = ph7_value_to_string(apArg[0], 0);
  1010. /* Perform the requested operation */
  1011. rc = pVfs->xIsFile(zPath);
  1012. /* IO return value */
  1013. ph7_result_bool(pCtx, rc == PH7_OK);
  1014. return PH7_OK;
  1015. }
  1016. /*
  1017. * bool is_link(string $filename)
  1018. * Tells whether the filename is a symbolic link.
  1019. * Parameters
  1020. * $filename
  1021. * Path to the file.
  1022. * Return
  1023. * TRUE on success or FALSE on failure.
  1024. */
  1025. static int PH7_vfs_is_link(ph7_context *pCtx, int nArg, ph7_value **apArg) {
  1026. const char *zPath;
  1027. ph7_vfs *pVfs;
  1028. int rc;
  1029. if(nArg < 1 || !ph7_value_is_string(apArg[0])) {
  1030. /* Missing/Invalid argument,return FALSE */
  1031. ph7_result_bool(pCtx, 0);
  1032. return PH7_OK;
  1033. }
  1034. /* Point to the underlying vfs */
  1035. pVfs = (ph7_vfs *)ph7_context_user_data(pCtx);
  1036. if(pVfs == 0 || pVfs->xIsLink == 0) {
  1037. /* IO routine not implemented,return NULL */
  1038. PH7_VmThrowError(pCtx->pVm, PH7_CTX_WARNING,
  1039. "IO routine(%s) not implemented in the underlying VFS",
  1040. ph7_function_name(pCtx)
  1041. );
  1042. ph7_result_bool(pCtx, 0);
  1043. return PH7_OK;
  1044. }
  1045. /* Point to the desired directory */
  1046. zPath = ph7_value_to_string(apArg[0], 0);
  1047. /* Perform the requested operation */
  1048. rc = pVfs->xIsLink(zPath);
  1049. /* IO return value */
  1050. ph7_result_bool(pCtx, rc == PH7_OK);
  1051. return PH7_OK;
  1052. }
  1053. /*
  1054. * bool is_readable(string $filename)
  1055. * Tells whether a file exists and is readable.
  1056. * Parameters
  1057. * $filename
  1058. * Path to the file.
  1059. * Return
  1060. * TRUE on success or FALSE on failure.
  1061. */
  1062. static int PH7_vfs_is_readable(ph7_context *pCtx, int nArg, ph7_value **apArg) {
  1063. const char *zPath;
  1064. ph7_vfs *pVfs;
  1065. int rc;
  1066. if(nArg < 1 || !ph7_value_is_string(apArg[0])) {
  1067. /* Missing/Invalid argument,return FALSE */
  1068. ph7_result_bool(pCtx, 0);
  1069. return PH7_OK;
  1070. }
  1071. /* Point to the underlying vfs */
  1072. pVfs = (ph7_vfs *)ph7_context_user_data(pCtx);
  1073. if(pVfs == 0 || pVfs->xReadable == 0) {
  1074. /* IO routine not implemented,return NULL */
  1075. PH7_VmThrowError(pCtx->pVm, PH7_CTX_WARNING,
  1076. "IO routine(%s) not implemented in the underlying VFS",
  1077. ph7_function_name(pCtx)
  1078. );
  1079. ph7_result_bool(pCtx, 0);
  1080. return PH7_OK;
  1081. }
  1082. /* Point to the desired directory */
  1083. zPath = ph7_value_to_string(apArg[0], 0);
  1084. /* Perform the requested operation */
  1085. rc = pVfs->xReadable(zPath);
  1086. /* IO return value */
  1087. ph7_result_bool(pCtx, rc == PH7_OK);
  1088. return PH7_OK;
  1089. }
  1090. /*
  1091. * bool is_writable(string $filename)
  1092. * Tells whether the filename is writable.
  1093. * Parameters
  1094. * $filename
  1095. * Path to the file.
  1096. * Return
  1097. * TRUE on success or FALSE on failure.
  1098. */
  1099. static int PH7_vfs_is_writable(ph7_context *pCtx, int nArg, ph7_value **apArg) {
  1100. const char *zPath;
  1101. ph7_vfs *pVfs;
  1102. int rc;
  1103. if(nArg < 1 || !ph7_value_is_string(apArg[0])) {
  1104. /* Missing/Invalid argument,return FALSE */
  1105. ph7_result_bool(pCtx, 0);
  1106. return PH7_OK;
  1107. }
  1108. /* Point to the underlying vfs */
  1109. pVfs = (ph7_vfs *)ph7_context_user_data(pCtx);
  1110. if(pVfs == 0 || pVfs->xWritable == 0) {
  1111. /* IO routine not implemented,return NULL */
  1112. PH7_VmThrowError(pCtx->pVm, PH7_CTX_WARNING,
  1113. "IO routine(%s) not implemented in the underlying VFS",
  1114. ph7_function_name(pCtx)
  1115. );
  1116. ph7_result_bool(pCtx, 0);
  1117. return PH7_OK;
  1118. }
  1119. /* Point to the desired directory */
  1120. zPath = ph7_value_to_string(apArg[0], 0);
  1121. /* Perform the requested operation */
  1122. rc = pVfs->xWritable(zPath);
  1123. /* IO return value */
  1124. ph7_result_bool(pCtx, rc == PH7_OK);
  1125. return PH7_OK;
  1126. }
  1127. /*
  1128. * bool is_executable(string $filename)
  1129. * Tells whether the filename is executable.
  1130. * Parameters
  1131. * $filename
  1132. * Path to the file.
  1133. * Return
  1134. * TRUE on success or FALSE on failure.
  1135. */
  1136. static int PH7_vfs_is_executable(ph7_context *pCtx, int nArg, ph7_value **apArg) {
  1137. const char *zPath;
  1138. ph7_vfs *pVfs;
  1139. int rc;
  1140. if(nArg < 1 || !ph7_value_is_string(apArg[0])) {
  1141. /* Missing/Invalid argument,return FALSE */
  1142. ph7_result_bool(pCtx, 0);
  1143. return PH7_OK;
  1144. }
  1145. /* Point to the underlying vfs */
  1146. pVfs = (ph7_vfs *)ph7_context_user_data(pCtx);
  1147. if(pVfs == 0 || pVfs->xExecutable == 0) {
  1148. /* IO routine not implemented,return NULL */
  1149. PH7_VmThrowError(pCtx->pVm, PH7_CTX_WARNING,
  1150. "IO routine(%s) not implemented in the underlying VFS",
  1151. ph7_function_name(pCtx)
  1152. );
  1153. ph7_result_bool(pCtx, 0);
  1154. return PH7_OK;
  1155. }
  1156. /* Point to the desired directory */
  1157. zPath = ph7_value_to_string(apArg[0], 0);
  1158. /* Perform the requested operation */
  1159. rc = pVfs->xExecutable(zPath);
  1160. /* IO return value */
  1161. ph7_result_bool(pCtx, rc == PH7_OK);
  1162. return PH7_OK;
  1163. }
  1164. /*
  1165. * string filetype(string $filename)
  1166. * Gets file type.
  1167. * Parameters
  1168. * $filename
  1169. * Path to the file.
  1170. * Return
  1171. * The type of the file. Possible values are fifo, char, dir, block, link
  1172. * file, socket and unknown.
  1173. */
  1174. static int PH7_vfs_filetype(ph7_context *pCtx, int nArg, ph7_value **apArg) {
  1175. const char *zPath;
  1176. ph7_vfs *pVfs;
  1177. if(nArg < 1 || !ph7_value_is_string(apArg[0])) {
  1178. /* Missing/Invalid argument,return 'unknown' */
  1179. ph7_result_string(pCtx, "unknown", sizeof("unknown") - 1);
  1180. return PH7_OK;
  1181. }
  1182. /* Point to the underlying vfs */
  1183. pVfs = (ph7_vfs *)ph7_context_user_data(pCtx);
  1184. if(pVfs == 0 || pVfs->xFiletype == 0) {
  1185. /* IO routine not implemented,return NULL */
  1186. PH7_VmThrowError(pCtx->pVm, PH7_CTX_WARNING,
  1187. "IO routine(%s) not implemented in the underlying VFS",
  1188. ph7_function_name(pCtx)
  1189. );
  1190. ph7_result_bool(pCtx, 0);
  1191. return PH7_OK;
  1192. }
  1193. /* Point to the desired directory */
  1194. zPath = ph7_value_to_string(apArg[0], 0);
  1195. /* Set the empty string as the default return value */
  1196. ph7_result_string(pCtx, "", 0);
  1197. /* Perform the requested operation */
  1198. pVfs->xFiletype(zPath, pCtx);
  1199. return PH7_OK;
  1200. }
  1201. /*
  1202. * array stat(string $filename)
  1203. * Gives information about a file.
  1204. * Parameters
  1205. * $filename
  1206. * Path to the file.
  1207. * Return
  1208. * An associative array on success holding the following entries on success
  1209. * 0 dev device number
  1210. * 1 ino inode number (zero on windows)
  1211. * 2 mode inode protection mode
  1212. * 3 nlink number of links
  1213. * 4 uid userid of owner (zero on windows)
  1214. * 5 gid groupid of owner (zero on windows)
  1215. * 6 rdev device type, if inode device
  1216. * 7 size size in bytes
  1217. * 8 atime time of last access (Unix timestamp)
  1218. * 9 mtime time of last modification (Unix timestamp)
  1219. * 10 ctime time of last inode change (Unix timestamp)
  1220. * 11 blksize blocksize of filesystem IO (zero on windows)
  1221. * 12 blocks number of 512-byte blocks allocated.
  1222. * Note:
  1223. * FALSE is returned on failure.
  1224. */
  1225. static int PH7_vfs_stat(ph7_context *pCtx, int nArg, ph7_value **apArg) {
  1226. ph7_value *pArray, *pValue;
  1227. const char *zPath;
  1228. ph7_vfs *pVfs;
  1229. int rc;
  1230. if(nArg < 1 || !ph7_value_is_string(apArg[0])) {
  1231. /* Missing/Invalid argument,return FALSE */
  1232. ph7_result_bool(pCtx, 0);
  1233. return PH7_OK;
  1234. }
  1235. /* Point to the underlying vfs */
  1236. pVfs = (ph7_vfs *)ph7_context_user_data(pCtx);
  1237. if(pVfs == 0 || pVfs->xStat == 0) {
  1238. /* IO routine not implemented,return NULL */
  1239. PH7_VmThrowError(pCtx->pVm, PH7_CTX_WARNING,
  1240. "IO routine(%s) not implemented in the underlying VFS",
  1241. ph7_function_name(pCtx)
  1242. );
  1243. ph7_result_bool(pCtx, 0);
  1244. return PH7_OK;
  1245. }
  1246. /* Create the array and the working value */
  1247. pArray = ph7_context_new_array(pCtx);
  1248. pValue = ph7_context_new_scalar(pCtx);
  1249. if(pArray == 0 || pValue == 0) {
  1250. PH7_VmMemoryError(pCtx->pVm);
  1251. }
  1252. /* Extract the file path */
  1253. zPath = ph7_value_to_string(apArg[0], 0);
  1254. /* Perform the requested operation */
  1255. rc = pVfs->xStat(zPath, pArray, pValue);
  1256. if(rc != PH7_OK) {
  1257. /* IO error,return FALSE */
  1258. ph7_result_bool(pCtx, 0);
  1259. } else {
  1260. /* Return the associative array */
  1261. ph7_result_value(pCtx, pArray);
  1262. }
  1263. /* Don't worry about freeing memory here,everything will be released
  1264. * automatically as soon we return from this function. */
  1265. return PH7_OK;
  1266. }
  1267. /*
  1268. * array lstat(string $filename)
  1269. * Gives information about a file or symbolic link.
  1270. * Parameters
  1271. * $filename
  1272. * Path to the file.
  1273. * Return
  1274. * An associative array on success holding the following entries on success
  1275. * 0 dev device number
  1276. * 1 ino inode number (zero on windows)
  1277. * 2 mode inode protection mode
  1278. * 3 nlink number of links
  1279. * 4 uid userid of owner (zero on windows)
  1280. * 5 gid groupid of owner (zero on windows)
  1281. * 6 rdev device type, if inode device
  1282. * 7 size size in bytes
  1283. * 8 atime time of last access (Unix timestamp)
  1284. * 9 mtime time of last modification (Unix timestamp)
  1285. * 10 ctime time of last inode change (Unix timestamp)
  1286. * 11 blksize blocksize of filesystem IO (zero on windows)
  1287. * 12 blocks number of 512-byte blocks allocated.
  1288. * Note:
  1289. * FALSE is returned on failure.
  1290. */
  1291. static int PH7_vfs_lstat(ph7_context *pCtx, int nArg, ph7_value **apArg) {
  1292. ph7_value *pArray, *pValue;
  1293. const char *zPath;
  1294. ph7_vfs *pVfs;
  1295. int rc;
  1296. if(nArg < 1 || !ph7_value_is_string(apArg[0])) {
  1297. /* Missing/Invalid argument,return FALSE */
  1298. ph7_result_bool(pCtx, 0);
  1299. return PH7_OK;
  1300. }
  1301. /* Point to the underlying vfs */
  1302. pVfs = (ph7_vfs *)ph7_context_user_data(pCtx);
  1303. if(pVfs == 0 || pVfs->xlStat == 0) {
  1304. /* IO routine not implemented,return NULL */
  1305. PH7_VmThrowError(pCtx->pVm, PH7_CTX_WARNING,
  1306. "IO routine(%s) not implemented in the underlying VFS",
  1307. ph7_function_name(pCtx)
  1308. );
  1309. ph7_result_bool(pCtx, 0);
  1310. return PH7_OK;
  1311. }
  1312. /* Create the array and the working value */
  1313. pArray = ph7_context_new_array(pCtx);
  1314. pValue = ph7_context_new_scalar(pCtx);
  1315. if(pArray == 0 || pValue == 0) {
  1316. PH7_VmMemoryError(pCtx->pVm);
  1317. }
  1318. /* Extract the file path */
  1319. zPath = ph7_value_to_string(apArg[0], 0);
  1320. /* Perform the requested operation */
  1321. rc = pVfs->xlStat(zPath, pArray, pValue);
  1322. if(rc != PH7_OK) {
  1323. /* IO error,return FALSE */
  1324. ph7_result_bool(pCtx, 0);
  1325. } else {
  1326. /* Return the associative array */
  1327. ph7_result_value(pCtx, pArray);
  1328. }
  1329. /* Don't worry about freeing memory here,everything will be released
  1330. * automatically as soon we return from this function. */
  1331. return PH7_OK;
  1332. }
  1333. /*
  1334. * string getenv(string $varname)
  1335. * Gets the value of an environment variable.
  1336. * Parameters
  1337. * $varname
  1338. * The variable name.
  1339. * Return
  1340. * Returns the value of the environment variable varname, or FALSE if the environment
  1341. * variable varname does not exist.
  1342. */
  1343. static int PH7_vfs_getenv(ph7_context *pCtx, int nArg, ph7_value **apArg) {
  1344. const char *zEnv;
  1345. ph7_vfs *pVfs;
  1346. int iLen;
  1347. if(nArg < 1 || !ph7_value_is_string(apArg[0])) {
  1348. /* Missing/Invalid argument,return FALSE */
  1349. ph7_result_bool(pCtx, 0);
  1350. return PH7_OK;
  1351. }
  1352. /* Point to the underlying vfs */
  1353. pVfs = (ph7_vfs *)ph7_context_user_data(pCtx);
  1354. if(pVfs == 0 || pVfs->xGetenv == 0) {
  1355. /* IO routine not implemented,return NULL */
  1356. PH7_VmThrowError(pCtx->pVm, PH7_CTX_WARNING,
  1357. "IO routine(%s) not implemented in the underlying VFS",
  1358. ph7_function_name(pCtx)
  1359. );
  1360. ph7_result_bool(pCtx, 0);
  1361. return PH7_OK;
  1362. }
  1363. /* Extract the environment variable */
  1364. zEnv = ph7_value_to_string(apArg[0], &iLen);
  1365. /* Set a boolean FALSE as the default return value */
  1366. ph7_result_bool(pCtx, 0);
  1367. if(iLen < 1) {
  1368. /* Empty string */
  1369. return PH7_OK;
  1370. }
  1371. /* Perform the requested operation */
  1372. pVfs->xGetenv(zEnv, pCtx);
  1373. return PH7_OK;
  1374. }
  1375. /*
  1376. * bool putenv(string $settings)
  1377. * Set the value of an environment variable.
  1378. * Parameters
  1379. * $setting
  1380. * The setting, like "FOO=BAR"
  1381. * Return
  1382. * TRUE on success or FALSE on failure.
  1383. */
  1384. static int PH7_vfs_putenv(ph7_context *pCtx, int nArg, ph7_value **apArg) {
  1385. const char *zName, *zValue;
  1386. char *zSettings, *zEnd;
  1387. ph7_vfs *pVfs;
  1388. int iLen, rc;
  1389. if(nArg < 1 || !ph7_value_is_string(apArg[0])) {
  1390. /* Missing/Invalid argument,return FALSE */
  1391. ph7_result_bool(pCtx, 0);
  1392. return PH7_OK;
  1393. }
  1394. /* Extract the setting variable */
  1395. zSettings = (char *)ph7_value_to_string(apArg[0], &iLen);
  1396. if(iLen < 1) {
  1397. /* Empty string,return FALSE */
  1398. ph7_result_bool(pCtx, 0);
  1399. return PH7_OK;
  1400. }
  1401. /* Parse the setting */
  1402. zEnd = &zSettings[iLen];
  1403. zValue = 0;
  1404. zName = zSettings;
  1405. while(zSettings < zEnd) {
  1406. if(zSettings[0] == '=') {
  1407. /* Null terminate the name */
  1408. zSettings[0] = 0;
  1409. zValue = &zSettings[1];
  1410. break;
  1411. }
  1412. zSettings++;
  1413. }
  1414. /* Install the environment variable in the $_Env array */
  1415. if(zValue == 0 || zName[0] == 0 || zValue >= zEnd || zName >= zValue) {
  1416. /* Invalid settings,retun FALSE */
  1417. ph7_result_bool(pCtx, 0);
  1418. if(zSettings < zEnd) {
  1419. zSettings[0] = '=';
  1420. }
  1421. return PH7_OK;
  1422. }
  1423. ph7_vm_config(pCtx->pVm, PH7_VM_CONFIG_ENV_ATTR, zName, zValue, (int)(zEnd - zValue));
  1424. /* Point to the underlying vfs */
  1425. pVfs = (ph7_vfs *)ph7_context_user_data(pCtx);
  1426. if(pVfs == 0 || pVfs->xSetenv == 0) {
  1427. /* IO routine not implemented,return NULL */
  1428. PH7_VmThrowError(pCtx->pVm, PH7_CTX_WARNING,
  1429. "IO routine(%s) not implemented in the underlying VFS",
  1430. ph7_function_name(pCtx)
  1431. );
  1432. ph7_result_bool(pCtx, 0);
  1433. zSettings[0] = '=';
  1434. return PH7_OK;
  1435. }
  1436. /* Perform the requested operation */
  1437. rc = pVfs->xSetenv(zName, zValue);
  1438. ph7_result_bool(pCtx, rc == PH7_OK);
  1439. zSettings[0] = '=';
  1440. return PH7_OK;
  1441. }
  1442. /*
  1443. * bool touch(string $filename[,int64 $time = time()[,int64 $atime]])
  1444. * Sets access and modification time of file.
  1445. * Note: On windows
  1446. * If the file does not exists,it will not be created.
  1447. * Parameters
  1448. * $filename
  1449. * The name of the file being touched.
  1450. * $time
  1451. * The touch time. If time is not supplied, the current system time is used.
  1452. * $atime
  1453. * If present, the access time of the given filename is set to the value of atime.
  1454. * Otherwise, it is set to the value passed to the time parameter. If neither are
  1455. * present, the current system time is used.
  1456. * Return
  1457. * TRUE on success or FALSE on failure.
  1458. */
  1459. static int PH7_vfs_touch(ph7_context *pCtx, int nArg, ph7_value **apArg) {
  1460. ph7_int64 nTime, nAccess;
  1461. const char *zFile;
  1462. ph7_vfs *pVfs;
  1463. int rc;
  1464. if(nArg < 1 || !ph7_value_is_string(apArg[0])) {
  1465. /* Missing/Invalid argument,return FALSE */
  1466. ph7_result_bool(pCtx, 0);
  1467. return PH7_OK;
  1468. }
  1469. /* Point to the underlying vfs */
  1470. pVfs = (ph7_vfs *)ph7_context_user_data(pCtx);
  1471. if(pVfs == 0 || pVfs->xTouch == 0) {
  1472. /* IO routine not implemented,return NULL */
  1473. PH7_VmThrowError(pCtx->pVm, PH7_CTX_WARNING,
  1474. "IO routine(%s) not implemented in the underlying VFS",
  1475. ph7_function_name(pCtx)
  1476. );
  1477. ph7_result_bool(pCtx, 0);
  1478. return PH7_OK;
  1479. }
  1480. /* Perform the requested operation */
  1481. nTime = nAccess = -1;
  1482. zFile = ph7_value_to_string(apArg[0], 0);
  1483. if(nArg > 1) {
  1484. nTime = ph7_value_to_int64(apArg[1]);
  1485. if(nArg > 2) {
  1486. nAccess = ph7_value_to_int64(apArg[1]);
  1487. } else {
  1488. nAccess = nTime;
  1489. }
  1490. }
  1491. rc = pVfs->xTouch(zFile, nTime, nAccess);
  1492. /* IO result */
  1493. ph7_result_bool(pCtx, rc == PH7_OK);
  1494. return PH7_OK;
  1495. }
  1496. /*
  1497. * Path processing functions that do not need access to the VFS layer
  1498. * Authors:
  1499. * Symisc Systems,devel@symisc.net.
  1500. * Copyright (C) Symisc Systems,https://ph7.symisc.net
  1501. * Status:
  1502. * Stable.
  1503. */
  1504. /*
  1505. * string dirname(string $path)
  1506. * Returns parent directory's path.
  1507. * Parameters
  1508. * $path
  1509. * Target path.
  1510. * On Windows, both slash (/) and backslash (\) are used as directory separator character.
  1511. * In other environments, it is the forward slash (/).
  1512. * Return
  1513. * The path of the parent directory. If there are no slashes in path, a dot ('.')
  1514. * is returned, indicating the current directory.
  1515. */
  1516. static int PH7_builtin_dirname(ph7_context *pCtx, int nArg, ph7_value **apArg) {
  1517. const char *zPath, *zDir;
  1518. int iLen, iDirlen;
  1519. if(nArg < 1 || !ph7_value_is_string(apArg[0])) {
  1520. /* Missing/Invalid arguments,return the empty string */
  1521. ph7_result_string(pCtx, "", 0);
  1522. return PH7_OK;
  1523. }
  1524. /* Point to the target path */
  1525. zPath = ph7_value_to_string(apArg[0], &iLen);
  1526. if(iLen < 1) {
  1527. /* Return "." */
  1528. ph7_result_string(pCtx, ".", sizeof(char));
  1529. return PH7_OK;
  1530. }
  1531. /* Perform the requested operation */
  1532. zDir = PH7_ExtractDirName(zPath, iLen, &iDirlen);
  1533. /* Return directory name */
  1534. ph7_result_string(pCtx, zDir, iDirlen);
  1535. return PH7_OK;
  1536. }
  1537. /*
  1538. * string basename(string $path[, string $suffix ])
  1539. * Returns trailing name component of path.
  1540. * Parameters
  1541. * $path
  1542. * Target path.
  1543. * On Windows, both slash (/) and backslash (\) are used as directory separator character.
  1544. * In other environments, it is the forward slash (/).
  1545. * $suffix
  1546. * If the name component ends in suffix this will also be cut off.
  1547. * Return
  1548. * The base name of the given path.
  1549. */
  1550. static int PH7_builtin_basename(ph7_context *pCtx, int nArg, ph7_value **apArg) {
  1551. const char *zPath, *zBase, *zEnd;
  1552. int c, d, iLen;
  1553. if(nArg < 1 || !ph7_value_is_string(apArg[0])) {
  1554. /* Missing/Invalid argument,return the empty string */
  1555. ph7_result_string(pCtx, "", 0);
  1556. return PH7_OK;
  1557. }
  1558. c = d = '/';
  1559. #ifdef __WINNT__
  1560. d = '\\';
  1561. #endif
  1562. /* Point to the target path */
  1563. zPath = ph7_value_to_string(apArg[0], &iLen);
  1564. if(iLen < 1) {
  1565. /* Empty string */
  1566. ph7_result_string(pCtx, "", 0);
  1567. return PH7_OK;
  1568. }
  1569. /* Perform the requested operation */
  1570. zEnd = &zPath[iLen - 1];
  1571. /* Ignore trailing '/' */
  1572. while(zEnd > zPath && ((int)zEnd[0] == c || (int)zEnd[0] == d)) {
  1573. zEnd--;
  1574. }
  1575. iLen = (int)(&zEnd[1] - zPath);
  1576. while(zEnd > zPath && ((int)zEnd[0] != c && (int)zEnd[0] != d)) {
  1577. zEnd--;
  1578. }
  1579. zBase = (zEnd > zPath) ? &zEnd[1] : zPath;
  1580. zEnd = &zPath[iLen];
  1581. if(nArg > 1 && ph7_value_is_string(apArg[1])) {
  1582. const char *zSuffix;
  1583. int nSuffix;
  1584. /* Strip suffix */
  1585. zSuffix = ph7_value_to_string(apArg[1], &nSuffix);
  1586. if(nSuffix > 0 && nSuffix < iLen && SyMemcmp(&zEnd[-nSuffix], zSuffix, nSuffix) == 0) {
  1587. zEnd -= nSuffix;
  1588. }
  1589. }
  1590. /* Store the basename */
  1591. ph7_result_string(pCtx, zBase, (int)(zEnd - zBase));
  1592. return PH7_OK;
  1593. }
  1594. /*
  1595. * value pathinfo(string $path [,int $options = PATHINFO_DIRNAME | PATHINFO_BASENAME | PATHINFO_EXTENSION | PATHINFO_FILENAME ])
  1596. * Returns information about a file path.
  1597. * Parameter
  1598. * $path
  1599. * The path to be parsed.
  1600. * $options
  1601. * If present, specifies a specific element to be returned; one of
  1602. * PATHINFO_DIRNAME, PATHINFO_BASENAME, PATHINFO_EXTENSION or PATHINFO_FILENAME.
  1603. * Return
  1604. * If the options parameter is not passed, an associative array containing the following
  1605. * elements is returned: dirname, basename, extension (if any), and filename.
  1606. * If options is present, returns a string containing the requested element.
  1607. */
  1608. typedef struct path_info path_info;
  1609. struct path_info {
  1610. SyString sDir; /* Directory [i.e: /var/www] */
  1611. SyString sBasename; /* Basename [i.e httpd.conf] */
  1612. SyString sExtension; /* File extension [i.e xml,pdf..] */
  1613. SyString sFilename; /* Filename */
  1614. };
  1615. /*
  1616. * Extract path fields.
  1617. */
  1618. static sxi32 ExtractPathInfo(const char *zPath, int nByte, path_info *pOut) {
  1619. const char *zPtr, *zEnd = &zPath[nByte - 1];
  1620. SyString *pCur;
  1621. int c, d;
  1622. c = d = '/';
  1623. #ifdef __WINNT__
  1624. d = '\\';
  1625. #endif
  1626. /* Zero the structure */
  1627. SyZero(pOut, sizeof(path_info));
  1628. /* Handle special case */
  1629. if(nByte == sizeof(char) && ((int)zPath[0] == c || (int)zPath[0] == d)) {
  1630. #ifdef __WINNT__
  1631. SyStringInitFromBuf(&pOut->sDir, "\\", sizeof(char));
  1632. #else
  1633. SyStringInitFromBuf(&pOut->sDir, "/", sizeof(char));
  1634. #endif
  1635. return SXRET_OK;
  1636. }
  1637. /* Extract the basename */
  1638. while(zEnd > zPath && ((int)zEnd[0] != c && (int)zEnd[0] != d)) {
  1639. zEnd--;
  1640. }
  1641. zPtr = (zEnd > zPath) ? &zEnd[1] : zPath;
  1642. zEnd = &zPath[nByte];
  1643. /* dirname */
  1644. pCur = &pOut->sDir;
  1645. SyStringInitFromBuf(pCur, zPath, zPtr - zPath);
  1646. if(pCur->nByte > 1) {
  1647. SyStringTrimTrailingChar(pCur, '/');
  1648. #ifdef __WINNT__
  1649. SyStringTrimTrailingChar(pCur, '\\');
  1650. #endif
  1651. } else if((int)zPath[0] == c || (int)zPath[0] == d) {
  1652. #ifdef __WINNT__
  1653. SyStringInitFromBuf(&pOut->sDir, "\\", sizeof(char));
  1654. #else
  1655. SyStringInitFromBuf(&pOut->sDir, "/", sizeof(char));
  1656. #endif
  1657. }
  1658. /* basename/filename */
  1659. pCur = &pOut->sBasename;
  1660. SyStringInitFromBuf(pCur, zPtr, zEnd - zPtr);
  1661. SyStringTrimLeadingChar(pCur, '/');
  1662. #ifdef __WINNT__
  1663. SyStringTrimLeadingChar(pCur, '\\');
  1664. #endif
  1665. SyStringDupPtr(&pOut->sFilename, pCur);
  1666. if(pCur->nByte > 0) {
  1667. /* extension */
  1668. zEnd--;
  1669. while(zEnd > pCur->zString /*basename*/ && zEnd[0] != '.') {
  1670. zEnd--;
  1671. }
  1672. if(zEnd > pCur->zString) {
  1673. zEnd++; /* Jump leading dot */
  1674. SyStringInitFromBuf(&pOut->sExtension, zEnd, &zPath[nByte] - zEnd);
  1675. /* Fix filename */
  1676. pCur = &pOut->sFilename;
  1677. if(pCur->nByte > SyStringLength(&pOut->sExtension)) {
  1678. pCur->nByte -= 1 + SyStringLength(&pOut->sExtension);
  1679. }
  1680. }
  1681. }
  1682. return SXRET_OK;
  1683. }
  1684. /*
  1685. * value pathinfo(string $path [,int $options = PATHINFO_DIRNAME | PATHINFO_BASENAME | PATHINFO_EXTENSION | PATHINFO_FILENAME ])
  1686. * See block comment above.
  1687. */
  1688. static int PH7_builtin_pathinfo(ph7_context *pCtx, int nArg, ph7_value **apArg) {
  1689. const char *zPath;
  1690. path_info sInfo;
  1691. SyString *pComp;
  1692. int iLen;
  1693. if(nArg < 1 || !ph7_value_is_string(apArg[0])) {
  1694. /* Missing/Invalid argument,return the empty string */
  1695. ph7_result_string(pCtx, "", 0);
  1696. return PH7_OK;
  1697. }
  1698. /* Point to the target path */
  1699. zPath = ph7_value_to_string(apArg[0], &iLen);
  1700. if(iLen < 1) {
  1701. /* Empty string */
  1702. ph7_result_string(pCtx, "", 0);
  1703. return PH7_OK;
  1704. }
  1705. /* Extract path info */
  1706. ExtractPathInfo(zPath, iLen, &sInfo);
  1707. if(nArg > 1 && ph7_value_is_int(apArg[1])) {
  1708. /* Return path component */
  1709. int nComp = ph7_value_to_int(apArg[1]);
  1710. switch(nComp) {
  1711. case 1: /* PATHINFO_DIRNAME */
  1712. pComp = &sInfo.sDir;
  1713. if(pComp->nByte > 0) {
  1714. ph7_result_string(pCtx, pComp->zString, (int)pComp->nByte);
  1715. } else {
  1716. /* Expand the empty string */
  1717. ph7_result_string(pCtx, "", 0);
  1718. }
  1719. break;
  1720. case 2: /*PATHINFO_BASENAME*/
  1721. pComp = &sInfo.sBasename;
  1722. if(pComp->nByte > 0) {
  1723. ph7_result_string(pCtx, pComp->zString, (int)pComp->nByte);
  1724. } else {
  1725. /* Expand the empty string */
  1726. ph7_result_string(pCtx, "", 0);
  1727. }
  1728. break;
  1729. case 3: /*PATHINFO_EXTENSION*/
  1730. pComp = &sInfo.sExtension;
  1731. if(pComp->nByte > 0) {
  1732. ph7_result_string(pCtx, pComp->zString, (int)pComp->nByte);
  1733. } else {
  1734. /* Expand the empty string */
  1735. ph7_result_string(pCtx, "", 0);
  1736. }
  1737. break;
  1738. case 4: /*PATHINFO_FILENAME*/
  1739. pComp = &sInfo.sFilename;
  1740. if(pComp->nByte > 0) {
  1741. ph7_result_string(pCtx, pComp->zString, (int)pComp->nByte);
  1742. } else {
  1743. /* Expand the empty string */
  1744. ph7_result_string(pCtx, "", 0);
  1745. }
  1746. break;
  1747. default:
  1748. /* Expand the empty string */
  1749. ph7_result_string(pCtx, "", 0);
  1750. break;
  1751. }
  1752. } else {
  1753. /* Return an associative array */
  1754. ph7_value *pArray, *pValue;
  1755. pArray = ph7_context_new_array(pCtx);
  1756. pValue = ph7_context_new_scalar(pCtx);
  1757. if(pArray == 0 || pValue == 0) {
  1758. /* Out of mem,return NULL */
  1759. ph7_result_bool(pCtx, 0);
  1760. return PH7_OK;
  1761. }
  1762. /* dirname */
  1763. pComp = &sInfo.sDir;
  1764. if(pComp->nByte > 0) {
  1765. ph7_value_string(pValue, pComp->zString, (int)pComp->nByte);
  1766. /* Perform the insertion */
  1767. ph7_array_add_strkey_elem(pArray, "dirname", pValue); /* Will make it's own copy */
  1768. }
  1769. /* Reset the string cursor */
  1770. ph7_value_reset_string_cursor(pValue);
  1771. /* basername */
  1772. pComp = &sInfo.sBasename;
  1773. if(pComp->nByte > 0) {
  1774. ph7_value_string(pValue, pComp->zString, (int)pComp->nByte);
  1775. /* Perform the insertion */
  1776. ph7_array_add_strkey_elem(pArray, "basename", pValue); /* Will make it's own copy */
  1777. }
  1778. /* Reset the string cursor */
  1779. ph7_value_reset_string_cursor(pValue);
  1780. /* extension */
  1781. pComp = &sInfo.sExtension;
  1782. if(pComp->nByte > 0) {
  1783. ph7_value_string(pValue, pComp->zString, (int)pComp->nByte);
  1784. /* Perform the insertion */
  1785. ph7_array_add_strkey_elem(pArray, "extension", pValue); /* Will make it's own copy */
  1786. }
  1787. /* Reset the string cursor */
  1788. ph7_value_reset_string_cursor(pValue);
  1789. /* filename */
  1790. pComp = &sInfo.sFilename;
  1791. if(pComp->nByte > 0) {
  1792. ph7_value_string(pValue, pComp->zString, (int)pComp->nByte);
  1793. /* Perform the insertion */
  1794. ph7_array_add_strkey_elem(pArray, "filename", pValue); /* Will make it's own copy */
  1795. }
  1796. /* Return the created array */
  1797. ph7_result_value(pCtx, pArray);
  1798. /* Don't worry about freeing memory, everything will be released
  1799. * automatically as soon we return from this foreign function.
  1800. */
  1801. }
  1802. return PH7_OK;
  1803. }
  1804. /*
  1805. * Globbing implementation extracted from the sqlite3 source tree.
  1806. * Original author: D. Richard Hipp (https://www.sqlite.org)
  1807. * Status: Public Domain
  1808. */
  1809. typedef unsigned char u8;
  1810. /* An array to map all upper-case characters into their corresponding
  1811. ** lower-case character.
  1812. **
  1813. ** SQLite only considers US-ASCII (or EBCDIC) characters. We do not
  1814. ** handle case conversions for the UTF character set since the tables
  1815. ** involved are nearly as big or bigger than SQLite itself.
  1816. */
  1817. static const unsigned char sqlite3UpperToLower[] = {
  1818. 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
  1819. 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
  1820. 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53,
  1821. 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 97, 98, 99, 100, 101, 102, 103,
  1822. 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121,
  1823. 122, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107,
  1824. 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125,
  1825. 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143,
  1826. 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161,
  1827. 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179,
  1828. 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197,
  1829. 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215,
  1830. 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233,
  1831. 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251,
  1832. 252, 253, 254, 255
  1833. };
  1834. #define GlogUpperToLower(A) if( A<0x80 ){ A = sqlite3UpperToLower[A]; }
  1835. /*
  1836. ** Assuming zIn points to the first byte of a UTF-8 character,
  1837. ** advance zIn to point to the first byte of the next UTF-8 character.
  1838. */
  1839. #define SQLITE_SKIP_UTF8(zIn) { \
  1840. if( (*(zIn++))>=0xc0 ){ \
  1841. while( (*zIn & 0xc0)==0x80 ){ zIn++; } \
  1842. } \
  1843. }
  1844. /*
  1845. ** Compare two UTF-8 strings for equality where the first string can
  1846. ** potentially be a "glob" expression. Return true (1) if they
  1847. ** are the same and false (0) if they are different.
  1848. **
  1849. ** Globbing rules:
  1850. **
  1851. ** '*' Matches any sequence of zero or more characters.
  1852. **
  1853. ** '?' Matches exactly one character.
  1854. **
  1855. ** [...] Matches one character from the enclosed list of
  1856. ** characters.
  1857. **
  1858. ** [^...] Matches one character not in the enclosed list.
  1859. **
  1860. ** With the [...] and [^...] matching, a ']' character can be included
  1861. ** in the list by making it the first character after '[' or '^'. A
  1862. ** range of characters can be specified using '-'. Example:
  1863. ** "[a-z]" matches any single lower-case letter. To match a '-', make
  1864. ** it the last character in the list.
  1865. **
  1866. ** This routine is usually quick, but can be N**2 in the worst case.
  1867. **
  1868. ** Hints: to match '*' or '?', put them in "[]". Like this:
  1869. **
  1870. ** abc[*]xyz Matches "abc*xyz" only
  1871. */
  1872. static int patternCompare(
  1873. const u8 *zPattern, /* The glob pattern */
  1874. const u8 *zString, /* The string to compare against the glob */
  1875. const int esc, /* The escape character */
  1876. int noCase
  1877. ) {
  1878. int c, c2;
  1879. int invert;
  1880. int seen;
  1881. u8 matchOne = '?';
  1882. u8 matchAll = '*';
  1883. u8 matchSet = '[';
  1884. int prevEscape = 0; /* True if the previous character was 'escape' */
  1885. if(!zPattern || !zString) {
  1886. return 0;
  1887. }
  1888. while((c = PH7_Utf8Read(zPattern, 0, &zPattern)) != 0) {
  1889. if(!prevEscape && c == matchAll) {
  1890. while((c = PH7_Utf8Read(zPattern, 0, &zPattern)) == matchAll
  1891. || c == matchOne) {
  1892. if(c == matchOne && PH7_Utf8Read(zString, 0, &zString) == 0) {
  1893. return 0;
  1894. }
  1895. }
  1896. if(c == 0) {
  1897. return 1;
  1898. } else if(c == esc) {
  1899. c = PH7_Utf8Read(zPattern, 0, &zPattern);
  1900. if(c == 0) {
  1901. return 0;
  1902. }
  1903. } else if(c == matchSet) {
  1904. if((esc == 0) || (matchSet < 0x80)) {
  1905. return 0;
  1906. }
  1907. while(*zString && patternCompare(&zPattern[-1], zString, esc, noCase) == 0) {
  1908. SQLITE_SKIP_UTF8(zString);
  1909. }
  1910. return *zString != 0;
  1911. }
  1912. while((c2 = PH7_Utf8Read(zString, 0, &zString)) != 0) {
  1913. if(noCase) {
  1914. GlogUpperToLower(c2);
  1915. GlogUpperToLower(c);
  1916. while(c2 != 0 && c2 != c) {
  1917. c2 = PH7_Utf8Read(zString, 0, &zString);
  1918. GlogUpperToLower(c2);
  1919. }
  1920. } else {
  1921. while(c2 != 0 && c2 != c) {
  1922. c2 = PH7_Utf8Read(zString, 0, &zString);
  1923. }
  1924. }
  1925. if(c2 == 0) {
  1926. return 0;
  1927. }
  1928. if(patternCompare(zPattern, zString, esc, noCase)) {
  1929. return 1;
  1930. }
  1931. }
  1932. return 0;
  1933. } else if(!prevEscape && c == matchOne) {
  1934. if(PH7_Utf8Read(zString, 0, &zString) == 0) {
  1935. return 0;
  1936. }
  1937. } else if(c == matchSet) {
  1938. int prior_c = 0;
  1939. if(esc == 0) {
  1940. return 0;
  1941. }
  1942. seen = 0;
  1943. invert = 0;
  1944. c = PH7_Utf8Read(zString, 0, &zString);
  1945. if(c == 0) {
  1946. return 0;
  1947. }
  1948. c2 = PH7_Utf8Read(zPattern, 0, &zPattern);
  1949. if(c2 == '^') {
  1950. invert = 1;
  1951. c2 = PH7_Utf8Read(zPattern, 0, &zPattern);
  1952. }
  1953. if(c2 == ']') {
  1954. if(c == ']') {
  1955. seen = 1;
  1956. }
  1957. c2 = PH7_Utf8Read(zPattern, 0, &zPattern);
  1958. }
  1959. while(c2 && c2 != ']') {
  1960. if(c2 == '-' && zPattern[0] != ']' && zPattern[0] != 0 && prior_c > 0) {
  1961. c2 = PH7_Utf8Read(zPattern, 0, &zPattern);
  1962. if(c >= prior_c && c <= c2) {
  1963. seen = 1;
  1964. }
  1965. prior_c = 0;
  1966. } else {
  1967. if(c == c2) {
  1968. seen = 1;
  1969. }
  1970. prior_c = c2;
  1971. }
  1972. c2 = PH7_Utf8Read(zPattern, 0, &zPattern);
  1973. }
  1974. if(c2 == 0 || (seen ^ invert) == 0) {
  1975. return 0;
  1976. }
  1977. } else if(esc == c && !prevEscape) {
  1978. prevEscape = 1;
  1979. } else {
  1980. c2 = PH7_Utf8Read(zString, 0, &zString);
  1981. if(noCase) {
  1982. GlogUpperToLower(c);
  1983. GlogUpperToLower(c2);
  1984. }
  1985. if(c != c2) {
  1986. return 0;
  1987. }
  1988. prevEscape = 0;
  1989. }
  1990. }
  1991. return *zString == 0;
  1992. }
  1993. /*
  1994. * Wrapper around patternCompare() defined above.
  1995. * See block comment above for more information.
  1996. */
  1997. static int Glob(const unsigned char *zPattern, const unsigned char *zString, int iEsc, int CaseCompare) {
  1998. int rc;
  1999. if(iEsc < 0) {
  2000. iEsc = '\\';
  2001. }
  2002. rc = patternCompare(zPattern, zString, iEsc, CaseCompare);
  2003. return rc;
  2004. }
  2005. /*
  2006. * bool fnmatch(string $pattern,string $string[,int $flags = 0 ])
  2007. * Match filename against a pattern.
  2008. * Parameters
  2009. * $pattern
  2010. * The shell wildcard pattern.
  2011. * $string
  2012. * The tested string.
  2013. * $flags
  2014. * A list of possible flags:
  2015. * FNM_NOESCAPE Disable backslash escaping.
  2016. * FNM_PATHNAME Slash in string only matches slash in the given pattern.
  2017. * FNM_PERIOD Leading period in string must be exactly matched by period in the given pattern.
  2018. * FNM_CASEFOLD Caseless match.
  2019. * Return
  2020. * TRUE if there is a match, FALSE otherwise.
  2021. */
  2022. static int PH7_builtin_fnmatch(ph7_context *pCtx, int nArg, ph7_value **apArg) {
  2023. const char *zString, *zPattern;
  2024. int iEsc = '\\';
  2025. int noCase = 0;
  2026. int rc;
  2027. if(nArg < 2 || !ph7_value_is_string(apArg[0]) || !ph7_value_is_string(apArg[1])) {
  2028. /* Missing/Invalid arguments,return FALSE */
  2029. ph7_result_bool(pCtx, 0);
  2030. return PH7_OK;
  2031. }
  2032. /* Extract the pattern and the string */
  2033. zPattern = ph7_value_to_string(apArg[0], 0);
  2034. zString = ph7_value_to_string(apArg[1], 0);
  2035. /* Extract the flags if avaialble */
  2036. if(nArg > 2 && ph7_value_is_int(apArg[2])) {
  2037. rc = ph7_value_to_int(apArg[2]);
  2038. if(rc & 0x01 /*FNM_NOESCAPE*/) {
  2039. iEsc = 0;
  2040. }
  2041. if(rc & 0x08 /*FNM_CASEFOLD*/) {
  2042. noCase = 1;
  2043. }
  2044. }
  2045. /* Go globbing */
  2046. rc = Glob((const unsigned char *)zPattern, (const unsigned char *)zString, iEsc, noCase);
  2047. /* Globbing result */
  2048. ph7_result_bool(pCtx, rc);
  2049. return PH7_OK;
  2050. }
  2051. /*
  2052. * bool strglob(string $pattern,string $string)
  2053. * Match string against a pattern.
  2054. * Parameters
  2055. * $pattern
  2056. * The shell wildcard pattern.
  2057. * $string
  2058. * The tested string.
  2059. * Return
  2060. * TRUE if there is a match, FALSE otherwise.
  2061. * Note that this a symisc eXtension.
  2062. */
  2063. static int PH7_builtin_strglob(ph7_context *pCtx, int nArg, ph7_value **apArg) {
  2064. const char *zString, *zPattern;
  2065. int iEsc = '\\';
  2066. int rc;
  2067. if(nArg < 2 || !ph7_value_is_string(apArg[0]) || !ph7_value_is_string(apArg[1])) {
  2068. /* Missing/Invalid arguments,return FALSE */
  2069. ph7_result_bool(pCtx, 0);
  2070. return PH7_OK;
  2071. }
  2072. /* Extract the pattern and the string */
  2073. zPattern = ph7_value_to_string(apArg[0], 0);
  2074. zString = ph7_value_to_string(apArg[1], 0);
  2075. /* Go globbing */
  2076. rc = Glob((const unsigned char *)zPattern, (const unsigned char *)zString, iEsc, 0);
  2077. /* Globbing result */
  2078. ph7_result_bool(pCtx, rc);
  2079. return PH7_OK;
  2080. }
  2081. /*
  2082. * bool link(string $target,string $link)
  2083. * Create a hard link.
  2084. * Parameters
  2085. * $target
  2086. * Target of the link.
  2087. * $link
  2088. * The link name.
  2089. * Return
  2090. * TRUE on success or FALSE on failure.
  2091. */
  2092. static int PH7_vfs_link(ph7_context *pCtx, int nArg, ph7_value **apArg) {
  2093. const char *zTarget, *zLink;
  2094. ph7_vfs *pVfs;
  2095. int rc;
  2096. if(nArg < 2 || !ph7_value_is_string(apArg[0]) || !ph7_value_is_string(apArg[1])) {
  2097. /* Missing/Invalid arguments,return FALSE */
  2098. ph7_result_bool(pCtx, 0);
  2099. return PH7_OK;
  2100. }
  2101. /* Point to the underlying vfs */
  2102. pVfs = (ph7_vfs *)ph7_context_user_data(pCtx);
  2103. if(pVfs == 0 || pVfs->xLink == 0) {
  2104. /* IO routine not implemented,return NULL */
  2105. PH7_VmThrowError(pCtx->pVm, PH7_CTX_WARNING,
  2106. "IO routine(%s) not implemented in the underlying VFS",
  2107. ph7_function_name(pCtx)
  2108. );
  2109. ph7_result_bool(pCtx, 0);
  2110. return PH7_OK;
  2111. }
  2112. /* Extract the given arguments */
  2113. zTarget = ph7_value_to_string(apArg[0], 0);
  2114. zLink = ph7_value_to_string(apArg[1], 0);
  2115. /* Perform the requested operation */
  2116. rc = pVfs->xLink(zTarget, zLink, 0/*Not a symbolic link */);
  2117. /* IO result */
  2118. ph7_result_bool(pCtx, rc == PH7_OK);
  2119. return PH7_OK;
  2120. }
  2121. /*
  2122. * bool symlink(string $target,string $link)
  2123. * Creates a symbolic link.
  2124. * Parameters
  2125. * $target
  2126. * Target of the link.
  2127. * $link
  2128. * The link name.
  2129. * Return
  2130. * TRUE on success or FALSE on failure.
  2131. */
  2132. static int PH7_vfs_symlink(ph7_context *pCtx, int nArg, ph7_value **apArg) {
  2133. const char *zTarget, *zLink;
  2134. ph7_vfs *pVfs;
  2135. int rc;
  2136. if(nArg < 2 || !ph7_value_is_string(apArg[0]) || !ph7_value_is_string(apArg[1])) {
  2137. /* Missing/Invalid arguments,return FALSE */
  2138. ph7_result_bool(pCtx, 0);
  2139. return PH7_OK;
  2140. }
  2141. /* Point to the underlying vfs */
  2142. pVfs = (ph7_vfs *)ph7_context_user_data(pCtx);
  2143. if(pVfs == 0 || pVfs->xLink == 0) {
  2144. /* IO routine not implemented,return NULL */
  2145. PH7_VmThrowError(pCtx->pVm, PH7_CTX_WARNING,
  2146. "IO routine(%s) not implemented in the underlying VFS",
  2147. ph7_function_name(pCtx)
  2148. );
  2149. ph7_result_bool(pCtx, 0);
  2150. return PH7_OK;
  2151. }
  2152. /* Extract the given arguments */
  2153. zTarget = ph7_value_to_string(apArg[0], 0);
  2154. zLink = ph7_value_to_string(apArg[1], 0);
  2155. /* Perform the requested operation */
  2156. rc = pVfs->xLink(zTarget, zLink, 1/*A symbolic link */);
  2157. /* IO result */
  2158. ph7_result_bool(pCtx, rc == PH7_OK);
  2159. return PH7_OK;
  2160. }
  2161. /*
  2162. * int umask([ int $mask ])
  2163. * Changes the current umask.
  2164. * Parameters
  2165. * $mask
  2166. * The new umask.
  2167. * Return
  2168. * umask() without arguments simply returns the current umask.
  2169. * Otherwise the old umask is returned.
  2170. */
  2171. static int PH7_vfs_umask(ph7_context *pCtx, int nArg, ph7_value **apArg) {
  2172. int iOld, iNew;
  2173. ph7_vfs *pVfs;
  2174. /* Point to the underlying vfs */
  2175. pVfs = (ph7_vfs *)ph7_context_user_data(pCtx);
  2176. if(pVfs == 0 || pVfs->xUmask == 0) {
  2177. /* IO routine not implemented,return -1 */
  2178. PH7_VmThrowError(pCtx->pVm, PH7_CTX_WARNING,
  2179. "IO routine(%s) not implemented in the underlying VFS",
  2180. ph7_function_name(pCtx)
  2181. );
  2182. ph7_result_int(pCtx, 0);
  2183. return PH7_OK;
  2184. }
  2185. iNew = 0;
  2186. if(nArg > 0) {
  2187. iNew = ph7_value_to_int(apArg[0]);
  2188. }
  2189. /* Perform the requested operation */
  2190. iOld = pVfs->xUmask(iNew);
  2191. /* Old mask */
  2192. ph7_result_int(pCtx, iOld);
  2193. return PH7_OK;
  2194. }
  2195. /*
  2196. * string sys_get_temp_dir()
  2197. * Returns directory path used for temporary files.
  2198. * Parameters
  2199. * None
  2200. * Return
  2201. * Returns the path of the temporary directory.
  2202. */
  2203. static int PH7_vfs_sys_get_temp_dir(ph7_context *pCtx, int nArg, ph7_value **apArg) {
  2204. ph7_vfs *pVfs;
  2205. /* Set the empty string as the default return value */
  2206. ph7_result_string(pCtx, "", 0);
  2207. /* Point to the underlying vfs */
  2208. pVfs = (ph7_vfs *)ph7_context_user_data(pCtx);
  2209. if(pVfs == 0 || pVfs->xTempDir == 0) {
  2210. SXUNUSED(nArg); /* cc warning */
  2211. SXUNUSED(apArg);
  2212. /* IO routine not implemented,return "" */
  2213. PH7_VmThrowError(pCtx->pVm, PH7_CTX_WARNING,
  2214. "IO routine(%s) not implemented in the underlying VFS",
  2215. ph7_function_name(pCtx)
  2216. );
  2217. return PH7_OK;
  2218. }
  2219. /* Perform the requested operation */
  2220. pVfs->xTempDir(pCtx);
  2221. return PH7_OK;
  2222. }
  2223. /*
  2224. * string get_current_user()
  2225. * Returns the name of the current working user.
  2226. * Parameters
  2227. * None
  2228. * Return
  2229. * Returns the name of the current working user.
  2230. */
  2231. static int PH7_vfs_get_current_user(ph7_context *pCtx, int nArg, ph7_value **apArg) {
  2232. ph7_vfs *pVfs;
  2233. /* Point to the underlying vfs */
  2234. pVfs = (ph7_vfs *)ph7_context_user_data(pCtx);
  2235. if(pVfs == 0 || pVfs->xUsername == 0) {
  2236. SXUNUSED(nArg); /* cc warning */
  2237. SXUNUSED(apArg);
  2238. /* IO routine not implemented */
  2239. PH7_VmThrowError(pCtx->pVm, PH7_CTX_WARNING,
  2240. "IO routine(%s) not implemented in the underlying VFS",
  2241. ph7_function_name(pCtx)
  2242. );
  2243. /* Set a dummy username */
  2244. ph7_result_string(pCtx, "unknown", sizeof("unknown") - 1);
  2245. return PH7_OK;
  2246. }
  2247. /* Perform the requested operation */
  2248. pVfs->xUsername(pCtx);
  2249. return PH7_OK;
  2250. }
  2251. /*
  2252. * int64 getmypid()
  2253. * Gets process ID.
  2254. * Parameters
  2255. * None
  2256. * Return
  2257. * Returns the process ID.
  2258. */
  2259. static int PH7_vfs_getmypid(ph7_context *pCtx, int nArg, ph7_value **apArg) {
  2260. ph7_int64 nProcessId;
  2261. ph7_vfs *pVfs;
  2262. /* Point to the underlying vfs */
  2263. pVfs = (ph7_vfs *)ph7_context_user_data(pCtx);
  2264. if(pVfs == 0 || pVfs->xProcessId == 0) {
  2265. SXUNUSED(nArg); /* cc warning */
  2266. SXUNUSED(apArg);
  2267. /* IO routine not implemented,return -1 */
  2268. PH7_VmThrowError(pCtx->pVm, PH7_CTX_WARNING,
  2269. "IO routine(%s) not implemented in the underlying VFS",
  2270. ph7_function_name(pCtx)
  2271. );
  2272. ph7_result_int(pCtx, -1);
  2273. return PH7_OK;
  2274. }
  2275. /* Perform the requested operation */
  2276. nProcessId = (ph7_int64)pVfs->xProcessId();
  2277. /* Set the result */
  2278. ph7_result_int64(pCtx, nProcessId);
  2279. return PH7_OK;
  2280. }
  2281. /*
  2282. * int getmyuid()
  2283. * Get user ID.
  2284. * Parameters
  2285. * None
  2286. * Return
  2287. * Returns the user ID.
  2288. */
  2289. static int PH7_vfs_getmyuid(ph7_context *pCtx, int nArg, ph7_value **apArg) {
  2290. ph7_vfs *pVfs;
  2291. int nUid;
  2292. /* Point to the underlying vfs */
  2293. pVfs = (ph7_vfs *)ph7_context_user_data(pCtx);
  2294. if(pVfs == 0 || pVfs->xUid == 0) {
  2295. SXUNUSED(nArg); /* cc warning */
  2296. SXUNUSED(apArg);
  2297. /* IO routine not implemented,return -1 */
  2298. PH7_VmThrowError(pCtx->pVm, PH7_CTX_WARNING,
  2299. "IO routine(%s) not implemented in the underlying VFS",
  2300. ph7_function_name(pCtx)
  2301. );
  2302. ph7_result_int(pCtx, -1);
  2303. return PH7_OK;
  2304. }
  2305. /* Perform the requested operation */
  2306. nUid = pVfs->xUid();
  2307. /* Set the result */
  2308. ph7_result_int(pCtx, nUid);
  2309. return PH7_OK;
  2310. }
  2311. /*
  2312. * int getmygid()
  2313. * Get group ID.
  2314. * Parameters
  2315. * None
  2316. * Return
  2317. * Returns the group ID.
  2318. */
  2319. static int PH7_vfs_getmygid(ph7_context *pCtx, int nArg, ph7_value **apArg) {
  2320. ph7_vfs *pVfs;
  2321. int nGid;
  2322. /* Point to the underlying vfs */
  2323. pVfs = (ph7_vfs *)ph7_context_user_data(pCtx);
  2324. if(pVfs == 0 || pVfs->xGid == 0) {
  2325. SXUNUSED(nArg); /* cc warning */
  2326. SXUNUSED(apArg);
  2327. /* IO routine not implemented,return -1 */
  2328. PH7_VmThrowError(pCtx->pVm, PH7_CTX_WARNING,
  2329. "IO routine(%s) not implemented in the underlying VFS",
  2330. ph7_function_name(pCtx)
  2331. );
  2332. ph7_result_int(pCtx, -1);
  2333. return PH7_OK;
  2334. }
  2335. /* Perform the requested operation */
  2336. nGid = pVfs->xGid();
  2337. /* Set the result */
  2338. ph7_result_int(pCtx, nGid);
  2339. return PH7_OK;
  2340. }
  2341. #ifdef __WINNT__
  2342. #include <Windows.h>
  2343. #elif defined(__UNIXES__)
  2344. #include <sys/utsname.h>
  2345. #endif
  2346. /*
  2347. * string php_uname([ string $mode = "a" ])
  2348. * Returns information about the host operating system.
  2349. * Parameters
  2350. * $mode
  2351. * mode is a single character that defines what information is returned:
  2352. * 'a': This is the default. Contains all modes in the sequence "s n r v m".
  2353. * 's': Operating system name. eg. FreeBSD.
  2354. * 'n': Host name. eg. localhost.example.com.
  2355. * 'r': Release name. eg. 5.1.2-RELEASE.
  2356. * 'v': Version information. Varies a lot between operating systems.
  2357. * 'm': Machine type. eg. i386.
  2358. * Return
  2359. * OS description as a string.
  2360. */
  2361. static int PH7_vfs_ph7_uname(ph7_context *pCtx, int nArg, ph7_value **apArg) {
  2362. #if defined(__WINNT__)
  2363. const char *zName = "Microsoft Windows";
  2364. OSVERSIONINFOW sVer;
  2365. #elif defined(__UNIXES__)
  2366. struct utsname sName;
  2367. #endif
  2368. const char *zMode = "a";
  2369. if(nArg > 0 && ph7_value_is_string(apArg[0])) {
  2370. /* Extract the desired mode */
  2371. zMode = ph7_value_to_string(apArg[0], 0);
  2372. }
  2373. #if defined(__WINNT__)
  2374. sVer.dwOSVersionInfoSize = sizeof(sVer);
  2375. if(TRUE != GetVersionExW(&sVer)) {
  2376. ph7_result_string(pCtx, zName, -1);
  2377. return PH7_OK;
  2378. }
  2379. if(sVer.dwPlatformId == VER_PLATFORM_WIN32_NT) {
  2380. if(sVer.dwMajorVersion <= 4) {
  2381. zName = "Microsoft Windows NT";
  2382. } else if(sVer.dwMajorVersion == 5) {
  2383. switch(sVer.dwMinorVersion) {
  2384. case 0:
  2385. zName = "Microsoft Windows 2000";
  2386. break;
  2387. case 1:
  2388. zName = "Microsoft Windows XP";
  2389. break;
  2390. case 2:
  2391. zName = "Microsoft Windows Server 2003";
  2392. break;
  2393. }
  2394. } else if(sVer.dwMajorVersion == 6) {
  2395. switch(sVer.dwMinorVersion) {
  2396. case 0:
  2397. zName = "Microsoft Windows Vista";
  2398. break;
  2399. case 1:
  2400. zName = "Microsoft Windows 7";
  2401. break;
  2402. case 2:
  2403. zName = "Microsoft Windows Server 2008";
  2404. break;
  2405. case 3:
  2406. zName = "Microsoft Windows 8";
  2407. break;
  2408. default:
  2409. break;
  2410. }
  2411. } else if(sVer.dwMajorVersion == 10) {
  2412. switch(sVer.dwMinorVersion) {
  2413. case 0:
  2414. zName = "Microsoft Windows 10";
  2415. break;
  2416. default:
  2417. break;
  2418. }
  2419. }
  2420. }
  2421. switch(zMode[0]) {
  2422. case 's':
  2423. /* Operating system name */
  2424. ph7_result_string(pCtx, zName, -1/* Compute length automatically*/);
  2425. break;
  2426. case 'n':
  2427. /* Host name */
  2428. ph7_result_string(pCtx, "localhost", (int)sizeof("localhost") - 1);
  2429. break;
  2430. case 'r':
  2431. case 'v':
  2432. /* Version information. */
  2433. ph7_result_string_format(pCtx, "%u.%u build %u",
  2434. sVer.dwMajorVersion, sVer.dwMinorVersion, sVer.dwBuildNumber
  2435. );
  2436. break;
  2437. case 'm':
  2438. /* Machine name */
  2439. ph7_result_string(pCtx, "x86", (int)sizeof("x86") - 1);
  2440. break;
  2441. default:
  2442. ph7_result_string_format(pCtx, "%s localhost %u.%u build %u x86",
  2443. zName,
  2444. sVer.dwMajorVersion, sVer.dwMinorVersion, sVer.dwBuildNumber
  2445. );
  2446. break;
  2447. }
  2448. #elif defined(__UNIXES__)
  2449. if(uname(&sName) != 0) {
  2450. ph7_result_string(pCtx, "Unix", (int)sizeof("Unix") - 1);
  2451. return PH7_OK;
  2452. }
  2453. switch(zMode[0]) {
  2454. case 's':
  2455. /* Operating system name */
  2456. ph7_result_string(pCtx, sName.sysname, -1/* Compute length automatically*/);
  2457. break;
  2458. case 'n':
  2459. /* Host name */
  2460. ph7_result_string(pCtx, sName.nodename, -1/* Compute length automatically*/);
  2461. break;
  2462. case 'r':
  2463. /* Release information */
  2464. ph7_result_string(pCtx, sName.release, -1/* Compute length automatically*/);
  2465. break;
  2466. case 'v':
  2467. /* Version information. */
  2468. ph7_result_string(pCtx, sName.version, -1/* Compute length automatically*/);
  2469. break;
  2470. case 'm':
  2471. /* Machine name */
  2472. ph7_result_string(pCtx, sName.machine, -1/* Compute length automatically*/);
  2473. break;
  2474. default:
  2475. ph7_result_string_format(pCtx,
  2476. "%s %s %s %s %s",
  2477. sName.sysname,
  2478. sName.release,
  2479. sName.version,
  2480. sName.nodename,
  2481. sName.machine
  2482. );
  2483. break;
  2484. }
  2485. #else
  2486. ph7_result_string(pCtx, "Unknown Operating System", (int)sizeof("Unknown Operating System") - 1);
  2487. #endif
  2488. return PH7_OK;
  2489. }
  2490. /*
  2491. * Section:
  2492. * IO stream implementation.
  2493. * Authors:
  2494. * Symisc Systems,devel@symisc.net.
  2495. * Copyright (C) Symisc Systems,https://ph7.symisc.net
  2496. * Status:
  2497. * Stable.
  2498. */
  2499. typedef struct io_private io_private;
  2500. struct io_private {
  2501. const ph7_io_stream *pStream; /* Underlying IO device */
  2502. void *pHandle; /* IO handle */
  2503. /* Unbuffered IO */
  2504. SyBlob sBuffer; /* Working buffer */
  2505. sxu32 nOfft; /* Current read offset */
  2506. sxu32 iMagic; /* Sanity check to avoid misuse */
  2507. };
  2508. #define IO_PRIVATE_MAGIC 0xFEAC14
  2509. /* Make sure we are dealing with a valid io_private instance */
  2510. #define IO_PRIVATE_INVALID(IO) ( IO == 0 || IO->iMagic != IO_PRIVATE_MAGIC )
  2511. /* Forward declaration */
  2512. static void ResetIOPrivate(io_private *pDev);
  2513. /*
  2514. * bool ftruncate(resource $handle,int64 $size)
  2515. * Truncates a file to a given length.
  2516. * Parameters
  2517. * $handle
  2518. * The file pointer.
  2519. * Note:
  2520. * The handle must be open for writing.
  2521. * $size
  2522. * The size to truncate to.
  2523. * Return
  2524. * TRUE on success or FALSE on failure.
  2525. */
  2526. static int PH7_builtin_ftruncate(ph7_context *pCtx, int nArg, ph7_value **apArg) {
  2527. const ph7_io_stream *pStream;
  2528. io_private *pDev;
  2529. int rc;
  2530. if(nArg < 2 || !ph7_value_is_resource(apArg[0])) {
  2531. /* Missing/Invalid arguments,return FALSE */
  2532. PH7_VmThrowError(pCtx->pVm, PH7_CTX_WARNING, "Expecting an IO handle");
  2533. ph7_result_bool(pCtx, 0);
  2534. return PH7_OK;
  2535. }
  2536. /* Extract our private data */
  2537. pDev = (io_private *)ph7_value_to_resource(apArg[0]);
  2538. /* Make sure we are dealing with a valid io_private instance */
  2539. if(IO_PRIVATE_INVALID(pDev)) {
  2540. /*Expecting an IO handle */
  2541. PH7_VmThrowError(pCtx->pVm, PH7_CTX_WARNING, "Expecting an IO handle");
  2542. ph7_result_bool(pCtx, 0);
  2543. return PH7_OK;
  2544. }
  2545. /* Point to the target IO stream device */
  2546. pStream = pDev->pStream;
  2547. if(pStream == 0 || pStream->xTrunc == 0) {
  2548. PH7_VmThrowError(pCtx->pVm, PH7_CTX_WARNING,
  2549. "IO routine(%s) not implemented in the underlying stream(%s) device",
  2550. ph7_function_name(pCtx), pStream ? pStream->zName : "null_stream"
  2551. );
  2552. ph7_result_bool(pCtx, 0);
  2553. return PH7_OK;
  2554. }
  2555. /* Perform the requested operation */
  2556. rc = pStream->xTrunc(pDev->pHandle, ph7_value_to_int64(apArg[1]));
  2557. if(rc == PH7_OK) {
  2558. /* Discard buffered data */
  2559. ResetIOPrivate(pDev);
  2560. }
  2561. /* IO result */
  2562. ph7_result_bool(pCtx, rc == PH7_OK);
  2563. return PH7_OK;
  2564. }
  2565. /*
  2566. * int fseek(resource $handle,int $offset[,int $whence = SEEK_SET ])
  2567. * Seeks on a file pointer.
  2568. * Parameters
  2569. * $handle
  2570. * A file system pointer resource that is typically created using fopen().
  2571. * $offset
  2572. * The offset.
  2573. * To move to a position before the end-of-file, you need to pass a negative
  2574. * value in offset and set whence to SEEK_END.
  2575. * whence
  2576. * whence values are:
  2577. * SEEK_SET - Set position equal to offset bytes.
  2578. * SEEK_CUR - Set position to current location plus offset.
  2579. * SEEK_END - Set position to end-of-file plus offset.
  2580. * Return
  2581. * 0 on success,-1 on failure
  2582. */
  2583. static int PH7_builtin_fseek(ph7_context *pCtx, int nArg, ph7_value **apArg) {
  2584. const ph7_io_stream *pStream;
  2585. io_private *pDev;
  2586. ph7_int64 iOfft;
  2587. int whence;
  2588. int rc;
  2589. if(nArg < 2 || !ph7_value_is_resource(apArg[0])) {
  2590. /* Missing/Invalid arguments,return FALSE */
  2591. PH7_VmThrowError(pCtx->pVm, PH7_CTX_WARNING, "Expecting an IO handle");
  2592. ph7_result_int(pCtx, -1);
  2593. return PH7_OK;
  2594. }
  2595. /* Extract our private data */
  2596. pDev = (io_private *)ph7_value_to_resource(apArg[0]);
  2597. /* Make sure we are dealing with a valid io_private instance */
  2598. if(IO_PRIVATE_INVALID(pDev)) {
  2599. /*Expecting an IO handle */
  2600. PH7_VmThrowError(pCtx->pVm, PH7_CTX_WARNING, "Expecting an IO handle");
  2601. ph7_result_int(pCtx, -1);
  2602. return PH7_OK;
  2603. }
  2604. /* Point to the target IO stream device */
  2605. pStream = pDev->pStream;
  2606. if(pStream == 0 || pStream->xSeek == 0) {
  2607. PH7_VmThrowError(pCtx->pVm, PH7_CTX_WARNING,
  2608. "IO routine(%s) not implemented in the underlying stream(%s) device",
  2609. ph7_function_name(pCtx), pStream ? pStream->zName : "null_stream"
  2610. );
  2611. ph7_result_int(pCtx, -1);
  2612. return PH7_OK;
  2613. }
  2614. /* Extract the offset */
  2615. iOfft = ph7_value_to_int64(apArg[1]);
  2616. whence = 0;/* SEEK_SET */
  2617. if(nArg > 2 && ph7_value_is_int(apArg[2])) {
  2618. whence = ph7_value_to_int(apArg[2]);
  2619. }
  2620. /* Perform the requested operation */
  2621. rc = pStream->xSeek(pDev->pHandle, iOfft, whence);
  2622. if(rc == PH7_OK) {
  2623. /* Ignore buffered data */
  2624. ResetIOPrivate(pDev);
  2625. }
  2626. /* IO result */
  2627. ph7_result_int(pCtx, rc == PH7_OK ? 0 : - 1);
  2628. return PH7_OK;
  2629. }
  2630. /*
  2631. * int64 ftell(resource $handle)
  2632. * Returns the current position of the file read/write pointer.
  2633. * Parameters
  2634. * $handle
  2635. * The file pointer.
  2636. * Return
  2637. * Returns the position of the file pointer referenced by handle
  2638. * as an integer; i.e., its offset into the file stream.
  2639. * FALSE is returned on failure.
  2640. */
  2641. static int PH7_builtin_ftell(ph7_context *pCtx, int nArg, ph7_value **apArg) {
  2642. const ph7_io_stream *pStream;
  2643. io_private *pDev;
  2644. ph7_int64 iOfft;
  2645. if(nArg < 1 || !ph7_value_is_resource(apArg[0])) {
  2646. /* Missing/Invalid arguments,return FALSE */
  2647. PH7_VmThrowError(pCtx->pVm, PH7_CTX_WARNING, "Expecting an IO handle");
  2648. ph7_result_bool(pCtx, 0);
  2649. return PH7_OK;
  2650. }
  2651. /* Extract our private data */
  2652. pDev = (io_private *)ph7_value_to_resource(apArg[0]);
  2653. /* Make sure we are dealing with a valid io_private instance */
  2654. if(IO_PRIVATE_INVALID(pDev)) {
  2655. /*Expecting an IO handle */
  2656. PH7_VmThrowError(pCtx->pVm, PH7_CTX_WARNING, "Expecting an IO handle");
  2657. ph7_result_bool(pCtx, 0);
  2658. return PH7_OK;
  2659. }
  2660. /* Point to the target IO stream device */
  2661. pStream = pDev->pStream;
  2662. if(pStream == 0 || pStream->xTell == 0) {
  2663. PH7_VmThrowError(pCtx->pVm, PH7_CTX_WARNING,
  2664. "IO routine(%s) not implemented in the underlying stream(%s) device",
  2665. ph7_function_name(pCtx), pStream ? pStream->zName : "null_stream"
  2666. );
  2667. ph7_result_bool(pCtx, 0);
  2668. return PH7_OK;
  2669. }
  2670. /* Perform the requested operation */
  2671. iOfft = pStream->xTell(pDev->pHandle);
  2672. /* IO result */
  2673. ph7_result_int64(pCtx, iOfft);
  2674. return PH7_OK;
  2675. }
  2676. /*
  2677. * bool rewind(resource $handle)
  2678. * Rewind the position of a file pointer.
  2679. * Parameters
  2680. * $handle
  2681. * The file pointer.
  2682. * Return
  2683. * TRUE on success or FALSE on failure.
  2684. */
  2685. static int PH7_builtin_rewind(ph7_context *pCtx, int nArg, ph7_value **apArg) {
  2686. const ph7_io_stream *pStream;
  2687. io_private *pDev;
  2688. int rc;
  2689. if(nArg < 1 || !ph7_value_is_resource(apArg[0])) {
  2690. /* Missing/Invalid arguments,return FALSE */
  2691. PH7_VmThrowError(pCtx->pVm, PH7_CTX_WARNING, "Expecting an IO handle");
  2692. ph7_result_bool(pCtx, 0);
  2693. return PH7_OK;
  2694. }
  2695. /* Extract our private data */
  2696. pDev = (io_private *)ph7_value_to_resource(apArg[0]);
  2697. /* Make sure we are dealing with a valid io_private instance */
  2698. if(IO_PRIVATE_INVALID(pDev)) {
  2699. /*Expecting an IO handle */
  2700. PH7_VmThrowError(pCtx->pVm, PH7_CTX_WARNING, "Expecting an IO handle");
  2701. ph7_result_bool(pCtx, 0);
  2702. return PH7_OK;
  2703. }
  2704. /* Point to the target IO stream device */
  2705. pStream = pDev->pStream;
  2706. if(pStream == 0 || pStream->xSeek == 0) {
  2707. PH7_VmThrowError(pCtx->pVm, PH7_CTX_WARNING,
  2708. "IO routine(%s) not implemented in the underlying stream(%s) device",
  2709. ph7_function_name(pCtx), pStream ? pStream->zName : "null_stream"
  2710. );
  2711. ph7_result_bool(pCtx, 0);
  2712. return PH7_OK;
  2713. }
  2714. /* Perform the requested operation */
  2715. rc = pStream->xSeek(pDev->pHandle, 0, 0/*SEEK_SET*/);
  2716. if(rc == PH7_OK) {
  2717. /* Ignore buffered data */
  2718. ResetIOPrivate(pDev);
  2719. }
  2720. /* IO result */
  2721. ph7_result_bool(pCtx, rc == PH7_OK);
  2722. return PH7_OK;
  2723. }
  2724. /*
  2725. * bool fflush(resource $handle)
  2726. * Flushes the output to a file.
  2727. * Parameters
  2728. * $handle
  2729. * The file pointer.
  2730. * Return
  2731. * TRUE on success or FALSE on failure.
  2732. */
  2733. static int PH7_builtin_fflush(ph7_context *pCtx, int nArg, ph7_value **apArg) {
  2734. const ph7_io_stream *pStream;
  2735. io_private *pDev;
  2736. int rc;
  2737. if(nArg < 1 || !ph7_value_is_resource(apArg[0])) {
  2738. /* Missing/Invalid arguments,return FALSE */
  2739. PH7_VmThrowError(pCtx->pVm, PH7_CTX_WARNING, "Expecting an IO handle");
  2740. ph7_result_bool(pCtx, 0);
  2741. return PH7_OK;
  2742. }
  2743. /* Extract our private data */
  2744. pDev = (io_private *)ph7_value_to_resource(apArg[0]);
  2745. /* Make sure we are dealing with a valid io_private instance */
  2746. if(IO_PRIVATE_INVALID(pDev)) {
  2747. /*Expecting an IO handle */
  2748. PH7_VmThrowError(pCtx->pVm, PH7_CTX_WARNING, "Expecting an IO handle");
  2749. ph7_result_bool(pCtx, 0);
  2750. return PH7_OK;
  2751. }
  2752. /* Point to the target IO stream device */
  2753. pStream = pDev->pStream;
  2754. if(pStream == 0 || pStream->xSync == 0) {
  2755. PH7_VmThrowError(pCtx->pVm, PH7_CTX_WARNING,
  2756. "IO routine(%s) not implemented in the underlying stream(%s) device",
  2757. ph7_function_name(pCtx), pStream ? pStream->zName : "null_stream"
  2758. );
  2759. ph7_result_bool(pCtx, 0);
  2760. return PH7_OK;
  2761. }
  2762. /* Perform the requested operation */
  2763. rc = pStream->xSync(pDev->pHandle);
  2764. /* IO result */
  2765. ph7_result_bool(pCtx, rc == PH7_OK);
  2766. return PH7_OK;
  2767. }
  2768. /*
  2769. * bool feof(resource $handle)
  2770. * Tests for end-of-file on a file pointer.
  2771. * Parameters
  2772. * $handle
  2773. * The file pointer.
  2774. * Return
  2775. * Returns TRUE if the file pointer is at EOF.FALSE otherwise
  2776. */
  2777. static int PH7_builtin_feof(ph7_context *pCtx, int nArg, ph7_value **apArg) {
  2778. const ph7_io_stream *pStream;
  2779. io_private *pDev;
  2780. int rc;
  2781. if(nArg < 1 || !ph7_value_is_resource(apArg[0])) {
  2782. /* Missing/Invalid arguments */
  2783. PH7_VmThrowError(pCtx->pVm, PH7_CTX_WARNING, "Expecting an IO handle");
  2784. ph7_result_bool(pCtx, 1);
  2785. return PH7_OK;
  2786. }
  2787. /* Extract our private data */
  2788. pDev = (io_private *)ph7_value_to_resource(apArg[0]);
  2789. /* Make sure we are dealing with a valid io_private instance */
  2790. if(IO_PRIVATE_INVALID(pDev)) {
  2791. /*Expecting an IO handle */
  2792. PH7_VmThrowError(pCtx->pVm, PH7_CTX_WARNING, "Expecting an IO handle");
  2793. ph7_result_bool(pCtx, 1);
  2794. return PH7_OK;
  2795. }
  2796. /* Point to the target IO stream device */
  2797. pStream = pDev->pStream;
  2798. if(pStream == 0) {
  2799. PH7_VmThrowError(pCtx->pVm, PH7_CTX_WARNING,
  2800. "IO routine(%s) not implemented in the underlying stream(%s) device",
  2801. ph7_function_name(pCtx), pStream ? pStream->zName : "null_stream"
  2802. );
  2803. ph7_result_bool(pCtx, 1);
  2804. return PH7_OK;
  2805. }
  2806. rc = SXERR_EOF;
  2807. /* Perform the requested operation */
  2808. if(SyBlobLength(&pDev->sBuffer) - pDev->nOfft > 0) {
  2809. /* Data is available */
  2810. rc = PH7_OK;
  2811. } else {
  2812. char zBuf[4096];
  2813. ph7_int64 n;
  2814. /* Perform a buffered read */
  2815. n = pStream->xRead(pDev->pHandle, zBuf, sizeof(zBuf));
  2816. if(n > 0) {
  2817. /* Copy buffered data */
  2818. SyBlobAppend(&pDev->sBuffer, zBuf, (sxu32)n);
  2819. rc = PH7_OK;
  2820. }
  2821. }
  2822. /* EOF or not */
  2823. ph7_result_bool(pCtx, rc == SXERR_EOF);
  2824. return PH7_OK;
  2825. }
  2826. /*
  2827. * Read n bytes from the underlying IO stream device.
  2828. * Return total numbers of bytes readen on success. A number < 1 on failure
  2829. * [i.e: IO error ] or EOF.
  2830. */
  2831. static ph7_int64 StreamRead(io_private *pDev, void *pBuf, ph7_int64 nLen) {
  2832. const ph7_io_stream *pStream = pDev->pStream;
  2833. char *zBuf = (char *)pBuf;
  2834. ph7_int64 n, nRead;
  2835. n = SyBlobLength(&pDev->sBuffer) - pDev->nOfft;
  2836. if(n > 0) {
  2837. if(n > nLen) {
  2838. n = nLen;
  2839. }
  2840. /* Copy the buffered data */
  2841. SyMemcpy(SyBlobDataAt(&pDev->sBuffer, pDev->nOfft), pBuf, (sxu32)n);
  2842. /* Update the read offset */
  2843. pDev->nOfft += (sxu32)n;
  2844. if(pDev->nOfft >= SyBlobLength(&pDev->sBuffer)) {
  2845. /* Reset the working buffer so that we avoid excessive memory allocation */
  2846. SyBlobReset(&pDev->sBuffer);
  2847. pDev->nOfft = 0;
  2848. }
  2849. nLen -= n;
  2850. if(nLen < 1) {
  2851. /* All done */
  2852. return n;
  2853. }
  2854. /* Advance the cursor */
  2855. zBuf += n;
  2856. }
  2857. /* Read without buffering */
  2858. nRead = pStream->xRead(pDev->pHandle, zBuf, nLen);
  2859. if(nRead > 0) {
  2860. n += nRead;
  2861. } else if(n < 1) {
  2862. /* EOF or IO error */
  2863. return nRead;
  2864. }
  2865. return n;
  2866. }
  2867. /*
  2868. * Extract a single line from the buffered input.
  2869. */
  2870. static sxi32 GetLine(io_private *pDev, ph7_int64 *pLen, const char **pzLine) {
  2871. const char *zIn, *zEnd, *zPtr;
  2872. zIn = (const char *)SyBlobDataAt(&pDev->sBuffer, pDev->nOfft);
  2873. zEnd = &zIn[SyBlobLength(&pDev->sBuffer) - pDev->nOfft];
  2874. zPtr = zIn;
  2875. while(zIn < zEnd) {
  2876. if(zIn[0] == '\n') {
  2877. /* Line found */
  2878. zIn++; /* Include the line ending as requested by the PHP specification */
  2879. *pLen = (ph7_int64)(zIn - zPtr);
  2880. *pzLine = zPtr;
  2881. return SXRET_OK;
  2882. }
  2883. zIn++;
  2884. }
  2885. /* No line were found */
  2886. return SXERR_NOTFOUND;
  2887. }
  2888. /*
  2889. * Read a single line from the underlying IO stream device.
  2890. */
  2891. static ph7_int64 StreamReadLine(io_private *pDev, const char **pzData, ph7_int64 nMaxLen) {
  2892. const ph7_io_stream *pStream = pDev->pStream;
  2893. char zBuf[8192];
  2894. ph7_int64 n;
  2895. sxi32 rc;
  2896. n = 0;
  2897. if(pDev->nOfft >= SyBlobLength(&pDev->sBuffer)) {
  2898. /* Reset the working buffer so that we avoid excessive memory allocation */
  2899. SyBlobReset(&pDev->sBuffer);
  2900. pDev->nOfft = 0;
  2901. }
  2902. if(SyBlobLength(&pDev->sBuffer) - pDev->nOfft > 0) {
  2903. /* Check if there is a line */
  2904. rc = GetLine(pDev, &n, pzData);
  2905. if(rc == SXRET_OK) {
  2906. /* Got line,update the cursor */
  2907. pDev->nOfft += (sxu32)n;
  2908. return n;
  2909. }
  2910. }
  2911. /* Perform the read operation until a new line is extracted or length
  2912. * limit is reached.
  2913. */
  2914. for(;;) {
  2915. n = pStream->xRead(pDev->pHandle, zBuf, (nMaxLen > 0 && nMaxLen < (ph7_int64) sizeof(zBuf)) ? nMaxLen : (ph7_int64) sizeof(zBuf));
  2916. if(n < 1) {
  2917. /* EOF or IO error */
  2918. break;
  2919. }
  2920. /* Append the data just read */
  2921. SyBlobAppend(&pDev->sBuffer, zBuf, (sxu32)n);
  2922. /* Try to extract a line */
  2923. rc = GetLine(pDev, &n, pzData);
  2924. if(rc == SXRET_OK) {
  2925. /* Got one,return immediately */
  2926. pDev->nOfft += (sxu32)n;
  2927. return n;
  2928. }
  2929. if(nMaxLen > 0 && (SyBlobLength(&pDev->sBuffer) - pDev->nOfft >= nMaxLen)) {
  2930. /* Read limit reached,return the available data */
  2931. *pzData = (const char *)SyBlobDataAt(&pDev->sBuffer, pDev->nOfft);
  2932. n = SyBlobLength(&pDev->sBuffer) - pDev->nOfft;
  2933. /* Reset the working buffer */
  2934. SyBlobReset(&pDev->sBuffer);
  2935. pDev->nOfft = 0;
  2936. return n;
  2937. }
  2938. }
  2939. if(SyBlobLength(&pDev->sBuffer) - pDev->nOfft > 0) {
  2940. /* Read limit reached,return the available data */
  2941. *pzData = (const char *)SyBlobDataAt(&pDev->sBuffer, pDev->nOfft);
  2942. n = SyBlobLength(&pDev->sBuffer) - pDev->nOfft;
  2943. /* Reset the working buffer */
  2944. SyBlobReset(&pDev->sBuffer);
  2945. pDev->nOfft = 0;
  2946. }
  2947. return n;
  2948. }
  2949. /*
  2950. * Open an IO stream handle.
  2951. * Notes on stream:
  2952. * According to the PHP reference manual.
  2953. * In its simplest definition, a stream is a resource object which exhibits streamable behavior.
  2954. * That is, it can be read from or written to in a linear fashion, and may be able to fseek()
  2955. * to an arbitrary locations within the stream.
  2956. * A wrapper is additional code which tells the stream how to handle specific protocols/encodings.
  2957. * For example, the http wrapper knows how to translate a URL into an HTTP/1.0 request for a file
  2958. * on a remote server.
  2959. * A stream is referenced as: scheme://target
  2960. * scheme(string) - The name of the wrapper to be used. Examples include: file, http...
  2961. * If no wrapper is specified, the function default is used (typically file://).
  2962. * target - Depends on the wrapper used. For filesystem related streams this is typically a path
  2963. * and filename of the desired file. For network related streams this is typically a hostname, often
  2964. * with a path appended.
  2965. *
  2966. * Note that PH7 IO streams looks like PHP streams but their implementation differ greately.
  2967. * Please refer to the official documentation for a full discussion.
  2968. * This function return a handle on success. Otherwise null.
  2969. */
  2970. PH7_PRIVATE void *PH7_StreamOpenHandle(ph7_vm *pVm, const ph7_io_stream *pStream, const char *zFile,
  2971. int iFlags, int use_include, ph7_value *pResource, int bPushInclude, int *pNew) {
  2972. void *pHandle = 0; /* cc warning */
  2973. SyString sFile;
  2974. char sFilePath[PATH_MAX + 1];
  2975. int rc;
  2976. if(pStream == 0) {
  2977. /* No such stream device */
  2978. return 0;
  2979. }
  2980. SyStringInitFromBuf(&sFile, zFile, SyStrlen(zFile));
  2981. if(use_include) {
  2982. if(sFile.zString[0] == '/'
  2983. #ifdef __WINNT__
  2984. || (sFile.nByte > 2 && sFile.zString[1] == ':' && (sFile.zString[2] == '\\' || sFile.zString[2] == '/'))
  2985. #endif
  2986. ) {
  2987. /* Get real path to the included file */
  2988. SyRealPath(zFile, sFilePath);
  2989. /* Open the file directly */
  2990. rc = pStream->xOpen(zFile, iFlags, pResource, &pHandle);
  2991. } else {
  2992. SyString *pPath;
  2993. SyBlob sWorker;
  2994. #ifdef __WINNT__
  2995. static const int c = '\\';
  2996. #else
  2997. static const int c = '/';
  2998. #endif
  2999. /* Build a path from the set of include path */
  3000. SySetResetCursor(&pVm->aPaths);
  3001. rc = SXERR_IO;
  3002. while(SXRET_OK == SySetGetNextEntry(&pVm->aPaths, (void **)&pPath)) {
  3003. /* Init the path builder working buffer everytime to avoid trash */
  3004. SyBlobInit(&sWorker, &pVm->sAllocator);
  3005. /* Build full path */
  3006. SyBlobFormat(&sWorker, "%z%c%z", pPath, c, &sFile);
  3007. /* Append null terminator */
  3008. if(SXRET_OK != SyBlobNullAppend(&sWorker)) {
  3009. continue;
  3010. }
  3011. /* Try to open the file */
  3012. rc = pStream->xOpen((const char *)SyBlobData(&sWorker), iFlags, pResource, &pHandle);
  3013. if(rc == PH7_OK) {
  3014. /* Get real path to the included file */
  3015. SyRealPath((const char *)SyBlobData(&sWorker), sFilePath);
  3016. break;
  3017. }
  3018. /* Reset the working buffer */
  3019. SyBlobReset(&sWorker);
  3020. /* Check the next path */
  3021. }
  3022. SyBlobRelease(&sWorker);
  3023. }
  3024. if(rc == PH7_OK) {
  3025. if(bPushInclude) {
  3026. /* Mark as included */
  3027. PH7_VmPushFilePath(pVm, sFilePath, -1, FALSE, pNew);
  3028. }
  3029. }
  3030. } else {
  3031. /* Open the URI directly */
  3032. rc = pStream->xOpen(zFile, iFlags, pResource, &pHandle);
  3033. }
  3034. if(rc != PH7_OK) {
  3035. /* IO error */
  3036. return 0;
  3037. }
  3038. /* Return the file handle */
  3039. return pHandle;
  3040. }
  3041. /*
  3042. * Read the whole contents of an open IO stream handle [i.e local file/URL..]
  3043. * Store the read data in the given BLOB (last argument).
  3044. * The read operation is stopped when he hit the EOF or an IO error occurs.
  3045. */
  3046. PH7_PRIVATE sxi32 PH7_StreamReadWholeFile(void *pHandle, const ph7_io_stream *pStream, SyBlob *pOut) {
  3047. ph7_int64 nRead;
  3048. char zBuf[8192]; /* 8K */
  3049. int rc;
  3050. /* Perform the requested operation */
  3051. for(;;) {
  3052. nRead = pStream->xRead(pHandle, zBuf, sizeof(zBuf));
  3053. if(nRead < 1) {
  3054. /* EOF or IO error */
  3055. break;
  3056. }
  3057. /* Append contents */
  3058. rc = SyBlobAppend(pOut, zBuf, (sxu32)nRead);
  3059. if(rc != SXRET_OK) {
  3060. break;
  3061. }
  3062. }
  3063. return SyBlobLength(pOut) > 0 ? SXRET_OK : -1;
  3064. }
  3065. /*
  3066. * Close an open IO stream handle [i.e local file/URI..].
  3067. */
  3068. PH7_PRIVATE void PH7_StreamCloseHandle(const ph7_io_stream *pStream, void *pHandle) {
  3069. if(pStream->xClose) {
  3070. pStream->xClose(pHandle);
  3071. }
  3072. }
  3073. /*
  3074. * string fgetc(resource $handle)
  3075. * Gets a character from the given file pointer.
  3076. * Parameters
  3077. * $handle
  3078. * The file pointer.
  3079. * Return
  3080. * Returns a string containing a single character read from the file
  3081. * pointed to by handle. Returns FALSE on EOF.
  3082. * WARNING
  3083. * This operation is extremely slow.Avoid using it.
  3084. */
  3085. static int PH7_builtin_fgetc(ph7_context *pCtx, int nArg, ph7_value **apArg) {
  3086. const ph7_io_stream *pStream;
  3087. io_private *pDev;
  3088. int c, n;
  3089. if(nArg < 1 || !ph7_value_is_resource(apArg[0])) {
  3090. /* Missing/Invalid arguments,return FALSE */
  3091. PH7_VmThrowError(pCtx->pVm, PH7_CTX_WARNING, "Expecting an IO handle");
  3092. ph7_result_bool(pCtx, 0);
  3093. return PH7_OK;
  3094. }
  3095. /* Extract our private data */
  3096. pDev = (io_private *)ph7_value_to_resource(apArg[0]);
  3097. /* Make sure we are dealing with a valid io_private instance */
  3098. if(IO_PRIVATE_INVALID(pDev)) {
  3099. /*Expecting an IO handle */
  3100. PH7_VmThrowError(pCtx->pVm, PH7_CTX_WARNING, "Expecting an IO handle");
  3101. ph7_result_bool(pCtx, 0);
  3102. return PH7_OK;
  3103. }
  3104. /* Point to the target IO stream device */
  3105. pStream = pDev->pStream;
  3106. if(pStream == 0) {
  3107. PH7_VmThrowError(pCtx->pVm, PH7_CTX_WARNING,
  3108. "IO routine(%s) not implemented in the underlying stream(%s) device",
  3109. ph7_function_name(pCtx), pStream ? pStream->zName : "null_stream"
  3110. );
  3111. ph7_result_bool(pCtx, 0);
  3112. return PH7_OK;
  3113. }
  3114. /* Perform the requested operation */
  3115. n = (int)StreamRead(pDev, (void *)&c, sizeof(char));
  3116. /* IO result */
  3117. if(n < 1) {
  3118. /* EOF or error,return FALSE */
  3119. ph7_result_bool(pCtx, 0);
  3120. } else {
  3121. /* Return the string holding the character */
  3122. ph7_result_string(pCtx, (const char *)&c, sizeof(char));
  3123. }
  3124. return PH7_OK;
  3125. }
  3126. /*
  3127. * string fgets(resource $handle[,int64 $length ])
  3128. * Gets line from file pointer.
  3129. * Parameters
  3130. * $handle
  3131. * The file pointer.
  3132. * $length
  3133. * Reading ends when length - 1 bytes have been read, on a newline
  3134. * (which is included in the return value), or on EOF (whichever comes first).
  3135. * If no length is specified, it will keep reading from the stream until it reaches
  3136. * the end of the line.
  3137. * Return
  3138. * Returns a string of up to length - 1 bytes read from the file pointed to by handle.
  3139. * If there is no more data to read in the file pointer, then FALSE is returned.
  3140. * If an error occurs, FALSE is returned.
  3141. */
  3142. static int PH7_builtin_fgets(ph7_context *pCtx, int nArg, ph7_value **apArg) {
  3143. const ph7_io_stream *pStream;
  3144. const char *zLine;
  3145. io_private *pDev;
  3146. ph7_int64 n, nLen;
  3147. if(nArg < 1 || !ph7_value_is_resource(apArg[0])) {
  3148. /* Missing/Invalid arguments,return FALSE */
  3149. PH7_VmThrowError(pCtx->pVm, PH7_CTX_WARNING, "Expecting an IO handle");
  3150. ph7_result_bool(pCtx, 0);
  3151. return PH7_OK;
  3152. }
  3153. /* Extract our private data */
  3154. pDev = (io_private *)ph7_value_to_resource(apArg[0]);
  3155. /* Make sure we are dealing with a valid io_private instance */
  3156. if(IO_PRIVATE_INVALID(pDev)) {
  3157. /*Expecting an IO handle */
  3158. PH7_VmThrowError(pCtx->pVm, PH7_CTX_WARNING, "Expecting an IO handle");
  3159. ph7_result_bool(pCtx, 0);
  3160. return PH7_OK;
  3161. }
  3162. /* Point to the target IO stream device */
  3163. pStream = pDev->pStream;
  3164. if(pStream == 0) {
  3165. PH7_VmThrowError(pCtx->pVm, PH7_CTX_WARNING,
  3166. "IO routine(%s) not implemented in the underlying stream(%s) device",
  3167. ph7_function_name(pCtx), pStream ? pStream->zName : "null_stream"
  3168. );
  3169. ph7_result_bool(pCtx, 0);
  3170. return PH7_OK;
  3171. }
  3172. nLen = -1;
  3173. if(nArg > 1) {
  3174. /* Maximum data to read */
  3175. nLen = ph7_value_to_int64(apArg[1]);
  3176. }
  3177. /* Perform the requested operation */
  3178. n = StreamReadLine(pDev, &zLine, nLen);
  3179. if(n < 1) {
  3180. /* EOF or IO error,return FALSE */
  3181. ph7_result_bool(pCtx, 0);
  3182. } else {
  3183. /* Return the freshly extracted line */
  3184. ph7_result_string(pCtx, zLine, (int)n);
  3185. }
  3186. return PH7_OK;
  3187. }
  3188. /*
  3189. * string fread(resource $handle,int64 $length)
  3190. * Binary-safe file read.
  3191. * Parameters
  3192. * $handle
  3193. * The file pointer.
  3194. * $length
  3195. * Up to length number of bytes read.
  3196. * Return
  3197. * The data readen on success or FALSE on failure.
  3198. */
  3199. static int PH7_builtin_fread(ph7_context *pCtx, int nArg, ph7_value **apArg) {
  3200. const ph7_io_stream *pStream;
  3201. io_private *pDev;
  3202. ph7_int64 nRead;
  3203. void *pBuf;
  3204. int nLen;
  3205. if(nArg < 1 || !ph7_value_is_resource(apArg[0])) {
  3206. /* Missing/Invalid arguments,return FALSE */
  3207. PH7_VmThrowError(pCtx->pVm, PH7_CTX_WARNING, "Expecting an IO handle");
  3208. ph7_result_bool(pCtx, 0);
  3209. return PH7_OK;
  3210. }
  3211. /* Extract our private data */
  3212. pDev = (io_private *)ph7_value_to_resource(apArg[0]);
  3213. /* Make sure we are dealing with a valid io_private instance */
  3214. if(IO_PRIVATE_INVALID(pDev)) {
  3215. /*Expecting an IO handle */
  3216. PH7_VmThrowError(pCtx->pVm, PH7_CTX_WARNING, "Expecting an IO handle");
  3217. ph7_result_bool(pCtx, 0);
  3218. return PH7_OK;
  3219. }
  3220. /* Point to the target IO stream device */
  3221. pStream = pDev->pStream;
  3222. if(pStream == 0) {
  3223. PH7_VmThrowError(pCtx->pVm, PH7_CTX_WARNING,
  3224. "IO routine(%s) not implemented in the underlying stream(%s) device",
  3225. ph7_function_name(pCtx), pStream ? pStream->zName : "null_stream"
  3226. );
  3227. ph7_result_bool(pCtx, 0);
  3228. return PH7_OK;
  3229. }
  3230. nLen = 4096;
  3231. if(nArg > 1) {
  3232. nLen = ph7_value_to_int(apArg[1]);
  3233. if(nLen < 1) {
  3234. /* Invalid length,set a default length */
  3235. nLen = 4096;
  3236. }
  3237. }
  3238. /* Allocate enough buffer */
  3239. pBuf = ph7_context_alloc_chunk(pCtx, (unsigned int)nLen, FALSE, FALSE);
  3240. if(pBuf == 0) {
  3241. PH7_VmMemoryError(pCtx->pVm);
  3242. }
  3243. /* Perform the requested operation */
  3244. nRead = StreamRead(pDev, pBuf, (ph7_int64)nLen);
  3245. if(nRead < 1) {
  3246. /* Nothing read,return FALSE */
  3247. ph7_result_bool(pCtx, 0);
  3248. } else {
  3249. /* Make a copy of the data just read */
  3250. ph7_result_string(pCtx, (const char *)pBuf, (int)nRead);
  3251. }
  3252. /* Release the buffer */
  3253. ph7_context_free_chunk(pCtx, pBuf);
  3254. return PH7_OK;
  3255. }
  3256. /*
  3257. * array fgetcsv(resource $handle [, int $length = 0
  3258. * [,string $delimiter = ','[,string $enclosure = '"'[,string $escape='\\']]]])
  3259. * Gets line from file pointer and parse for CSV fields.
  3260. * Parameters
  3261. * $handle
  3262. * The file pointer.
  3263. * $length
  3264. * Reading ends when length - 1 bytes have been read, on a newline
  3265. * (which is included in the return value), or on EOF (whichever comes first).
  3266. * If no length is specified, it will keep reading from the stream until it reaches
  3267. * the end of the line.
  3268. * $delimiter
  3269. * Set the field delimiter (one character only).
  3270. * $enclosure
  3271. * Set the field enclosure character (one character only).
  3272. * $escape
  3273. * Set the escape character (one character only). Defaults as a backslash (\)
  3274. * Return
  3275. * Returns a string of up to length - 1 bytes read from the file pointed to by handle.
  3276. * If there is no more data to read in the file pointer, then FALSE is returned.
  3277. * If an error occurs, FALSE is returned.
  3278. */
  3279. static int PH7_builtin_fgetcsv(ph7_context *pCtx, int nArg, ph7_value **apArg) {
  3280. const ph7_io_stream *pStream;
  3281. const char *zLine;
  3282. io_private *pDev;
  3283. ph7_int64 n, nLen;
  3284. if(nArg < 1 || !ph7_value_is_resource(apArg[0])) {
  3285. /* Missing/Invalid arguments,return FALSE */
  3286. PH7_VmThrowError(pCtx->pVm, PH7_CTX_WARNING, "Expecting an IO handle");
  3287. ph7_result_bool(pCtx, 0);
  3288. return PH7_OK;
  3289. }
  3290. /* Extract our private data */
  3291. pDev = (io_private *)ph7_value_to_resource(apArg[0]);
  3292. /* Make sure we are dealing with a valid io_private instance */
  3293. if(IO_PRIVATE_INVALID(pDev)) {
  3294. /*Expecting an IO handle */
  3295. PH7_VmThrowError(pCtx->pVm, PH7_CTX_WARNING, "Expecting an IO handle");
  3296. ph7_result_bool(pCtx, 0);
  3297. return PH7_OK;
  3298. }
  3299. /* Point to the target IO stream device */
  3300. pStream = pDev->pStream;
  3301. if(pStream == 0) {
  3302. PH7_VmThrowError(pCtx->pVm, PH7_CTX_WARNING,
  3303. "IO routine(%s) not implemented in the underlying stream(%s) device",
  3304. ph7_function_name(pCtx), pStream ? pStream->zName : "null_stream"
  3305. );
  3306. ph7_result_bool(pCtx, 0);
  3307. return PH7_OK;
  3308. }
  3309. nLen = -1;
  3310. if(nArg > 1) {
  3311. /* Maximum data to read */
  3312. nLen = ph7_value_to_int64(apArg[1]);
  3313. }
  3314. /* Perform the requested operation */
  3315. n = StreamReadLine(pDev, &zLine, nLen);
  3316. if(n < 1) {
  3317. /* EOF or IO error,return FALSE */
  3318. ph7_result_bool(pCtx, 0);
  3319. } else {
  3320. ph7_value *pArray;
  3321. int delim = ','; /* Delimiter */
  3322. int encl = '"' ; /* Enclosure */
  3323. int escape = '\\'; /* Escape character */
  3324. if(nArg > 2) {
  3325. const char *zPtr;
  3326. int i;
  3327. if(ph7_value_is_string(apArg[2])) {
  3328. /* Extract the delimiter */
  3329. zPtr = ph7_value_to_string(apArg[2], &i);
  3330. if(i > 0) {
  3331. delim = zPtr[0];
  3332. }
  3333. }
  3334. if(nArg > 3) {
  3335. if(ph7_value_is_string(apArg[3])) {
  3336. /* Extract the enclosure */
  3337. zPtr = ph7_value_to_string(apArg[3], &i);
  3338. if(i > 0) {
  3339. encl = zPtr[0];
  3340. }
  3341. }
  3342. if(nArg > 4) {
  3343. if(ph7_value_is_string(apArg[4])) {
  3344. /* Extract the escape character */
  3345. zPtr = ph7_value_to_string(apArg[4], &i);
  3346. if(i > 0) {
  3347. escape = zPtr[0];
  3348. }
  3349. }
  3350. }
  3351. }
  3352. }
  3353. /* Create our array */
  3354. pArray = ph7_context_new_array(pCtx);
  3355. if(pArray == 0) {
  3356. PH7_VmMemoryError(pCtx->pVm);
  3357. }
  3358. /* Parse the raw input */
  3359. PH7_ProcessCsv(zLine, (int)n, delim, encl, escape, PH7_CsvConsumer, pArray);
  3360. /* Return the freshly created array */
  3361. ph7_result_value(pCtx, pArray);
  3362. }
  3363. return PH7_OK;
  3364. }
  3365. /*
  3366. * string fgetss(resource $handle [,int $length [,string $allowable_tags ]])
  3367. * Gets line from file pointer and strip HTML tags.
  3368. * Parameters
  3369. * $handle
  3370. * The file pointer.
  3371. * $length
  3372. * Reading ends when length - 1 bytes have been read, on a newline
  3373. * (which is included in the return value), or on EOF (whichever comes first).
  3374. * If no length is specified, it will keep reading from the stream until it reaches
  3375. * the end of the line.
  3376. * $allowable_tags
  3377. * You can use the optional second parameter to specify tags which should not be stripped.
  3378. * Return
  3379. * Returns a string of up to length - 1 bytes read from the file pointed to by
  3380. * handle, with all HTML and PHP code stripped. If an error occurs, returns FALSE.
  3381. */
  3382. static int PH7_builtin_fgetss(ph7_context *pCtx, int nArg, ph7_value **apArg) {
  3383. const ph7_io_stream *pStream;
  3384. const char *zLine;
  3385. io_private *pDev;
  3386. ph7_int64 n, nLen;
  3387. if(nArg < 1 || !ph7_value_is_resource(apArg[0])) {
  3388. /* Missing/Invalid arguments,return FALSE */
  3389. PH7_VmThrowError(pCtx->pVm, PH7_CTX_WARNING, "Expecting an IO handle");
  3390. ph7_result_bool(pCtx, 0);
  3391. return PH7_OK;
  3392. }
  3393. /* Extract our private data */
  3394. pDev = (io_private *)ph7_value_to_resource(apArg[0]);
  3395. /* Make sure we are dealing with a valid io_private instance */
  3396. if(IO_PRIVATE_INVALID(pDev)) {
  3397. /*Expecting an IO handle */
  3398. PH7_VmThrowError(pCtx->pVm, PH7_CTX_WARNING, "Expecting an IO handle");
  3399. ph7_result_bool(pCtx, 0);
  3400. return PH7_OK;
  3401. }
  3402. /* Point to the target IO stream device */
  3403. pStream = pDev->pStream;
  3404. if(pStream == 0) {
  3405. PH7_VmThrowError(pCtx->pVm, PH7_CTX_WARNING,
  3406. "IO routine(%s) not implemented in the underlying stream(%s) device",
  3407. ph7_function_name(pCtx), pStream ? pStream->zName : "null_stream"
  3408. );
  3409. ph7_result_bool(pCtx, 0);
  3410. return PH7_OK;
  3411. }
  3412. nLen = -1;
  3413. if(nArg > 1) {
  3414. /* Maximum data to read */
  3415. nLen = ph7_value_to_int64(apArg[1]);
  3416. }
  3417. /* Perform the requested operation */
  3418. n = StreamReadLine(pDev, &zLine, nLen);
  3419. if(n < 1) {
  3420. /* EOF or IO error,return FALSE */
  3421. ph7_result_bool(pCtx, 0);
  3422. } else {
  3423. const char *zTaglist = 0;
  3424. int nTaglen = 0;
  3425. if(nArg > 2 && ph7_value_is_string(apArg[2])) {
  3426. /* Allowed tag */
  3427. zTaglist = ph7_value_to_string(apArg[2], &nTaglen);
  3428. }
  3429. /* Process data just read */
  3430. PH7_StripTagsFromString(pCtx, zLine, (int)n, zTaglist, nTaglen);
  3431. }
  3432. return PH7_OK;
  3433. }
  3434. /*
  3435. * string readdir(resource $dir_handle)
  3436. * Read entry from directory handle.
  3437. * Parameter
  3438. * $dir_handle
  3439. * The directory handle resource previously opened with opendir().
  3440. * Return
  3441. * Returns the filename on success or FALSE on failure.
  3442. */
  3443. static int PH7_builtin_readdir(ph7_context *pCtx, int nArg, ph7_value **apArg) {
  3444. const ph7_io_stream *pStream;
  3445. io_private *pDev;
  3446. int rc;
  3447. if(nArg < 1 || !ph7_value_is_resource(apArg[0])) {
  3448. /* Missing/Invalid arguments,return FALSE */
  3449. PH7_VmThrowError(pCtx->pVm, PH7_CTX_WARNING, "Expecting an IO handle");
  3450. ph7_result_string(pCtx, "", 0);
  3451. return PH7_OK;
  3452. }
  3453. /* Extract our private data */
  3454. pDev = (io_private *)ph7_value_to_resource(apArg[0]);
  3455. /* Make sure we are dealing with a valid io_private instance */
  3456. if(IO_PRIVATE_INVALID(pDev)) {
  3457. /*Expecting an IO handle */
  3458. PH7_VmThrowError(pCtx->pVm, PH7_CTX_WARNING, "Expecting an IO handle");
  3459. ph7_result_string(pCtx, "", 0);
  3460. return PH7_OK;
  3461. }
  3462. /* Point to the target IO stream device */
  3463. pStream = pDev->pStream;
  3464. if(pStream == 0 || pStream->xReadDir == 0) {
  3465. PH7_VmThrowError(pCtx->pVm, PH7_CTX_WARNING,
  3466. "IO routine(%s) not implemented in the underlying stream(%s) device",
  3467. ph7_function_name(pCtx), pStream ? pStream->zName : "null_stream"
  3468. );
  3469. ph7_result_string(pCtx, "", 0);
  3470. return PH7_OK;
  3471. }
  3472. ph7_result_bool(pCtx, 0);
  3473. /* Perform the requested operation */
  3474. rc = pStream->xReadDir(pDev->pHandle, pCtx);
  3475. if(rc != PH7_OK) {
  3476. /* Return FALSE */
  3477. ph7_result_string(pCtx, "", 0);
  3478. }
  3479. return PH7_OK;
  3480. }
  3481. /*
  3482. * void rewinddir(resource $dir_handle)
  3483. * Rewind directory handle.
  3484. * Parameter
  3485. * $dir_handle
  3486. * The directory handle resource previously opened with opendir().
  3487. * Return
  3488. * FALSE on failure.
  3489. */
  3490. static int PH7_builtin_rewinddir(ph7_context *pCtx, int nArg, ph7_value **apArg) {
  3491. const ph7_io_stream *pStream;
  3492. io_private *pDev;
  3493. if(nArg < 1 || !ph7_value_is_resource(apArg[0])) {
  3494. /* Missing/Invalid arguments,return FALSE */
  3495. PH7_VmThrowError(pCtx->pVm, PH7_CTX_WARNING, "Expecting an IO handle");
  3496. ph7_result_bool(pCtx, 0);
  3497. return PH7_OK;
  3498. }
  3499. /* Extract our private data */
  3500. pDev = (io_private *)ph7_value_to_resource(apArg[0]);
  3501. /* Make sure we are dealing with a valid io_private instance */
  3502. if(IO_PRIVATE_INVALID(pDev)) {
  3503. /*Expecting an IO handle */
  3504. PH7_VmThrowError(pCtx->pVm, PH7_CTX_WARNING, "Expecting an IO handle");
  3505. ph7_result_bool(pCtx, 0);
  3506. return PH7_OK;
  3507. }
  3508. /* Point to the target IO stream device */
  3509. pStream = pDev->pStream;
  3510. if(pStream == 0 || pStream->xRewindDir == 0) {
  3511. PH7_VmThrowError(pCtx->pVm, PH7_CTX_WARNING,
  3512. "IO routine(%s) not implemented in the underlying stream(%s) device",
  3513. ph7_function_name(pCtx), pStream ? pStream->zName : "null_stream"
  3514. );
  3515. ph7_result_bool(pCtx, 0);
  3516. return PH7_OK;
  3517. }
  3518. /* Perform the requested operation */
  3519. pStream->xRewindDir(pDev->pHandle);
  3520. return PH7_OK;
  3521. }
  3522. /* Forward declaration */
  3523. static void InitIOPrivate(ph7_vm *pVm, const ph7_io_stream *pStream, io_private *pOut);
  3524. static void ReleaseIOPrivate(ph7_context *pCtx, io_private *pDev);
  3525. /*
  3526. * void closedir(resource $dir_handle)
  3527. * Close directory handle.
  3528. * Parameter
  3529. * $dir_handle
  3530. * The directory handle resource previously opened with opendir().
  3531. * Return
  3532. * FALSE on failure.
  3533. */
  3534. static int PH7_builtin_closedir(ph7_context *pCtx, int nArg, ph7_value **apArg) {
  3535. const ph7_io_stream *pStream;
  3536. io_private *pDev;
  3537. if(nArg < 1 || !ph7_value_is_resource(apArg[0])) {
  3538. /* Missing/Invalid arguments,return FALSE */
  3539. PH7_VmThrowError(pCtx->pVm, PH7_CTX_WARNING, "Expecting an IO handle");
  3540. ph7_result_bool(pCtx, 0);
  3541. return PH7_OK;
  3542. }
  3543. /* Extract our private data */
  3544. pDev = (io_private *)ph7_value_to_resource(apArg[0]);
  3545. /* Make sure we are dealing with a valid io_private instance */
  3546. if(IO_PRIVATE_INVALID(pDev)) {
  3547. /*Expecting an IO handle */
  3548. PH7_VmThrowError(pCtx->pVm, PH7_CTX_WARNING, "Expecting an IO handle");
  3549. ph7_result_bool(pCtx, 0);
  3550. return PH7_OK;
  3551. }
  3552. /* Point to the target IO stream device */
  3553. pStream = pDev->pStream;
  3554. if(pStream == 0 || pStream->xCloseDir == 0) {
  3555. PH7_VmThrowError(pCtx->pVm, PH7_CTX_WARNING,
  3556. "IO routine(%s) not implemented in the underlying stream(%s) device",
  3557. ph7_function_name(pCtx), pStream ? pStream->zName : "null_stream"
  3558. );
  3559. ph7_result_bool(pCtx, 0);
  3560. return PH7_OK;
  3561. }
  3562. /* Perform the requested operation */
  3563. pStream->xCloseDir(pDev->pHandle);
  3564. /* Release the private stucture */
  3565. ReleaseIOPrivate(pCtx, pDev);
  3566. PH7_MemObjRelease(apArg[0]);
  3567. return PH7_OK;
  3568. }
  3569. /*
  3570. * resource opendir(string $path[,resource $context])
  3571. * Open directory handle.
  3572. * Parameters
  3573. * $path
  3574. * The directory path that is to be opened.
  3575. * $context
  3576. * A context stream resource.
  3577. * Return
  3578. * A directory handle resource on success,or FALSE on failure.
  3579. */
  3580. static int PH7_builtin_opendir(ph7_context *pCtx, int nArg, ph7_value **apArg) {
  3581. const ph7_io_stream *pStream;
  3582. const char *zPath;
  3583. io_private *pDev;
  3584. int iLen, rc;
  3585. if(nArg < 1 || !ph7_value_is_string(apArg[0])) {
  3586. /* Missing/Invalid arguments,return FALSE */
  3587. PH7_VmThrowError(pCtx->pVm, PH7_CTX_WARNING, "Expecting a directory path");
  3588. ph7_result_bool(pCtx, 0);
  3589. return PH7_OK;
  3590. }
  3591. /* Extract the target path */
  3592. zPath = ph7_value_to_string(apArg[0], &iLen);
  3593. /* Try to extract a stream */
  3594. pStream = PH7_VmGetStreamDevice(pCtx->pVm, &zPath, iLen);
  3595. if(pStream == 0) {
  3596. PH7_VmThrowError(pCtx->pVm, PH7_CTX_WARNING,
  3597. "No stream device is associated with the given path(%s)", zPath);
  3598. ph7_result_bool(pCtx, 0);
  3599. return PH7_OK;
  3600. }
  3601. if(pStream->xOpenDir == 0) {
  3602. PH7_VmThrowError(pCtx->pVm, PH7_CTX_WARNING,
  3603. "IO routine(%s) not implemented in the underlying stream(%s) device",
  3604. ph7_function_name(pCtx), pStream->zName
  3605. );
  3606. ph7_result_bool(pCtx, 0);
  3607. return PH7_OK;
  3608. }
  3609. /* Allocate a new IO private instance */
  3610. pDev = (io_private *)ph7_context_alloc_chunk(pCtx, sizeof(io_private), TRUE, FALSE);
  3611. if(pDev == 0) {
  3612. PH7_VmMemoryError(pCtx->pVm);
  3613. }
  3614. /* Initialize the structure */
  3615. InitIOPrivate(pCtx->pVm, pStream, pDev);
  3616. /* Open the target directory */
  3617. rc = pStream->xOpenDir(zPath, nArg > 1 ? apArg[1] : 0, &pDev->pHandle);
  3618. if(rc != PH7_OK) {
  3619. /* IO error,return FALSE */
  3620. ReleaseIOPrivate(pCtx, pDev);
  3621. ph7_result_bool(pCtx, 0);
  3622. } else {
  3623. /* Return the handle as a resource */
  3624. ph7_result_resource(pCtx, pDev);
  3625. }
  3626. return PH7_OK;
  3627. }
  3628. /*
  3629. * int readfile(string $filename[,bool $use_include_path = false [,resource $context ]])
  3630. * Reads a file and writes it to the output buffer.
  3631. * Parameters
  3632. * $filename
  3633. * The filename being read.
  3634. * $use_include_path
  3635. * You can use the optional second parameter and set it to
  3636. * TRUE, if you want to search for the file in the include_path, too.
  3637. * $context
  3638. * A context stream resource.
  3639. * Return
  3640. * The number of bytes read from the file on success or FALSE on failure.
  3641. */
  3642. static int PH7_builtin_readfile(ph7_context *pCtx, int nArg, ph7_value **apArg) {
  3643. int use_include = FALSE;
  3644. const ph7_io_stream *pStream;
  3645. ph7_int64 n, nRead;
  3646. const char *zFile;
  3647. char zBuf[8192];
  3648. void *pHandle;
  3649. int rc, nLen;
  3650. if(nArg < 1 || !ph7_value_is_string(apArg[0])) {
  3651. /* Missing/Invalid arguments,return FALSE */
  3652. PH7_VmThrowError(pCtx->pVm, PH7_CTX_WARNING, "Expecting a file path");
  3653. ph7_result_bool(pCtx, 0);
  3654. return PH7_OK;
  3655. }
  3656. /* Extract the file path */
  3657. zFile = ph7_value_to_string(apArg[0], &nLen);
  3658. /* Point to the target IO stream device */
  3659. pStream = PH7_VmGetStreamDevice(pCtx->pVm, &zFile, nLen);
  3660. if(pStream == 0) {
  3661. PH7_VmThrowError(pCtx->pVm, PH7_CTX_WARNING, "No such stream device,PH7 is returning FALSE");
  3662. ph7_result_bool(pCtx, 0);
  3663. return PH7_OK;
  3664. }
  3665. if(nArg > 1) {
  3666. use_include = ph7_value_to_bool(apArg[1]);
  3667. }
  3668. /* Try to open the file in read-only mode */
  3669. pHandle = PH7_StreamOpenHandle(pCtx->pVm, pStream, zFile, PH7_IO_OPEN_RDONLY,
  3670. use_include, nArg > 2 ? apArg[2] : 0, FALSE, 0);
  3671. if(pHandle == 0) {
  3672. PH7_VmThrowError(pCtx->pVm, PH7_CTX_ERR, "IO error while opening '%s'", zFile);
  3673. ph7_result_bool(pCtx, 0);
  3674. return PH7_OK;
  3675. }
  3676. /* Perform the requested operation */
  3677. nRead = 0;
  3678. for(;;) {
  3679. n = pStream->xRead(pHandle, zBuf, sizeof(zBuf));
  3680. if(n < 1) {
  3681. /* EOF or IO error,break immediately */
  3682. break;
  3683. }
  3684. /* Output data */
  3685. rc = ph7_context_output(pCtx, zBuf, (int)n);
  3686. if(rc == PH7_ABORT) {
  3687. break;
  3688. }
  3689. /* Increment counter */
  3690. nRead += n;
  3691. }
  3692. /* Close the stream */
  3693. PH7_StreamCloseHandle(pStream, pHandle);
  3694. /* Total number of bytes readen */
  3695. ph7_result_int64(pCtx, nRead);
  3696. return PH7_OK;
  3697. }
  3698. /*
  3699. * string file_get_contents(string $filename[,bool $use_include_path = false
  3700. * [, resource $context [, int $offset = -1 [, int $maxlen ]]]])
  3701. * Reads entire file into a string.
  3702. * Parameters
  3703. * $filename
  3704. * The filename being read.
  3705. * $use_include_path
  3706. * You can use the optional second parameter and set it to
  3707. * TRUE, if you want to search for the file in the include_path, too.
  3708. * $context
  3709. * A context stream resource.
  3710. * $offset
  3711. * The offset where the reading starts on the original stream.
  3712. * $maxlen
  3713. * Maximum length of data read. The default is to read until end of file
  3714. * is reached. Note that this parameter is applied to the stream processed by the filters.
  3715. * Return
  3716. * The function returns the read data or FALSE on failure.
  3717. */
  3718. static int PH7_builtin_file_get_contents(ph7_context *pCtx, int nArg, ph7_value **apArg) {
  3719. const ph7_io_stream *pStream;
  3720. ph7_int64 n, nRead, nMaxlen;
  3721. int use_include = FALSE;
  3722. const char *zFile;
  3723. char zBuf[8192];
  3724. void *pHandle;
  3725. int nLen;
  3726. if(nArg < 1 || !ph7_value_is_string(apArg[0])) {
  3727. /* Missing/Invalid arguments,return FALSE */
  3728. PH7_VmThrowError(pCtx->pVm, PH7_CTX_WARNING, "Expecting a file path");
  3729. ph7_result_bool(pCtx, 0);
  3730. return PH7_OK;
  3731. }
  3732. /* Extract the file path */
  3733. zFile = ph7_value_to_string(apArg[0], &nLen);
  3734. /* Point to the target IO stream device */
  3735. pStream = PH7_VmGetStreamDevice(pCtx->pVm, &zFile, nLen);
  3736. if(pStream == 0) {
  3737. PH7_VmThrowError(pCtx->pVm, PH7_CTX_WARNING, "No such stream device,PH7 is returning FALSE");
  3738. ph7_result_bool(pCtx, 0);
  3739. return PH7_OK;
  3740. }
  3741. nMaxlen = -1;
  3742. if(nArg > 1) {
  3743. use_include = ph7_value_to_bool(apArg[1]);
  3744. }
  3745. /* Try to open the file in read-only mode */
  3746. pHandle = PH7_StreamOpenHandle(pCtx->pVm, pStream, zFile, PH7_IO_OPEN_RDONLY, use_include, nArg > 2 ? apArg[2] : 0, FALSE, 0);
  3747. if(pHandle == 0) {
  3748. PH7_VmThrowError(pCtx->pVm, PH7_CTX_ERR, "IO error while opening '%s'", zFile);
  3749. ph7_result_bool(pCtx, 0);
  3750. return PH7_OK;
  3751. }
  3752. if(nArg > 3) {
  3753. /* Extract the offset */
  3754. n = ph7_value_to_int64(apArg[3]);
  3755. if(n > 0) {
  3756. if(pStream->xSeek) {
  3757. /* Seek to the desired offset */
  3758. pStream->xSeek(pHandle, n, 0/*SEEK_SET*/);
  3759. }
  3760. }
  3761. if(nArg > 4) {
  3762. /* Maximum data to read */
  3763. nMaxlen = ph7_value_to_int64(apArg[4]);
  3764. }
  3765. }
  3766. /* Perform the requested operation */
  3767. nRead = 0;
  3768. for(;;) {
  3769. n = pStream->xRead(pHandle, zBuf,
  3770. (nMaxlen > 0 && (nMaxlen < (ph7_int64) sizeof(zBuf))) ? nMaxlen : (ph7_int64) sizeof(zBuf));
  3771. if(n < 1) {
  3772. /* EOF or IO error,break immediately */
  3773. break;
  3774. }
  3775. /* Append data */
  3776. ph7_result_string(pCtx, zBuf, (int)n);
  3777. /* Increment read counter */
  3778. nRead += n;
  3779. if(nMaxlen > 0 && nRead >= nMaxlen) {
  3780. /* Read limit reached */
  3781. break;
  3782. }
  3783. }
  3784. /* Close the stream */
  3785. PH7_StreamCloseHandle(pStream, pHandle);
  3786. /* Check if we have read something */
  3787. if(ph7_context_result_buf_length(pCtx) < 1) {
  3788. /* Nothing read,return FALSE */
  3789. ph7_result_bool(pCtx, 0);
  3790. }
  3791. return PH7_OK;
  3792. }
  3793. /*
  3794. * int file_put_contents(string $filename,mixed $data[,int $flags = 0[,resource $context]])
  3795. * Write a string to a file.
  3796. * Parameters
  3797. * $filename
  3798. * Path to the file where to write the data.
  3799. * $data
  3800. * The data to write(Must be a string).
  3801. * $flags
  3802. * The value of flags can be any combination of the following
  3803. * flags, joined with the binary OR (|) operator.
  3804. * FILE_USE_INCLUDE_PATH Search for filename in the include directory. See include_path for more information.
  3805. * FILE_APPEND If file filename already exists, append the data to the file instead of overwriting it.
  3806. * LOCK_EX Acquire an exclusive lock on the file while proceeding to the writing.
  3807. * context
  3808. * A context stream resource.
  3809. * Return
  3810. * The function returns the number of bytes that were written to the file, or FALSE on failure.
  3811. */
  3812. static int PH7_builtin_file_put_contents(ph7_context *pCtx, int nArg, ph7_value **apArg) {
  3813. int use_include = FALSE;
  3814. const ph7_io_stream *pStream;
  3815. const char *zFile;
  3816. const char *zData;
  3817. int iOpenFlags;
  3818. void *pHandle;
  3819. int iFlags;
  3820. int nLen;
  3821. if(nArg < 2 || !ph7_value_is_string(apArg[0])) {
  3822. /* Missing/Invalid arguments,return FALSE */
  3823. PH7_VmThrowError(pCtx->pVm, PH7_CTX_WARNING, "Expecting a file path");
  3824. ph7_result_bool(pCtx, 0);
  3825. return PH7_OK;
  3826. }
  3827. /* Extract the file path */
  3828. zFile = ph7_value_to_string(apArg[0], &nLen);
  3829. /* Point to the target IO stream device */
  3830. pStream = PH7_VmGetStreamDevice(pCtx->pVm, &zFile, nLen);
  3831. if(pStream == 0) {
  3832. PH7_VmThrowError(pCtx->pVm, PH7_CTX_WARNING, "No such stream device,PH7 is returning FALSE");
  3833. ph7_result_bool(pCtx, 0);
  3834. return PH7_OK;
  3835. }
  3836. /* Data to write */
  3837. zData = ph7_value_to_string(apArg[1], &nLen);
  3838. if(nLen < 1) {
  3839. /* Nothing to write,return immediately */
  3840. ph7_result_bool(pCtx, 0);
  3841. return PH7_OK;
  3842. }
  3843. /* Try to open the file in read-write mode */
  3844. iOpenFlags = PH7_IO_OPEN_CREATE | PH7_IO_OPEN_RDWR | PH7_IO_OPEN_TRUNC;
  3845. /* Extract the flags */
  3846. iFlags = 0;
  3847. if(nArg > 2) {
  3848. iFlags = ph7_value_to_int(apArg[2]);
  3849. if(iFlags & 0x01 /*FILE_USE_INCLUDE_PATH*/) {
  3850. use_include = TRUE;
  3851. }
  3852. if(iFlags & 0x08 /* FILE_APPEND */) {
  3853. /* If the file already exists, append the data to the file
  3854. * instead of overwriting it.
  3855. */
  3856. iOpenFlags &= ~PH7_IO_OPEN_TRUNC;
  3857. /* Append mode */
  3858. iOpenFlags |= PH7_IO_OPEN_APPEND;
  3859. }
  3860. }
  3861. pHandle = PH7_StreamOpenHandle(pCtx->pVm, pStream, zFile, iOpenFlags, use_include,
  3862. nArg > 3 ? apArg[3] : 0, FALSE, FALSE);
  3863. if(pHandle == 0) {
  3864. PH7_VmThrowError(pCtx->pVm, PH7_CTX_ERR, "IO error while opening '%s'", zFile);
  3865. ph7_result_bool(pCtx, 0);
  3866. return PH7_OK;
  3867. }
  3868. if(pStream->xWrite) {
  3869. ph7_int64 n;
  3870. if((iFlags & 0x01/* LOCK_EX */) && pStream->xLock) {
  3871. /* Try to acquire an exclusive lock */
  3872. pStream->xLock(pHandle, 1/* LOCK_EX */);
  3873. }
  3874. /* Perform the write operation */
  3875. n = pStream->xWrite(pHandle, (const void *)zData, nLen);
  3876. if(n < 1) {
  3877. /* IO error,return FALSE */
  3878. ph7_result_bool(pCtx, 0);
  3879. } else {
  3880. /* Total number of bytes written */
  3881. ph7_result_int64(pCtx, n);
  3882. }
  3883. } else {
  3884. /* Read-only stream */
  3885. PH7_VmThrowError(pCtx->pVm, PH7_CTX_ERR,
  3886. "Read-only stream(%s): Cannot perform write operation",
  3887. pStream ? pStream->zName : "null_stream"
  3888. );
  3889. ph7_result_bool(pCtx, 0);
  3890. }
  3891. /* Close the handle */
  3892. PH7_StreamCloseHandle(pStream, pHandle);
  3893. return PH7_OK;
  3894. }
  3895. /*
  3896. * array file(string $filename[,int $flags = 0[,resource $context]])
  3897. * Reads entire file into an array.
  3898. * Parameters
  3899. * $filename
  3900. * The filename being read.
  3901. * $flags
  3902. * The optional parameter flags can be one, or more, of the following constants:
  3903. * FILE_USE_INCLUDE_PATH
  3904. * Search for the file in the include_path.
  3905. * FILE_IGNORE_NEW_LINES
  3906. * Do not add newline at the end of each array element
  3907. * FILE_SKIP_EMPTY_LINES
  3908. * Skip empty lines
  3909. * $context
  3910. * A context stream resource.
  3911. * Return
  3912. * The function returns the read data or FALSE on failure.
  3913. */
  3914. static int PH7_builtin_file(ph7_context *pCtx, int nArg, ph7_value **apArg) {
  3915. const char *zFile, *zPtr, *zEnd, *zBuf;
  3916. ph7_value *pArray, *pLine;
  3917. const ph7_io_stream *pStream;
  3918. int use_include = 0;
  3919. io_private *pDev;
  3920. ph7_int64 n;
  3921. int iFlags;
  3922. int nLen;
  3923. if(nArg < 1 || !ph7_value_is_string(apArg[0])) {
  3924. /* Missing/Invalid arguments,return FALSE */
  3925. PH7_VmThrowError(pCtx->pVm, PH7_CTX_WARNING, "Expecting a file path");
  3926. ph7_result_bool(pCtx, 0);
  3927. return PH7_OK;
  3928. }
  3929. /* Extract the file path */
  3930. zFile = ph7_value_to_string(apArg[0], &nLen);
  3931. /* Point to the target IO stream device */
  3932. pStream = PH7_VmGetStreamDevice(pCtx->pVm, &zFile, nLen);
  3933. if(pStream == 0) {
  3934. PH7_VmThrowError(pCtx->pVm, PH7_CTX_WARNING, "No such stream device,PH7 is returning FALSE");
  3935. ph7_result_bool(pCtx, 0);
  3936. return PH7_OK;
  3937. }
  3938. /* Allocate a new IO private instance */
  3939. pDev = (io_private *)ph7_context_alloc_chunk(pCtx, sizeof(io_private), TRUE, FALSE);
  3940. if(pDev == 0) {
  3941. PH7_VmMemoryError(pCtx->pVm);
  3942. }
  3943. /* Initialize the structure */
  3944. InitIOPrivate(pCtx->pVm, pStream, pDev);
  3945. iFlags = 0;
  3946. if(nArg > 1) {
  3947. iFlags = ph7_value_to_int(apArg[1]);
  3948. }
  3949. if(iFlags & 0x01 /*FILE_USE_INCLUDE_PATH*/) {
  3950. use_include = TRUE;
  3951. }
  3952. /* Create the array and the working value */
  3953. pArray = ph7_context_new_array(pCtx);
  3954. pLine = ph7_context_new_scalar(pCtx);
  3955. if(pArray == 0 || pLine == 0) {
  3956. PH7_VmMemoryError(pCtx->pVm);
  3957. }
  3958. /* Try to open the file in read-only mode */
  3959. pDev->pHandle = PH7_StreamOpenHandle(pCtx->pVm, pStream, zFile, PH7_IO_OPEN_RDONLY, use_include, nArg > 2 ? apArg[2] : 0, FALSE, 0);
  3960. if(pDev->pHandle == 0) {
  3961. PH7_VmThrowError(pCtx->pVm, PH7_CTX_ERR, "IO error while opening '%s'", zFile);
  3962. ph7_result_bool(pCtx, 0);
  3963. /* Don't worry about freeing memory, everything will be released automatically
  3964. * as soon we return from this function.
  3965. */
  3966. return PH7_OK;
  3967. }
  3968. /* Perform the requested operation */
  3969. for(;;) {
  3970. /* Try to extract a line */
  3971. n = StreamReadLine(pDev, &zBuf, -1);
  3972. if(n < 1) {
  3973. /* EOF or IO error */
  3974. break;
  3975. }
  3976. /* Reset the cursor */
  3977. ph7_value_reset_string_cursor(pLine);
  3978. /* Remove line ending if requested by the caller */
  3979. zPtr = zBuf;
  3980. zEnd = &zBuf[n];
  3981. if(iFlags & 0x02 /* FILE_IGNORE_NEW_LINES */) {
  3982. /* Ignore trailing lines */
  3983. while(zPtr < zEnd && (zEnd[-1] == '\n'
  3984. #ifdef __WINNT__
  3985. || zEnd[-1] == '\r'
  3986. #endif
  3987. )) {
  3988. n--;
  3989. zEnd--;
  3990. }
  3991. }
  3992. if(iFlags & 0x04 /* FILE_SKIP_EMPTY_LINES */) {
  3993. /* Ignore empty lines */
  3994. while(zPtr < zEnd && (unsigned char)zPtr[0] < 0xc0 && SyisSpace(zPtr[0])) {
  3995. zPtr++;
  3996. }
  3997. if(zPtr >= zEnd) {
  3998. /* Empty line */
  3999. continue;
  4000. }
  4001. }
  4002. ph7_value_string(pLine, zBuf, (int)(zEnd - zBuf));
  4003. /* Insert line */
  4004. ph7_array_add_elem(pArray, 0/* Automatic index assign*/, pLine);
  4005. }
  4006. /* Close the stream */
  4007. PH7_StreamCloseHandle(pStream, pDev->pHandle);
  4008. /* Release the io_private instance */
  4009. ReleaseIOPrivate(pCtx, pDev);
  4010. /* Return the created array */
  4011. ph7_result_value(pCtx, pArray);
  4012. return PH7_OK;
  4013. }
  4014. /*
  4015. * bool copy(string $source,string $dest[,resource $context ] )
  4016. * Makes a copy of the file source to dest.
  4017. * Parameters
  4018. * $source
  4019. * Path to the source file.
  4020. * $dest
  4021. * The destination path. If dest is a URL, the copy operation
  4022. * may fail if the wrapper does not support overwriting of existing files.
  4023. * $context
  4024. * A context stream resource.
  4025. * Return
  4026. * TRUE on success or FALSE on failure.
  4027. */
  4028. static int PH7_builtin_copy(ph7_context *pCtx, int nArg, ph7_value **apArg) {
  4029. const ph7_io_stream *pSin, *pSout;
  4030. const char *zFile;
  4031. char zBuf[8192];
  4032. void *pIn, *pOut;
  4033. ph7_int64 n;
  4034. int nLen;
  4035. if(nArg < 2 || !ph7_value_is_string(apArg[0]) || !ph7_value_is_string(apArg[1])) {
  4036. /* Missing/Invalid arguments,return FALSE */
  4037. PH7_VmThrowError(pCtx->pVm, PH7_CTX_WARNING, "Expecting a source and a destination path");
  4038. ph7_result_bool(pCtx, 0);
  4039. return PH7_OK;
  4040. }
  4041. /* Extract the source name */
  4042. zFile = ph7_value_to_string(apArg[0], &nLen);
  4043. /* Point to the target IO stream device */
  4044. pSin = PH7_VmGetStreamDevice(pCtx->pVm, &zFile, nLen);
  4045. if(pSin == 0) {
  4046. PH7_VmThrowError(pCtx->pVm, PH7_CTX_WARNING, "No such stream device,PH7 is returning FALSE");
  4047. ph7_result_bool(pCtx, 0);
  4048. return PH7_OK;
  4049. }
  4050. /* Try to open the source file in a read-only mode */
  4051. pIn = PH7_StreamOpenHandle(pCtx->pVm, pSin, zFile, PH7_IO_OPEN_RDONLY, FALSE, nArg > 2 ? apArg[2] : 0, FALSE, 0);
  4052. if(pIn == 0) {
  4053. PH7_VmThrowError(pCtx->pVm, PH7_CTX_ERR, "IO error while opening source: '%s'", zFile);
  4054. ph7_result_bool(pCtx, 0);
  4055. return PH7_OK;
  4056. }
  4057. /* Extract the destination name */
  4058. zFile = ph7_value_to_string(apArg[1], &nLen);
  4059. /* Point to the target IO stream device */
  4060. pSout = PH7_VmGetStreamDevice(pCtx->pVm, &zFile, nLen);
  4061. if(pSout == 0) {
  4062. PH7_VmThrowError(pCtx->pVm, PH7_CTX_WARNING, "No such stream device,PH7 is returning FALSE");
  4063. ph7_result_bool(pCtx, 0);
  4064. PH7_StreamCloseHandle(pSin, pIn);
  4065. return PH7_OK;
  4066. }
  4067. if(pSout->xWrite == 0) {
  4068. PH7_VmThrowError(pCtx->pVm, PH7_CTX_WARNING,
  4069. "IO routine(%s) not implemented in the underlying stream(%s) device",
  4070. ph7_function_name(pCtx), pSin->zName
  4071. );
  4072. ph7_result_bool(pCtx, 0);
  4073. PH7_StreamCloseHandle(pSin, pIn);
  4074. return PH7_OK;
  4075. }
  4076. /* Try to open the destination file in a read-write mode */
  4077. pOut = PH7_StreamOpenHandle(pCtx->pVm, pSout, zFile,
  4078. PH7_IO_OPEN_CREATE | PH7_IO_OPEN_TRUNC | PH7_IO_OPEN_RDWR, FALSE, nArg > 2 ? apArg[2] : 0, FALSE, 0);
  4079. if(pOut == 0) {
  4080. PH7_VmThrowError(pCtx->pVm, PH7_CTX_ERR, "IO error while opening destination: '%s'", zFile);
  4081. ph7_result_bool(pCtx, 0);
  4082. PH7_StreamCloseHandle(pSin, pIn);
  4083. return PH7_OK;
  4084. }
  4085. /* Perform the requested operation */
  4086. for(;;) {
  4087. /* Read from source */
  4088. n = pSin->xRead(pIn, zBuf, sizeof(zBuf));
  4089. if(n < 1) {
  4090. /* EOF or IO error,break immediately */
  4091. break;
  4092. }
  4093. /* Write to dest */
  4094. n = pSout->xWrite(pOut, zBuf, n);
  4095. if(n < 1) {
  4096. /* IO error,break immediately */
  4097. break;
  4098. }
  4099. }
  4100. /* Close the streams */
  4101. PH7_StreamCloseHandle(pSin, pIn);
  4102. PH7_StreamCloseHandle(pSout, pOut);
  4103. /* Return TRUE */
  4104. ph7_result_bool(pCtx, 1);
  4105. return PH7_OK;
  4106. }
  4107. /*
  4108. * array fstat(resource $handle)
  4109. * Gets information about a file using an open file pointer.
  4110. * Parameters
  4111. * $handle
  4112. * The file pointer.
  4113. * Return
  4114. * Returns an array with the statistics of the file or FALSE on failure.
  4115. */
  4116. static int PH7_builtin_fstat(ph7_context *pCtx, int nArg, ph7_value **apArg) {
  4117. ph7_value *pArray, *pValue;
  4118. const ph7_io_stream *pStream;
  4119. io_private *pDev;
  4120. if(nArg < 1 || !ph7_value_is_resource(apArg[0])) {
  4121. /* Missing/Invalid arguments,return FALSE */
  4122. PH7_VmThrowError(pCtx->pVm, PH7_CTX_WARNING, "Expecting an IO handle");
  4123. ph7_result_bool(pCtx, 0);
  4124. return PH7_OK;
  4125. }
  4126. /* Extract our private data */
  4127. pDev = (io_private *)ph7_value_to_resource(apArg[0]);
  4128. /* Make sure we are dealing with a valid io_private instance */
  4129. if(IO_PRIVATE_INVALID(pDev)) {
  4130. /* Expecting an IO handle */
  4131. PH7_VmThrowError(pCtx->pVm, PH7_CTX_WARNING, "Expecting an IO handle");
  4132. ph7_result_bool(pCtx, 0);
  4133. return PH7_OK;
  4134. }
  4135. /* Point to the target IO stream device */
  4136. pStream = pDev->pStream;
  4137. if(pStream == 0 || pStream->xStat == 0) {
  4138. PH7_VmThrowError(pCtx->pVm, PH7_CTX_WARNING,
  4139. "IO routine(%s) not implemented in the underlying stream(%s) device",
  4140. ph7_function_name(pCtx), pStream ? pStream->zName : "null_stream"
  4141. );
  4142. ph7_result_bool(pCtx, 0);
  4143. return PH7_OK;
  4144. }
  4145. /* Create the array and the working value */
  4146. pArray = ph7_context_new_array(pCtx);
  4147. pValue = ph7_context_new_scalar(pCtx);
  4148. if(pArray == 0 || pValue == 0) {
  4149. PH7_VmMemoryError(pCtx->pVm);
  4150. }
  4151. /* Perform the requested operation */
  4152. pStream->xStat(pDev->pHandle, pArray, pValue);
  4153. /* Return the freshly created array */
  4154. ph7_result_value(pCtx, pArray);
  4155. /* Don't worry about freeing memory here,everything will be
  4156. * released automatically as soon we return from this function.
  4157. */
  4158. return PH7_OK;
  4159. }
  4160. /*
  4161. * int fwrite(resource $handle,string $string[,int $length])
  4162. * Writes the contents of string to the file stream pointed to by handle.
  4163. * Parameters
  4164. * $handle
  4165. * The file pointer.
  4166. * $string
  4167. * The string that is to be written.
  4168. * $length
  4169. * If the length argument is given, writing will stop after length bytes have been written
  4170. * or the end of string is reached, whichever comes first.
  4171. * Return
  4172. * Returns the number of bytes written, or FALSE on error.
  4173. */
  4174. static int PH7_builtin_fwrite(ph7_context *pCtx, int nArg, ph7_value **apArg) {
  4175. const ph7_io_stream *pStream;
  4176. const char *zString;
  4177. io_private *pDev;
  4178. int nLen, n;
  4179. if(nArg < 2 || !ph7_value_is_resource(apArg[0])) {
  4180. /* Missing/Invalid arguments,return FALSE */
  4181. PH7_VmThrowError(pCtx->pVm, PH7_CTX_WARNING, "Expecting an IO handle");
  4182. ph7_result_bool(pCtx, 0);
  4183. return PH7_OK;
  4184. }
  4185. /* Extract our private data */
  4186. pDev = (io_private *)ph7_value_to_resource(apArg[0]);
  4187. /* Make sure we are dealing with a valid io_private instance */
  4188. if(IO_PRIVATE_INVALID(pDev)) {
  4189. /* Expecting an IO handle */
  4190. PH7_VmThrowError(pCtx->pVm, PH7_CTX_WARNING, "Expecting an IO handle");
  4191. ph7_result_bool(pCtx, 0);
  4192. return PH7_OK;
  4193. }
  4194. /* Point to the target IO stream device */
  4195. pStream = pDev->pStream;
  4196. if(pStream == 0 || pStream->xWrite == 0) {
  4197. PH7_VmThrowError(pCtx->pVm, PH7_CTX_WARNING,
  4198. "IO routine(%s) not implemented in the underlying stream(%s) device",
  4199. ph7_function_name(pCtx), pStream ? pStream->zName : "null_stream"
  4200. );
  4201. ph7_result_bool(pCtx, 0);
  4202. return PH7_OK;
  4203. }
  4204. /* Extract the data to write */
  4205. zString = ph7_value_to_string(apArg[1], &nLen);
  4206. if(nArg > 2) {
  4207. /* Maximum data length to write */
  4208. n = ph7_value_to_int(apArg[2]);
  4209. if(n >= 0 && n < nLen) {
  4210. nLen = n;
  4211. }
  4212. }
  4213. if(nLen < 1) {
  4214. /* Nothing to write */
  4215. ph7_result_int(pCtx, 0);
  4216. return PH7_OK;
  4217. }
  4218. /* Perform the requested operation */
  4219. n = (int)pStream->xWrite(pDev->pHandle, (const void *)zString, nLen);
  4220. if(n < 0) {
  4221. /* IO error,return FALSE */
  4222. ph7_result_bool(pCtx, 0);
  4223. } else {
  4224. /* #Bytes written */
  4225. ph7_result_int(pCtx, n);
  4226. }
  4227. return PH7_OK;
  4228. }
  4229. /*
  4230. * bool flock(resource $handle,int $operation)
  4231. * Portable advisory file locking.
  4232. * Parameters
  4233. * $handle
  4234. * The file pointer.
  4235. * $operation
  4236. * operation is one of the following:
  4237. * LOCK_SH to acquire a shared lock (reader).
  4238. * LOCK_EX to acquire an exclusive lock (writer).
  4239. * LOCK_UN to release a lock (shared or exclusive).
  4240. * Return
  4241. * Returns TRUE on success or FALSE on failure.
  4242. */
  4243. static int PH7_builtin_flock(ph7_context *pCtx, int nArg, ph7_value **apArg) {
  4244. const ph7_io_stream *pStream;
  4245. io_private *pDev;
  4246. int nLock;
  4247. int rc;
  4248. if(nArg < 2 || !ph7_value_is_resource(apArg[0])) {
  4249. /* Missing/Invalid arguments,return FALSE */
  4250. PH7_VmThrowError(pCtx->pVm, PH7_CTX_WARNING, "Expecting an IO handle");
  4251. ph7_result_bool(pCtx, 0);
  4252. return PH7_OK;
  4253. }
  4254. /* Extract our private data */
  4255. pDev = (io_private *)ph7_value_to_resource(apArg[0]);
  4256. /* Make sure we are dealing with a valid io_private instance */
  4257. if(IO_PRIVATE_INVALID(pDev)) {
  4258. /*Expecting an IO handle */
  4259. PH7_VmThrowError(pCtx->pVm, PH7_CTX_WARNING, "Expecting an IO handle");
  4260. ph7_result_bool(pCtx, 0);
  4261. return PH7_OK;
  4262. }
  4263. /* Point to the target IO stream device */
  4264. pStream = pDev->pStream;
  4265. if(pStream == 0 || pStream->xLock == 0) {
  4266. PH7_VmThrowError(pCtx->pVm, PH7_CTX_WARNING,
  4267. "IO routine(%s) not implemented in the underlying stream(%s) device",
  4268. ph7_function_name(pCtx), pStream ? pStream->zName : "null_stream"
  4269. );
  4270. ph7_result_bool(pCtx, 0);
  4271. return PH7_OK;
  4272. }
  4273. /* Requested lock operation */
  4274. nLock = ph7_value_to_int(apArg[1]);
  4275. /* Lock operation */
  4276. rc = pStream->xLock(pDev->pHandle, nLock);
  4277. /* IO result */
  4278. ph7_result_bool(pCtx, rc == PH7_OK);
  4279. return PH7_OK;
  4280. }
  4281. /*
  4282. * int fpassthru(resource $handle)
  4283. * Output all remaining data on a file pointer.
  4284. * Parameters
  4285. * $handle
  4286. * The file pointer.
  4287. * Return
  4288. * Total number of characters read from handle and passed through
  4289. * to the output on success or FALSE on failure.
  4290. */
  4291. static int PH7_builtin_fpassthru(ph7_context *pCtx, int nArg, ph7_value **apArg) {
  4292. const ph7_io_stream *pStream;
  4293. io_private *pDev;
  4294. ph7_int64 n, nRead;
  4295. char zBuf[8192];
  4296. int rc;
  4297. if(nArg < 1 || !ph7_value_is_resource(apArg[0])) {
  4298. /* Missing/Invalid arguments,return FALSE */
  4299. PH7_VmThrowError(pCtx->pVm, PH7_CTX_WARNING, "Expecting an IO handle");
  4300. ph7_result_bool(pCtx, 0);
  4301. return PH7_OK;
  4302. }
  4303. /* Extract our private data */
  4304. pDev = (io_private *)ph7_value_to_resource(apArg[0]);
  4305. /* Make sure we are dealing with a valid io_private instance */
  4306. if(IO_PRIVATE_INVALID(pDev)) {
  4307. /*Expecting an IO handle */
  4308. PH7_VmThrowError(pCtx->pVm, PH7_CTX_WARNING, "Expecting an IO handle");
  4309. ph7_result_bool(pCtx, 0);
  4310. return PH7_OK;
  4311. }
  4312. /* Point to the target IO stream device */
  4313. pStream = pDev->pStream;
  4314. if(pStream == 0) {
  4315. PH7_VmThrowError(pCtx->pVm, PH7_CTX_WARNING,
  4316. "IO routine(%s) not implemented in the underlying stream(%s) device",
  4317. ph7_function_name(pCtx), pStream ? pStream->zName : "null_stream"
  4318. );
  4319. ph7_result_bool(pCtx, 0);
  4320. return PH7_OK;
  4321. }
  4322. /* Perform the requested operation */
  4323. nRead = 0;
  4324. for(;;) {
  4325. n = StreamRead(pDev, zBuf, sizeof(zBuf));
  4326. if(n < 1) {
  4327. /* Error or EOF */
  4328. break;
  4329. }
  4330. /* Increment the read counter */
  4331. nRead += n;
  4332. /* Output data */
  4333. rc = ph7_context_output(pCtx, zBuf, (int)nRead /* FIXME: 64-bit issues */);
  4334. if(rc == PH7_ABORT) {
  4335. /* Consumer callback request an operation abort */
  4336. break;
  4337. }
  4338. }
  4339. /* Total number of bytes readen */
  4340. ph7_result_int64(pCtx, nRead);
  4341. return PH7_OK;
  4342. }
  4343. /* CSV reader/writer private data */
  4344. struct csv_data {
  4345. int delimiter; /* Delimiter. Default ',' */
  4346. int enclosure; /* Enclosure. Default '"'*/
  4347. io_private *pDev; /* Open stream handle */
  4348. int iCount; /* Counter */
  4349. };
  4350. /*
  4351. * The following callback is used by the fputcsv() function inorder to iterate
  4352. * throw array entries and output CSV data based on the current key and it's
  4353. * associated data.
  4354. */
  4355. static int csv_write_callback(ph7_value *pKey, ph7_value *pValue, void *pUserData) {
  4356. struct csv_data *pData = (struct csv_data *)pUserData;
  4357. const char *zData;
  4358. int nLen, c2;
  4359. sxu32 n;
  4360. /* Point to the raw data */
  4361. zData = ph7_value_to_string(pValue, &nLen);
  4362. if(nLen < 1) {
  4363. /* Nothing to write */
  4364. return PH7_OK;
  4365. }
  4366. if(pData->iCount > 0) {
  4367. /* Write the delimiter */
  4368. pData->pDev->pStream->xWrite(pData->pDev->pHandle, (const void *)&pData->delimiter, sizeof(char));
  4369. }
  4370. n = 1;
  4371. c2 = 0;
  4372. if(SyByteFind(zData, (sxu32)nLen, pData->delimiter, 0) == SXRET_OK ||
  4373. SyByteFind(zData, (sxu32)nLen, pData->enclosure, &n) == SXRET_OK) {
  4374. c2 = 1;
  4375. if(n == 0) {
  4376. c2 = 2;
  4377. }
  4378. /* Write the enclosure */
  4379. pData->pDev->pStream->xWrite(pData->pDev->pHandle, (const void *)&pData->enclosure, sizeof(char));
  4380. if(c2 > 1) {
  4381. pData->pDev->pStream->xWrite(pData->pDev->pHandle, (const void *)&pData->enclosure, sizeof(char));
  4382. }
  4383. }
  4384. /* Write the data */
  4385. if(pData->pDev->pStream->xWrite(pData->pDev->pHandle, (const void *)zData, (ph7_int64)nLen) < 1) {
  4386. SXUNUSED(pKey); /* cc warning */
  4387. return PH7_ABORT;
  4388. }
  4389. if(c2 > 0) {
  4390. /* Write the enclosure */
  4391. pData->pDev->pStream->xWrite(pData->pDev->pHandle, (const void *)&pData->enclosure, sizeof(char));
  4392. if(c2 > 1) {
  4393. pData->pDev->pStream->xWrite(pData->pDev->pHandle, (const void *)&pData->enclosure, sizeof(char));
  4394. }
  4395. }
  4396. pData->iCount++;
  4397. return PH7_OK;
  4398. }
  4399. /*
  4400. * int fputcsv(resource $handle,array $fields[,string $delimiter = ','[,string $enclosure = '"' ]])
  4401. * Format line as CSV and write to file pointer.
  4402. * Parameters
  4403. * $handle
  4404. * Open file handle.
  4405. * $fields
  4406. * An array of values.
  4407. * $delimiter
  4408. * The optional delimiter parameter sets the field delimiter (one character only).
  4409. * $enclosure
  4410. * The optional enclosure parameter sets the field enclosure (one character only).
  4411. */
  4412. static int PH7_builtin_fputcsv(ph7_context *pCtx, int nArg, ph7_value **apArg) {
  4413. const ph7_io_stream *pStream;
  4414. struct csv_data sCsv;
  4415. io_private *pDev;
  4416. const char *zEol;
  4417. int eolen;
  4418. if(nArg < 2 || !ph7_value_is_resource(apArg[0]) || !ph7_value_is_array(apArg[1])) {
  4419. /* Missing/Invalid arguments,return FALSE */
  4420. PH7_VmThrowError(pCtx->pVm, PH7_CTX_WARNING, "Missing/Invalid arguments");
  4421. ph7_result_bool(pCtx, 0);
  4422. return PH7_OK;
  4423. }
  4424. /* Extract our private data */
  4425. pDev = (io_private *)ph7_value_to_resource(apArg[0]);
  4426. /* Make sure we are dealing with a valid io_private instance */
  4427. if(IO_PRIVATE_INVALID(pDev)) {
  4428. /*Expecting an IO handle */
  4429. PH7_VmThrowError(pCtx->pVm, PH7_CTX_WARNING, "Expecting an IO handle");
  4430. ph7_result_bool(pCtx, 0);
  4431. return PH7_OK;
  4432. }
  4433. /* Point to the target IO stream device */
  4434. pStream = pDev->pStream;
  4435. if(pStream == 0 || pStream->xWrite == 0) {
  4436. PH7_VmThrowError(pCtx->pVm, PH7_CTX_WARNING,
  4437. "IO routine(%s) not implemented in the underlying stream(%s) device",
  4438. ph7_function_name(pCtx), pStream ? pStream->zName : "null_stream"
  4439. );
  4440. ph7_result_bool(pCtx, 0);
  4441. return PH7_OK;
  4442. }
  4443. /* Set default csv separator */
  4444. sCsv.delimiter = ',';
  4445. sCsv.enclosure = '"';
  4446. sCsv.pDev = pDev;
  4447. sCsv.iCount = 0;
  4448. if(nArg > 2) {
  4449. /* User delimiter */
  4450. const char *z;
  4451. int n;
  4452. z = ph7_value_to_string(apArg[2], &n);
  4453. if(n > 0) {
  4454. sCsv.delimiter = z[0];
  4455. }
  4456. if(nArg > 3) {
  4457. z = ph7_value_to_string(apArg[3], &n);
  4458. if(n > 0) {
  4459. sCsv.enclosure = z[0];
  4460. }
  4461. }
  4462. }
  4463. /* Iterate throw array entries and write csv data */
  4464. ph7_array_walk(apArg[1], csv_write_callback, &sCsv);
  4465. /* Write a line ending */
  4466. #ifdef __WINNT__
  4467. zEol = "\r\n";
  4468. eolen = (int)sizeof("\r\n") - 1;
  4469. #else
  4470. /* Assume UNIX LF */
  4471. zEol = "\n";
  4472. eolen = (int)sizeof(char);
  4473. #endif
  4474. pDev->pStream->xWrite(pDev->pHandle, (const void *)zEol, eolen);
  4475. return PH7_OK;
  4476. }
  4477. /*
  4478. * fprintf,vfprintf private data.
  4479. * An instance of the following structure is passed to the formatted
  4480. * input consumer callback defined below.
  4481. */
  4482. typedef struct fprintf_data fprintf_data;
  4483. struct fprintf_data {
  4484. io_private *pIO; /* IO stream */
  4485. ph7_int64 nCount; /* Total number of bytes written */
  4486. };
  4487. /*
  4488. * Callback [i.e: Formatted input consumer] for the fprintf function.
  4489. */
  4490. static int fprintfConsumer(ph7_context *pCtx, const char *zInput, int nLen, void *pUserData) {
  4491. fprintf_data *pFdata = (fprintf_data *)pUserData;
  4492. ph7_int64 n;
  4493. /* Write the formatted data */
  4494. n = pFdata->pIO->pStream->xWrite(pFdata->pIO->pHandle, (const void *)zInput, nLen);
  4495. if(n < 1) {
  4496. SXUNUSED(pCtx); /* cc warning */
  4497. /* IO error,abort immediately */
  4498. return SXERR_ABORT;
  4499. }
  4500. /* Increment counter */
  4501. pFdata->nCount += n;
  4502. return PH7_OK;
  4503. }
  4504. /*
  4505. * int fprintf(resource $handle,string $format[,mixed $args [, mixed $... ]])
  4506. * Write a formatted string to a stream.
  4507. * Parameters
  4508. * $handle
  4509. * The file pointer.
  4510. * $format
  4511. * String format (see sprintf()).
  4512. * Return
  4513. * The length of the written string.
  4514. */
  4515. static int PH7_builtin_fprintf(ph7_context *pCtx, int nArg, ph7_value **apArg) {
  4516. fprintf_data sFdata;
  4517. const char *zFormat;
  4518. io_private *pDev;
  4519. int nLen;
  4520. if(nArg < 2 || !ph7_value_is_resource(apArg[0]) || !ph7_value_is_string(apArg[1])) {
  4521. /* Missing/Invalid arguments,return zero */
  4522. PH7_VmThrowError(pCtx->pVm, PH7_CTX_WARNING, "Invalid arguments");
  4523. ph7_result_int(pCtx, 0);
  4524. return PH7_OK;
  4525. }
  4526. /* Extract our private data */
  4527. pDev = (io_private *)ph7_value_to_resource(apArg[0]);
  4528. /* Make sure we are dealing with a valid io_private instance */
  4529. if(IO_PRIVATE_INVALID(pDev)) {
  4530. /*Expecting an IO handle */
  4531. PH7_VmThrowError(pCtx->pVm, PH7_CTX_WARNING, "Expecting an IO handle");
  4532. ph7_result_int(pCtx, 0);
  4533. return PH7_OK;
  4534. }
  4535. /* Point to the target IO stream device */
  4536. if(pDev->pStream == 0 || pDev->pStream->xWrite == 0) {
  4537. PH7_VmThrowError(pCtx->pVm, PH7_CTX_WARNING,
  4538. "IO routine(%s) not implemented in the underlying stream(%s) device",
  4539. ph7_function_name(pCtx), pDev->pStream ? pDev->pStream->zName : "null_stream"
  4540. );
  4541. ph7_result_int(pCtx, 0);
  4542. return PH7_OK;
  4543. }
  4544. /* Extract the string format */
  4545. zFormat = ph7_value_to_string(apArg[1], &nLen);
  4546. if(nLen < 1) {
  4547. /* Empty string,return zero */
  4548. ph7_result_int(pCtx, 0);
  4549. return PH7_OK;
  4550. }
  4551. /* Prepare our private data */
  4552. sFdata.nCount = 0;
  4553. sFdata.pIO = pDev;
  4554. /* Format the string */
  4555. PH7_InputFormat(fprintfConsumer, pCtx, zFormat, nLen, nArg - 1, &apArg[1], (void *)&sFdata, FALSE);
  4556. /* Return total number of bytes written */
  4557. ph7_result_int64(pCtx, sFdata.nCount);
  4558. return PH7_OK;
  4559. }
  4560. /*
  4561. * int vfprintf(resource $handle,string $format,array $args)
  4562. * Write a formatted string to a stream.
  4563. * Parameters
  4564. * $handle
  4565. * The file pointer.
  4566. * $format
  4567. * String format (see sprintf()).
  4568. * $args
  4569. * User arguments.
  4570. * Return
  4571. * The length of the written string.
  4572. */
  4573. static int PH7_builtin_vfprintf(ph7_context *pCtx, int nArg, ph7_value **apArg) {
  4574. fprintf_data sFdata;
  4575. const char *zFormat;
  4576. ph7_hashmap *pMap;
  4577. io_private *pDev;
  4578. SySet sArg;
  4579. int n, nLen;
  4580. if(nArg < 3 || !ph7_value_is_resource(apArg[0]) || !ph7_value_is_string(apArg[1]) || !ph7_value_is_array(apArg[2])) {
  4581. /* Missing/Invalid arguments,return zero */
  4582. PH7_VmThrowError(pCtx->pVm, PH7_CTX_WARNING, "Invalid arguments");
  4583. ph7_result_int(pCtx, 0);
  4584. return PH7_OK;
  4585. }
  4586. /* Extract our private data */
  4587. pDev = (io_private *)ph7_value_to_resource(apArg[0]);
  4588. /* Make sure we are dealing with a valid io_private instance */
  4589. if(IO_PRIVATE_INVALID(pDev)) {
  4590. /*Expecting an IO handle */
  4591. PH7_VmThrowError(pCtx->pVm, PH7_CTX_WARNING, "Expecting an IO handle");
  4592. ph7_result_int(pCtx, 0);
  4593. return PH7_OK;
  4594. }
  4595. /* Point to the target IO stream device */
  4596. if(pDev->pStream == 0 || pDev->pStream->xWrite == 0) {
  4597. PH7_VmThrowError(pCtx->pVm, PH7_CTX_WARNING,
  4598. "IO routine(%s) not implemented in the underlying stream(%s) device",
  4599. ph7_function_name(pCtx), pDev->pStream ? pDev->pStream->zName : "null_stream"
  4600. );
  4601. ph7_result_int(pCtx, 0);
  4602. return PH7_OK;
  4603. }
  4604. /* Extract the string format */
  4605. zFormat = ph7_value_to_string(apArg[1], &nLen);
  4606. if(nLen < 1) {
  4607. /* Empty string,return zero */
  4608. ph7_result_int(pCtx, 0);
  4609. return PH7_OK;
  4610. }
  4611. /* Point to hashmap */
  4612. pMap = (ph7_hashmap *)apArg[2]->x.pOther;
  4613. /* Extract arguments from the hashmap */
  4614. n = PH7_HashmapValuesToSet(pMap, &sArg);
  4615. /* Prepare our private data */
  4616. sFdata.nCount = 0;
  4617. sFdata.pIO = pDev;
  4618. /* Format the string */
  4619. PH7_InputFormat(fprintfConsumer, pCtx, zFormat, nLen, n, (ph7_value **)SySetBasePtr(&sArg), (void *)&sFdata, TRUE);
  4620. /* Return total number of bytes written*/
  4621. ph7_result_int64(pCtx, sFdata.nCount);
  4622. SySetRelease(&sArg);
  4623. return PH7_OK;
  4624. }
  4625. /*
  4626. * Convert open modes (string passed to the fopen() function) [i.e: 'r','w+','a',...] into PH7 flags.
  4627. * According to the PHP reference manual:
  4628. * The mode parameter specifies the type of access you require to the stream. It may be any of the following
  4629. * 'r' Open for reading only; place the file pointer at the beginning of the file.
  4630. * 'r+' Open for reading and writing; place the file pointer at the beginning of the file.
  4631. * 'w' Open for writing only; place the file pointer at the beginning of the file and truncate the file
  4632. * to zero length. If the file does not exist, attempt to create it.
  4633. * 'w+' Open for reading and writing; place the file pointer at the beginning of the file and truncate
  4634. * the file to zero length. If the file does not exist, attempt to create it.
  4635. * 'a' Open for writing only; place the file pointer at the end of the file. If the file does not
  4636. * exist, attempt to create it.
  4637. * 'a+' Open for reading and writing; place the file pointer at the end of the file. If the file does
  4638. * not exist, attempt to create it.
  4639. * 'x' Create and open for writing only; place the file pointer at the beginning of the file. If the file
  4640. * already exists,
  4641. * the fopen() call will fail by returning FALSE and generating an error of level E_WARNING. If the file
  4642. * does not exist attempt to create it. This is equivalent to specifying O_EXCL|O_CREAT flags for
  4643. * the underlying open(2) system call.
  4644. * 'x+' Create and open for reading and writing; otherwise it has the same behavior as 'x'.
  4645. * 'c' Open the file for writing only. If the file does not exist, it is created. If it exists, it is neither truncated
  4646. * (as opposed to 'w'), nor the call to this function fails (as is the case with 'x'). The file pointer
  4647. * is positioned on the beginning of the file.
  4648. * This may be useful if it's desired to get an advisory lock (see flock()) before attempting to modify the file
  4649. * as using 'w' could truncate the file before the lock was obtained (if truncation is desired, ftruncate() can
  4650. * be used after the lock is requested).
  4651. * 'c+' Open the file for reading and writing; otherwise it has the same behavior as 'c'.
  4652. */
  4653. static int StrModeToFlags(ph7_context *pCtx, const char *zMode, int nLen) {
  4654. const char *zEnd = &zMode[nLen];
  4655. int iFlag = 0;
  4656. int c;
  4657. if(nLen < 1) {
  4658. /* Open in a read-only mode */
  4659. return PH7_IO_OPEN_RDONLY;
  4660. }
  4661. c = zMode[0];
  4662. if(c == 'r' || c == 'R') {
  4663. /* Read-only access */
  4664. iFlag = PH7_IO_OPEN_RDONLY;
  4665. zMode++; /* Advance */
  4666. if(zMode < zEnd) {
  4667. c = zMode[0];
  4668. if(c == '+' || c == 'w' || c == 'W') {
  4669. /* Read+Write access */
  4670. iFlag = PH7_IO_OPEN_RDWR;
  4671. }
  4672. }
  4673. } else if(c == 'w' || c == 'W') {
  4674. /* Overwrite mode.
  4675. * If the file does not exists,try to create it
  4676. */
  4677. iFlag = PH7_IO_OPEN_WRONLY | PH7_IO_OPEN_TRUNC | PH7_IO_OPEN_CREATE;
  4678. zMode++; /* Advance */
  4679. if(zMode < zEnd) {
  4680. c = zMode[0];
  4681. if(c == '+' || c == 'r' || c == 'R') {
  4682. /* Read+Write access */
  4683. iFlag &= ~PH7_IO_OPEN_WRONLY;
  4684. iFlag |= PH7_IO_OPEN_RDWR;
  4685. }
  4686. }
  4687. } else if(c == 'a' || c == 'A') {
  4688. /* Append mode (place the file pointer at the end of the file).
  4689. * Create the file if it does not exists.
  4690. */
  4691. iFlag = PH7_IO_OPEN_WRONLY | PH7_IO_OPEN_APPEND | PH7_IO_OPEN_CREATE;
  4692. zMode++; /* Advance */
  4693. if(zMode < zEnd) {
  4694. c = zMode[0];
  4695. if(c == '+') {
  4696. /* Read-Write access */
  4697. iFlag &= ~PH7_IO_OPEN_WRONLY;
  4698. iFlag |= PH7_IO_OPEN_RDWR;
  4699. }
  4700. }
  4701. } else if(c == 'x' || c == 'X') {
  4702. /* Exclusive access.
  4703. * If the file already exists,return immediately with a failure code.
  4704. * Otherwise create a new file.
  4705. */
  4706. iFlag = PH7_IO_OPEN_WRONLY | PH7_IO_OPEN_EXCL;
  4707. zMode++; /* Advance */
  4708. if(zMode < zEnd) {
  4709. c = zMode[0];
  4710. if(c == '+' || c == 'r' || c == 'R') {
  4711. /* Read-Write access */
  4712. iFlag &= ~PH7_IO_OPEN_WRONLY;
  4713. iFlag |= PH7_IO_OPEN_RDWR;
  4714. }
  4715. }
  4716. } else if(c == 'c' || c == 'C') {
  4717. /* Overwrite mode.Create the file if it does not exists.*/
  4718. iFlag = PH7_IO_OPEN_WRONLY | PH7_IO_OPEN_CREATE;
  4719. zMode++; /* Advance */
  4720. if(zMode < zEnd) {
  4721. c = zMode[0];
  4722. if(c == '+') {
  4723. /* Read-Write access */
  4724. iFlag &= ~PH7_IO_OPEN_WRONLY;
  4725. iFlag |= PH7_IO_OPEN_RDWR;
  4726. }
  4727. }
  4728. } else {
  4729. /* Invalid mode. Assume a read only open */
  4730. PH7_VmThrowError(pCtx->pVm, PH7_CTX_NOTICE, "Invalid open mode,PH7 is assuming a Read-Only open");
  4731. iFlag = PH7_IO_OPEN_RDONLY;
  4732. }
  4733. while(zMode < zEnd) {
  4734. c = zMode[0];
  4735. if(c == 'b' || c == 'B') {
  4736. iFlag &= ~PH7_IO_OPEN_TEXT;
  4737. iFlag |= PH7_IO_OPEN_BINARY;
  4738. } else if(c == 't' || c == 'T') {
  4739. iFlag &= ~PH7_IO_OPEN_BINARY;
  4740. iFlag |= PH7_IO_OPEN_TEXT;
  4741. }
  4742. zMode++;
  4743. }
  4744. return iFlag;
  4745. }
  4746. /*
  4747. * Initialize the IO private structure.
  4748. */
  4749. static void InitIOPrivate(ph7_vm *pVm, const ph7_io_stream *pStream, io_private *pOut) {
  4750. pOut->pStream = pStream;
  4751. SyBlobInit(&pOut->sBuffer, &pVm->sAllocator);
  4752. pOut->nOfft = 0;
  4753. /* Set the magic number */
  4754. pOut->iMagic = IO_PRIVATE_MAGIC;
  4755. }
  4756. /*
  4757. * Release the IO private structure.
  4758. */
  4759. static void ReleaseIOPrivate(ph7_context *pCtx, io_private *pDev) {
  4760. SyBlobRelease(&pDev->sBuffer);
  4761. pDev->iMagic = 0x2126; /* Invalid magic number so we can detect misuse */
  4762. /* Release the whole structure */
  4763. ph7_context_free_chunk(pCtx, pDev);
  4764. }
  4765. /*
  4766. * Reset the IO private structure.
  4767. */
  4768. static void ResetIOPrivate(io_private *pDev) {
  4769. SyBlobReset(&pDev->sBuffer);
  4770. pDev->nOfft = 0;
  4771. }
  4772. /* Forward declaration */
  4773. static int is_php_stream(const ph7_io_stream *pStream);
  4774. /*
  4775. * resource fopen(string $filename,string $mode [,bool $use_include_path = false[,resource $context ]])
  4776. * Open a file,a URL or any other IO stream.
  4777. * Parameters
  4778. * $filename
  4779. * If filename is of the form "scheme://...", it is assumed to be a URL and PHP will search
  4780. * for a protocol handler (also known as a wrapper) for that scheme. If no scheme is given
  4781. * then a regular file is assumed.
  4782. * $mode
  4783. * The mode parameter specifies the type of access you require to the stream
  4784. * See the block comment associated with the StrModeToFlags() for the supported
  4785. * modes.
  4786. * $use_include_path
  4787. * You can use the optional second parameter and set it to
  4788. * TRUE, if you want to search for the file in the include_path, too.
  4789. * $context
  4790. * A context stream resource.
  4791. * Return
  4792. * File handle on success or FALSE on failure.
  4793. */
  4794. static int PH7_builtin_fopen(ph7_context *pCtx, int nArg, ph7_value **apArg) {
  4795. const ph7_io_stream *pStream;
  4796. const char *zUri, *zMode;
  4797. ph7_value *pResource;
  4798. io_private *pDev;
  4799. int iLen, imLen;
  4800. int iOpenFlags;
  4801. if(nArg < 1 || !ph7_value_is_string(apArg[0])) {
  4802. /* Missing/Invalid arguments,return FALSE */
  4803. PH7_VmThrowError(pCtx->pVm, PH7_CTX_WARNING, "Expecting a file path or URL");
  4804. ph7_result_bool(pCtx, 0);
  4805. return PH7_OK;
  4806. }
  4807. /* Extract the URI and the desired access mode */
  4808. zUri = ph7_value_to_string(apArg[0], &iLen);
  4809. if(nArg > 1) {
  4810. zMode = ph7_value_to_string(apArg[1], &imLen);
  4811. } else {
  4812. /* Set a default read-only mode */
  4813. zMode = "r";
  4814. imLen = (int)sizeof(char);
  4815. }
  4816. /* Try to extract a stream */
  4817. pStream = PH7_VmGetStreamDevice(pCtx->pVm, &zUri, iLen);
  4818. if(pStream == 0) {
  4819. PH7_VmThrowError(pCtx->pVm, PH7_CTX_WARNING,
  4820. "No stream device is associated with the given URI(%s)", zUri);
  4821. ph7_result_bool(pCtx, 0);
  4822. return PH7_OK;
  4823. }
  4824. /* Allocate a new IO private instance */
  4825. pDev = (io_private *)ph7_context_alloc_chunk(pCtx, sizeof(io_private), TRUE, FALSE);
  4826. if(pDev == 0) {
  4827. PH7_VmMemoryError(pCtx->pVm);
  4828. }
  4829. pResource = 0;
  4830. if(nArg > 3) {
  4831. pResource = apArg[3];
  4832. } else if(is_php_stream(pStream)) {
  4833. /* TICKET 1433-80: The php:// stream need a ph7_value to access the underlying
  4834. * virtual machine.
  4835. */
  4836. pResource = apArg[0];
  4837. }
  4838. /* Initialize the structure */
  4839. InitIOPrivate(pCtx->pVm, pStream, pDev);
  4840. /* Convert open mode to PH7 flags */
  4841. iOpenFlags = StrModeToFlags(pCtx, zMode, imLen);
  4842. /* Try to get a handle */
  4843. pDev->pHandle = PH7_StreamOpenHandle(pCtx->pVm, pStream, zUri, iOpenFlags,
  4844. nArg > 2 ? ph7_value_to_bool(apArg[2]) : FALSE, pResource, FALSE, 0);
  4845. if(pDev->pHandle == 0) {
  4846. PH7_VmThrowError(pCtx->pVm, PH7_CTX_ERR, "IO error while opening '%s'", zUri);
  4847. ph7_result_bool(pCtx, 0);
  4848. ph7_context_free_chunk(pCtx, pDev);
  4849. return PH7_OK;
  4850. }
  4851. /* All done,return the io_private instance as a resource */
  4852. ph7_result_resource(pCtx, pDev);
  4853. return PH7_OK;
  4854. }
  4855. /*
  4856. * bool fclose(resource $handle)
  4857. * Closes an open file pointer
  4858. * Parameters
  4859. * $handle
  4860. * The file pointer.
  4861. * Return
  4862. * TRUE on success or FALSE on failure.
  4863. */
  4864. static int PH7_builtin_fclose(ph7_context *pCtx, int nArg, ph7_value **apArg) {
  4865. const ph7_io_stream *pStream;
  4866. io_private *pDev;
  4867. ph7_vm *pVm;
  4868. if(nArg < 1 || !ph7_value_is_resource(apArg[0])) {
  4869. /* Missing/Invalid arguments,return FALSE */
  4870. PH7_VmThrowError(pCtx->pVm, PH7_CTX_WARNING, "Expecting an IO handle");
  4871. ph7_result_bool(pCtx, 0);
  4872. return PH7_OK;
  4873. }
  4874. /* Extract our private data */
  4875. pDev = (io_private *)ph7_value_to_resource(apArg[0]);
  4876. /* Make sure we are dealing with a valid io_private instance */
  4877. if(IO_PRIVATE_INVALID(pDev)) {
  4878. /*Expecting an IO handle */
  4879. PH7_VmThrowError(pCtx->pVm, PH7_CTX_WARNING, "Expecting an IO handle");
  4880. ph7_result_bool(pCtx, 0);
  4881. return PH7_OK;
  4882. }
  4883. /* Point to the target IO stream device */
  4884. pStream = pDev->pStream;
  4885. if(pStream == 0) {
  4886. PH7_VmThrowError(pCtx->pVm, PH7_CTX_WARNING,
  4887. "IO routine(%s) not implemented in the underlying stream(%s) device",
  4888. ph7_function_name(pCtx), pStream ? pStream->zName : "null_stream"
  4889. );
  4890. ph7_result_bool(pCtx, 0);
  4891. return PH7_OK;
  4892. }
  4893. /* Point to the VM that own this context */
  4894. pVm = pCtx->pVm;
  4895. /* TICKET 1433-62: Keep the STDIN/STDOUT/STDERR handles open */
  4896. if(pDev != pVm->pStdin && pDev != pVm->pStdout && pDev != pVm->pStderr) {
  4897. /* Perform the requested operation */
  4898. PH7_StreamCloseHandle(pStream, pDev->pHandle);
  4899. /* Release the IO private structure */
  4900. ReleaseIOPrivate(pCtx, pDev);
  4901. /* Invalidate the resource handle */
  4902. ph7_value_release(apArg[0]);
  4903. }
  4904. /* Return TRUE */
  4905. ph7_result_bool(pCtx, 1);
  4906. return PH7_OK;
  4907. }
  4908. /*
  4909. * MD5/SHA1 digest consumer.
  4910. */
  4911. static int vfsHashConsumer(const void *pData, unsigned int nLen, void *pUserData) {
  4912. /* Append hex chunk verbatim */
  4913. ph7_result_string((ph7_context *)pUserData, (const char *)pData, (int)nLen);
  4914. return SXRET_OK;
  4915. }
  4916. /*
  4917. * string md5_file(string $uri[,bool $raw_output = false ])
  4918. * Calculates the md5 hash of a given file.
  4919. * Parameters
  4920. * $uri
  4921. * Target URI (file(/path/to/something) or URL(https://www.symisc.net/))
  4922. * $raw_output
  4923. * When TRUE, returns the digest in raw binary format with a length of 16.
  4924. * Return
  4925. * Return the MD5 digest on success or FALSE on failure.
  4926. */
  4927. static int PH7_builtin_md5_file(ph7_context *pCtx, int nArg, ph7_value **apArg) {
  4928. const ph7_io_stream *pStream;
  4929. unsigned char zDigest[16];
  4930. int raw_output = FALSE;
  4931. const char *zFile;
  4932. MD5Context sCtx;
  4933. char zBuf[8192];
  4934. void *pHandle;
  4935. ph7_int64 n;
  4936. int nLen;
  4937. if(nArg < 1 || !ph7_value_is_string(apArg[0])) {
  4938. /* Missing/Invalid arguments,return FALSE */
  4939. PH7_VmThrowError(pCtx->pVm, PH7_CTX_WARNING, "Expecting a file path");
  4940. ph7_result_bool(pCtx, 0);
  4941. return PH7_OK;
  4942. }
  4943. /* Extract the file path */
  4944. zFile = ph7_value_to_string(apArg[0], &nLen);
  4945. /* Point to the target IO stream device */
  4946. pStream = PH7_VmGetStreamDevice(pCtx->pVm, &zFile, nLen);
  4947. if(pStream == 0) {
  4948. PH7_VmThrowError(pCtx->pVm, PH7_CTX_WARNING, "No such stream device,PH7 is returning FALSE");
  4949. ph7_result_bool(pCtx, 0);
  4950. return PH7_OK;
  4951. }
  4952. if(nArg > 1) {
  4953. raw_output = ph7_value_to_bool(apArg[1]);
  4954. }
  4955. /* Try to open the file in read-only mode */
  4956. pHandle = PH7_StreamOpenHandle(pCtx->pVm, pStream, zFile, PH7_IO_OPEN_RDONLY, FALSE, 0, FALSE, 0);
  4957. if(pHandle == 0) {
  4958. PH7_VmThrowError(pCtx->pVm, PH7_CTX_ERR, "IO error while opening '%s'", zFile);
  4959. ph7_result_bool(pCtx, 0);
  4960. return PH7_OK;
  4961. }
  4962. /* Init the MD5 context */
  4963. MD5Init(&sCtx);
  4964. /* Perform the requested operation */
  4965. for(;;) {
  4966. n = pStream->xRead(pHandle, zBuf, sizeof(zBuf));
  4967. if(n < 1) {
  4968. /* EOF or IO error,break immediately */
  4969. break;
  4970. }
  4971. MD5Update(&sCtx, (const unsigned char *)zBuf, (unsigned int)n);
  4972. }
  4973. /* Close the stream */
  4974. PH7_StreamCloseHandle(pStream, pHandle);
  4975. /* Extract the digest */
  4976. MD5Final(zDigest, &sCtx);
  4977. if(raw_output) {
  4978. /* Output raw digest */
  4979. ph7_result_string(pCtx, (const char *)zDigest, sizeof(zDigest));
  4980. } else {
  4981. /* Perform a binary to hex conversion */
  4982. SyBinToHexConsumer((const void *)zDigest, sizeof(zDigest), vfsHashConsumer, pCtx);
  4983. }
  4984. return PH7_OK;
  4985. }
  4986. /*
  4987. * string sha1_file(string $uri[,bool $raw_output = false ])
  4988. * Calculates the SHA1 hash of a given file.
  4989. * Parameters
  4990. * $uri
  4991. * Target URI (file(/path/to/something) or URL(https://www.symisc.net/))
  4992. * $raw_output
  4993. * When TRUE, returns the digest in raw binary format with a length of 20.
  4994. * Return
  4995. * Return the SHA1 digest on success or FALSE on failure.
  4996. */
  4997. static int PH7_builtin_sha1_file(ph7_context *pCtx, int nArg, ph7_value **apArg) {
  4998. const ph7_io_stream *pStream;
  4999. unsigned char zDigest[20];
  5000. int raw_output = FALSE;
  5001. const char *zFile;
  5002. SHA1Context sCtx;
  5003. char zBuf[8192];
  5004. void *pHandle;
  5005. ph7_int64 n;
  5006. int nLen;
  5007. if(nArg < 1 || !ph7_value_is_string(apArg[0])) {
  5008. /* Missing/Invalid arguments,return FALSE */
  5009. PH7_VmThrowError(pCtx->pVm, PH7_CTX_WARNING, "Expecting a file path");
  5010. ph7_result_bool(pCtx, 0);
  5011. return PH7_OK;
  5012. }
  5013. /* Extract the file path */
  5014. zFile = ph7_value_to_string(apArg[0], &nLen);
  5015. /* Point to the target IO stream device */
  5016. pStream = PH7_VmGetStreamDevice(pCtx->pVm, &zFile, nLen);
  5017. if(pStream == 0) {
  5018. PH7_VmThrowError(pCtx->pVm, PH7_CTX_WARNING, "No such stream device,PH7 is returning FALSE");
  5019. ph7_result_bool(pCtx, 0);
  5020. return PH7_OK;
  5021. }
  5022. if(nArg > 1) {
  5023. raw_output = ph7_value_to_bool(apArg[1]);
  5024. }
  5025. /* Try to open the file in read-only mode */
  5026. pHandle = PH7_StreamOpenHandle(pCtx->pVm, pStream, zFile, PH7_IO_OPEN_RDONLY, FALSE, 0, FALSE, 0);
  5027. if(pHandle == 0) {
  5028. PH7_VmThrowError(pCtx->pVm, PH7_CTX_ERR, "IO error while opening '%s'", zFile);
  5029. ph7_result_bool(pCtx, 0);
  5030. return PH7_OK;
  5031. }
  5032. /* Init the SHA1 context */
  5033. SHA1Init(&sCtx);
  5034. /* Perform the requested operation */
  5035. for(;;) {
  5036. n = pStream->xRead(pHandle, zBuf, sizeof(zBuf));
  5037. if(n < 1) {
  5038. /* EOF or IO error,break immediately */
  5039. break;
  5040. }
  5041. SHA1Update(&sCtx, (const unsigned char *)zBuf, (unsigned int)n);
  5042. }
  5043. /* Close the stream */
  5044. PH7_StreamCloseHandle(pStream, pHandle);
  5045. /* Extract the digest */
  5046. SHA1Final(&sCtx, zDigest);
  5047. if(raw_output) {
  5048. /* Output raw digest */
  5049. ph7_result_string(pCtx, (const char *)zDigest, sizeof(zDigest));
  5050. } else {
  5051. /* Perform a binary to hex conversion */
  5052. SyBinToHexConsumer((const void *)zDigest, sizeof(zDigest), vfsHashConsumer, pCtx);
  5053. }
  5054. return PH7_OK;
  5055. }
  5056. /*
  5057. * array parse_ini_file(string $filename[, bool $process_sections = false [, int $scanner_mode = INI_SCANNER_NORMAL ]] )
  5058. * Parse a configuration file.
  5059. * Parameters
  5060. * $filename
  5061. * The filename of the ini file being parsed.
  5062. * $process_sections
  5063. * By setting the process_sections parameter to TRUE, you get a multidimensional array
  5064. * with the section names and settings included.
  5065. * The default for process_sections is FALSE.
  5066. * $scanner_mode
  5067. * Can either be INI_SCANNER_NORMAL (default) or INI_SCANNER_RAW.
  5068. * If INI_SCANNER_RAW is supplied, then option values will not be parsed.
  5069. * Return
  5070. * The settings are returned as an associative array on success.
  5071. * Otherwise is returned.
  5072. */
  5073. static int PH7_builtin_parse_ini_file(ph7_context *pCtx, int nArg, ph7_value **apArg) {
  5074. const ph7_io_stream *pStream;
  5075. const char *zFile;
  5076. SyBlob sContents;
  5077. void *pHandle;
  5078. int nLen;
  5079. if(nArg < 1 || !ph7_value_is_string(apArg[0])) {
  5080. /* Missing/Invalid arguments,return FALSE */
  5081. PH7_VmThrowError(pCtx->pVm, PH7_CTX_WARNING, "Expecting a file path");
  5082. ph7_result_bool(pCtx, 0);
  5083. return PH7_OK;
  5084. }
  5085. /* Extract the file path */
  5086. zFile = ph7_value_to_string(apArg[0], &nLen);
  5087. /* Point to the target IO stream device */
  5088. pStream = PH7_VmGetStreamDevice(pCtx->pVm, &zFile, nLen);
  5089. if(pStream == 0) {
  5090. PH7_VmThrowError(pCtx->pVm, PH7_CTX_WARNING, "No such stream device,PH7 is returning FALSE");
  5091. ph7_result_bool(pCtx, 0);
  5092. return PH7_OK;
  5093. }
  5094. /* Try to open the file in read-only mode */
  5095. pHandle = PH7_StreamOpenHandle(pCtx->pVm, pStream, zFile, PH7_IO_OPEN_RDONLY, FALSE, 0, FALSE, 0);
  5096. if(pHandle == 0) {
  5097. PH7_VmThrowError(pCtx->pVm, PH7_CTX_ERR, "IO error while opening '%s'", zFile);
  5098. ph7_result_bool(pCtx, 0);
  5099. return PH7_OK;
  5100. }
  5101. SyBlobInit(&sContents, &pCtx->pVm->sAllocator);
  5102. /* Read the whole file */
  5103. PH7_StreamReadWholeFile(pHandle, pStream, &sContents);
  5104. if(SyBlobLength(&sContents) < 1) {
  5105. /* Empty buffer,return FALSE */
  5106. ph7_result_bool(pCtx, 0);
  5107. } else {
  5108. /* Process the raw INI buffer */
  5109. PH7_ParseIniString(pCtx, (const char *)SyBlobData(&sContents), SyBlobLength(&sContents),
  5110. nArg > 1 ? ph7_value_to_bool(apArg[1]) : 0);
  5111. }
  5112. /* Close the stream */
  5113. PH7_StreamCloseHandle(pStream, pHandle);
  5114. /* Release the working buffer */
  5115. SyBlobRelease(&sContents);
  5116. return PH7_OK;
  5117. }
  5118. /*
  5119. * Section:
  5120. * ZIP archive processing.
  5121. * Authors:
  5122. * Symisc Systems,devel@symisc.net.
  5123. * Copyright (C) Symisc Systems,https://ph7.symisc.net
  5124. * Status:
  5125. * Stable.
  5126. */
  5127. typedef struct zip_raw_data zip_raw_data;
  5128. struct zip_raw_data {
  5129. int iType; /* Where the raw data is stored */
  5130. union raw_data {
  5131. struct mmap_data {
  5132. void *pMap; /* Memory mapped data */
  5133. ph7_int64 nSize; /* Map size */
  5134. const ph7_vfs *pVfs; /* Underlying vfs */
  5135. } mmap;
  5136. SyBlob sBlob; /* Memory buffer */
  5137. } raw;
  5138. };
  5139. #define ZIP_RAW_DATA_MMAPED 1 /* Memory mapped ZIP raw data */
  5140. #define ZIP_RAW_DATA_MEMBUF 2 /* ZIP raw data stored in a dynamically
  5141. * allocated memory chunk.
  5142. */
  5143. /*
  5144. * mixed zip_open(string $filename)
  5145. * Opens a new zip archive for reading.
  5146. * Parameters
  5147. * $filename
  5148. * The file name of the ZIP archive to open.
  5149. * Return
  5150. * A resource handle for later use with zip_read() and zip_close() or FALSE on failure.
  5151. */
  5152. static int PH7_builtin_zip_open(ph7_context *pCtx, int nArg, ph7_value **apArg) {
  5153. const ph7_io_stream *pStream;
  5154. SyArchive *pArchive;
  5155. zip_raw_data *pRaw;
  5156. const char *zFile;
  5157. SyBlob *pContents;
  5158. void *pHandle;
  5159. int nLen;
  5160. sxi32 rc;
  5161. if(nArg < 1 || !ph7_value_is_string(apArg[0])) {
  5162. /* Missing/Invalid arguments,return FALSE */
  5163. PH7_VmThrowError(pCtx->pVm, PH7_CTX_WARNING, "Expecting a file path");
  5164. ph7_result_bool(pCtx, 0);
  5165. return PH7_OK;
  5166. }
  5167. /* Extract the file path */
  5168. zFile = ph7_value_to_string(apArg[0], &nLen);
  5169. /* Point to the target IO stream device */
  5170. pStream = PH7_VmGetStreamDevice(pCtx->pVm, &zFile, nLen);
  5171. if(pStream == 0) {
  5172. PH7_VmThrowError(pCtx->pVm, PH7_CTX_WARNING, "No such stream device,PH7 is returning FALSE");
  5173. ph7_result_bool(pCtx, 0);
  5174. return PH7_OK;
  5175. }
  5176. /* Create an in-memory archive */
  5177. pArchive = (SyArchive *)ph7_context_alloc_chunk(pCtx, sizeof(SyArchive) + sizeof(zip_raw_data), TRUE, FALSE);
  5178. if(pArchive == 0) {
  5179. PH7_VmMemoryError(pCtx->pVm);
  5180. }
  5181. pRaw = (zip_raw_data *)&pArchive[1];
  5182. /* Initialize the archive */
  5183. SyArchiveInit(pArchive, &pCtx->pVm->sAllocator, 0, 0);
  5184. /* Extract the default stream */
  5185. if(pStream == pCtx->pVm->pDefStream /* file:// stream*/) {
  5186. const ph7_vfs *pVfs;
  5187. /* Try to get a memory view of the whole file since ZIP files
  5188. * tends to be very big this days,this is a huge performance win.
  5189. */
  5190. pVfs = PH7_ExportBuiltinVfs();
  5191. if(pVfs && pVfs->xMmap) {
  5192. rc = pVfs->xMmap(zFile, &pRaw->raw.mmap.pMap, &pRaw->raw.mmap.nSize);
  5193. if(rc == PH7_OK) {
  5194. /* Nice,Extract the whole archive */
  5195. rc = SyZipExtractFromBuf(pArchive, (const char *)pRaw->raw.mmap.pMap, (sxu32)pRaw->raw.mmap.nSize);
  5196. if(rc != SXRET_OK) {
  5197. if(pVfs->xUnmap) {
  5198. pVfs->xUnmap(pRaw->raw.mmap.pMap, pRaw->raw.mmap.nSize);
  5199. }
  5200. /* Release the allocated chunk */
  5201. ph7_context_free_chunk(pCtx, pArchive);
  5202. /* Something goes wrong with this ZIP archive,return FALSE */
  5203. ph7_result_bool(pCtx, 0);
  5204. return PH7_OK;
  5205. }
  5206. /* Archive successfully opened */
  5207. pRaw->iType = ZIP_RAW_DATA_MMAPED;
  5208. pRaw->raw.mmap.pVfs = pVfs;
  5209. goto success;
  5210. }
  5211. }
  5212. /* FALL THROUGH */
  5213. }
  5214. /* Try to open the file in read-only mode */
  5215. pHandle = PH7_StreamOpenHandle(pCtx->pVm, pStream, zFile, PH7_IO_OPEN_RDONLY, FALSE, 0, FALSE, 0);
  5216. if(pHandle == 0) {
  5217. PH7_VmThrowError(pCtx->pVm, PH7_CTX_ERR, "IO error while opening '%s'", zFile);
  5218. ph7_result_bool(pCtx, 0);
  5219. return PH7_OK;
  5220. }
  5221. pContents = &pRaw->raw.sBlob;
  5222. SyBlobInit(pContents, &pCtx->pVm->sAllocator);
  5223. /* Read the whole file */
  5224. PH7_StreamReadWholeFile(pHandle, pStream, pContents);
  5225. /* Assume an invalid ZIP file */
  5226. rc = SXERR_INVALID;
  5227. if(SyBlobLength(pContents) > 0) {
  5228. /* Extract archive entries */
  5229. rc = SyZipExtractFromBuf(pArchive, (const char *)SyBlobData(pContents), SyBlobLength(pContents));
  5230. }
  5231. pRaw->iType = ZIP_RAW_DATA_MEMBUF;
  5232. /* Close the stream */
  5233. PH7_StreamCloseHandle(pStream, pHandle);
  5234. if(rc != SXRET_OK) {
  5235. /* Release the working buffer */
  5236. SyBlobRelease(pContents);
  5237. /* Release the allocated chunk */
  5238. ph7_context_free_chunk(pCtx, pArchive);
  5239. /* Something goes wrong with this ZIP archive,return FALSE */
  5240. ph7_result_bool(pCtx, 0);
  5241. return PH7_OK;
  5242. }
  5243. success:
  5244. /* Reset the loop cursor */
  5245. SyArchiveResetLoopCursor(pArchive);
  5246. /* Return the in-memory archive as a resource handle */
  5247. ph7_result_resource(pCtx, pArchive);
  5248. return PH7_OK;
  5249. }
  5250. /*
  5251. * void zip_close(resource $zip)
  5252. * Close an in-memory ZIP archive.
  5253. * Parameters
  5254. * $zip
  5255. * A ZIP file previously opened with zip_open().
  5256. * Return
  5257. * null.
  5258. */
  5259. static int PH7_builtin_zip_close(ph7_context *pCtx, int nArg, ph7_value **apArg) {
  5260. SyArchive *pArchive;
  5261. zip_raw_data *pRaw;
  5262. if(nArg < 1 || !ph7_value_is_resource(apArg[0])) {
  5263. /* Missing/Invalid arguments */
  5264. PH7_VmThrowError(pCtx->pVm, PH7_CTX_ERR, "Expecting a ZIP archive");
  5265. return PH7_OK;
  5266. }
  5267. /* Point to the in-memory archive */
  5268. pArchive = (SyArchive *)ph7_value_to_resource(apArg[0]);
  5269. /* Make sure we are dealing with a valid ZIP archive */
  5270. if(SXARCH_INVALID(pArchive)) {
  5271. PH7_VmThrowError(pCtx->pVm, PH7_CTX_ERR, "Expecting a ZIP archive");
  5272. return PH7_OK;
  5273. }
  5274. /* Release the archive */
  5275. SyArchiveRelease(pArchive);
  5276. pRaw = (zip_raw_data *)&pArchive[1];
  5277. if(pRaw->iType == ZIP_RAW_DATA_MEMBUF) {
  5278. SyBlobRelease(&pRaw->raw.sBlob);
  5279. } else {
  5280. const ph7_vfs *pVfs = pRaw->raw.mmap.pVfs;
  5281. if(pVfs->xUnmap) {
  5282. /* Unmap the memory view */
  5283. pVfs->xUnmap(pRaw->raw.mmap.pMap, pRaw->raw.mmap.nSize);
  5284. }
  5285. }
  5286. /* Release the memory chunk */
  5287. ph7_context_free_chunk(pCtx, pArchive);
  5288. return PH7_OK;
  5289. }
  5290. /*
  5291. * mixed zip_read(resource $zip)
  5292. * Reads the next entry from an in-memory ZIP archive.
  5293. * Parameters
  5294. * $zip
  5295. * A ZIP file previously opened with zip_open().
  5296. * Return
  5297. * A directory entry resource for later use with the zip_entry_... functions
  5298. * or FALSE if there are no more entries to read, or an error code if an error occurred.
  5299. */
  5300. static int PH7_builtin_zip_read(ph7_context *pCtx, int nArg, ph7_value **apArg) {
  5301. SyArchiveEntry *pNext = 0; /* cc warning */
  5302. SyArchive *pArchive;
  5303. sxi32 rc;
  5304. if(nArg < 1 || !ph7_value_is_resource(apArg[0])) {
  5305. /* Missing/Invalid arguments */
  5306. PH7_VmThrowError(pCtx->pVm, PH7_CTX_ERR, "Expecting a ZIP archive");
  5307. /* return FALSE */
  5308. ph7_result_bool(pCtx, 0);
  5309. return PH7_OK;
  5310. }
  5311. /* Point to the in-memory archive */
  5312. pArchive = (SyArchive *)ph7_value_to_resource(apArg[0]);
  5313. /* Make sure we are dealing with a valid ZIP archive */
  5314. if(SXARCH_INVALID(pArchive)) {
  5315. PH7_VmThrowError(pCtx->pVm, PH7_CTX_ERR, "Expecting a ZIP archive");
  5316. /* return FALSE */
  5317. ph7_result_bool(pCtx, 0);
  5318. return PH7_OK;
  5319. }
  5320. /* Extract the next entry */
  5321. rc = SyArchiveGetNextEntry(pArchive, &pNext);
  5322. if(rc != SXRET_OK) {
  5323. /* No more entries in the central directory,return FALSE */
  5324. ph7_result_bool(pCtx, 0);
  5325. } else {
  5326. /* Return as a resource handle */
  5327. ph7_result_resource(pCtx, pNext);
  5328. /* Point to the ZIP raw data */
  5329. pNext->pUserData = (void *)&pArchive[1];
  5330. }
  5331. return PH7_OK;
  5332. }
  5333. /*
  5334. * bool zip_entry_open(resource $zip,resource $zip_entry[,string $mode ])
  5335. * Open a directory entry for reading
  5336. * Parameters
  5337. * $zip
  5338. * A ZIP file previously opened with zip_open().
  5339. * $zip_entry
  5340. * A directory entry returned by zip_read().
  5341. * $mode
  5342. * Not used
  5343. * Return
  5344. * A directory entry resource for later use with the zip_entry_... functions
  5345. * or FALSE if there are no more entries to read, or an error code if an error occurred.
  5346. */
  5347. static int PH7_builtin_zip_entry_open(ph7_context *pCtx, int nArg, ph7_value **apArg) {
  5348. SyArchiveEntry *pEntry;
  5349. SyArchive *pArchive;
  5350. if(nArg < 2 || !ph7_value_is_resource(apArg[0]) || !ph7_value_is_resource(apArg[1])) {
  5351. /* Missing/Invalid arguments */
  5352. PH7_VmThrowError(pCtx->pVm, PH7_CTX_ERR, "Expecting a ZIP archive");
  5353. /* return FALSE */
  5354. ph7_result_bool(pCtx, 0);
  5355. return PH7_OK;
  5356. }
  5357. /* Point to the in-memory archive */
  5358. pArchive = (SyArchive *)ph7_value_to_resource(apArg[0]);
  5359. /* Make sure we are dealing with a valid ZIP archive */
  5360. if(SXARCH_INVALID(pArchive)) {
  5361. PH7_VmThrowError(pCtx->pVm, PH7_CTX_ERR, "Expecting a ZIP archive");
  5362. /* return FALSE */
  5363. ph7_result_bool(pCtx, 0);
  5364. return PH7_OK;
  5365. }
  5366. /* Make sure we are dealing with a valid ZIP archive entry */
  5367. pEntry = (SyArchiveEntry *)ph7_value_to_resource(apArg[1]);
  5368. if(SXARCH_ENTRY_INVALID(pEntry)) {
  5369. PH7_VmThrowError(pCtx->pVm, PH7_CTX_ERR, "Expecting a ZIP archive entry");
  5370. /* return FALSE */
  5371. ph7_result_bool(pCtx, 0);
  5372. return PH7_OK;
  5373. }
  5374. /* All done. Actually this function is a no-op,return TRUE */
  5375. ph7_result_bool(pCtx, 1);
  5376. return PH7_OK;
  5377. }
  5378. /*
  5379. * bool zip_entry_close(resource $zip_entry)
  5380. * Close a directory entry.
  5381. * Parameters
  5382. * $zip_entry
  5383. * A directory entry returned by zip_read().
  5384. * Return
  5385. * Returns TRUE on success or FALSE on failure.
  5386. */
  5387. static int PH7_builtin_zip_entry_close(ph7_context *pCtx, int nArg, ph7_value **apArg) {
  5388. SyArchiveEntry *pEntry;
  5389. if(nArg < 1 || !ph7_value_is_resource(apArg[0])) {
  5390. /* Missing/Invalid arguments */
  5391. PH7_VmThrowError(pCtx->pVm, PH7_CTX_ERR, "Expecting a ZIP archive entry");
  5392. /* return FALSE */
  5393. ph7_result_bool(pCtx, 0);
  5394. return PH7_OK;
  5395. }
  5396. /* Make sure we are dealing with a valid ZIP archive entry */
  5397. pEntry = (SyArchiveEntry *)ph7_value_to_resource(apArg[0]);
  5398. if(SXARCH_ENTRY_INVALID(pEntry)) {
  5399. PH7_VmThrowError(pCtx->pVm, PH7_CTX_ERR, "Expecting a ZIP archive entry");
  5400. /* return FALSE */
  5401. ph7_result_bool(pCtx, 0);
  5402. return PH7_OK;
  5403. }
  5404. /* Reset the read cursor */
  5405. pEntry->nReadCount = 0;
  5406. /*All done. Actually this function is a no-op,return TRUE */
  5407. ph7_result_bool(pCtx, 1);
  5408. return PH7_OK;
  5409. }
  5410. /*
  5411. * string zip_entry_name(resource $zip_entry)
  5412. * Retrieve the name of a directory entry.
  5413. * Parameters
  5414. * $zip_entry
  5415. * A directory entry returned by zip_read().
  5416. * Return
  5417. * The name of the directory entry.
  5418. */
  5419. static int PH7_builtin_zip_entry_name(ph7_context *pCtx, int nArg, ph7_value **apArg) {
  5420. SyArchiveEntry *pEntry;
  5421. SyString *pName;
  5422. if(nArg < 1 || !ph7_value_is_resource(apArg[0])) {
  5423. /* Missing/Invalid arguments */
  5424. PH7_VmThrowError(pCtx->pVm, PH7_CTX_ERR, "Expecting a ZIP archive entry");
  5425. /* return FALSE */
  5426. ph7_result_bool(pCtx, 0);
  5427. return PH7_OK;
  5428. }
  5429. /* Make sure we are dealing with a valid ZIP archive entry */
  5430. pEntry = (SyArchiveEntry *)ph7_value_to_resource(apArg[0]);
  5431. if(SXARCH_ENTRY_INVALID(pEntry)) {
  5432. PH7_VmThrowError(pCtx->pVm, PH7_CTX_ERR, "Expecting a ZIP archive entry");
  5433. /* return FALSE */
  5434. ph7_result_bool(pCtx, 0);
  5435. return PH7_OK;
  5436. }
  5437. /* Return entry name */
  5438. pName = &pEntry->sFileName;
  5439. ph7_result_string(pCtx, pName->zString, (int)pName->nByte);
  5440. return PH7_OK;
  5441. }
  5442. /*
  5443. * int64 zip_entry_filesize(resource $zip_entry)
  5444. * Retrieve the actual file size of a directory entry.
  5445. * Parameters
  5446. * $zip_entry
  5447. * A directory entry returned by zip_read().
  5448. * Return
  5449. * The size of the directory entry.
  5450. */
  5451. static int PH7_builtin_zip_entry_filesize(ph7_context *pCtx, int nArg, ph7_value **apArg) {
  5452. SyArchiveEntry *pEntry;
  5453. if(nArg < 1 || !ph7_value_is_resource(apArg[0])) {
  5454. /* Missing/Invalid arguments */
  5455. PH7_VmThrowError(pCtx->pVm, PH7_CTX_ERR, "Expecting a ZIP archive entry");
  5456. /* return FALSE */
  5457. ph7_result_bool(pCtx, 0);
  5458. return PH7_OK;
  5459. }
  5460. /* Make sure we are dealing with a valid ZIP archive entry */
  5461. pEntry = (SyArchiveEntry *)ph7_value_to_resource(apArg[0]);
  5462. if(SXARCH_ENTRY_INVALID(pEntry)) {
  5463. PH7_VmThrowError(pCtx->pVm, PH7_CTX_ERR, "Expecting a ZIP archive entry");
  5464. /* return FALSE */
  5465. ph7_result_bool(pCtx, 0);
  5466. return PH7_OK;
  5467. }
  5468. /* Return entry size */
  5469. ph7_result_int64(pCtx, (ph7_int64)pEntry->nByte);
  5470. return PH7_OK;
  5471. }
  5472. /*
  5473. * int64 zip_entry_compressedsize(resource $zip_entry)
  5474. * Retrieve the compressed size of a directory entry.
  5475. * Parameters
  5476. * $zip_entry
  5477. * A directory entry returned by zip_read().
  5478. * Return
  5479. * The compressed size.
  5480. */
  5481. static int PH7_builtin_zip_entry_compressedsize(ph7_context *pCtx, int nArg, ph7_value **apArg) {
  5482. SyArchiveEntry *pEntry;
  5483. if(nArg < 1 || !ph7_value_is_resource(apArg[0])) {
  5484. /* Missing/Invalid arguments */
  5485. PH7_VmThrowError(pCtx->pVm, PH7_CTX_ERR, "Expecting a ZIP archive entry");
  5486. /* return FALSE */
  5487. ph7_result_bool(pCtx, 0);
  5488. return PH7_OK;
  5489. }
  5490. /* Make sure we are dealing with a valid ZIP archive entry */
  5491. pEntry = (SyArchiveEntry *)ph7_value_to_resource(apArg[0]);
  5492. if(SXARCH_ENTRY_INVALID(pEntry)) {
  5493. PH7_VmThrowError(pCtx->pVm, PH7_CTX_ERR, "Expecting a ZIP archive entry");
  5494. /* return FALSE */
  5495. ph7_result_bool(pCtx, 0);
  5496. return PH7_OK;
  5497. }
  5498. /* Return entry compressed size */
  5499. ph7_result_int64(pCtx, (ph7_int64)pEntry->nByteCompr);
  5500. return PH7_OK;
  5501. }
  5502. /*
  5503. * string zip_entry_read(resource $zip_entry[,int $length])
  5504. * Reads from an open directory entry.
  5505. * Parameters
  5506. * $zip_entry
  5507. * A directory entry returned by zip_read().
  5508. * $length
  5509. * The number of bytes to return. If not specified, this function
  5510. * will attempt to read 1024 bytes.
  5511. * Return
  5512. * Returns the data read, or FALSE if the end of the file is reached.
  5513. */
  5514. static int PH7_builtin_zip_entry_read(ph7_context *pCtx, int nArg, ph7_value **apArg) {
  5515. SyArchiveEntry *pEntry;
  5516. zip_raw_data *pRaw;
  5517. const char *zData;
  5518. int iLength;
  5519. if(nArg < 1 || !ph7_value_is_resource(apArg[0])) {
  5520. /* Missing/Invalid arguments */
  5521. PH7_VmThrowError(pCtx->pVm, PH7_CTX_ERR, "Expecting a ZIP archive entry");
  5522. /* return FALSE */
  5523. ph7_result_bool(pCtx, 0);
  5524. return PH7_OK;
  5525. }
  5526. /* Make sure we are dealing with a valid ZIP archive entry */
  5527. pEntry = (SyArchiveEntry *)ph7_value_to_resource(apArg[0]);
  5528. if(SXARCH_ENTRY_INVALID(pEntry)) {
  5529. PH7_VmThrowError(pCtx->pVm, PH7_CTX_ERR, "Expecting a ZIP archive entry");
  5530. /* return FALSE */
  5531. ph7_result_bool(pCtx, 0);
  5532. return PH7_OK;
  5533. }
  5534. zData = 0;
  5535. if(pEntry->nReadCount >= pEntry->nByteCompr) {
  5536. /* No more data to read,return FALSE */
  5537. ph7_result_bool(pCtx, 0);
  5538. return PH7_OK;
  5539. }
  5540. /* Set a default read length */
  5541. iLength = 1024;
  5542. if(nArg > 1) {
  5543. iLength = ph7_value_to_int(apArg[1]);
  5544. if(iLength < 1) {
  5545. iLength = 1024;
  5546. }
  5547. }
  5548. if((sxu32)iLength > pEntry->nByteCompr - pEntry->nReadCount) {
  5549. iLength = (int)(pEntry->nByteCompr - pEntry->nReadCount);
  5550. }
  5551. /* Return the entry contents */
  5552. pRaw = (zip_raw_data *)pEntry->pUserData;
  5553. if(pRaw->iType == ZIP_RAW_DATA_MEMBUF) {
  5554. zData = (const char *)SyBlobDataAt(&pRaw->raw.sBlob, (pEntry->nOfft + pEntry->nReadCount));
  5555. } else {
  5556. const char *zMap = (const char *)pRaw->raw.mmap.pMap;
  5557. /* Memory mapped chunk */
  5558. zData = &zMap[pEntry->nOfft + pEntry->nReadCount];
  5559. }
  5560. /* Increment the read counter */
  5561. pEntry->nReadCount += iLength;
  5562. /* Return the raw data */
  5563. ph7_result_string(pCtx, zData, iLength);
  5564. return PH7_OK;
  5565. }
  5566. /*
  5567. * bool zip_entry_reset_read_cursor(resource $zip_entry)
  5568. * Reset the read cursor of an open directory entry.
  5569. * Parameters
  5570. * $zip_entry
  5571. * A directory entry returned by zip_read().
  5572. * Return
  5573. * TRUE on success,FALSE on failure.
  5574. * Note that this is a symisc eXtension.
  5575. */
  5576. static int PH7_builtin_zip_entry_reset_read_cursor(ph7_context *pCtx, int nArg, ph7_value **apArg) {
  5577. SyArchiveEntry *pEntry;
  5578. if(nArg < 1 || !ph7_value_is_resource(apArg[0])) {
  5579. /* Missing/Invalid arguments */
  5580. PH7_VmThrowError(pCtx->pVm, PH7_CTX_ERR, "Expecting a ZIP archive entry");
  5581. /* return FALSE */
  5582. ph7_result_bool(pCtx, 0);
  5583. return PH7_OK;
  5584. }
  5585. /* Make sure we are dealing with a valid ZIP archive entry */
  5586. pEntry = (SyArchiveEntry *)ph7_value_to_resource(apArg[0]);
  5587. if(SXARCH_ENTRY_INVALID(pEntry)) {
  5588. PH7_VmThrowError(pCtx->pVm, PH7_CTX_ERR, "Expecting a ZIP archive entry");
  5589. /* return FALSE */
  5590. ph7_result_bool(pCtx, 0);
  5591. return PH7_OK;
  5592. }
  5593. /* Reset the cursor */
  5594. pEntry->nReadCount = 0;
  5595. /* Return TRUE */
  5596. ph7_result_bool(pCtx, 1);
  5597. return PH7_OK;
  5598. }
  5599. /*
  5600. * string zip_entry_compressionmethod(resource $zip_entry)
  5601. * Retrieve the compression method of a directory entry.
  5602. * Parameters
  5603. * $zip_entry
  5604. * A directory entry returned by zip_read().
  5605. * Return
  5606. * The compression method on success or FALSE on failure.
  5607. */
  5608. static int PH7_builtin_zip_entry_compressionmethod(ph7_context *pCtx, int nArg, ph7_value **apArg) {
  5609. SyArchiveEntry *pEntry;
  5610. if(nArg < 1 || !ph7_value_is_resource(apArg[0])) {
  5611. /* Missing/Invalid arguments */
  5612. PH7_VmThrowError(pCtx->pVm, PH7_CTX_ERR, "Expecting a ZIP archive entry");
  5613. /* return FALSE */
  5614. ph7_result_bool(pCtx, 0);
  5615. return PH7_OK;
  5616. }
  5617. /* Make sure we are dealing with a valid ZIP archive entry */
  5618. pEntry = (SyArchiveEntry *)ph7_value_to_resource(apArg[0]);
  5619. if(SXARCH_ENTRY_INVALID(pEntry)) {
  5620. PH7_VmThrowError(pCtx->pVm, PH7_CTX_ERR, "Expecting a ZIP archive entry");
  5621. /* return FALSE */
  5622. ph7_result_bool(pCtx, 0);
  5623. return PH7_OK;
  5624. }
  5625. switch(pEntry->nComprMeth) {
  5626. case 0:
  5627. /* No compression;entry is stored */
  5628. ph7_result_string(pCtx, "stored", (int)sizeof("stored") - 1);
  5629. break;
  5630. case 8:
  5631. /* Entry is deflated (Default compression algorithm) */
  5632. ph7_result_string(pCtx, "deflate", (int)sizeof("deflate") - 1);
  5633. break;
  5634. /* Exotic compression algorithms */
  5635. case 1:
  5636. ph7_result_string(pCtx, "shrunk", (int)sizeof("shrunk") - 1);
  5637. break;
  5638. case 2:
  5639. case 3:
  5640. case 4:
  5641. case 5:
  5642. /* Entry is reduced */
  5643. ph7_result_string(pCtx, "reduced", (int)sizeof("reduced") - 1);
  5644. break;
  5645. case 6:
  5646. /* Entry is imploded */
  5647. ph7_result_string(pCtx, "implode", (int)sizeof("implode") - 1);
  5648. break;
  5649. default:
  5650. ph7_result_string(pCtx, "unknown", (int)sizeof("unknown") - 1);
  5651. break;
  5652. }
  5653. return PH7_OK;
  5654. }
  5655. #ifdef __WINNT__
  5656. /*
  5657. * Windows VFS implementation for the PH7 engine.
  5658. * Authors:
  5659. * Symisc Systems,devel@symisc.net.
  5660. * Copyright (C) Symisc Systems,https://ph7.symisc.net
  5661. * Status:
  5662. * Stable.
  5663. */
  5664. /* What follows here is code that is specific to windows systems. */
  5665. #include <Windows.h>
  5666. /*
  5667. ** Convert a UTF-8 string to microsoft unicode (UTF-16?).
  5668. **
  5669. ** Space to hold the returned string is obtained from HeapAlloc().
  5670. ** Taken from the sqlite3 source tree
  5671. ** status: Public Domain
  5672. */
  5673. static WCHAR *utf8ToUnicode(const char *zFilename) {
  5674. int nChar;
  5675. WCHAR *zWideFilename;
  5676. nChar = MultiByteToWideChar(CP_UTF8, 0, zFilename, -1, 0, 0);
  5677. zWideFilename = (WCHAR *)HeapAlloc(GetProcessHeap(), 0, nChar * sizeof(zWideFilename[0]));
  5678. if(zWideFilename == 0) {
  5679. return 0;
  5680. }
  5681. nChar = MultiByteToWideChar(CP_UTF8, 0, zFilename, -1, zWideFilename, nChar);
  5682. if(nChar == 0) {
  5683. HeapFree(GetProcessHeap(), 0, zWideFilename);
  5684. return 0;
  5685. }
  5686. return zWideFilename;
  5687. }
  5688. /*
  5689. ** Convert a UTF-8 filename into whatever form the underlying
  5690. ** operating system wants filenames in.Space to hold the result
  5691. ** is obtained from HeapAlloc() and must be freed by the calling
  5692. ** function.
  5693. ** Taken from the sqlite3 source tree
  5694. ** status: Public Domain
  5695. */
  5696. static void *convertUtf8Filename(const char *zFilename) {
  5697. void *zConverted;
  5698. zConverted = utf8ToUnicode(zFilename);
  5699. return zConverted;
  5700. }
  5701. /*
  5702. ** Convert microsoft unicode to UTF-8. Space to hold the returned string is
  5703. ** obtained from HeapAlloc().
  5704. ** Taken from the sqlite3 source tree
  5705. ** status: Public Domain
  5706. */
  5707. static char *unicodeToUtf8(const WCHAR *zWideFilename) {
  5708. char *zFilename;
  5709. int nByte;
  5710. nByte = WideCharToMultiByte(CP_UTF8, 0, zWideFilename, -1, 0, 0, 0, 0);
  5711. zFilename = (char *)HeapAlloc(GetProcessHeap(), 0, nByte);
  5712. if(zFilename == 0) {
  5713. return 0;
  5714. }
  5715. nByte = WideCharToMultiByte(CP_UTF8, 0, zWideFilename, -1, zFilename, nByte, 0, 0);
  5716. if(nByte == 0) {
  5717. HeapFree(GetProcessHeap(), 0, zFilename);
  5718. return 0;
  5719. }
  5720. return zFilename;
  5721. }
  5722. /* int (*xchdir)(const char *) */
  5723. static int WinVfs_chdir(const char *zPath) {
  5724. void *pConverted;
  5725. BOOL rc;
  5726. pConverted = convertUtf8Filename(zPath);
  5727. if(pConverted == 0) {
  5728. return -1;
  5729. }
  5730. rc = SetCurrentDirectoryW((LPCWSTR)pConverted);
  5731. HeapFree(GetProcessHeap(), 0, pConverted);
  5732. return rc ? PH7_OK : -1;
  5733. }
  5734. /* int (*xGetcwd)(ph7_context *) */
  5735. static int WinVfs_getcwd(ph7_context *pCtx) {
  5736. WCHAR zDir[2048];
  5737. char *zConverted;
  5738. DWORD rc;
  5739. /* Get the current directory */
  5740. rc = GetCurrentDirectoryW(sizeof(zDir), zDir);
  5741. if(rc < 1) {
  5742. return -1;
  5743. }
  5744. zConverted = unicodeToUtf8(zDir);
  5745. if(zConverted == 0) {
  5746. return -1;
  5747. }
  5748. ph7_result_string(pCtx, zConverted, -1/*Compute length automatically*/); /* Will make it's own copy */
  5749. HeapFree(GetProcessHeap(), 0, zConverted);
  5750. return PH7_OK;
  5751. }
  5752. /* int (*xMkdir)(const char *,int,int) */
  5753. static int WinVfs_mkdir(const char *zPath, int mode, int recursive) {
  5754. void *pConverted;
  5755. BOOL rc;
  5756. pConverted = convertUtf8Filename(zPath);
  5757. if(pConverted == 0) {
  5758. return -1;
  5759. }
  5760. mode = 0; /* MSVC warning */
  5761. recursive = 0;
  5762. rc = CreateDirectoryW((LPCWSTR)pConverted, 0);
  5763. HeapFree(GetProcessHeap(), 0, pConverted);
  5764. return rc ? PH7_OK : -1;
  5765. }
  5766. /* int (*xRmdir)(const char *) */
  5767. static int WinVfs_rmdir(const char *zPath) {
  5768. void *pConverted;
  5769. BOOL rc;
  5770. pConverted = convertUtf8Filename(zPath);
  5771. if(pConverted == 0) {
  5772. return -1;
  5773. }
  5774. rc = RemoveDirectoryW((LPCWSTR)pConverted);
  5775. HeapFree(GetProcessHeap(), 0, pConverted);
  5776. return rc ? PH7_OK : -1;
  5777. }
  5778. /* int (*xIsdir)(const char *) */
  5779. static int WinVfs_isdir(const char *zPath) {
  5780. void *pConverted;
  5781. DWORD dwAttr;
  5782. pConverted = convertUtf8Filename(zPath);
  5783. if(pConverted == 0) {
  5784. return -1;
  5785. }
  5786. dwAttr = GetFileAttributesW((LPCWSTR)pConverted);
  5787. HeapFree(GetProcessHeap(), 0, pConverted);
  5788. if(dwAttr == INVALID_FILE_ATTRIBUTES) {
  5789. return -1;
  5790. }
  5791. return (dwAttr & FILE_ATTRIBUTE_DIRECTORY) ? PH7_OK : -1;
  5792. }
  5793. /* int (*xRename)(const char *,const char *) */
  5794. static int WinVfs_Rename(const char *zOld, const char *zNew) {
  5795. void *pOld, *pNew;
  5796. BOOL rc = 0;
  5797. pOld = convertUtf8Filename(zOld);
  5798. if(pOld == 0) {
  5799. return -1;
  5800. }
  5801. pNew = convertUtf8Filename(zNew);
  5802. if(pNew) {
  5803. rc = MoveFileW((LPCWSTR)pOld, (LPCWSTR)pNew);
  5804. }
  5805. HeapFree(GetProcessHeap(), 0, pOld);
  5806. if(pNew) {
  5807. HeapFree(GetProcessHeap(), 0, pNew);
  5808. }
  5809. return rc ? PH7_OK : - 1;
  5810. }
  5811. /* int (*xRealpath)(const char *,ph7_context *) */
  5812. static int WinVfs_Realpath(const char *zPath, ph7_context *pCtx) {
  5813. WCHAR zTemp[2048];
  5814. void *pPath;
  5815. char *zReal;
  5816. DWORD n;
  5817. pPath = convertUtf8Filename(zPath);
  5818. if(pPath == 0) {
  5819. return -1;
  5820. }
  5821. n = GetFullPathNameW((LPCWSTR)pPath, 0, 0, 0);
  5822. if(n > 0) {
  5823. if(n >= sizeof(zTemp)) {
  5824. n = sizeof(zTemp) - 1;
  5825. }
  5826. GetFullPathNameW((LPCWSTR)pPath, n, zTemp, 0);
  5827. }
  5828. HeapFree(GetProcessHeap(), 0, pPath);
  5829. if(!n) {
  5830. return -1;
  5831. }
  5832. zReal = unicodeToUtf8(zTemp);
  5833. if(zReal == 0) {
  5834. return -1;
  5835. }
  5836. ph7_result_string(pCtx, zReal, -1); /* Will make it's own copy */
  5837. HeapFree(GetProcessHeap(), 0, zReal);
  5838. return PH7_OK;
  5839. }
  5840. /* int (*xSleep)(unsigned int) */
  5841. static int WinVfs_Sleep(unsigned int uSec) {
  5842. Sleep(uSec / 1000/*uSec per Millisec */);
  5843. return PH7_OK;
  5844. }
  5845. /* int (*xUnlink)(const char *) */
  5846. static int WinVfs_unlink(const char *zPath) {
  5847. void *pConverted;
  5848. BOOL rc;
  5849. pConverted = convertUtf8Filename(zPath);
  5850. if(pConverted == 0) {
  5851. return -1;
  5852. }
  5853. rc = DeleteFileW((LPCWSTR)pConverted);
  5854. HeapFree(GetProcessHeap(), 0, pConverted);
  5855. return rc ? PH7_OK : - 1;
  5856. }
  5857. /* ph7_int64 (*xFreeSpace)(const char *) */
  5858. static ph7_int64 WinVfs_DiskFreeSpace(const char *zPath) {
  5859. #ifdef _WIN32_WCE
  5860. /* GetDiskFreeSpace is not supported under WINCE */
  5861. SXUNUSED(zPath);
  5862. return 0;
  5863. #else
  5864. DWORD dwSectPerClust, dwBytesPerSect, dwFreeClusters, dwTotalClusters;
  5865. void *pConverted;
  5866. WCHAR *p;
  5867. BOOL rc;
  5868. pConverted = convertUtf8Filename(zPath);
  5869. if(pConverted == 0) {
  5870. return 0;
  5871. }
  5872. p = (WCHAR *)pConverted;
  5873. for(; *p; p++) {
  5874. if(*p == '\\' || *p == '/') {
  5875. *p = '\0';
  5876. break;
  5877. }
  5878. }
  5879. rc = GetDiskFreeSpaceW((LPCWSTR)pConverted, &dwSectPerClust, &dwBytesPerSect, &dwFreeClusters, &dwTotalClusters);
  5880. if(!rc) {
  5881. return 0;
  5882. }
  5883. return (ph7_int64)dwFreeClusters * dwSectPerClust * dwBytesPerSect;
  5884. #endif
  5885. }
  5886. /* ph7_int64 (*xTotalSpace)(const char *) */
  5887. static ph7_int64 WinVfs_DiskTotalSpace(const char *zPath) {
  5888. #ifdef _WIN32_WCE
  5889. /* GetDiskFreeSpace is not supported under WINCE */
  5890. SXUNUSED(zPath);
  5891. return 0;
  5892. #else
  5893. DWORD dwSectPerClust, dwBytesPerSect, dwFreeClusters, dwTotalClusters;
  5894. void *pConverted;
  5895. WCHAR *p;
  5896. BOOL rc;
  5897. pConverted = convertUtf8Filename(zPath);
  5898. if(pConverted == 0) {
  5899. return 0;
  5900. }
  5901. p = (WCHAR *)pConverted;
  5902. for(; *p; p++) {
  5903. if(*p == '\\' || *p == '/') {
  5904. *p = '\0';
  5905. break;
  5906. }
  5907. }
  5908. rc = GetDiskFreeSpaceW((LPCWSTR)pConverted, &dwSectPerClust, &dwBytesPerSect, &dwFreeClusters, &dwTotalClusters);
  5909. if(!rc) {
  5910. return 0;
  5911. }
  5912. return (ph7_int64)dwTotalClusters * dwSectPerClust * dwBytesPerSect;
  5913. #endif
  5914. }
  5915. /* int (*xFileExists)(const char *) */
  5916. static int WinVfs_FileExists(const char *zPath) {
  5917. void *pConverted;
  5918. DWORD dwAttr;
  5919. pConverted = convertUtf8Filename(zPath);
  5920. if(pConverted == 0) {
  5921. return -1;
  5922. }
  5923. dwAttr = GetFileAttributesW((LPCWSTR)pConverted);
  5924. HeapFree(GetProcessHeap(), 0, pConverted);
  5925. if(dwAttr == INVALID_FILE_ATTRIBUTES) {
  5926. return -1;
  5927. }
  5928. return PH7_OK;
  5929. }
  5930. /* Open a file in a read-only mode */
  5931. static HANDLE OpenReadOnly(LPCWSTR pPath) {
  5932. DWORD dwType = FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS;
  5933. DWORD dwShare = FILE_SHARE_READ | FILE_SHARE_WRITE;
  5934. DWORD dwAccess = GENERIC_READ;
  5935. DWORD dwCreate = OPEN_EXISTING;
  5936. HANDLE pHandle;
  5937. pHandle = CreateFileW(pPath, dwAccess, dwShare, 0, dwCreate, dwType, 0);
  5938. if(pHandle == INVALID_HANDLE_VALUE) {
  5939. return 0;
  5940. }
  5941. return pHandle;
  5942. }
  5943. /* ph7_int64 (*xFileSize)(const char *) */
  5944. static ph7_int64 WinVfs_FileSize(const char *zPath) {
  5945. DWORD dwLow, dwHigh;
  5946. void *pConverted;
  5947. ph7_int64 nSize;
  5948. HANDLE pHandle;
  5949. pConverted = convertUtf8Filename(zPath);
  5950. if(pConverted == 0) {
  5951. return -1;
  5952. }
  5953. /* Open the file in read-only mode */
  5954. pHandle = OpenReadOnly((LPCWSTR)pConverted);
  5955. HeapFree(GetProcessHeap(), 0, pConverted);
  5956. if(pHandle) {
  5957. dwLow = GetFileSize(pHandle, &dwHigh);
  5958. nSize = dwHigh;
  5959. nSize <<= 32;
  5960. nSize += dwLow;
  5961. CloseHandle(pHandle);
  5962. } else {
  5963. nSize = -1;
  5964. }
  5965. return nSize;
  5966. }
  5967. #define TICKS_PER_SECOND 10000000
  5968. #define EPOCH_DIFFERENCE 11644473600LL
  5969. /* Convert Windows timestamp to UNIX timestamp */
  5970. static ph7_int64 convertWindowsTimeToUnixTime(LPFILETIME pTime) {
  5971. ph7_int64 input, temp;
  5972. input = pTime->dwHighDateTime;
  5973. input <<= 32;
  5974. input += pTime->dwLowDateTime;
  5975. temp = input / TICKS_PER_SECOND; /*convert from 100ns intervals to seconds*/
  5976. temp = temp - EPOCH_DIFFERENCE; /*subtract number of seconds between epochs*/
  5977. return temp;
  5978. }
  5979. /* Convert UNIX timestamp to Windows timestamp */
  5980. static void convertUnixTimeToWindowsTime(ph7_int64 nUnixtime, LPFILETIME pOut) {
  5981. ph7_int64 result = EPOCH_DIFFERENCE;
  5982. result += nUnixtime;
  5983. result *= 10000000LL;
  5984. pOut->dwHighDateTime = (DWORD)(nUnixtime >> 32);
  5985. pOut->dwLowDateTime = (DWORD)nUnixtime;
  5986. }
  5987. /* int (*xTouch)(const char *,ph7_int64,ph7_int64) */
  5988. static int WinVfs_Touch(const char *zPath, ph7_int64 touch_time, ph7_int64 access_time) {
  5989. FILETIME sTouch, sAccess;
  5990. void *pConverted;
  5991. void *pHandle;
  5992. BOOL rc = 0;
  5993. pConverted = convertUtf8Filename(zPath);
  5994. if(pConverted == 0) {
  5995. return -1;
  5996. }
  5997. pHandle = OpenReadOnly((LPCWSTR)pConverted);
  5998. if(pHandle) {
  5999. if(touch_time < 0) {
  6000. GetSystemTimeAsFileTime(&sTouch);
  6001. } else {
  6002. convertUnixTimeToWindowsTime(touch_time, &sTouch);
  6003. }
  6004. if(access_time < 0) {
  6005. /* Use the touch time */
  6006. sAccess = sTouch; /* Structure assignment */
  6007. } else {
  6008. convertUnixTimeToWindowsTime(access_time, &sAccess);
  6009. }
  6010. rc = SetFileTime(pHandle, &sTouch, &sAccess, 0);
  6011. /* Close the handle */
  6012. CloseHandle(pHandle);
  6013. }
  6014. HeapFree(GetProcessHeap(), 0, pConverted);
  6015. return rc ? PH7_OK : -1;
  6016. }
  6017. /* ph7_int64 (*xFileAtime)(const char *) */
  6018. static ph7_int64 WinVfs_FileAtime(const char *zPath) {
  6019. BY_HANDLE_FILE_INFORMATION sInfo;
  6020. void *pConverted;
  6021. ph7_int64 atime;
  6022. HANDLE pHandle;
  6023. pConverted = convertUtf8Filename(zPath);
  6024. if(pConverted == 0) {
  6025. return -1;
  6026. }
  6027. /* Open the file in read-only mode */
  6028. pHandle = OpenReadOnly((LPCWSTR)pConverted);
  6029. if(pHandle) {
  6030. BOOL rc;
  6031. rc = GetFileInformationByHandle(pHandle, &sInfo);
  6032. if(rc) {
  6033. atime = convertWindowsTimeToUnixTime(&sInfo.ftLastAccessTime);
  6034. } else {
  6035. atime = -1;
  6036. }
  6037. CloseHandle(pHandle);
  6038. } else {
  6039. atime = -1;
  6040. }
  6041. HeapFree(GetProcessHeap(), 0, pConverted);
  6042. return atime;
  6043. }
  6044. /* ph7_int64 (*xFileMtime)(const char *) */
  6045. static ph7_int64 WinVfs_FileMtime(const char *zPath) {
  6046. BY_HANDLE_FILE_INFORMATION sInfo;
  6047. void *pConverted;
  6048. ph7_int64 mtime;
  6049. HANDLE pHandle;
  6050. pConverted = convertUtf8Filename(zPath);
  6051. if(pConverted == 0) {
  6052. return -1;
  6053. }
  6054. /* Open the file in read-only mode */
  6055. pHandle = OpenReadOnly((LPCWSTR)pConverted);
  6056. if(pHandle) {
  6057. BOOL rc;
  6058. rc = GetFileInformationByHandle(pHandle, &sInfo);
  6059. if(rc) {
  6060. mtime = convertWindowsTimeToUnixTime(&sInfo.ftLastWriteTime);
  6061. } else {
  6062. mtime = -1;
  6063. }
  6064. CloseHandle(pHandle);
  6065. } else {
  6066. mtime = -1;
  6067. }
  6068. HeapFree(GetProcessHeap(), 0, pConverted);
  6069. return mtime;
  6070. }
  6071. /* ph7_int64 (*xFileCtime)(const char *) */
  6072. static ph7_int64 WinVfs_FileCtime(const char *zPath) {
  6073. BY_HANDLE_FILE_INFORMATION sInfo;
  6074. void *pConverted;
  6075. ph7_int64 ctime;
  6076. HANDLE pHandle;
  6077. pConverted = convertUtf8Filename(zPath);
  6078. if(pConverted == 0) {
  6079. return -1;
  6080. }
  6081. /* Open the file in read-only mode */
  6082. pHandle = OpenReadOnly((LPCWSTR)pConverted);
  6083. if(pHandle) {
  6084. BOOL rc;
  6085. rc = GetFileInformationByHandle(pHandle, &sInfo);
  6086. if(rc) {
  6087. ctime = convertWindowsTimeToUnixTime(&sInfo.ftCreationTime);
  6088. } else {
  6089. ctime = -1;
  6090. }
  6091. CloseHandle(pHandle);
  6092. } else {
  6093. ctime = -1;
  6094. }
  6095. HeapFree(GetProcessHeap(), 0, pConverted);
  6096. return ctime;
  6097. }
  6098. /* ph7_int64 (*xFileGroup)(const char *) */
  6099. static int WinVfs_FileGroup(const char *zPath) {
  6100. BY_HANDLE_FILE_INFORMATION sInfo;
  6101. void *pConverted;
  6102. ph7_int64 group;
  6103. HANDLE pHandle;
  6104. pConverted = convertUtf8Filename(zPath);
  6105. if(pConverted == 0) {
  6106. return -1;
  6107. }
  6108. /* Open the file in read-only mode */
  6109. pHandle = OpenReadOnly((LPCWSTR)pConverted);
  6110. if(pHandle) {
  6111. group = 0;
  6112. CloseHandle(pHandle);
  6113. } else {
  6114. group = -1;
  6115. }
  6116. HeapFree(GetProcessHeap(), 0, pConverted);
  6117. return group;
  6118. }
  6119. /* ph7_int64 (*xFileInode)(const char *) */
  6120. static int WinVfs_FileInode(const char *zPath) {
  6121. BY_HANDLE_FILE_INFORMATION sInfo;
  6122. void *pConverted;
  6123. ph7_int64 inode;
  6124. HANDLE pHandle;
  6125. pConverted = convertUtf8Filename(zPath);
  6126. if(pConverted == 0) {
  6127. return -1;
  6128. }
  6129. /* Open the file in read-only mode */
  6130. pHandle = OpenReadOnly((LPCWSTR)pConverted);
  6131. if(pHandle) {
  6132. BOOL rc;
  6133. rc = GetFileInformationByHandle(pHandle, &sInfo);
  6134. if(rc) {
  6135. inode = (ph7_int64)(((ph7_int64)sInfo.nFileIndexHigh << 32) | sInfo.nFileIndexLow);
  6136. } else {
  6137. inode = -1;
  6138. }
  6139. CloseHandle(pHandle);
  6140. } else {
  6141. inode = -1;
  6142. }
  6143. HeapFree(GetProcessHeap(), 0, pConverted);
  6144. return inode;
  6145. }
  6146. /* ph7_int64 (*xFileOwner)(const char *) */
  6147. static int WinVfs_FileOwner(const char *zPath) {
  6148. BY_HANDLE_FILE_INFORMATION sInfo;
  6149. void *pConverted;
  6150. ph7_int64 owner;
  6151. HANDLE pHandle;
  6152. pConverted = convertUtf8Filename(zPath);
  6153. if(pConverted == 0) {
  6154. return -1;
  6155. }
  6156. /* Open the file in read-only mode */
  6157. pHandle = OpenReadOnly((LPCWSTR)pConverted);
  6158. if(pHandle) {
  6159. owner = 0;
  6160. CloseHandle(pHandle);
  6161. } else {
  6162. owner = -1;
  6163. }
  6164. HeapFree(GetProcessHeap(), 0, pConverted);
  6165. return owner;
  6166. }
  6167. /* int (*xStat)(const char *,ph7_value *,ph7_value *) */
  6168. /* int (*xlStat)(const char *,ph7_value *,ph7_value *) */
  6169. static int WinVfs_Stat(const char *zPath, ph7_value *pArray, ph7_value *pWorker) {
  6170. BY_HANDLE_FILE_INFORMATION sInfo;
  6171. void *pConverted;
  6172. HANDLE pHandle;
  6173. BOOL rc;
  6174. pConverted = convertUtf8Filename(zPath);
  6175. if(pConverted == 0) {
  6176. return -1;
  6177. }
  6178. /* Open the file in read-only mode */
  6179. pHandle = OpenReadOnly((LPCWSTR)pConverted);
  6180. HeapFree(GetProcessHeap(), 0, pConverted);
  6181. if(pHandle == 0) {
  6182. return -1;
  6183. }
  6184. rc = GetFileInformationByHandle(pHandle, &sInfo);
  6185. CloseHandle(pHandle);
  6186. if(!rc) {
  6187. return -1;
  6188. }
  6189. /* dev */
  6190. ph7_value_int64(pWorker, (ph7_int64)sInfo.dwVolumeSerialNumber);
  6191. ph7_array_add_strkey_elem(pArray, "dev", pWorker); /* Will make it's own copy */
  6192. /* ino */
  6193. ph7_value_int64(pWorker, (ph7_int64)(((ph7_int64)sInfo.nFileIndexHigh << 32) | sInfo.nFileIndexLow));
  6194. ph7_array_add_strkey_elem(pArray, "ino", pWorker); /* Will make it's own copy */
  6195. /* mode */
  6196. ph7_value_int(pWorker, 0);
  6197. ph7_array_add_strkey_elem(pArray, "mode", pWorker);
  6198. /* nlink */
  6199. ph7_value_int(pWorker, (int)sInfo.nNumberOfLinks);
  6200. ph7_array_add_strkey_elem(pArray, "nlink", pWorker); /* Will make it's own copy */
  6201. /* uid,gid,rdev */
  6202. ph7_value_int(pWorker, 0);
  6203. ph7_array_add_strkey_elem(pArray, "uid", pWorker);
  6204. ph7_array_add_strkey_elem(pArray, "gid", pWorker);
  6205. ph7_array_add_strkey_elem(pArray, "rdev", pWorker);
  6206. /* size */
  6207. ph7_value_int64(pWorker, (ph7_int64)(((ph7_int64)sInfo.nFileSizeHigh << 32) | sInfo.nFileSizeLow));
  6208. ph7_array_add_strkey_elem(pArray, "size", pWorker); /* Will make it's own copy */
  6209. /* atime */
  6210. ph7_value_int64(pWorker, convertWindowsTimeToUnixTime(&sInfo.ftLastAccessTime));
  6211. ph7_array_add_strkey_elem(pArray, "atime", pWorker); /* Will make it's own copy */
  6212. /* mtime */
  6213. ph7_value_int64(pWorker, convertWindowsTimeToUnixTime(&sInfo.ftLastWriteTime));
  6214. ph7_array_add_strkey_elem(pArray, "mtime", pWorker); /* Will make it's own copy */
  6215. /* ctime */
  6216. ph7_value_int64(pWorker, convertWindowsTimeToUnixTime(&sInfo.ftCreationTime));
  6217. ph7_array_add_strkey_elem(pArray, "ctime", pWorker); /* Will make it's own copy */
  6218. /* blksize,blocks */
  6219. ph7_value_int(pWorker, 0);
  6220. ph7_array_add_strkey_elem(pArray, "blksize", pWorker);
  6221. ph7_array_add_strkey_elem(pArray, "blocks", pWorker);
  6222. return PH7_OK;
  6223. }
  6224. /* int (*xIsFile)(const char *) */
  6225. static int WinVfs_isFile(const char *zPath) {
  6226. void *pConverted;
  6227. DWORD dwAttr;
  6228. pConverted = convertUtf8Filename(zPath);
  6229. if(pConverted == 0) {
  6230. return -1;
  6231. }
  6232. dwAttr = GetFileAttributesW((LPCWSTR)pConverted);
  6233. HeapFree(GetProcessHeap(), 0, pConverted);
  6234. if(dwAttr == INVALID_FILE_ATTRIBUTES) {
  6235. return -1;
  6236. }
  6237. return (dwAttr & (FILE_ATTRIBUTE_NORMAL | FILE_ATTRIBUTE_ARCHIVE)) ? PH7_OK : -1;
  6238. }
  6239. /* int (*xIsLink)(const char *) */
  6240. static int WinVfs_isLink(const char *zPath) {
  6241. void *pConverted;
  6242. DWORD dwAttr;
  6243. pConverted = convertUtf8Filename(zPath);
  6244. if(pConverted == 0) {
  6245. return -1;
  6246. }
  6247. dwAttr = GetFileAttributesW((LPCWSTR)pConverted);
  6248. HeapFree(GetProcessHeap(), 0, pConverted);
  6249. if(dwAttr == INVALID_FILE_ATTRIBUTES) {
  6250. return -1;
  6251. }
  6252. return (dwAttr & FILE_ATTRIBUTE_REPARSE_POINT) ? PH7_OK : -1;
  6253. }
  6254. /* int (*xWritable)(const char *) */
  6255. static int WinVfs_isWritable(const char *zPath) {
  6256. void *pConverted;
  6257. DWORD dwAttr;
  6258. pConverted = convertUtf8Filename(zPath);
  6259. if(pConverted == 0) {
  6260. return -1;
  6261. }
  6262. dwAttr = GetFileAttributesW((LPCWSTR)pConverted);
  6263. HeapFree(GetProcessHeap(), 0, pConverted);
  6264. if(dwAttr == INVALID_FILE_ATTRIBUTES) {
  6265. return -1;
  6266. }
  6267. if((dwAttr & (FILE_ATTRIBUTE_ARCHIVE | FILE_ATTRIBUTE_NORMAL)) == 0) {
  6268. /* Not a regular file */
  6269. return -1;
  6270. }
  6271. if(dwAttr & FILE_ATTRIBUTE_READONLY) {
  6272. /* Read-only file */
  6273. return -1;
  6274. }
  6275. /* File is writable */
  6276. return PH7_OK;
  6277. }
  6278. /* int (*xExecutable)(const char *) */
  6279. static int WinVfs_isExecutable(const char *zPath) {
  6280. void *pConverted;
  6281. DWORD dwAttr;
  6282. pConverted = convertUtf8Filename(zPath);
  6283. if(pConverted == 0) {
  6284. return -1;
  6285. }
  6286. dwAttr = GetFileAttributesW((LPCWSTR)pConverted);
  6287. HeapFree(GetProcessHeap(), 0, pConverted);
  6288. if(dwAttr == INVALID_FILE_ATTRIBUTES) {
  6289. return -1;
  6290. }
  6291. if((dwAttr & FILE_ATTRIBUTE_NORMAL) == 0) {
  6292. /* Not a regular file */
  6293. return -1;
  6294. }
  6295. /* File is executable */
  6296. return PH7_OK;
  6297. }
  6298. /* int (*xFiletype)(const char *,ph7_context *) */
  6299. static int WinVfs_Filetype(const char *zPath, ph7_context *pCtx) {
  6300. void *pConverted;
  6301. DWORD dwAttr;
  6302. pConverted = convertUtf8Filename(zPath);
  6303. if(pConverted == 0) {
  6304. /* Expand 'unknown' */
  6305. ph7_result_string(pCtx, "unknown", sizeof("unknown") - 1);
  6306. return -1;
  6307. }
  6308. dwAttr = GetFileAttributesW((LPCWSTR)pConverted);
  6309. HeapFree(GetProcessHeap(), 0, pConverted);
  6310. if(dwAttr == INVALID_FILE_ATTRIBUTES) {
  6311. /* Expand 'unknown' */
  6312. ph7_result_string(pCtx, "unknown", sizeof("unknown") - 1);
  6313. return -1;
  6314. }
  6315. if(dwAttr & (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_NORMAL | FILE_ATTRIBUTE_ARCHIVE)) {
  6316. ph7_result_string(pCtx, "file", sizeof("file") - 1);
  6317. } else if(dwAttr & FILE_ATTRIBUTE_DIRECTORY) {
  6318. ph7_result_string(pCtx, "dir", sizeof("dir") - 1);
  6319. } else if(dwAttr & FILE_ATTRIBUTE_REPARSE_POINT) {
  6320. ph7_result_string(pCtx, "link", sizeof("link") - 1);
  6321. } else if(dwAttr & (FILE_ATTRIBUTE_DEVICE)) {
  6322. ph7_result_string(pCtx, "block", sizeof("block") - 1);
  6323. } else {
  6324. ph7_result_string(pCtx, "unknown", sizeof("unknown") - 1);
  6325. }
  6326. return PH7_OK;
  6327. }
  6328. /* int (*xGetenv)(const char *,ph7_context *) */
  6329. static int WinVfs_Getenv(const char *zVar, ph7_context *pCtx) {
  6330. char zValue[1024];
  6331. DWORD n;
  6332. /*
  6333. * According to MSDN
  6334. * If lpBuffer is not large enough to hold the data, the return
  6335. * value is the buffer size, in characters, required to hold the
  6336. * string and its terminating null character and the contents
  6337. * of lpBuffer are undefined.
  6338. */
  6339. n = sizeof(zValue);
  6340. SyMemcpy("Undefined", zValue, sizeof("Undefined") - 1);
  6341. /* Extract the environment value */
  6342. n = GetEnvironmentVariableA(zVar, zValue, sizeof(zValue));
  6343. if(!n) {
  6344. /* No such variable*/
  6345. return -1;
  6346. }
  6347. ph7_result_string(pCtx, zValue, (int)n);
  6348. return PH7_OK;
  6349. }
  6350. /* int (*xSetenv)(const char *,const char *) */
  6351. static int WinVfs_Setenv(const char *zName, const char *zValue) {
  6352. BOOL rc;
  6353. rc = SetEnvironmentVariableA(zName, zValue);
  6354. return rc ? PH7_OK : -1;
  6355. }
  6356. /* int (*xMmap)(const char *,void **,ph7_int64 *) */
  6357. static int WinVfs_Mmap(const char *zPath, void **ppMap, ph7_int64 *pSize) {
  6358. DWORD dwSizeLow, dwSizeHigh;
  6359. HANDLE pHandle, pMapHandle;
  6360. void *pConverted, *pView;
  6361. pConverted = convertUtf8Filename(zPath);
  6362. if(pConverted == 0) {
  6363. return -1;
  6364. }
  6365. pHandle = OpenReadOnly((LPCWSTR)pConverted);
  6366. HeapFree(GetProcessHeap(), 0, pConverted);
  6367. if(pHandle == 0) {
  6368. return -1;
  6369. }
  6370. /* Get the file size */
  6371. dwSizeLow = GetFileSize(pHandle, &dwSizeHigh);
  6372. /* Create the mapping */
  6373. pMapHandle = CreateFileMappingW(pHandle, 0, PAGE_READONLY, dwSizeHigh, dwSizeLow, 0);
  6374. if(pMapHandle == 0) {
  6375. CloseHandle(pHandle);
  6376. return -1;
  6377. }
  6378. *pSize = ((ph7_int64)dwSizeHigh << 32) | dwSizeLow;
  6379. /* Obtain the view */
  6380. pView = MapViewOfFile(pMapHandle, FILE_MAP_READ, 0, 0, (SIZE_T)(*pSize));
  6381. if(pView) {
  6382. /* Let the upper layer point to the view */
  6383. *ppMap = pView;
  6384. }
  6385. /* Close the handle
  6386. * According to MSDN it's OK the close the HANDLES.
  6387. */
  6388. CloseHandle(pMapHandle);
  6389. CloseHandle(pHandle);
  6390. return pView ? PH7_OK : -1;
  6391. }
  6392. /* void (*xUnmap)(void *,ph7_int64) */
  6393. static void WinVfs_Unmap(void *pView, ph7_int64 nSize) {
  6394. nSize = 0; /* Compiler warning */
  6395. UnmapViewOfFile(pView);
  6396. }
  6397. /* void (*xTempDir)(ph7_context *) */
  6398. static void WinVfs_TempDir(ph7_context *pCtx) {
  6399. CHAR zTemp[1024];
  6400. DWORD n;
  6401. n = GetTempPathA(sizeof(zTemp), zTemp);
  6402. if(n < 1) {
  6403. /* Assume the default windows temp directory */
  6404. ph7_result_string(pCtx, "C:\\Windows\\Temp", -1/*Compute length automatically*/);
  6405. } else {
  6406. ph7_result_string(pCtx, zTemp, (int)n);
  6407. }
  6408. }
  6409. /* unsigned int (*xProcessId)(void) */
  6410. static unsigned int WinVfs_ProcessId(void) {
  6411. DWORD nID = 0;
  6412. #ifndef __MINGW32__
  6413. nID = GetProcessId(GetCurrentProcess());
  6414. #endif /* __MINGW32__ */
  6415. return (unsigned int)nID;
  6416. }
  6417. /* void (*xUsername)(ph7_context *) */
  6418. static void WinVfs_Username(ph7_context *pCtx) {
  6419. WCHAR zUser[1024];
  6420. DWORD nByte;
  6421. BOOL rc;
  6422. nByte = sizeof(zUser);
  6423. rc = GetUserNameW(zUser, &nByte);
  6424. if(!rc) {
  6425. /* Set a dummy name */
  6426. ph7_result_string(pCtx, "Unknown", sizeof("Unknown") - 1);
  6427. } else {
  6428. char *zName;
  6429. zName = unicodeToUtf8(zUser);
  6430. if(zName == 0) {
  6431. ph7_result_string(pCtx, "Unknown", sizeof("Unknown") - 1);
  6432. } else {
  6433. ph7_result_string(pCtx, zName, -1/*Compute length automatically*/); /* Will make it's own copy */
  6434. HeapFree(GetProcessHeap(), 0, zName);
  6435. }
  6436. }
  6437. }
  6438. /* Export the windows vfs */
  6439. static const ph7_vfs sWinVfs = {
  6440. "WinVFS",
  6441. PH7_VFS_VERSION,
  6442. WinVfs_chdir, /* int (*xChdir)(const char *) */
  6443. 0, /* int (*xChroot)(const char *); */
  6444. WinVfs_getcwd, /* int (*xGetcwd)(ph7_context *) */
  6445. WinVfs_mkdir, /* int (*xMkdir)(const char *,int,int) */
  6446. WinVfs_rmdir, /* int (*xRmdir)(const char *) */
  6447. WinVfs_isdir, /* int (*xIsdir)(const char *) */
  6448. WinVfs_Rename, /* int (*xRename)(const char *,const char *) */
  6449. WinVfs_Realpath, /*int (*xRealpath)(const char *,ph7_context *)*/
  6450. WinVfs_Sleep, /* int (*xSleep)(unsigned int) */
  6451. WinVfs_unlink, /* int (*xUnlink)(const char *) */
  6452. WinVfs_FileExists, /* int (*xFileExists)(const char *) */
  6453. 0, /*int (*xChmod)(const char *,int)*/
  6454. 0, /*int (*xChown)(const char *,const char *)*/
  6455. 0, /*int (*xChgrp)(const char *,const char *)*/
  6456. WinVfs_DiskFreeSpace,/* ph7_int64 (*xFreeSpace)(const char *) */
  6457. WinVfs_DiskTotalSpace,/* ph7_int64 (*xTotalSpace)(const char *) */
  6458. WinVfs_FileSize, /* ph7_int64 (*xFileSize)(const char *) */
  6459. WinVfs_FileAtime,/* ph7_int64 (*xFileAtime)(const char *) */
  6460. WinVfs_FileMtime,/* ph7_int64 (*xFileMtime)(const char *) */
  6461. WinVfs_FileCtime,/* ph7_int64 (*xFileCtime)(const char *) */
  6462. WinVfs_FileGroup,/* ph7_int64 (*xFileGroup)(const char *) */
  6463. WinVfs_FileInode,/* ph7_int64 (*xFileInode)(const char *) */
  6464. WinVfs_FileOwner,/* ph7_int64 (*xFileOwner)(const char *) */
  6465. WinVfs_Stat, /* int (*xStat)(const char *,ph7_value *,ph7_value *) */
  6466. WinVfs_Stat, /* int (*xlStat)(const char *,ph7_value *,ph7_value *) */
  6467. WinVfs_isFile, /* int (*xIsFile)(const char *) */
  6468. WinVfs_isLink, /* int (*xIsLink)(const char *) */
  6469. WinVfs_isFile, /* int (*xReadable)(const char *) */
  6470. WinVfs_isWritable, /* int (*xWritable)(const char *) */
  6471. WinVfs_isExecutable, /* int (*xExecutable)(const char *) */
  6472. WinVfs_Filetype, /* int (*xFiletype)(const char *,ph7_context *) */
  6473. WinVfs_Getenv, /* int (*xGetenv)(const char *,ph7_context *) */
  6474. WinVfs_Setenv, /* int (*xSetenv)(const char *,const char *) */
  6475. WinVfs_Touch, /* int (*xTouch)(const char *,ph7_int64,ph7_int64) */
  6476. WinVfs_Mmap, /* int (*xMmap)(const char *,void **,ph7_int64 *) */
  6477. WinVfs_Unmap, /* void (*xUnmap)(void *,ph7_int64); */
  6478. 0, /* int (*xLink)(const char *,const char *,int) */
  6479. 0, /* int (*xUmask)(int) */
  6480. WinVfs_TempDir, /* void (*xTempDir)(ph7_context *) */
  6481. WinVfs_ProcessId, /* unsigned int (*xProcessId)(void) */
  6482. 0, /* int (*xUid)(void) */
  6483. 0, /* int (*xGid)(void) */
  6484. WinVfs_Username /* void (*xUsername)(ph7_context *) */
  6485. };
  6486. /* Windows file IO */
  6487. #ifndef INVALID_SET_FILE_POINTER
  6488. #define INVALID_SET_FILE_POINTER ((DWORD)-1)
  6489. #endif
  6490. /* int (*xOpen)(const char *,int,ph7_value *,void **) */
  6491. static int WinFile_Open(const char *zPath, int iOpenMode, ph7_value *pResource, void **ppHandle) {
  6492. DWORD dwType = FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS;
  6493. DWORD dwAccess = GENERIC_READ;
  6494. DWORD dwShare, dwCreate;
  6495. void *pConverted;
  6496. HANDLE pHandle;
  6497. pConverted = convertUtf8Filename(zPath);
  6498. if(pConverted == 0) {
  6499. return -1;
  6500. }
  6501. /* Set the desired flags according to the open mode */
  6502. if(iOpenMode & PH7_IO_OPEN_CREATE) {
  6503. /* Open existing file, or create if it doesn't exist */
  6504. dwCreate = OPEN_ALWAYS;
  6505. if(iOpenMode & PH7_IO_OPEN_TRUNC) {
  6506. /* If the specified file exists and is writable, the function overwrites the file */
  6507. dwCreate = CREATE_ALWAYS;
  6508. }
  6509. } else if(iOpenMode & PH7_IO_OPEN_EXCL) {
  6510. /* Creates a new file, only if it does not already exist.
  6511. * If the file exists, it fails.
  6512. */
  6513. dwCreate = CREATE_NEW;
  6514. } else if(iOpenMode & PH7_IO_OPEN_TRUNC) {
  6515. /* Opens a file and truncates it so that its size is zero bytes
  6516. * The file must exist.
  6517. */
  6518. dwCreate = TRUNCATE_EXISTING;
  6519. } else {
  6520. /* Opens a file, only if it exists. */
  6521. dwCreate = OPEN_EXISTING;
  6522. }
  6523. if(iOpenMode & PH7_IO_OPEN_RDWR) {
  6524. /* Read+Write access */
  6525. dwAccess |= GENERIC_WRITE;
  6526. } else if(iOpenMode & PH7_IO_OPEN_WRONLY) {
  6527. /* Write only access */
  6528. dwAccess = GENERIC_WRITE;
  6529. }
  6530. if(iOpenMode & PH7_IO_OPEN_APPEND) {
  6531. /* Append mode */
  6532. dwAccess = FILE_APPEND_DATA;
  6533. }
  6534. if(iOpenMode & PH7_IO_OPEN_TEMP) {
  6535. /* File is temporary */
  6536. dwType = FILE_ATTRIBUTE_TEMPORARY;
  6537. }
  6538. dwShare = FILE_SHARE_READ | FILE_SHARE_WRITE;
  6539. pHandle = CreateFileW((LPCWSTR)pConverted, dwAccess, dwShare, 0, dwCreate, dwType, 0);
  6540. HeapFree(GetProcessHeap(), 0, pConverted);
  6541. if(pHandle == INVALID_HANDLE_VALUE) {
  6542. SXUNUSED(pResource); /* MSVC warning */
  6543. return -1;
  6544. }
  6545. /* Make the handle accessible to the upper layer */
  6546. *ppHandle = (void *)pHandle;
  6547. return PH7_OK;
  6548. }
  6549. /* An instance of the following structure is used to record state information
  6550. * while iterating throw directory entries.
  6551. */
  6552. typedef struct WinDir_Info WinDir_Info;
  6553. struct WinDir_Info {
  6554. HANDLE pDirHandle;
  6555. void *pPath;
  6556. WIN32_FIND_DATAW sInfo;
  6557. int rc;
  6558. };
  6559. /* int (*xOpenDir)(const char *,ph7_value *,void **) */
  6560. static int WinDir_Open(const char *zPath, ph7_value *pResource, void **ppHandle) {
  6561. WinDir_Info *pDirInfo;
  6562. void *pConverted;
  6563. char *zPrep;
  6564. sxu32 n;
  6565. /* Prepare the path */
  6566. n = SyStrlen(zPath);
  6567. zPrep = (char *)HeapAlloc(GetProcessHeap(), 0, n + sizeof("\\*") + 4);
  6568. if(zPrep == 0) {
  6569. return -1;
  6570. }
  6571. SyMemcpy((const void *)zPath, zPrep, n);
  6572. zPrep[n] = '\\';
  6573. zPrep[n + 1] = '*';
  6574. zPrep[n + 2] = 0;
  6575. pConverted = convertUtf8Filename(zPrep);
  6576. HeapFree(GetProcessHeap(), 0, zPrep);
  6577. if(pConverted == 0) {
  6578. return -1;
  6579. }
  6580. /* Allocate a new instance */
  6581. pDirInfo = (WinDir_Info *)HeapAlloc(GetProcessHeap(), 0, sizeof(WinDir_Info));
  6582. if(pDirInfo == 0) {
  6583. pResource = 0; /* Compiler warning */
  6584. return -1;
  6585. }
  6586. pDirInfo->rc = SXRET_OK;
  6587. pDirInfo->pDirHandle = FindFirstFileW((LPCWSTR)pConverted, &pDirInfo->sInfo);
  6588. if(pDirInfo->pDirHandle == INVALID_HANDLE_VALUE) {
  6589. /* Cannot open directory */
  6590. HeapFree(GetProcessHeap(), 0, pConverted);
  6591. HeapFree(GetProcessHeap(), 0, pDirInfo);
  6592. return -1;
  6593. }
  6594. /* Save the path */
  6595. pDirInfo->pPath = pConverted;
  6596. /* Save our structure */
  6597. *ppHandle = pDirInfo;
  6598. return PH7_OK;
  6599. }
  6600. /* void (*xCloseDir)(void *) */
  6601. static void WinDir_Close(void *pUserData) {
  6602. WinDir_Info *pDirInfo = (WinDir_Info *)pUserData;
  6603. if(pDirInfo->pDirHandle != INVALID_HANDLE_VALUE) {
  6604. FindClose(pDirInfo->pDirHandle);
  6605. }
  6606. HeapFree(GetProcessHeap(), 0, pDirInfo->pPath);
  6607. HeapFree(GetProcessHeap(), 0, pDirInfo);
  6608. }
  6609. /* void (*xClose)(void *); */
  6610. static void WinFile_Close(void *pUserData) {
  6611. HANDLE pHandle = (HANDLE)pUserData;
  6612. CloseHandle(pHandle);
  6613. }
  6614. /* int (*xReadDir)(void *,ph7_context *) */
  6615. static int WinDir_Read(void *pUserData, ph7_context *pCtx) {
  6616. WinDir_Info *pDirInfo = (WinDir_Info *)pUserData;
  6617. LPWIN32_FIND_DATAW pData;
  6618. char *zName;
  6619. BOOL rc;
  6620. sxu32 n;
  6621. if(pDirInfo->rc != SXRET_OK) {
  6622. /* No more entry to process */
  6623. return -1;
  6624. }
  6625. pData = &pDirInfo->sInfo;
  6626. for(;;) {
  6627. zName = unicodeToUtf8(pData->cFileName);
  6628. if(zName == 0) {
  6629. /* Out of memory */
  6630. return -1;
  6631. }
  6632. n = SyStrlen(zName);
  6633. /* Ignore '.' && '..' */
  6634. if(n > sizeof("..") - 1 || zName[0] != '.' || (n == sizeof("..") - 1 && zName[1] != '.')) {
  6635. break;
  6636. }
  6637. HeapFree(GetProcessHeap(), 0, zName);
  6638. rc = FindNextFileW(pDirInfo->pDirHandle, &pDirInfo->sInfo);
  6639. if(!rc) {
  6640. return -1;
  6641. }
  6642. }
  6643. /* Return the current file name */
  6644. ph7_result_string(pCtx, zName, -1);
  6645. HeapFree(GetProcessHeap(), 0, zName);
  6646. /* Point to the next entry */
  6647. rc = FindNextFileW(pDirInfo->pDirHandle, &pDirInfo->sInfo);
  6648. if(!rc) {
  6649. pDirInfo->rc = SXERR_EOF;
  6650. }
  6651. return PH7_OK;
  6652. }
  6653. /* void (*xRewindDir)(void *) */
  6654. static void WinDir_RewindDir(void *pUserData) {
  6655. WinDir_Info *pDirInfo = (WinDir_Info *)pUserData;
  6656. FindClose(pDirInfo->pDirHandle);
  6657. pDirInfo->pDirHandle = FindFirstFileW((LPCWSTR)pDirInfo->pPath, &pDirInfo->sInfo);
  6658. if(pDirInfo->pDirHandle == INVALID_HANDLE_VALUE) {
  6659. pDirInfo->rc = SXERR_EOF;
  6660. } else {
  6661. pDirInfo->rc = SXRET_OK;
  6662. }
  6663. }
  6664. /* ph7_int64 (*xRead)(void *,void *,ph7_int64); */
  6665. static ph7_int64 WinFile_Read(void *pOS, void *pBuffer, ph7_int64 nDatatoRead) {
  6666. HANDLE pHandle = (HANDLE)pOS;
  6667. DWORD nRd;
  6668. BOOL rc;
  6669. rc = ReadFile(pHandle, pBuffer, (DWORD)nDatatoRead, &nRd, 0);
  6670. if(!rc) {
  6671. /* EOF or IO error */
  6672. return -1;
  6673. }
  6674. return (ph7_int64)nRd;
  6675. }
  6676. /* ph7_int64 (*xWrite)(void *,const void *,ph7_int64); */
  6677. static ph7_int64 WinFile_Write(void *pOS, const void *pBuffer, ph7_int64 nWrite) {
  6678. const char *zData = (const char *)pBuffer;
  6679. HANDLE pHandle = (HANDLE)pOS;
  6680. ph7_int64 nCount;
  6681. DWORD nWr;
  6682. BOOL rc;
  6683. nWr = 0;
  6684. nCount = 0;
  6685. for(;;) {
  6686. if(nWrite < 1) {
  6687. break;
  6688. }
  6689. rc = WriteFile(pHandle, zData, (DWORD)nWrite, &nWr, 0);
  6690. if(!rc) {
  6691. /* IO error */
  6692. break;
  6693. }
  6694. nWrite -= nWr;
  6695. nCount += nWr;
  6696. zData += nWr;
  6697. }
  6698. if(nWrite > 0) {
  6699. return -1;
  6700. }
  6701. return nCount;
  6702. }
  6703. /* int (*xSeek)(void *,ph7_int64,int) */
  6704. static int WinFile_Seek(void *pUserData, ph7_int64 iOfft, int whence) {
  6705. HANDLE pHandle = (HANDLE)pUserData;
  6706. DWORD dwMove, dwNew;
  6707. LONG nHighOfft;
  6708. switch(whence) {
  6709. case 1:/*SEEK_CUR*/
  6710. dwMove = FILE_CURRENT;
  6711. break;
  6712. case 2: /* SEEK_END */
  6713. dwMove = FILE_END;
  6714. break;
  6715. case 0: /* SEEK_SET */
  6716. default:
  6717. dwMove = FILE_BEGIN;
  6718. break;
  6719. }
  6720. nHighOfft = (LONG)(iOfft >> 32);
  6721. dwNew = SetFilePointer(pHandle, (LONG)iOfft, &nHighOfft, dwMove);
  6722. if(dwNew == INVALID_SET_FILE_POINTER) {
  6723. return -1;
  6724. }
  6725. return PH7_OK;
  6726. }
  6727. /* int (*xLock)(void *,int) */
  6728. static int WinFile_Lock(void *pUserData, int lock_type) {
  6729. HANDLE pHandle = (HANDLE)pUserData;
  6730. static DWORD dwLo = 0, dwHi = 0; /* xx: MT-SAFE */
  6731. OVERLAPPED sDummy;
  6732. BOOL rc;
  6733. SyZero(&sDummy, sizeof(sDummy));
  6734. /* Get the file size */
  6735. if(lock_type < 1) {
  6736. /* Unlock the file */
  6737. rc = UnlockFileEx(pHandle, 0, dwLo, dwHi, &sDummy);
  6738. } else {
  6739. DWORD dwFlags = LOCKFILE_FAIL_IMMEDIATELY; /* Shared non-blocking lock by default*/
  6740. /* Lock the file */
  6741. if(lock_type == 1 /* LOCK_EXCL */) {
  6742. dwFlags |= LOCKFILE_EXCLUSIVE_LOCK;
  6743. }
  6744. dwLo = GetFileSize(pHandle, &dwHi);
  6745. rc = LockFileEx(pHandle, dwFlags, 0, dwLo, dwHi, &sDummy);
  6746. }
  6747. return rc ? PH7_OK : -1 /* Lock error */;
  6748. }
  6749. /* ph7_int64 (*xTell)(void *) */
  6750. static ph7_int64 WinFile_Tell(void *pUserData) {
  6751. HANDLE pHandle = (HANDLE)pUserData;
  6752. DWORD dwNew;
  6753. dwNew = SetFilePointer(pHandle, 0, 0, FILE_CURRENT/* SEEK_CUR */);
  6754. if(dwNew == INVALID_SET_FILE_POINTER) {
  6755. return -1;
  6756. }
  6757. return (ph7_int64)dwNew;
  6758. }
  6759. /* int (*xTrunc)(void *,ph7_int64) */
  6760. static int WinFile_Trunc(void *pUserData, ph7_int64 nOfft) {
  6761. HANDLE pHandle = (HANDLE)pUserData;
  6762. LONG HighOfft;
  6763. DWORD dwNew;
  6764. BOOL rc;
  6765. HighOfft = (LONG)(nOfft >> 32);
  6766. dwNew = SetFilePointer(pHandle, (LONG)nOfft, &HighOfft, FILE_BEGIN);
  6767. if(dwNew == INVALID_SET_FILE_POINTER) {
  6768. return -1;
  6769. }
  6770. rc = SetEndOfFile(pHandle);
  6771. return rc ? PH7_OK : -1;
  6772. }
  6773. /* int (*xSync)(void *); */
  6774. static int WinFile_Sync(void *pUserData) {
  6775. HANDLE pHandle = (HANDLE)pUserData;
  6776. BOOL rc;
  6777. rc = FlushFileBuffers(pHandle);
  6778. return rc ? PH7_OK : - 1;
  6779. }
  6780. /* int (*xStat)(void *,ph7_value *,ph7_value *) */
  6781. static int WinFile_Stat(void *pUserData, ph7_value *pArray, ph7_value *pWorker) {
  6782. BY_HANDLE_FILE_INFORMATION sInfo;
  6783. HANDLE pHandle = (HANDLE)pUserData;
  6784. BOOL rc;
  6785. rc = GetFileInformationByHandle(pHandle, &sInfo);
  6786. if(!rc) {
  6787. return -1;
  6788. }
  6789. /* dev */
  6790. ph7_value_int64(pWorker, (ph7_int64)sInfo.dwVolumeSerialNumber);
  6791. ph7_array_add_strkey_elem(pArray, "dev", pWorker); /* Will make it's own copy */
  6792. /* ino */
  6793. ph7_value_int64(pWorker, (ph7_int64)(((ph7_int64)sInfo.nFileIndexHigh << 32) | sInfo.nFileIndexLow));
  6794. ph7_array_add_strkey_elem(pArray, "ino", pWorker); /* Will make it's own copy */
  6795. /* mode */
  6796. ph7_value_int(pWorker, 0);
  6797. ph7_array_add_strkey_elem(pArray, "mode", pWorker);
  6798. /* nlink */
  6799. ph7_value_int(pWorker, (int)sInfo.nNumberOfLinks);
  6800. ph7_array_add_strkey_elem(pArray, "nlink", pWorker); /* Will make it's own copy */
  6801. /* uid,gid,rdev */
  6802. ph7_value_int(pWorker, 0);
  6803. ph7_array_add_strkey_elem(pArray, "uid", pWorker);
  6804. ph7_array_add_strkey_elem(pArray, "gid", pWorker);
  6805. ph7_array_add_strkey_elem(pArray, "rdev", pWorker);
  6806. /* size */
  6807. ph7_value_int64(pWorker, (ph7_int64)(((ph7_int64)sInfo.nFileSizeHigh << 32) | sInfo.nFileSizeLow));
  6808. ph7_array_add_strkey_elem(pArray, "size", pWorker); /* Will make it's own copy */
  6809. /* atime */
  6810. ph7_value_int64(pWorker, convertWindowsTimeToUnixTime(&sInfo.ftLastAccessTime));
  6811. ph7_array_add_strkey_elem(pArray, "atime", pWorker); /* Will make it's own copy */
  6812. /* mtime */
  6813. ph7_value_int64(pWorker, convertWindowsTimeToUnixTime(&sInfo.ftLastWriteTime));
  6814. ph7_array_add_strkey_elem(pArray, "mtime", pWorker); /* Will make it's own copy */
  6815. /* ctime */
  6816. ph7_value_int64(pWorker, convertWindowsTimeToUnixTime(&sInfo.ftCreationTime));
  6817. ph7_array_add_strkey_elem(pArray, "ctime", pWorker); /* Will make it's own copy */
  6818. /* blksize,blocks */
  6819. ph7_value_int(pWorker, 0);
  6820. ph7_array_add_strkey_elem(pArray, "blksize", pWorker);
  6821. ph7_array_add_strkey_elem(pArray, "blocks", pWorker);
  6822. return PH7_OK;
  6823. }
  6824. /* Export the file:// stream */
  6825. static const ph7_io_stream sWinFileStream = {
  6826. "file", /* Stream name */
  6827. PH7_IO_STREAM_VERSION,
  6828. WinFile_Open, /* xOpen */
  6829. WinDir_Open, /* xOpenDir */
  6830. WinFile_Close, /* xClose */
  6831. WinDir_Close, /* xCloseDir */
  6832. WinFile_Read, /* xRead */
  6833. WinDir_Read, /* xReadDir */
  6834. WinFile_Write, /* xWrite */
  6835. WinFile_Seek, /* xSeek */
  6836. WinFile_Lock, /* xLock */
  6837. WinDir_RewindDir, /* xRewindDir */
  6838. WinFile_Tell, /* xTell */
  6839. WinFile_Trunc, /* xTrunc */
  6840. WinFile_Sync, /* xSeek */
  6841. WinFile_Stat /* xStat */
  6842. };
  6843. #elif defined(__UNIXES__)
  6844. /*
  6845. * UNIX VFS implementation for the PH7 engine.
  6846. * Authors:
  6847. * Symisc Systems,devel@symisc.net.
  6848. * Copyright (C) Symisc Systems,https://ph7.symisc.net
  6849. * Status:
  6850. * Stable.
  6851. */
  6852. #include <sys/types.h>
  6853. #include <limits.h>
  6854. #include <fcntl.h>
  6855. #include <unistd.h>
  6856. #include <sys/uio.h>
  6857. #include <sys/stat.h>
  6858. #include <sys/mman.h>
  6859. #include <sys/file.h>
  6860. #include <pwd.h>
  6861. #include <grp.h>
  6862. #include <dirent.h>
  6863. #include <utime.h>
  6864. #include <stdio.h>
  6865. #include <stdlib.h>
  6866. /* int (*xchdir)(const char *) */
  6867. static int UnixVfs_chdir(const char *zPath) {
  6868. int rc;
  6869. rc = chdir(zPath);
  6870. return rc == 0 ? PH7_OK : -1;
  6871. }
  6872. /* int (*xGetcwd)(ph7_context *) */
  6873. static int UnixVfs_getcwd(ph7_context *pCtx) {
  6874. char zBuf[4096];
  6875. char *zDir;
  6876. /* Get the current directory */
  6877. zDir = getcwd(zBuf, sizeof(zBuf));
  6878. if(zDir == 0) {
  6879. return -1;
  6880. }
  6881. ph7_result_string(pCtx, zDir, -1/*Compute length automatically*/);
  6882. return PH7_OK;
  6883. }
  6884. /* int (*xMkdir)(const char *,int,int) */
  6885. static int UnixVfs_mkdir(const char *zPath, int mode, int recursive) {
  6886. int rc;
  6887. SXUNUSED(recursive);
  6888. rc = mkdir(zPath, mode);
  6889. return rc == 0 ? PH7_OK : -1;
  6890. }
  6891. /* int (*xRmdir)(const char *) */
  6892. static int UnixVfs_rmdir(const char *zPath) {
  6893. int rc;
  6894. rc = rmdir(zPath);
  6895. return rc == 0 ? PH7_OK : -1;
  6896. }
  6897. /* int (*xIsdir)(const char *) */
  6898. static int UnixVfs_isdir(const char *zPath) {
  6899. struct stat st;
  6900. int rc;
  6901. rc = stat(zPath, &st);
  6902. if(rc != 0) {
  6903. return -1;
  6904. }
  6905. rc = S_ISDIR(st.st_mode);
  6906. return rc ? PH7_OK : -1 ;
  6907. }
  6908. /* int (*xRename)(const char *,const char *) */
  6909. static int UnixVfs_Rename(const char *zOld, const char *zNew) {
  6910. int rc;
  6911. rc = rename(zOld, zNew);
  6912. return rc == 0 ? PH7_OK : -1;
  6913. }
  6914. /* int (*xRealpath)(const char *,ph7_context *) */
  6915. static int UnixVfs_Realpath(const char *zPath, ph7_context *pCtx) {
  6916. char *zReal;
  6917. zReal = realpath(zPath, 0);
  6918. if(zReal == 0) {
  6919. return -1;
  6920. }
  6921. ph7_result_string(pCtx, zReal, -1/*Compute length automatically*/);
  6922. /* Release the allocated buffer */
  6923. free(zReal);
  6924. return PH7_OK;
  6925. }
  6926. /* int (*xSleep)(unsigned int) */
  6927. static int UnixVfs_Sleep(unsigned int uSec) {
  6928. usleep(uSec);
  6929. return PH7_OK;
  6930. }
  6931. /* int (*xUnlink)(const char *) */
  6932. static int UnixVfs_unlink(const char *zPath) {
  6933. int rc;
  6934. rc = unlink(zPath);
  6935. return rc == 0 ? PH7_OK : -1 ;
  6936. }
  6937. /* int (*xFileExists)(const char *) */
  6938. static int UnixVfs_FileExists(const char *zPath) {
  6939. int rc;
  6940. rc = access(zPath, F_OK);
  6941. return rc == 0 ? PH7_OK : -1;
  6942. }
  6943. /* ph7_int64 (*xFileSize)(const char *) */
  6944. static ph7_int64 UnixVfs_FileSize(const char *zPath) {
  6945. struct stat st;
  6946. int rc;
  6947. rc = stat(zPath, &st);
  6948. if(rc != 0) {
  6949. return -1;
  6950. }
  6951. return (ph7_int64)st.st_size;
  6952. }
  6953. /* int (*xTouch)(const char *,ph7_int64,ph7_int64) */
  6954. static int UnixVfs_Touch(const char *zPath, ph7_int64 touch_time, ph7_int64 access_time) {
  6955. struct utimbuf ut;
  6956. int rc;
  6957. ut.actime = (time_t)access_time;
  6958. ut.modtime = (time_t)touch_time;
  6959. rc = utime(zPath, &ut);
  6960. if(rc != 0) {
  6961. return -1;
  6962. }
  6963. return PH7_OK;
  6964. }
  6965. /* ph7_int64 (*xFileAtime)(const char *) */
  6966. static ph7_int64 UnixVfs_FileAtime(const char *zPath) {
  6967. struct stat st;
  6968. int rc;
  6969. rc = stat(zPath, &st);
  6970. if(rc != 0) {
  6971. return -1;
  6972. }
  6973. return (ph7_int64)st.st_atime;
  6974. }
  6975. /* ph7_int64 (*xFileMtime)(const char *) */
  6976. static ph7_int64 UnixVfs_FileMtime(const char *zPath) {
  6977. struct stat st;
  6978. int rc;
  6979. rc = stat(zPath, &st);
  6980. if(rc != 0) {
  6981. return -1;
  6982. }
  6983. return (ph7_int64)st.st_mtime;
  6984. }
  6985. /* ph7_int64 (*xFileCtime)(const char *) */
  6986. static ph7_int64 UnixVfs_FileCtime(const char *zPath) {
  6987. struct stat st;
  6988. int rc;
  6989. rc = stat(zPath, &st);
  6990. if(rc != 0) {
  6991. return -1;
  6992. }
  6993. return (ph7_int64)st.st_ctime;
  6994. }
  6995. /* ph7_int64 (*xFileGroup)(const char *) */
  6996. static ph7_int64 UnixVfs_FileGroup(const char *zPath) {
  6997. struct stat st;
  6998. int rc;
  6999. rc = stat(zPath, &st);
  7000. if(rc != 0) {
  7001. return -1;
  7002. }
  7003. return (ph7_int64)st.st_gid;
  7004. }
  7005. /* ph7_int64 (*xFileInode)(const char *) */
  7006. static ph7_int64 UnixVfs_FileInode(const char *zPath) {
  7007. struct stat st;
  7008. int rc;
  7009. rc = stat(zPath, &st);
  7010. if(rc != 0) {
  7011. return -1;
  7012. }
  7013. return (ph7_int64)st.st_ino;
  7014. }
  7015. /* ph7_int64 (*xFileOwner)(const char *) */
  7016. static ph7_int64 UnixVfs_FileOwner(const char *zPath) {
  7017. struct stat st;
  7018. int rc;
  7019. rc = stat(zPath, &st);
  7020. if(rc != 0) {
  7021. return -1;
  7022. }
  7023. return (ph7_int64)st.st_uid;
  7024. }
  7025. /* int (*xStat)(const char *,ph7_value *,ph7_value *) */
  7026. static int UnixVfs_Stat(const char *zPath, ph7_value *pArray, ph7_value *pWorker) {
  7027. struct stat st;
  7028. int rc;
  7029. rc = stat(zPath, &st);
  7030. if(rc != 0) {
  7031. return -1;
  7032. }
  7033. /* dev */
  7034. ph7_value_int64(pWorker, (ph7_int64)st.st_dev);
  7035. ph7_array_add_strkey_elem(pArray, "dev", pWorker); /* Will make it's own copy */
  7036. /* ino */
  7037. ph7_value_int64(pWorker, (ph7_int64)st.st_ino);
  7038. ph7_array_add_strkey_elem(pArray, "ino", pWorker); /* Will make it's own copy */
  7039. /* mode */
  7040. ph7_value_int(pWorker, (int)st.st_mode);
  7041. ph7_array_add_strkey_elem(pArray, "mode", pWorker);
  7042. /* nlink */
  7043. ph7_value_int(pWorker, (int)st.st_nlink);
  7044. ph7_array_add_strkey_elem(pArray, "nlink", pWorker); /* Will make it's own copy */
  7045. /* uid,gid,rdev */
  7046. ph7_value_int(pWorker, (int)st.st_uid);
  7047. ph7_array_add_strkey_elem(pArray, "uid", pWorker);
  7048. ph7_value_int(pWorker, (int)st.st_gid);
  7049. ph7_array_add_strkey_elem(pArray, "gid", pWorker);
  7050. ph7_value_int(pWorker, (int)st.st_rdev);
  7051. ph7_array_add_strkey_elem(pArray, "rdev", pWorker);
  7052. /* size */
  7053. ph7_value_int64(pWorker, (ph7_int64)st.st_size);
  7054. ph7_array_add_strkey_elem(pArray, "size", pWorker); /* Will make it's own copy */
  7055. /* atime */
  7056. ph7_value_int64(pWorker, (ph7_int64)st.st_atime);
  7057. ph7_array_add_strkey_elem(pArray, "atime", pWorker); /* Will make it's own copy */
  7058. /* mtime */
  7059. ph7_value_int64(pWorker, (ph7_int64)st.st_mtime);
  7060. ph7_array_add_strkey_elem(pArray, "mtime", pWorker); /* Will make it's own copy */
  7061. /* ctime */
  7062. ph7_value_int64(pWorker, (ph7_int64)st.st_ctime);
  7063. ph7_array_add_strkey_elem(pArray, "ctime", pWorker); /* Will make it's own copy */
  7064. /* blksize,blocks */
  7065. ph7_value_int(pWorker, (int)st.st_blksize);
  7066. ph7_array_add_strkey_elem(pArray, "blksize", pWorker);
  7067. ph7_value_int(pWorker, (int)st.st_blocks);
  7068. ph7_array_add_strkey_elem(pArray, "blocks", pWorker);
  7069. return PH7_OK;
  7070. }
  7071. /* int (*xlStat)(const char *,ph7_value *,ph7_value *) */
  7072. static int UnixVfs_lStat(const char *zPath, ph7_value *pArray, ph7_value *pWorker) {
  7073. struct stat st;
  7074. int rc;
  7075. rc = lstat(zPath, &st);
  7076. if(rc != 0) {
  7077. return -1;
  7078. }
  7079. /* dev */
  7080. ph7_value_int64(pWorker, (ph7_int64)st.st_dev);
  7081. ph7_array_add_strkey_elem(pArray, "dev", pWorker); /* Will make it's own copy */
  7082. /* ino */
  7083. ph7_value_int64(pWorker, (ph7_int64)st.st_ino);
  7084. ph7_array_add_strkey_elem(pArray, "ino", pWorker); /* Will make it's own copy */
  7085. /* mode */
  7086. ph7_value_int(pWorker, (int)st.st_mode);
  7087. ph7_array_add_strkey_elem(pArray, "mode", pWorker);
  7088. /* nlink */
  7089. ph7_value_int(pWorker, (int)st.st_nlink);
  7090. ph7_array_add_strkey_elem(pArray, "nlink", pWorker); /* Will make it's own copy */
  7091. /* uid,gid,rdev */
  7092. ph7_value_int(pWorker, (int)st.st_uid);
  7093. ph7_array_add_strkey_elem(pArray, "uid", pWorker);
  7094. ph7_value_int(pWorker, (int)st.st_gid);
  7095. ph7_array_add_strkey_elem(pArray, "gid", pWorker);
  7096. ph7_value_int(pWorker, (int)st.st_rdev);
  7097. ph7_array_add_strkey_elem(pArray, "rdev", pWorker);
  7098. /* size */
  7099. ph7_value_int64(pWorker, (ph7_int64)st.st_size);
  7100. ph7_array_add_strkey_elem(pArray, "size", pWorker); /* Will make it's own copy */
  7101. /* atime */
  7102. ph7_value_int64(pWorker, (ph7_int64)st.st_atime);
  7103. ph7_array_add_strkey_elem(pArray, "atime", pWorker); /* Will make it's own copy */
  7104. /* mtime */
  7105. ph7_value_int64(pWorker, (ph7_int64)st.st_mtime);
  7106. ph7_array_add_strkey_elem(pArray, "mtime", pWorker); /* Will make it's own copy */
  7107. /* ctime */
  7108. ph7_value_int64(pWorker, (ph7_int64)st.st_ctime);
  7109. ph7_array_add_strkey_elem(pArray, "ctime", pWorker); /* Will make it's own copy */
  7110. /* blksize,blocks */
  7111. ph7_value_int(pWorker, (int)st.st_blksize);
  7112. ph7_array_add_strkey_elem(pArray, "blksize", pWorker);
  7113. ph7_value_int(pWorker, (int)st.st_blocks);
  7114. ph7_array_add_strkey_elem(pArray, "blocks", pWorker);
  7115. return PH7_OK;
  7116. }
  7117. /* int (*xChmod)(const char *,int) */
  7118. static int UnixVfs_Chmod(const char *zPath, int mode) {
  7119. int rc;
  7120. rc = chmod(zPath, (mode_t)mode);
  7121. return rc == 0 ? PH7_OK : - 1;
  7122. }
  7123. /* int (*xChown)(const char *,const char *) */
  7124. static int UnixVfs_Chown(const char *zPath, const char *zUser) {
  7125. #ifndef PH7_UNIX_STATIC_BUILD
  7126. struct passwd *pwd;
  7127. uid_t uid;
  7128. int rc;
  7129. pwd = getpwnam(zUser); /* Try getting UID for username */
  7130. if(pwd == 0) {
  7131. return -1;
  7132. }
  7133. uid = pwd->pw_uid;
  7134. rc = chown(zPath, uid, -1);
  7135. return rc == 0 ? PH7_OK : -1;
  7136. #else
  7137. SXUNUSED(zPath);
  7138. SXUNUSED(zUser);
  7139. return -1;
  7140. #endif /* PH7_UNIX_STATIC_BUILD */
  7141. }
  7142. /* int (*xChgrp)(const char *,const char *) */
  7143. static int UnixVfs_Chgrp(const char *zPath, const char *zGroup) {
  7144. #ifndef PH7_UNIX_STATIC_BUILD
  7145. struct group *group;
  7146. gid_t gid;
  7147. int rc;
  7148. group = getgrnam(zGroup);
  7149. if(group == 0) {
  7150. return -1;
  7151. }
  7152. gid = group->gr_gid;
  7153. rc = chown(zPath, -1, gid);
  7154. return rc == 0 ? PH7_OK : -1;
  7155. #else
  7156. SXUNUSED(zPath);
  7157. SXUNUSED(zGroup);
  7158. return -1;
  7159. #endif /* PH7_UNIX_STATIC_BUILD */
  7160. }
  7161. /* int (*xIsFile)(const char *) */
  7162. static int UnixVfs_isFile(const char *zPath) {
  7163. struct stat st;
  7164. int rc;
  7165. rc = stat(zPath, &st);
  7166. if(rc != 0) {
  7167. return -1;
  7168. }
  7169. rc = S_ISREG(st.st_mode);
  7170. return rc ? PH7_OK : -1 ;
  7171. }
  7172. /* int (*xIsLink)(const char *) */
  7173. static int UnixVfs_isLink(const char *zPath) {
  7174. struct stat st;
  7175. int rc;
  7176. rc = stat(zPath, &st);
  7177. if(rc != 0) {
  7178. return -1;
  7179. }
  7180. rc = S_ISLNK(st.st_mode);
  7181. return rc ? PH7_OK : -1 ;
  7182. }
  7183. /* int (*xReadable)(const char *) */
  7184. static int UnixVfs_isReadable(const char *zPath) {
  7185. int rc;
  7186. rc = access(zPath, R_OK);
  7187. return rc == 0 ? PH7_OK : -1;
  7188. }
  7189. /* int (*xWritable)(const char *) */
  7190. static int UnixVfs_isWritable(const char *zPath) {
  7191. int rc;
  7192. rc = access(zPath, W_OK);
  7193. return rc == 0 ? PH7_OK : -1;
  7194. }
  7195. /* int (*xExecutable)(const char *) */
  7196. static int UnixVfs_isExecutable(const char *zPath) {
  7197. int rc;
  7198. rc = access(zPath, X_OK);
  7199. return rc == 0 ? PH7_OK : -1;
  7200. }
  7201. /* int (*xFiletype)(const char *,ph7_context *) */
  7202. static int UnixVfs_Filetype(const char *zPath, ph7_context *pCtx) {
  7203. struct stat st;
  7204. int rc;
  7205. rc = stat(zPath, &st);
  7206. if(rc != 0) {
  7207. /* Expand 'unknown' */
  7208. ph7_result_string(pCtx, "unknown", sizeof("unknown") - 1);
  7209. return -1;
  7210. }
  7211. if(S_ISREG(st.st_mode)) {
  7212. ph7_result_string(pCtx, "file", sizeof("file") - 1);
  7213. } else if(S_ISDIR(st.st_mode)) {
  7214. ph7_result_string(pCtx, "dir", sizeof("dir") - 1);
  7215. } else if(S_ISLNK(st.st_mode)) {
  7216. ph7_result_string(pCtx, "link", sizeof("link") - 1);
  7217. } else if(S_ISBLK(st.st_mode)) {
  7218. ph7_result_string(pCtx, "block", sizeof("block") - 1);
  7219. } else if(S_ISSOCK(st.st_mode)) {
  7220. ph7_result_string(pCtx, "socket", sizeof("socket") - 1);
  7221. } else if(S_ISFIFO(st.st_mode)) {
  7222. ph7_result_string(pCtx, "fifo", sizeof("fifo") - 1);
  7223. } else {
  7224. ph7_result_string(pCtx, "unknown", sizeof("unknown") - 1);
  7225. }
  7226. return PH7_OK;
  7227. }
  7228. /* int (*xGetenv)(const char *,ph7_context *) */
  7229. static int UnixVfs_Getenv(const char *zVar, ph7_context *pCtx) {
  7230. char *zEnv;
  7231. zEnv = getenv(zVar);
  7232. if(zEnv == 0) {
  7233. return -1;
  7234. }
  7235. ph7_result_string(pCtx, zEnv, -1/*Compute length automatically*/);
  7236. return PH7_OK;
  7237. }
  7238. /* int (*xSetenv)(const char *,const char *) */
  7239. static int UnixVfs_Setenv(const char *zName, const char *zValue) {
  7240. int rc;
  7241. rc = setenv(zName, zValue, 1);
  7242. return rc == 0 ? PH7_OK : -1;
  7243. }
  7244. /* int (*xMmap)(const char *,void **,ph7_int64 *) */
  7245. static int UnixVfs_Mmap(const char *zPath, void **ppMap, ph7_int64 *pSize) {
  7246. struct stat st;
  7247. void *pMap;
  7248. int fd;
  7249. int rc;
  7250. /* Open the file in a read-only mode */
  7251. fd = open(zPath, O_RDONLY);
  7252. if(fd < 0) {
  7253. return -1;
  7254. }
  7255. /* stat the handle */
  7256. fstat(fd, &st);
  7257. /* Obtain a memory view of the whole file */
  7258. pMap = mmap(0, st.st_size, PROT_READ, MAP_PRIVATE | MAP_FILE, fd, 0);
  7259. rc = PH7_OK;
  7260. if(pMap == MAP_FAILED) {
  7261. rc = -1;
  7262. } else {
  7263. /* Point to the memory view */
  7264. *ppMap = pMap;
  7265. *pSize = (ph7_int64)st.st_size;
  7266. }
  7267. close(fd);
  7268. return rc;
  7269. }
  7270. /* void (*xUnmap)(void *,ph7_int64) */
  7271. static void UnixVfs_Unmap(void *pView, ph7_int64 nSize) {
  7272. munmap(pView, (size_t)nSize);
  7273. }
  7274. /* void (*xTempDir)(ph7_context *) */
  7275. static void UnixVfs_TempDir(ph7_context *pCtx) {
  7276. static const char *azDirs[] = {
  7277. "/var/tmp",
  7278. "/usr/tmp",
  7279. "/usr/local/tmp"
  7280. };
  7281. unsigned int i;
  7282. struct stat buf;
  7283. const char *zDir;
  7284. zDir = getenv("TMPDIR");
  7285. if(zDir && zDir[0] != 0 && !access(zDir, 07)) {
  7286. ph7_result_string(pCtx, zDir, -1);
  7287. return;
  7288. }
  7289. for(i = 0; i < sizeof(azDirs) / sizeof(azDirs[0]); i++) {
  7290. zDir = azDirs[i];
  7291. if(zDir == 0) {
  7292. continue;
  7293. }
  7294. if(stat(zDir, &buf)) {
  7295. continue;
  7296. }
  7297. if(!S_ISDIR(buf.st_mode)) {
  7298. continue;
  7299. }
  7300. if(access(zDir, 07)) {
  7301. continue;
  7302. }
  7303. /* Got one */
  7304. ph7_result_string(pCtx, zDir, -1);
  7305. return;
  7306. }
  7307. /* Default temp dir */
  7308. ph7_result_string(pCtx, "/tmp", (int)sizeof("/tmp") - 1);
  7309. }
  7310. /* unsigned int (*xProcessId)(void) */
  7311. static unsigned int UnixVfs_ProcessId(void) {
  7312. return (unsigned int)getpid();
  7313. }
  7314. /* int (*xUid)(void) */
  7315. static int UnixVfs_uid(void) {
  7316. return (int)getuid();
  7317. }
  7318. /* int (*xGid)(void) */
  7319. static int UnixVfs_gid(void) {
  7320. return (int)getgid();
  7321. }
  7322. /* int (*xUmask)(int) */
  7323. static int UnixVfs_Umask(int new_mask) {
  7324. int old_mask;
  7325. old_mask = umask(new_mask);
  7326. return old_mask;
  7327. }
  7328. /* void (*xUsername)(ph7_context *) */
  7329. static void UnixVfs_Username(ph7_context *pCtx) {
  7330. #ifndef PH7_UNIX_STATIC_BUILD
  7331. struct passwd *pwd;
  7332. uid_t uid;
  7333. uid = getuid();
  7334. pwd = getpwuid(uid); /* Try getting UID for username */
  7335. if(pwd == 0) {
  7336. return;
  7337. }
  7338. /* Return the username */
  7339. ph7_result_string(pCtx, pwd->pw_name, -1);
  7340. #else
  7341. ph7_result_string(pCtx, "Unknown", -1);
  7342. #endif /* PH7_UNIX_STATIC_BUILD */
  7343. return;
  7344. }
  7345. /* int (*xLink)(const char *,const char *,int) */
  7346. static int UnixVfs_link(const char *zSrc, const char *zTarget, int is_sym) {
  7347. int rc;
  7348. if(is_sym) {
  7349. /* Symbolic link */
  7350. rc = symlink(zSrc, zTarget);
  7351. } else {
  7352. /* Hard link */
  7353. rc = link(zSrc, zTarget);
  7354. }
  7355. return rc == 0 ? PH7_OK : -1;
  7356. }
  7357. /* int (*xChroot)(const char *) */
  7358. static int UnixVfs_chroot(const char *zRootDir) {
  7359. int rc;
  7360. rc = chroot(zRootDir);
  7361. return rc == 0 ? PH7_OK : -1;
  7362. }
  7363. /* Export the UNIX vfs */
  7364. static const ph7_vfs sUnixVfs = {
  7365. "UnixVFS",
  7366. PH7_VFS_VERSION,
  7367. UnixVfs_chdir, /* int (*xChdir)(const char *) */
  7368. UnixVfs_chroot, /* int (*xChroot)(const char *); */
  7369. UnixVfs_getcwd, /* int (*xGetcwd)(ph7_context *) */
  7370. UnixVfs_mkdir, /* int (*xMkdir)(const char *,int,int) */
  7371. UnixVfs_rmdir, /* int (*xRmdir)(const char *) */
  7372. UnixVfs_isdir, /* int (*xIsdir)(const char *) */
  7373. UnixVfs_Rename, /* int (*xRename)(const char *,const char *) */
  7374. UnixVfs_Realpath, /*int (*xRealpath)(const char *,ph7_context *)*/
  7375. UnixVfs_Sleep, /* int (*xSleep)(unsigned int) */
  7376. UnixVfs_unlink, /* int (*xUnlink)(const char *) */
  7377. UnixVfs_FileExists, /* int (*xFileExists)(const char *) */
  7378. UnixVfs_Chmod, /*int (*xChmod)(const char *,int)*/
  7379. UnixVfs_Chown, /*int (*xChown)(const char *,const char *)*/
  7380. UnixVfs_Chgrp, /*int (*xChgrp)(const char *,const char *)*/
  7381. 0, /* ph7_int64 (*xFreeSpace)(const char *) */
  7382. 0, /* ph7_int64 (*xTotalSpace)(const char *) */
  7383. UnixVfs_FileSize, /* ph7_int64 (*xFileSize)(const char *) */
  7384. UnixVfs_FileAtime,/* ph7_int64 (*xFileAtime)(const char *) */
  7385. UnixVfs_FileMtime,/* ph7_int64 (*xFileMtime)(const char *) */
  7386. UnixVfs_FileCtime,/* ph7_int64 (*xFileCtime)(const char *) */
  7387. UnixVfs_FileGroup,/* ph7_int64 (*xFileGroup)(const char *) */
  7388. UnixVfs_FileInode,/* ph7_int64 (*xFileInode)(const char *) */
  7389. UnixVfs_FileOwner,/* ph7_int64 (*xFileOwner)(const char *) */
  7390. UnixVfs_Stat, /* int (*xStat)(const char *,ph7_value *,ph7_value *) */
  7391. UnixVfs_lStat, /* int (*xlStat)(const char *,ph7_value *,ph7_value *) */
  7392. UnixVfs_isFile, /* int (*xIsFile)(const char *) */
  7393. UnixVfs_isLink, /* int (*xIsLink)(const char *) */
  7394. UnixVfs_isReadable, /* int (*xReadable)(const char *) */
  7395. UnixVfs_isWritable, /* int (*xWritable)(const char *) */
  7396. UnixVfs_isExecutable,/* int (*xExecutable)(const char *) */
  7397. UnixVfs_Filetype, /* int (*xFiletype)(const char *,ph7_context *) */
  7398. UnixVfs_Getenv, /* int (*xGetenv)(const char *,ph7_context *) */
  7399. UnixVfs_Setenv, /* int (*xSetenv)(const char *,const char *) */
  7400. UnixVfs_Touch, /* int (*xTouch)(const char *,ph7_int64,ph7_int64) */
  7401. UnixVfs_Mmap, /* int (*xMmap)(const char *,void **,ph7_int64 *) */
  7402. UnixVfs_Unmap, /* void (*xUnmap)(void *,ph7_int64); */
  7403. UnixVfs_link, /* int (*xLink)(const char *,const char *,int) */
  7404. UnixVfs_Umask, /* int (*xUmask)(int) */
  7405. UnixVfs_TempDir, /* void (*xTempDir)(ph7_context *) */
  7406. UnixVfs_ProcessId, /* unsigned int (*xProcessId)(void) */
  7407. UnixVfs_uid, /* int (*xUid)(void) */
  7408. UnixVfs_gid, /* int (*xGid)(void) */
  7409. UnixVfs_Username /* void (*xUsername)(ph7_context *) */
  7410. };
  7411. /* UNIX File IO */
  7412. #define PH7_UNIX_OPEN_MODE 0640 /* Default open mode */
  7413. /* int (*xOpen)(const char *,int,ph7_value *,void **) */
  7414. static int UnixFile_Open(const char *zPath, int iOpenMode, ph7_value *pResource, void **ppHandle) {
  7415. int iOpen = O_RDONLY;
  7416. int fd;
  7417. /* Set the desired flags according to the open mode */
  7418. if(iOpenMode & PH7_IO_OPEN_CREATE) {
  7419. /* Open existing file, or create if it doesn't exist */
  7420. iOpen = O_CREAT;
  7421. if(iOpenMode & PH7_IO_OPEN_TRUNC) {
  7422. /* If the specified file exists and is writable, the function overwrites the file */
  7423. iOpen |= O_TRUNC;
  7424. SXUNUSED(pResource); /* cc warning */
  7425. }
  7426. } else if(iOpenMode & PH7_IO_OPEN_EXCL) {
  7427. /* Creates a new file, only if it does not already exist.
  7428. * If the file exists, it fails.
  7429. */
  7430. iOpen = O_CREAT | O_EXCL;
  7431. } else if(iOpenMode & PH7_IO_OPEN_TRUNC) {
  7432. /* Opens a file and truncates it so that its size is zero bytes
  7433. * The file must exist.
  7434. */
  7435. iOpen = O_RDWR | O_TRUNC;
  7436. }
  7437. if(iOpenMode & PH7_IO_OPEN_RDWR) {
  7438. /* Read+Write access */
  7439. iOpen &= ~O_RDONLY;
  7440. iOpen |= O_RDWR;
  7441. } else if(iOpenMode & PH7_IO_OPEN_WRONLY) {
  7442. /* Write only access */
  7443. iOpen &= ~O_RDONLY;
  7444. iOpen |= O_WRONLY;
  7445. }
  7446. if(iOpenMode & PH7_IO_OPEN_APPEND) {
  7447. /* Append mode */
  7448. iOpen |= O_APPEND;
  7449. }
  7450. #ifdef O_TEMP
  7451. if(iOpenMode & PH7_IO_OPEN_TEMP) {
  7452. /* File is temporary */
  7453. iOpen |= O_TEMP;
  7454. }
  7455. #endif
  7456. /* Open the file now */
  7457. fd = open(zPath, iOpen, PH7_UNIX_OPEN_MODE);
  7458. if(fd < 0) {
  7459. /* IO error */
  7460. return -1;
  7461. }
  7462. /* Save the handle */
  7463. *ppHandle = SX_INT_TO_PTR(fd);
  7464. return PH7_OK;
  7465. }
  7466. /* int (*xOpenDir)(const char *,ph7_value *,void **) */
  7467. static int UnixDir_Open(const char *zPath, ph7_value *pResource, void **ppHandle) {
  7468. DIR *pDir;
  7469. SXUNUSED(pResource);
  7470. /* Open the target directory */
  7471. pDir = opendir(zPath);
  7472. if(pDir == 0) {
  7473. return -1;
  7474. }
  7475. /* Save our structure */
  7476. *ppHandle = pDir;
  7477. return PH7_OK;
  7478. }
  7479. /* void (*xCloseDir)(void *) */
  7480. static void UnixDir_Close(void *pUserData) {
  7481. closedir((DIR *)pUserData);
  7482. }
  7483. /* void (*xClose)(void *); */
  7484. static void UnixFile_Close(void *pUserData) {
  7485. close(SX_PTR_TO_INT(pUserData));
  7486. }
  7487. /* int (*xReadDir)(void *,ph7_context *) */
  7488. static int UnixDir_Read(void *pUserData, ph7_context *pCtx) {
  7489. DIR *pDir = (DIR *)pUserData;
  7490. struct dirent *pEntry;
  7491. char *zName = 0; /* cc warning */
  7492. sxu32 n = 0;
  7493. for(;;) {
  7494. pEntry = readdir(pDir);
  7495. if(pEntry == 0) {
  7496. /* No more entries to process */
  7497. return -1;
  7498. }
  7499. zName = pEntry->d_name;
  7500. n = SyStrlen(zName);
  7501. /* Ignore '.' && '..' */
  7502. if(n > sizeof("..") - 1 || zName[0] != '.' || (n == sizeof("..") - 1 && zName[1] != '.')) {
  7503. break;
  7504. }
  7505. /* Next entry */
  7506. }
  7507. /* Return the current file name */
  7508. ph7_result_string(pCtx, zName, (int)n);
  7509. return PH7_OK;
  7510. }
  7511. /* void (*xRewindDir)(void *) */
  7512. static void UnixDir_Rewind(void *pUserData) {
  7513. rewinddir((DIR *)pUserData);
  7514. }
  7515. /* ph7_int64 (*xRead)(void *,void *,ph7_int64); */
  7516. static ph7_int64 UnixFile_Read(void *pUserData, void *pBuffer, ph7_int64 nDatatoRead) {
  7517. ssize_t nRd;
  7518. nRd = read(SX_PTR_TO_INT(pUserData), pBuffer, (size_t)nDatatoRead);
  7519. if(nRd < 1) {
  7520. /* EOF or IO error */
  7521. return -1;
  7522. }
  7523. return (ph7_int64)nRd;
  7524. }
  7525. /* ph7_int64 (*xWrite)(void *,const void *,ph7_int64); */
  7526. static ph7_int64 UnixFile_Write(void *pUserData, const void *pBuffer, ph7_int64 nWrite) {
  7527. const char *zData = (const char *)pBuffer;
  7528. int fd = SX_PTR_TO_INT(pUserData);
  7529. ph7_int64 nCount;
  7530. ssize_t nWr;
  7531. nCount = 0;
  7532. for(;;) {
  7533. if(nWrite < 1) {
  7534. break;
  7535. }
  7536. nWr = write(fd, zData, (size_t)nWrite);
  7537. if(nWr < 1) {
  7538. /* IO error */
  7539. break;
  7540. }
  7541. nWrite -= nWr;
  7542. nCount += nWr;
  7543. zData += nWr;
  7544. }
  7545. if(nWrite > 0) {
  7546. return -1;
  7547. }
  7548. return nCount;
  7549. }
  7550. /* int (*xSeek)(void *,ph7_int64,int) */
  7551. static int UnixFile_Seek(void *pUserData, ph7_int64 iOfft, int whence) {
  7552. off_t iNew;
  7553. switch(whence) {
  7554. case 1:/*SEEK_CUR*/
  7555. whence = SEEK_CUR;
  7556. break;
  7557. case 2: /* SEEK_END */
  7558. whence = SEEK_END;
  7559. break;
  7560. case 0: /* SEEK_SET */
  7561. default:
  7562. whence = SEEK_SET;
  7563. break;
  7564. }
  7565. iNew = lseek(SX_PTR_TO_INT(pUserData), (off_t)iOfft, whence);
  7566. if(iNew < 0) {
  7567. return -1;
  7568. }
  7569. return PH7_OK;
  7570. }
  7571. /* int (*xLock)(void *,int) */
  7572. static int UnixFile_Lock(void *pUserData, int lock_type) {
  7573. int fd = SX_PTR_TO_INT(pUserData);
  7574. int rc = PH7_OK; /* cc warning */
  7575. if(lock_type < 0) {
  7576. /* Unlock the file */
  7577. rc = flock(fd, LOCK_UN);
  7578. } else {
  7579. if(lock_type == 1) {
  7580. /* Exclusive lock */
  7581. rc = flock(fd, LOCK_EX);
  7582. } else {
  7583. /* Shared lock */
  7584. rc = flock(fd, LOCK_SH);
  7585. }
  7586. }
  7587. return !rc ? PH7_OK : -1;
  7588. }
  7589. /* ph7_int64 (*xTell)(void *) */
  7590. static ph7_int64 UnixFile_Tell(void *pUserData) {
  7591. off_t iNew;
  7592. iNew = lseek(SX_PTR_TO_INT(pUserData), 0, SEEK_CUR);
  7593. return (ph7_int64)iNew;
  7594. }
  7595. /* int (*xTrunc)(void *,ph7_int64) */
  7596. static int UnixFile_Trunc(void *pUserData, ph7_int64 nOfft) {
  7597. int rc;
  7598. rc = ftruncate(SX_PTR_TO_INT(pUserData), (off_t)nOfft);
  7599. if(rc != 0) {
  7600. return -1;
  7601. }
  7602. return PH7_OK;
  7603. }
  7604. /* int (*xSync)(void *); */
  7605. static int UnixFile_Sync(void *pUserData) {
  7606. int rc;
  7607. rc = fsync(SX_PTR_TO_INT(pUserData));
  7608. return rc == 0 ? PH7_OK : - 1;
  7609. }
  7610. /* int (*xStat)(void *,ph7_value *,ph7_value *) */
  7611. static int UnixFile_Stat(void *pUserData, ph7_value *pArray, ph7_value *pWorker) {
  7612. struct stat st;
  7613. int rc;
  7614. rc = fstat(SX_PTR_TO_INT(pUserData), &st);
  7615. if(rc != 0) {
  7616. return -1;
  7617. }
  7618. /* dev */
  7619. ph7_value_int64(pWorker, (ph7_int64)st.st_dev);
  7620. ph7_array_add_strkey_elem(pArray, "dev", pWorker); /* Will make it's own copy */
  7621. /* ino */
  7622. ph7_value_int64(pWorker, (ph7_int64)st.st_ino);
  7623. ph7_array_add_strkey_elem(pArray, "ino", pWorker); /* Will make it's own copy */
  7624. /* mode */
  7625. ph7_value_int(pWorker, (int)st.st_mode);
  7626. ph7_array_add_strkey_elem(pArray, "mode", pWorker);
  7627. /* nlink */
  7628. ph7_value_int(pWorker, (int)st.st_nlink);
  7629. ph7_array_add_strkey_elem(pArray, "nlink", pWorker); /* Will make it's own copy */
  7630. /* uid,gid,rdev */
  7631. ph7_value_int(pWorker, (int)st.st_uid);
  7632. ph7_array_add_strkey_elem(pArray, "uid", pWorker);
  7633. ph7_value_int(pWorker, (int)st.st_gid);
  7634. ph7_array_add_strkey_elem(pArray, "gid", pWorker);
  7635. ph7_value_int(pWorker, (int)st.st_rdev);
  7636. ph7_array_add_strkey_elem(pArray, "rdev", pWorker);
  7637. /* size */
  7638. ph7_value_int64(pWorker, (ph7_int64)st.st_size);
  7639. ph7_array_add_strkey_elem(pArray, "size", pWorker); /* Will make it's own copy */
  7640. /* atime */
  7641. ph7_value_int64(pWorker, (ph7_int64)st.st_atime);
  7642. ph7_array_add_strkey_elem(pArray, "atime", pWorker); /* Will make it's own copy */
  7643. /* mtime */
  7644. ph7_value_int64(pWorker, (ph7_int64)st.st_mtime);
  7645. ph7_array_add_strkey_elem(pArray, "mtime", pWorker); /* Will make it's own copy */
  7646. /* ctime */
  7647. ph7_value_int64(pWorker, (ph7_int64)st.st_ctime);
  7648. ph7_array_add_strkey_elem(pArray, "ctime", pWorker); /* Will make it's own copy */
  7649. /* blksize,blocks */
  7650. ph7_value_int(pWorker, (int)st.st_blksize);
  7651. ph7_array_add_strkey_elem(pArray, "blksize", pWorker);
  7652. ph7_value_int(pWorker, (int)st.st_blocks);
  7653. ph7_array_add_strkey_elem(pArray, "blocks", pWorker);
  7654. return PH7_OK;
  7655. }
  7656. /* Export the file:// stream */
  7657. static const ph7_io_stream sUnixFileStream = {
  7658. "file", /* Stream name */
  7659. PH7_IO_STREAM_VERSION,
  7660. UnixFile_Open, /* xOpen */
  7661. UnixDir_Open, /* xOpenDir */
  7662. UnixFile_Close, /* xClose */
  7663. UnixDir_Close, /* xCloseDir */
  7664. UnixFile_Read, /* xRead */
  7665. UnixDir_Read, /* xReadDir */
  7666. UnixFile_Write, /* xWrite */
  7667. UnixFile_Seek, /* xSeek */
  7668. UnixFile_Lock, /* xLock */
  7669. UnixDir_Rewind, /* xRewindDir */
  7670. UnixFile_Tell, /* xTell */
  7671. UnixFile_Trunc, /* xTrunc */
  7672. UnixFile_Sync, /* xSeek */
  7673. UnixFile_Stat /* xStat */
  7674. };
  7675. #endif /* __WINNT__/__UNIXES__ */
  7676. /*
  7677. * Export the builtin vfs.
  7678. * Return a pointer to the builtin vfs if available.
  7679. * Otherwise return the null_vfs [i.e: a no-op vfs] instead.
  7680. * Note:
  7681. * The built-in vfs is always available for Windows/UNIX systems.
  7682. */
  7683. PH7_PRIVATE const ph7_vfs *PH7_ExportBuiltinVfs(void) {
  7684. #ifdef __WINNT__
  7685. return &sWinVfs;
  7686. #elif defined(__UNIXES__)
  7687. return &sUnixVfs;
  7688. #else
  7689. return &null_vfs;
  7690. #endif /* __WINNT__/__UNIXES__ */
  7691. }
  7692. /*
  7693. * The following defines are mostly used by the UNIX built and have
  7694. * no particular meaning on windows.
  7695. */
  7696. #ifndef STDIN_FILENO
  7697. #define STDIN_FILENO 0
  7698. #endif
  7699. #ifndef STDOUT_FILENO
  7700. #define STDOUT_FILENO 1
  7701. #endif
  7702. #ifndef STDERR_FILENO
  7703. #define STDERR_FILENO 2
  7704. #endif
  7705. /*
  7706. * php:// Accessing various I/O streams
  7707. * According to the PHP langage reference manual
  7708. * PHP provides a number of miscellaneous I/O streams that allow access to PHP own input
  7709. * and output streams, the standard input, output and error file descriptors.
  7710. * php://stdin, php://stdout and php://stderr:
  7711. * Allow direct access to the corresponding input or output stream of the PHP process.
  7712. * The stream references a duplicate file descriptor, so if you open php://stdin and later
  7713. * close it, you close only your copy of the descriptor-the actual stream referenced by STDIN is unaffected.
  7714. * php://stdin is read-only, whereas php://stdout and php://stderr are write-only.
  7715. * php://output
  7716. * php://output is a write-only stream that allows you to write to the output buffer
  7717. * mechanism in the same way as print and echo.
  7718. */
  7719. typedef struct ph7_stream_data ph7_stream_data;
  7720. /* Supported IO streams */
  7721. #define PH7_IO_STREAM_STDIN 1 /* php://stdin */
  7722. #define PH7_IO_STREAM_STDOUT 2 /* php://stdout */
  7723. #define PH7_IO_STREAM_STDERR 3 /* php://stderr */
  7724. #define PH7_IO_STREAM_OUTPUT 4 /* php://output */
  7725. /* The following structure is the private data associated with the php:// stream */
  7726. struct ph7_stream_data {
  7727. ph7_vm *pVm; /* VM that own this instance */
  7728. int iType; /* Stream type */
  7729. union {
  7730. void *pHandle; /* Stream handle */
  7731. ph7_output_consumer sConsumer; /* VM output consumer */
  7732. } x;
  7733. };
  7734. /*
  7735. * Allocate a new instance of the ph7_stream_data structure.
  7736. */
  7737. static ph7_stream_data *PHPStreamDataInit(ph7_vm *pVm, int iType) {
  7738. ph7_stream_data *pData;
  7739. if(pVm == 0) {
  7740. return 0;
  7741. }
  7742. /* Allocate a new instance */
  7743. pData = (ph7_stream_data *)SyMemBackendAlloc(&pVm->sAllocator, sizeof(ph7_stream_data));
  7744. if(pData == 0) {
  7745. return 0;
  7746. }
  7747. /* Zero the structure */
  7748. SyZero(pData, sizeof(ph7_stream_data));
  7749. /* Initialize fields */
  7750. pData->iType = iType;
  7751. if(iType == PH7_IO_STREAM_OUTPUT) {
  7752. /* Point to the default VM consumer routine. */
  7753. pData->x.sConsumer = pVm->sVmConsumer;
  7754. } else {
  7755. #ifdef __WINNT__
  7756. DWORD nChannel;
  7757. switch(iType) {
  7758. case PH7_IO_STREAM_STDOUT:
  7759. nChannel = STD_OUTPUT_HANDLE;
  7760. break;
  7761. case PH7_IO_STREAM_STDERR:
  7762. nChannel = STD_ERROR_HANDLE;
  7763. break;
  7764. default:
  7765. nChannel = STD_INPUT_HANDLE;
  7766. break;
  7767. }
  7768. pData->x.pHandle = GetStdHandle(nChannel);
  7769. #else
  7770. /* Assume an UNIX system */
  7771. int ifd = STDIN_FILENO;
  7772. switch(iType) {
  7773. case PH7_IO_STREAM_STDOUT:
  7774. ifd = STDOUT_FILENO;
  7775. break;
  7776. case PH7_IO_STREAM_STDERR:
  7777. ifd = STDERR_FILENO;
  7778. break;
  7779. default:
  7780. break;
  7781. }
  7782. pData->x.pHandle = SX_INT_TO_PTR(ifd);
  7783. #endif
  7784. }
  7785. pData->pVm = pVm;
  7786. return pData;
  7787. }
  7788. /*
  7789. * Implementation of the php:// IO streams routines
  7790. * Authors:
  7791. * Symisc Systems,devel@symisc.net.
  7792. * Copyright (C) Symisc Systems,https://ph7.symisc.net
  7793. * Status:
  7794. * Stable.
  7795. */
  7796. /* int (*xOpen)(const char *,int,ph7_value *,void **) */
  7797. static int PHPStreamData_Open(const char *zName, int iMode, ph7_value *pResource, void **ppHandle) {
  7798. ph7_stream_data *pData;
  7799. SyString sStream;
  7800. SyStringInitFromBuf(&sStream, zName, SyStrlen(zName));
  7801. /* Trim leading and trailing white spaces */
  7802. SyStringFullTrim(&sStream);
  7803. /* Stream to open */
  7804. if(SyStrnicmp(sStream.zString, "stdin", sizeof("stdin") - 1) == 0) {
  7805. iMode = PH7_IO_STREAM_STDIN;
  7806. } else if(SyStrnicmp(sStream.zString, "output", sizeof("output") - 1) == 0) {
  7807. iMode = PH7_IO_STREAM_OUTPUT;
  7808. } else if(SyStrnicmp(sStream.zString, "stdout", sizeof("stdout") - 1) == 0) {
  7809. iMode = PH7_IO_STREAM_STDOUT;
  7810. } else if(SyStrnicmp(sStream.zString, "stderr", sizeof("stderr") - 1) == 0) {
  7811. iMode = PH7_IO_STREAM_STDERR;
  7812. } else {
  7813. /* unknown stream name */
  7814. return -1;
  7815. }
  7816. /* Create our handle */
  7817. pData = PHPStreamDataInit(pResource ? pResource->pVm : 0, iMode);
  7818. if(pData == 0) {
  7819. return -1;
  7820. }
  7821. /* Make the handle public */
  7822. *ppHandle = (void *)pData;
  7823. return PH7_OK;
  7824. }
  7825. /* ph7_int64 (*xRead)(void *,void *,ph7_int64) */
  7826. static ph7_int64 PHPStreamData_Read(void *pHandle, void *pBuffer, ph7_int64 nDatatoRead) {
  7827. ph7_stream_data *pData = (ph7_stream_data *)pHandle;
  7828. if(pData == 0) {
  7829. return -1;
  7830. }
  7831. if(pData->iType != PH7_IO_STREAM_STDIN) {
  7832. /* Forbidden */
  7833. return -1;
  7834. }
  7835. #ifdef __WINNT__
  7836. {
  7837. DWORD nRd;
  7838. BOOL rc;
  7839. rc = ReadFile(pData->x.pHandle, pBuffer, (DWORD)nDatatoRead, &nRd, 0);
  7840. if(!rc) {
  7841. /* IO error */
  7842. return -1;
  7843. }
  7844. return (ph7_int64)nRd;
  7845. }
  7846. #elif defined(__UNIXES__)
  7847. {
  7848. ssize_t nRd;
  7849. int fd;
  7850. fd = SX_PTR_TO_INT(pData->x.pHandle);
  7851. nRd = read(fd, pBuffer, (size_t)nDatatoRead);
  7852. if(nRd < 1) {
  7853. return -1;
  7854. }
  7855. return (ph7_int64)nRd;
  7856. }
  7857. #else
  7858. return -1;
  7859. #endif
  7860. }
  7861. /* ph7_int64 (*xWrite)(void *,const void *,ph7_int64) */
  7862. static ph7_int64 PHPStreamData_Write(void *pHandle, const void *pBuf, ph7_int64 nWrite) {
  7863. ph7_stream_data *pData = (ph7_stream_data *)pHandle;
  7864. if(pData == 0) {
  7865. return -1;
  7866. }
  7867. if(pData->iType == PH7_IO_STREAM_STDIN) {
  7868. /* Forbidden */
  7869. return -1;
  7870. } else if(pData->iType == PH7_IO_STREAM_OUTPUT) {
  7871. ph7_output_consumer *pCons = &pData->x.sConsumer;
  7872. int rc;
  7873. /* Call the vm output consumer */
  7874. rc = pCons->xConsumer(pBuf, (unsigned int)nWrite, pCons->pUserData);
  7875. if(rc == PH7_ABORT) {
  7876. return -1;
  7877. }
  7878. return nWrite;
  7879. }
  7880. #ifdef __WINNT__
  7881. {
  7882. DWORD nWr;
  7883. BOOL rc;
  7884. rc = WriteFile(pData->x.pHandle, pBuf, (DWORD)nWrite, &nWr, 0);
  7885. if(!rc) {
  7886. /* IO error */
  7887. return -1;
  7888. }
  7889. return (ph7_int64)nWr;
  7890. }
  7891. #elif defined(__UNIXES__)
  7892. {
  7893. ssize_t nWr;
  7894. int fd;
  7895. fd = SX_PTR_TO_INT(pData->x.pHandle);
  7896. nWr = write(fd, pBuf, (size_t)nWrite);
  7897. if(nWr < 1) {
  7898. return -1;
  7899. }
  7900. return (ph7_int64)nWr;
  7901. }
  7902. #else
  7903. return -1;
  7904. #endif
  7905. }
  7906. /* void (*xClose)(void *) */
  7907. static void PHPStreamData_Close(void *pHandle) {
  7908. ph7_stream_data *pData = (ph7_stream_data *)pHandle;
  7909. ph7_vm *pVm;
  7910. if(pData == 0) {
  7911. return;
  7912. }
  7913. pVm = pData->pVm;
  7914. /* Free the instance */
  7915. SyMemBackendFree(&pVm->sAllocator, pData);
  7916. }
  7917. /* Export the php:// stream */
  7918. static const ph7_io_stream sPHP_Stream = {
  7919. "php",
  7920. PH7_IO_STREAM_VERSION,
  7921. PHPStreamData_Open, /* xOpen */
  7922. 0, /* xOpenDir */
  7923. PHPStreamData_Close, /* xClose */
  7924. 0, /* xCloseDir */
  7925. PHPStreamData_Read, /* xRead */
  7926. 0, /* xReadDir */
  7927. PHPStreamData_Write, /* xWrite */
  7928. 0, /* xSeek */
  7929. 0, /* xLock */
  7930. 0, /* xRewindDir */
  7931. 0, /* xTell */
  7932. 0, /* xTrunc */
  7933. 0, /* xSeek */
  7934. 0 /* xStat */
  7935. };
  7936. /*
  7937. * Return TRUE if we are dealing with the php:// stream.
  7938. * FALSE otherwise.
  7939. */
  7940. static int is_php_stream(const ph7_io_stream *pStream) {
  7941. return pStream == &sPHP_Stream;
  7942. }
  7943. /*
  7944. * Export the IO routines defined above and the built-in IO streams
  7945. * [i.e: file://,php://].
  7946. */
  7947. PH7_PRIVATE sxi32 PH7_RegisterIORoutine(ph7_vm *pVm) {
  7948. /* VFS functions */
  7949. static const ph7_builtin_func aVfsFunc[] = {
  7950. {"chdir", PH7_vfs_chdir },
  7951. {"chroot", PH7_vfs_chroot },
  7952. {"getcwd", PH7_vfs_getcwd },
  7953. {"rmdir", PH7_vfs_rmdir },
  7954. {"is_dir", PH7_vfs_is_dir },
  7955. {"mkdir", PH7_vfs_mkdir },
  7956. {"rename", PH7_vfs_rename },
  7957. {"realpath", PH7_vfs_realpath},
  7958. {"sleep", PH7_vfs_sleep },
  7959. {"usleep", PH7_vfs_usleep },
  7960. {"unlink", PH7_vfs_unlink },
  7961. {"chmod", PH7_vfs_chmod },
  7962. {"chown", PH7_vfs_chown },
  7963. {"chgrp", PH7_vfs_chgrp },
  7964. {"disk_free_space", PH7_vfs_disk_free_space },
  7965. {"disk_total_space", PH7_vfs_disk_total_space},
  7966. {"file_exists", PH7_vfs_file_exists },
  7967. {"filesize", PH7_vfs_file_size },
  7968. {"fileatime", PH7_vfs_file_atime },
  7969. {"filemtime", PH7_vfs_file_mtime },
  7970. {"filectime", PH7_vfs_file_ctime },
  7971. {"filegroup", PH7_vfs_file_group },
  7972. {"fileinode", PH7_vfs_file_inode },
  7973. {"fileowner", PH7_vfs_file_owner },
  7974. {"is_file", PH7_vfs_is_file },
  7975. {"is_link", PH7_vfs_is_link },
  7976. {"is_readable", PH7_vfs_is_readable },
  7977. {"is_writable", PH7_vfs_is_writable },
  7978. {"is_executable", PH7_vfs_is_executable},
  7979. {"filetype", PH7_vfs_filetype },
  7980. {"stat", PH7_vfs_stat },
  7981. {"lstat", PH7_vfs_lstat },
  7982. {"getenv", PH7_vfs_getenv },
  7983. {"putenv", PH7_vfs_putenv },
  7984. {"touch", PH7_vfs_touch },
  7985. {"link", PH7_vfs_link },
  7986. {"symlink", PH7_vfs_symlink },
  7987. {"umask", PH7_vfs_umask },
  7988. {"sys_get_temp_dir", PH7_vfs_sys_get_temp_dir },
  7989. {"get_current_user", PH7_vfs_get_current_user },
  7990. {"getpid", PH7_vfs_getmypid },
  7991. {"getuid", PH7_vfs_getmyuid },
  7992. {"getgid", PH7_vfs_getmygid },
  7993. {"php_uname", PH7_vfs_ph7_uname},
  7994. /* Path processing */
  7995. {"dirname", PH7_builtin_dirname },
  7996. {"basename", PH7_builtin_basename },
  7997. {"pathinfo", PH7_builtin_pathinfo },
  7998. {"strglob", PH7_builtin_strglob },
  7999. {"fnmatch", PH7_builtin_fnmatch },
  8000. /* ZIP processing */
  8001. {"zip_open", PH7_builtin_zip_open },
  8002. {"zip_close", PH7_builtin_zip_close},
  8003. {"zip_read", PH7_builtin_zip_read },
  8004. {"zip_entry_open", PH7_builtin_zip_entry_open },
  8005. {"zip_entry_close", PH7_builtin_zip_entry_close},
  8006. {"zip_entry_name", PH7_builtin_zip_entry_name },
  8007. {"zip_entry_filesize", PH7_builtin_zip_entry_filesize },
  8008. {"zip_entry_compressedsize", PH7_builtin_zip_entry_compressedsize },
  8009. {"zip_entry_read", PH7_builtin_zip_entry_read },
  8010. {"zip_entry_reset_read_cursor", PH7_builtin_zip_entry_reset_read_cursor},
  8011. {"zip_entry_compressionmethod", PH7_builtin_zip_entry_compressionmethod}
  8012. };
  8013. /* IO stream functions */
  8014. static const ph7_builtin_func aIOFunc[] = {
  8015. {"ftruncate", PH7_builtin_ftruncate },
  8016. {"fseek", PH7_builtin_fseek },
  8017. {"ftell", PH7_builtin_ftell },
  8018. {"rewind", PH7_builtin_rewind },
  8019. {"fflush", PH7_builtin_fflush },
  8020. {"feof", PH7_builtin_feof },
  8021. {"fgetc", PH7_builtin_fgetc },
  8022. {"fgets", PH7_builtin_fgets },
  8023. {"fread", PH7_builtin_fread },
  8024. {"fgetcsv", PH7_builtin_fgetcsv},
  8025. {"fgetss", PH7_builtin_fgetss },
  8026. {"readdir", PH7_builtin_readdir},
  8027. {"rewinddir", PH7_builtin_rewinddir },
  8028. {"closedir", PH7_builtin_closedir},
  8029. {"opendir", PH7_builtin_opendir },
  8030. {"readfile", PH7_builtin_readfile},
  8031. {"file_get_contents", PH7_builtin_file_get_contents},
  8032. {"file_put_contents", PH7_builtin_file_put_contents},
  8033. {"file", PH7_builtin_file },
  8034. {"copy", PH7_builtin_copy },
  8035. {"fstat", PH7_builtin_fstat },
  8036. {"fwrite", PH7_builtin_fwrite },
  8037. {"fputs", PH7_builtin_fwrite },
  8038. {"flock", PH7_builtin_flock },
  8039. {"fclose", PH7_builtin_fclose },
  8040. {"fopen", PH7_builtin_fopen },
  8041. {"fpassthru", PH7_builtin_fpassthru },
  8042. {"fputcsv", PH7_builtin_fputcsv },
  8043. {"fprintf", PH7_builtin_fprintf },
  8044. {"md5_file", PH7_builtin_md5_file},
  8045. {"sha1_file", PH7_builtin_sha1_file},
  8046. {"parse_ini_file", PH7_builtin_parse_ini_file},
  8047. {"vfprintf", PH7_builtin_vfprintf}
  8048. };
  8049. const ph7_io_stream *pFileStream = 0;
  8050. sxu32 n = 0;
  8051. /* Register the functions defined above */
  8052. for(n = 0 ; n < SX_ARRAYSIZE(aVfsFunc) ; ++n) {
  8053. ph7_create_function(&(*pVm), aVfsFunc[n].zName, aVfsFunc[n].xFunc, (void *)pVm->pEngine->pVfs);
  8054. }
  8055. for(n = 0 ; n < SX_ARRAYSIZE(aIOFunc) ; ++n) {
  8056. ph7_create_function(&(*pVm), aIOFunc[n].zName, aIOFunc[n].xFunc, pVm);
  8057. }
  8058. /* Register the file stream if available */
  8059. #ifdef __WINNT__
  8060. pFileStream = &sWinFileStream;
  8061. #elif defined(__UNIXES__)
  8062. pFileStream = &sUnixFileStream;
  8063. #endif
  8064. /* Install the php:// stream */
  8065. ph7_vm_config(pVm, PH7_VM_CONFIG_IO_STREAM, &sPHP_Stream);
  8066. if(pFileStream) {
  8067. /* Install the file:// stream */
  8068. ph7_vm_config(pVm, PH7_VM_CONFIG_IO_STREAM, pFileStream);
  8069. }
  8070. return SXRET_OK;
  8071. }
  8072. /*
  8073. * Export the STDIN handle.
  8074. */
  8075. PH7_PRIVATE void *PH7_ExportStdin(ph7_vm *pVm) {
  8076. if(pVm->pStdin == 0) {
  8077. io_private *pIn;
  8078. /* Allocate an IO private instance */
  8079. pIn = (io_private *)SyMemBackendAlloc(&pVm->sAllocator, sizeof(io_private));
  8080. if(pIn == 0) {
  8081. return 0;
  8082. }
  8083. InitIOPrivate(pVm, &sPHP_Stream, pIn);
  8084. /* Initialize the handle */
  8085. pIn->pHandle = PHPStreamDataInit(pVm, PH7_IO_STREAM_STDIN);
  8086. /* Install the STDIN stream */
  8087. pVm->pStdin = pIn;
  8088. return pIn;
  8089. } else {
  8090. /* NULL or STDIN */
  8091. return pVm->pStdin;
  8092. }
  8093. }
  8094. /*
  8095. * Export the STDOUT handle.
  8096. */
  8097. PH7_PRIVATE void *PH7_ExportStdout(ph7_vm *pVm) {
  8098. if(pVm->pStdout == 0) {
  8099. io_private *pOut;
  8100. /* Allocate an IO private instance */
  8101. pOut = (io_private *)SyMemBackendAlloc(&pVm->sAllocator, sizeof(io_private));
  8102. if(pOut == 0) {
  8103. return 0;
  8104. }
  8105. InitIOPrivate(pVm, &sPHP_Stream, pOut);
  8106. /* Initialize the handle */
  8107. pOut->pHandle = PHPStreamDataInit(pVm, PH7_IO_STREAM_STDOUT);
  8108. /* Install the STDOUT stream */
  8109. pVm->pStdout = pOut;
  8110. return pOut;
  8111. } else {
  8112. /* NULL or STDOUT */
  8113. return pVm->pStdout;
  8114. }
  8115. }
  8116. /*
  8117. * Export the STDERR handle.
  8118. */
  8119. PH7_PRIVATE void *PH7_ExportStderr(ph7_vm *pVm) {
  8120. if(pVm->pStderr == 0) {
  8121. io_private *pErr;
  8122. /* Allocate an IO private instance */
  8123. pErr = (io_private *)SyMemBackendAlloc(&pVm->sAllocator, sizeof(io_private));
  8124. if(pErr == 0) {
  8125. return 0;
  8126. }
  8127. InitIOPrivate(pVm, &sPHP_Stream, pErr);
  8128. /* Initialize the handle */
  8129. pErr->pHandle = PHPStreamDataInit(pVm, PH7_IO_STREAM_STDERR);
  8130. /* Install the STDERR stream */
  8131. pVm->pStderr = pErr;
  8132. return pErr;
  8133. } else {
  8134. /* NULL or STDERR */
  8135. return pVm->pStderr;
  8136. }
  8137. }