lfs.c 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900
  1. /*
  2. ** LuaFileSystem
  3. ** Copyright Kepler Project 2003 (http://www.keplerproject.org/luafilesystem)
  4. **
  5. ** File system manipulation library.
  6. ** This library offers these functions:
  7. ** lfs.attributes (filepath [, attributename])
  8. ** lfs.chdir (path)
  9. ** lfs.currentdir ()
  10. ** lfs.dir (path)
  11. ** lfs.lock (fh, mode)
  12. ** lfs.lock_dir (path)
  13. ** lfs.mkdir (path)
  14. ** lfs.rmdir (path)
  15. ** lfs.setmode (filepath, mode)
  16. ** lfs.symlinkattributes (filepath [, attributename]) -- thanks to Sam Roberts
  17. ** lfs.touch (filepath [, atime [, mtime]])
  18. ** lfs.unlock (fh)
  19. **
  20. ** $Id: lfs.c,v 1.61 2009/07/04 02:10:16 mascarenhas Exp $
  21. */
  22. #if LUA_VERSION_NUM == 501
  23. #define lua_pushinteger lua_pushnumber
  24. #endif
  25. #ifndef LFS_DO_NOT_USE_LARGE_FILE
  26. #ifndef _WIN32
  27. #ifndef _AIX
  28. #define _FILE_OFFSET_BITS 64 /* Linux, Solaris and HP-UX */
  29. #else
  30. #define _LARGE_FILES 1 /* AIX */
  31. #endif
  32. #endif
  33. #endif
  34. #ifndef LFS_DO_NOT_USE_LARGE_FILE
  35. #define _LARGEFILE64_SOURCE
  36. #endif
  37. #include <errno.h>
  38. #include <stdio.h>
  39. #include <string.h>
  40. #include <stdlib.h>
  41. #include <time.h>
  42. #include <sys/stat.h>
  43. #ifdef _WIN32
  44. #include <direct.h>
  45. #include <windows.h>
  46. #include <io.h>
  47. #include <sys/locking.h>
  48. #ifdef __BORLANDC__
  49. #include <utime.h>
  50. #else
  51. #include <sys/utime.h>
  52. #endif
  53. #include <fcntl.h>
  54. #else
  55. #include <unistd.h>
  56. #include <dirent.h>
  57. #include <fcntl.h>
  58. #include <sys/types.h>
  59. #include <utime.h>
  60. #endif
  61. #include "civetweb_lua.h"
  62. #include "lfs.h"
  63. #define LFS_VERSION "1.6.3"
  64. #define LFS_LIBNAME "lfs"
  65. #if LUA_VERSION_NUM >= 503 /* Lua 5.3 */
  66. #ifndef luaL_optlong
  67. #define luaL_optlong luaL_optinteger
  68. #endif
  69. #endif
  70. #if LUA_VERSION_NUM < 502
  71. # define luaL_newlib(L,l) (lua_newtable(L), luaL_register(L,NULL,l))
  72. #endif
  73. /* Define 'strerror' for systems that do not implement it */
  74. #ifdef NO_STRERROR
  75. #define strerror(_) "System unable to describe the error"
  76. #endif
  77. /* Define 'getcwd' for systems that do not implement it */
  78. #ifdef NO_GETCWD
  79. #define getcwd(p,s) NULL
  80. #define getcwd_error "Function 'getcwd' not provided by system"
  81. #else
  82. #define getcwd_error strerror(errno)
  83. #ifdef _WIN32
  84. /* MAX_PATH seems to be 260. Seems kind of small. Is there a better one? */
  85. #define LFS_MAXPATHLEN MAX_PATH
  86. #else
  87. /* For MAXPATHLEN: */
  88. #include <sys/param.h>
  89. #define LFS_MAXPATHLEN MAXPATHLEN
  90. #endif
  91. #endif
  92. #define DIR_METATABLE "directory metatable"
  93. typedef struct dir_data {
  94. int closed;
  95. #ifdef _WIN32
  96. intptr_t hFile;
  97. char pattern[MAX_PATH+1];
  98. #else
  99. DIR *dir;
  100. #endif
  101. } dir_data;
  102. #define LOCK_METATABLE "lock metatable"
  103. #ifdef _WIN32
  104. #ifdef __BORLANDC__
  105. #define lfs_setmode(L,file,m) ((void)L, setmode(_fileno(file), m))
  106. #define STAT_STRUCT struct stati64
  107. #else
  108. #define lfs_setmode(L,file,m) ((void)L, _setmode(_fileno(file), m))
  109. #define STAT_STRUCT struct _stati64
  110. #endif
  111. #define STAT_FUNC _stati64
  112. #define LSTAT_FUNC STAT_FUNC
  113. #else
  114. #define _O_TEXT 0
  115. #define _O_BINARY 0
  116. #define lfs_setmode(L,file,m) ((void)L, (void)file, (void)m, 0)
  117. #define STAT_STRUCT struct stat
  118. #define STAT_FUNC stat
  119. #define LSTAT_FUNC lstat
  120. #endif
  121. /*
  122. ** Utility functions
  123. */
  124. static int pusherror(lua_State *L, const char *info)
  125. {
  126. lua_pushnil(L);
  127. if (info==NULL)
  128. lua_pushstring(L, strerror(errno));
  129. else
  130. lua_pushfstring(L, "%s: %s", info, strerror(errno));
  131. lua_pushinteger(L, errno);
  132. return 3;
  133. }
  134. static int pushresult(lua_State *L, int i, const char *info)
  135. {
  136. if (i==-1)
  137. return pusherror(L, info);
  138. lua_pushinteger(L, i);
  139. return 1;
  140. }
  141. /*
  142. ** This function changes the working (current) directory
  143. */
  144. static int change_dir (lua_State *L) {
  145. const char *path = luaL_checkstring(L, 1);
  146. if (chdir(path)) {
  147. lua_pushnil (L);
  148. lua_pushfstring (L,"Unable to change working directory to '%s'\n%s\n",
  149. path, chdir_error);
  150. return 2;
  151. } else {
  152. lua_pushboolean (L, 1);
  153. return 1;
  154. }
  155. }
  156. /*
  157. ** This function returns the current directory
  158. ** If unable to get the current directory, it returns nil
  159. ** and a string describing the error
  160. */
  161. static int get_dir (lua_State *L) {
  162. char *path;
  163. /* Passing (NULL, 0) is not guaranteed to work. Use a temp buffer and size instead. */
  164. char buf[LFS_MAXPATHLEN];
  165. if ((path = getcwd(buf, LFS_MAXPATHLEN)) == NULL) {
  166. lua_pushnil(L);
  167. lua_pushstring(L, getcwd_error);
  168. return 2;
  169. }
  170. else {
  171. lua_pushstring(L, path);
  172. return 1;
  173. }
  174. }
  175. /*
  176. ** Check if the given element on the stack is a file and returns it.
  177. */
  178. static FILE *check_file (lua_State *L, int idx, const char *funcname) {
  179. FILE **fh = (FILE **)luaL_checkudata (L, idx, "FILE*");
  180. if (fh == NULL) {
  181. luaL_error (L, "%s: not a file", funcname);
  182. return 0;
  183. } else if (*fh == NULL) {
  184. luaL_error (L, "%s: closed file", funcname);
  185. return 0;
  186. } else
  187. return *fh;
  188. }
  189. /*
  190. **
  191. */
  192. static int _file_lock (lua_State *L, FILE *fh, const char *mode, const long start, long len, const char *funcname) {
  193. int code;
  194. #ifdef _WIN32
  195. /* lkmode valid values are:
  196. LK_LOCK Locks the specified bytes. If the bytes cannot be locked, the program immediately tries again after 1 second. If, after 10 attempts, the bytes cannot be locked, the constant returns an error.
  197. LK_NBLCK Locks the specified bytes. If the bytes cannot be locked, the constant returns an error.
  198. LK_NBRLCK Same as _LK_NBLCK.
  199. LK_RLCK Same as _LK_LOCK.
  200. LK_UNLCK Unlocks the specified bytes, which must have been previously locked.
  201. Regions should be locked only briefly and should be unlocked before closing a file or exiting the program.
  202. http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vclib/html/_crt__locking.asp
  203. */
  204. int lkmode;
  205. switch (*mode) {
  206. case 'r': lkmode = LK_NBLCK; break;
  207. case 'w': lkmode = LK_NBLCK; break;
  208. case 'u': lkmode = LK_UNLCK; break;
  209. default : return luaL_error (L, "%s: invalid mode", funcname);
  210. }
  211. if (!len) {
  212. fseek (fh, 0L, SEEK_END);
  213. len = ftell (fh);
  214. }
  215. fseek (fh, start, SEEK_SET);
  216. #ifdef __BORLANDC__
  217. code = locking (fileno(fh), lkmode, len);
  218. #else
  219. code = _locking (fileno(fh), lkmode, len);
  220. #endif
  221. #else
  222. struct flock f;
  223. switch (*mode) {
  224. case 'w': f.l_type = F_WRLCK; break;
  225. case 'r': f.l_type = F_RDLCK; break;
  226. case 'u': f.l_type = F_UNLCK; break;
  227. default : return luaL_error (L, "%s: invalid mode", funcname);
  228. }
  229. f.l_whence = SEEK_SET;
  230. f.l_start = (off_t)start;
  231. f.l_len = (off_t)len;
  232. code = fcntl (fileno(fh), F_SETLK, &f);
  233. #endif
  234. return (code != -1);
  235. }
  236. #ifdef _WIN32
  237. typedef struct lfs_Lock {
  238. HANDLE fd;
  239. } lfs_Lock;
  240. static int lfs_lock_dir(lua_State *L) {
  241. size_t pathl; HANDLE fd;
  242. lfs_Lock *lock;
  243. char *ln;
  244. const char *lockfile = "/lockfile.lfs";
  245. const char *path = luaL_checklstring(L, 1, &pathl);
  246. ln = (char*)malloc(pathl + strlen(lockfile) + 1);
  247. if(!ln) {
  248. lua_pushnil(L); lua_pushstring(L, strerror(errno)); return 2;
  249. }
  250. strcpy(ln, path); strcat(ln, lockfile);
  251. if((fd = CreateFile(ln, GENERIC_WRITE, 0, NULL, CREATE_NEW,
  252. FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE, NULL)) == INVALID_HANDLE_VALUE) {
  253. int en = GetLastError();
  254. free(ln); lua_pushnil(L);
  255. if(en == ERROR_FILE_EXISTS || en == ERROR_SHARING_VIOLATION)
  256. lua_pushstring(L, "File exists");
  257. else
  258. lua_pushstring(L, strerror(en));
  259. return 2;
  260. }
  261. free(ln);
  262. lock = (lfs_Lock*)lua_newuserdata(L, sizeof(lfs_Lock));
  263. lock->fd = fd;
  264. luaL_getmetatable (L, LOCK_METATABLE);
  265. lua_setmetatable (L, -2);
  266. return 1;
  267. }
  268. static int lfs_unlock_dir(lua_State *L) {
  269. lfs_Lock *lock = (lfs_Lock *)luaL_checkudata(L, 1, LOCK_METATABLE);
  270. if(lock->fd != INVALID_HANDLE_VALUE) {
  271. CloseHandle(lock->fd);
  272. lock->fd=INVALID_HANDLE_VALUE;
  273. }
  274. return 0;
  275. }
  276. #else
  277. typedef struct lfs_Lock {
  278. char *ln;
  279. } lfs_Lock;
  280. static int lfs_lock_dir(lua_State *L) {
  281. lfs_Lock *lock;
  282. size_t pathl;
  283. char *ln;
  284. const char *lockfile = "/lockfile.lfs";
  285. const char *path = luaL_checklstring(L, 1, &pathl);
  286. lock = (lfs_Lock*)lua_newuserdata(L, sizeof(lfs_Lock));
  287. ln = (char*)malloc(pathl + strlen(lockfile) + 1);
  288. if(!ln) {
  289. lua_pushnil(L); lua_pushstring(L, strerror(errno)); return 2;
  290. }
  291. strcpy(ln, path); strcat(ln, lockfile);
  292. if(symlink("lock", ln) == -1) {
  293. free(ln); lua_pushnil(L);
  294. lua_pushstring(L, strerror(errno)); return 2;
  295. }
  296. lock->ln = ln;
  297. luaL_getmetatable (L, LOCK_METATABLE);
  298. lua_setmetatable (L, -2);
  299. return 1;
  300. }
  301. static int lfs_unlock_dir(lua_State *L) {
  302. lfs_Lock *lock = (lfs_Lock *)luaL_checkudata(L, 1, LOCK_METATABLE);
  303. if(lock->ln) {
  304. unlink(lock->ln);
  305. free(lock->ln);
  306. lock->ln = NULL;
  307. }
  308. return 0;
  309. }
  310. #endif
  311. static int lfs_g_setmode (lua_State *L, FILE *f, int arg) {
  312. static const int mode[] = {_O_BINARY, _O_TEXT};
  313. static const char *const modenames[] = {"binary", "text", NULL};
  314. int op = luaL_checkoption(L, arg, NULL, modenames);
  315. int res = lfs_setmode(L, f, mode[op]);
  316. if (res != -1) {
  317. int i;
  318. lua_pushboolean(L, 1);
  319. for (i = 0; modenames[i] != NULL; i++) {
  320. if (mode[i] == res) {
  321. lua_pushstring(L, modenames[i]);
  322. goto exit;
  323. }
  324. }
  325. lua_pushnil(L);
  326. exit:
  327. return 2;
  328. } else {
  329. int en = errno;
  330. lua_pushnil(L);
  331. lua_pushfstring(L, "%s", strerror(en));
  332. lua_pushinteger(L, en);
  333. return 3;
  334. }
  335. }
  336. static int lfs_f_setmode(lua_State *L) {
  337. return lfs_g_setmode(L, check_file(L, 1, "setmode"), 2);
  338. }
  339. /*
  340. ** Locks a file.
  341. ** @param #1 File handle.
  342. ** @param #2 String with lock mode ('w'rite, 'r'ead).
  343. ** @param #3 Number with start position (optional).
  344. ** @param #4 Number with length (optional).
  345. */
  346. static int file_lock (lua_State *L) {
  347. FILE *fh = check_file (L, 1, "lock");
  348. const char *mode = luaL_checkstring (L, 2);
  349. const long start = (long) luaL_optinteger (L, 3, 0);
  350. long len = (long) luaL_optinteger (L, 4, 0);
  351. if (_file_lock (L, fh, mode, start, len, "lock")) {
  352. lua_pushboolean (L, 1);
  353. return 1;
  354. } else {
  355. lua_pushnil (L);
  356. lua_pushfstring (L, "%s", strerror(errno));
  357. return 2;
  358. }
  359. }
  360. /*
  361. ** Unlocks a file.
  362. ** @param #1 File handle.
  363. ** @param #2 Number with start position (optional).
  364. ** @param #3 Number with length (optional).
  365. */
  366. static int file_unlock (lua_State *L) {
  367. FILE *fh = check_file (L, 1, "unlock");
  368. const long start = (long) luaL_optinteger (L, 2, 0);
  369. long len = (long) luaL_optinteger (L, 3, 0);
  370. if (_file_lock (L, fh, "u", start, len, "unlock")) {
  371. lua_pushboolean (L, 1);
  372. return 1;
  373. } else {
  374. lua_pushnil (L);
  375. lua_pushfstring (L, "%s", strerror(errno));
  376. return 2;
  377. }
  378. }
  379. /*
  380. ** Creates a link.
  381. ** @param #1 Object to link to.
  382. ** @param #2 Name of link.
  383. ** @param #3 True if link is symbolic (optional).
  384. */
  385. static int make_link(lua_State *L)
  386. {
  387. #ifndef _WIN32
  388. const char *oldpath = luaL_checkstring(L, 1);
  389. const char *newpath = luaL_checkstring(L, 2);
  390. return pushresult(L,
  391. (lua_toboolean(L,3) ? symlink : link)(oldpath, newpath), NULL);
  392. #else
  393. return pusherror(L, "make_link is not supported on Windows");
  394. #endif
  395. }
  396. /*
  397. ** Creates a directory.
  398. ** @param #1 Directory path.
  399. */
  400. static int make_dir (lua_State *L) {
  401. const char *path = luaL_checkstring (L, 1);
  402. int fail;
  403. #ifdef _WIN32
  404. fail = _mkdir (path);
  405. #else
  406. fail = mkdir (path, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP |
  407. S_IWGRP | S_IXGRP | S_IROTH | S_IXOTH );
  408. #endif
  409. if (fail) {
  410. lua_pushnil (L);
  411. lua_pushfstring (L, "%s", strerror(errno));
  412. return 2;
  413. }
  414. lua_pushboolean (L, 1);
  415. return 1;
  416. }
  417. /*
  418. ** Removes a directory.
  419. ** @param #1 Directory path.
  420. */
  421. static int remove_dir (lua_State *L) {
  422. const char *path = luaL_checkstring (L, 1);
  423. int fail;
  424. fail = rmdir (path);
  425. if (fail) {
  426. lua_pushnil (L);
  427. lua_pushfstring (L, "%s", strerror(errno));
  428. return 2;
  429. }
  430. lua_pushboolean (L, 1);
  431. return 1;
  432. }
  433. /*
  434. ** Directory iterator
  435. */
  436. static int dir_iter (lua_State *L) {
  437. #ifdef _WIN32
  438. struct _finddata_t c_file;
  439. #else
  440. struct dirent *entry;
  441. #endif
  442. dir_data *d = (dir_data *)luaL_checkudata (L, 1, DIR_METATABLE);
  443. luaL_argcheck (L, d->closed == 0, 1, "closed directory");
  444. #ifdef _WIN32
  445. if (d->hFile == 0L) { /* first entry */
  446. if ((d->hFile = _findfirst (d->pattern, &c_file)) == -1L) {
  447. lua_pushnil (L);
  448. lua_pushstring (L, strerror (errno));
  449. d->closed = 1;
  450. return 2;
  451. } else {
  452. lua_pushstring (L, c_file.name);
  453. return 1;
  454. }
  455. } else { /* next entry */
  456. if (_findnext (d->hFile, &c_file) == -1L) {
  457. /* no more entries => close directory */
  458. _findclose (d->hFile);
  459. d->closed = 1;
  460. return 0;
  461. } else {
  462. lua_pushstring (L, c_file.name);
  463. return 1;
  464. }
  465. }
  466. #else
  467. if ((entry = readdir (d->dir)) != NULL) {
  468. lua_pushstring (L, entry->d_name);
  469. return 1;
  470. } else {
  471. /* no more entries => close directory */
  472. closedir (d->dir);
  473. d->closed = 1;
  474. return 0;
  475. }
  476. #endif
  477. }
  478. /*
  479. ** Closes directory iterators
  480. */
  481. static int dir_close (lua_State *L) {
  482. dir_data *d = (dir_data *)lua_touserdata (L, 1);
  483. #ifdef _WIN32
  484. if (!d->closed && d->hFile) {
  485. _findclose (d->hFile);
  486. }
  487. #else
  488. if (!d->closed && d->dir) {
  489. closedir (d->dir);
  490. }
  491. #endif
  492. d->closed = 1;
  493. return 0;
  494. }
  495. /*
  496. ** Factory of directory iterators
  497. */
  498. static int dir_iter_factory (lua_State *L) {
  499. const char *path = luaL_checkstring (L, 1);
  500. dir_data *d;
  501. lua_pushcfunction (L, dir_iter);
  502. d = (dir_data *) lua_newuserdata (L, sizeof(dir_data));
  503. luaL_getmetatable (L, DIR_METATABLE);
  504. lua_setmetatable (L, -2);
  505. d->closed = 0;
  506. #ifdef _WIN32
  507. d->hFile = 0L;
  508. if (strlen(path) > MAX_PATH-2)
  509. luaL_error (L, "path too long: %s", path);
  510. else
  511. sprintf (d->pattern, "%s/*", path);
  512. #else
  513. d->dir = opendir (path);
  514. if (d->dir == NULL)
  515. luaL_error (L, "cannot open %s: %s", path, strerror (errno));
  516. #endif
  517. return 2;
  518. }
  519. /*
  520. ** Creates directory metatable.
  521. */
  522. static int dir_create_meta (lua_State *L) {
  523. luaL_newmetatable (L, DIR_METATABLE);
  524. /* Method table */
  525. lua_newtable(L);
  526. lua_pushcfunction (L, dir_iter);
  527. lua_setfield(L, -2, "next");
  528. lua_pushcfunction (L, dir_close);
  529. lua_setfield(L, -2, "close");
  530. /* Metamethods */
  531. lua_setfield(L, -2, "__index");
  532. lua_pushcfunction (L, dir_close);
  533. lua_setfield (L, -2, "__gc");
  534. return 1;
  535. }
  536. /*
  537. ** Creates lock metatable.
  538. */
  539. static int lock_create_meta (lua_State *L) {
  540. luaL_newmetatable (L, LOCK_METATABLE);
  541. /* Method table */
  542. lua_newtable(L);
  543. lua_pushcfunction(L, lfs_unlock_dir);
  544. lua_setfield(L, -2, "free");
  545. /* Metamethods */
  546. lua_setfield(L, -2, "__index");
  547. lua_pushcfunction(L, lfs_unlock_dir);
  548. lua_setfield(L, -2, "__gc");
  549. return 1;
  550. }
  551. #ifdef _WIN32
  552. #ifndef S_ISDIR
  553. #define S_ISDIR(mode) (mode&_S_IFDIR)
  554. #endif
  555. #ifndef S_ISREG
  556. #define S_ISREG(mode) (mode&_S_IFREG)
  557. #endif
  558. #ifndef S_ISLNK
  559. #define S_ISLNK(mode) (0)
  560. #endif
  561. #ifndef S_ISSOCK
  562. #define S_ISSOCK(mode) (0)
  563. #endif
  564. #ifndef S_ISFIFO
  565. #define S_ISFIFO(mode) (0)
  566. #endif
  567. #ifndef S_ISCHR
  568. #define S_ISCHR(mode) (mode&_S_IFCHR)
  569. #endif
  570. #ifndef S_ISBLK
  571. #define S_ISBLK(mode) (0)
  572. #endif
  573. #endif
  574. /*
  575. ** Convert the inode protection mode to a string.
  576. */
  577. #ifdef _WIN32
  578. static const char *mode2string (unsigned short mode) {
  579. #else
  580. static const char *mode2string (mode_t mode) {
  581. #endif
  582. if ( S_ISREG(mode) )
  583. return "file";
  584. else if ( S_ISDIR(mode) )
  585. return "directory";
  586. else if ( S_ISLNK(mode) )
  587. return "link";
  588. else if ( S_ISSOCK(mode) )
  589. return "socket";
  590. else if ( S_ISFIFO(mode) )
  591. return "named pipe";
  592. else if ( S_ISCHR(mode) )
  593. return "char device";
  594. else if ( S_ISBLK(mode) )
  595. return "block device";
  596. else
  597. return "other";
  598. }
  599. /*
  600. ** Set access time and modification values for file
  601. */
  602. static int file_utime (lua_State *L) {
  603. const char *file = luaL_checkstring (L, 1);
  604. struct utimbuf utb, *buf;
  605. if (lua_gettop (L) == 1) /* set to current date/time */
  606. buf = NULL;
  607. else {
  608. utb.actime = (time_t)luaL_optnumber (L, 2, 0);
  609. utb.modtime = (time_t) luaL_optinteger (L, 3, utb.actime);
  610. buf = &utb;
  611. }
  612. if (utime (file, buf)) {
  613. lua_pushnil (L);
  614. lua_pushfstring (L, "%s", strerror (errno));
  615. return 2;
  616. }
  617. lua_pushboolean (L, 1);
  618. return 1;
  619. }
  620. /* inode protection mode */
  621. static void push_st_mode (lua_State *L, STAT_STRUCT *info) {
  622. lua_pushstring (L, mode2string (info->st_mode));
  623. }
  624. /* device inode resides on */
  625. static void push_st_dev (lua_State *L, STAT_STRUCT *info) {
  626. lua_pushinteger (L, (lua_Integer) info->st_dev);
  627. }
  628. /* inode's number */
  629. static void push_st_ino (lua_State *L, STAT_STRUCT *info) {
  630. lua_pushinteger (L, (lua_Integer) info->st_ino);
  631. }
  632. /* number of hard links to the file */
  633. static void push_st_nlink (lua_State *L, STAT_STRUCT *info) {
  634. lua_pushinteger (L, (lua_Integer)info->st_nlink);
  635. }
  636. /* user-id of owner */
  637. static void push_st_uid (lua_State *L, STAT_STRUCT *info) {
  638. lua_pushinteger (L, (lua_Integer)info->st_uid);
  639. }
  640. /* group-id of owner */
  641. static void push_st_gid (lua_State *L, STAT_STRUCT *info) {
  642. lua_pushinteger (L, (lua_Integer)info->st_gid);
  643. }
  644. /* device type, for special file inode */
  645. static void push_st_rdev (lua_State *L, STAT_STRUCT *info) {
  646. lua_pushinteger (L, (lua_Integer) info->st_rdev);
  647. }
  648. /* time of last access */
  649. static void push_st_atime (lua_State *L, STAT_STRUCT *info) {
  650. lua_pushinteger (L, (lua_Integer) info->st_atime);
  651. }
  652. /* time of last data modification */
  653. static void push_st_mtime (lua_State *L, STAT_STRUCT *info) {
  654. lua_pushinteger (L, (lua_Integer) info->st_mtime);
  655. }
  656. /* time of last file status change */
  657. static void push_st_ctime (lua_State *L, STAT_STRUCT *info) {
  658. lua_pushinteger (L, (lua_Integer) info->st_ctime);
  659. }
  660. /* file size, in bytes */
  661. static void push_st_size (lua_State *L, STAT_STRUCT *info) {
  662. lua_pushinteger (L, (lua_Integer)info->st_size);
  663. }
  664. #ifndef _WIN32
  665. /* blocks allocated for file */
  666. static void push_st_blocks (lua_State *L, STAT_STRUCT *info) {
  667. lua_pushinteger (L, (lua_Integer)info->st_blocks);
  668. }
  669. /* optimal file system I/O blocksize */
  670. static void push_st_blksize (lua_State *L, STAT_STRUCT *info) {
  671. lua_pushinteger (L, (lua_Integer)info->st_blksize);
  672. }
  673. #endif
  674. /*
  675. ** Convert the inode protection mode to a permission list.
  676. */
  677. #ifdef _WIN32
  678. static const char *perm2string (unsigned short mode) {
  679. static char perms[10] = "---------";
  680. int i;
  681. for (i=0;i<9;i++) perms[i]='-';
  682. if (mode & _S_IREAD)
  683. { perms[0] = 'r'; perms[3] = 'r'; perms[6] = 'r'; }
  684. if (mode & _S_IWRITE)
  685. { perms[1] = 'w'; perms[4] = 'w'; perms[7] = 'w'; }
  686. if (mode & _S_IEXEC)
  687. { perms[2] = 'x'; perms[5] = 'x'; perms[8] = 'x'; }
  688. return perms;
  689. }
  690. #else
  691. static const char *perm2string (mode_t mode) {
  692. static char perms[10] = "---------";
  693. int i;
  694. for (i=0;i<9;i++) perms[i]='-';
  695. if (mode & S_IRUSR) perms[0] = 'r';
  696. if (mode & S_IWUSR) perms[1] = 'w';
  697. if (mode & S_IXUSR) perms[2] = 'x';
  698. if (mode & S_IRGRP) perms[3] = 'r';
  699. if (mode & S_IWGRP) perms[4] = 'w';
  700. if (mode & S_IXGRP) perms[5] = 'x';
  701. if (mode & S_IROTH) perms[6] = 'r';
  702. if (mode & S_IWOTH) perms[7] = 'w';
  703. if (mode & S_IXOTH) perms[8] = 'x';
  704. return perms;
  705. }
  706. #endif
  707. /* permssions string */
  708. static void push_st_perm (lua_State *L, STAT_STRUCT *info) {
  709. lua_pushstring (L, perm2string (info->st_mode));
  710. }
  711. typedef void (*_push_function) (lua_State *L, STAT_STRUCT *info);
  712. struct _stat_members {
  713. const char *name;
  714. _push_function push;
  715. };
  716. struct _stat_members members[] = {
  717. { "mode", push_st_mode },
  718. { "dev", push_st_dev },
  719. { "ino", push_st_ino },
  720. { "nlink", push_st_nlink },
  721. { "uid", push_st_uid },
  722. { "gid", push_st_gid },
  723. { "rdev", push_st_rdev },
  724. { "access", push_st_atime },
  725. { "modification", push_st_mtime },
  726. { "change", push_st_ctime },
  727. { "size", push_st_size },
  728. { "permissions", push_st_perm },
  729. #ifndef _WIN32
  730. { "blocks", push_st_blocks },
  731. { "blksize", push_st_blksize },
  732. #endif
  733. { NULL, NULL }
  734. };
  735. /*
  736. ** Get file or symbolic link information
  737. */
  738. static int _file_info_ (lua_State *L, int (*st)(const char*, STAT_STRUCT*)) {
  739. STAT_STRUCT info;
  740. const char *file = luaL_checkstring (L, 1);
  741. int i;
  742. if (st(file, &info)) {
  743. lua_pushnil (L);
  744. lua_pushfstring (L, "cannot obtain information from file `%s'", file);
  745. return 2;
  746. }
  747. if (lua_isstring (L, 2)) {
  748. const char *member = lua_tostring (L, 2);
  749. for (i = 0; members[i].name; i++) {
  750. if (strcmp(members[i].name, member) == 0) {
  751. /* push member value and return */
  752. members[i].push (L, &info);
  753. return 1;
  754. }
  755. }
  756. /* member not found */
  757. return luaL_error(L, "invalid attribute name");
  758. }
  759. /* creates a table if none is given */
  760. if (!lua_istable (L, 2)) {
  761. lua_newtable (L);
  762. }
  763. /* stores all members in table on top of the stack */
  764. for (i = 0; members[i].name; i++) {
  765. lua_pushstring (L, members[i].name);
  766. members[i].push (L, &info);
  767. lua_rawset (L, -3);
  768. }
  769. return 1;
  770. }
  771. /*
  772. ** Get file information using stat.
  773. */
  774. static int file_info (lua_State *L) {
  775. return _file_info_ (L, STAT_FUNC);
  776. }
  777. /*
  778. ** Get symbolic link information using lstat.
  779. */
  780. static int link_info (lua_State *L) {
  781. return _file_info_ (L, LSTAT_FUNC);
  782. }
  783. /*
  784. ** Assumes the table is on top of the stack.
  785. */
  786. static void set_info (lua_State *L) {
  787. lua_pushliteral (L, "_COPYRIGHT");
  788. lua_pushliteral (L, "Copyright (C) 2003-2012 Kepler Project");
  789. lua_settable (L, -3);
  790. lua_pushliteral (L, "_DESCRIPTION");
  791. lua_pushliteral (L, "LuaFileSystem is a Lua library developed to complement the set of functions related to file systems offered by the standard Lua distribution");
  792. lua_settable (L, -3);
  793. lua_pushliteral (L, "_VERSION");
  794. lua_pushliteral (L, "LuaFileSystem "LFS_VERSION);
  795. lua_settable (L, -3);
  796. }
  797. static const struct luaL_Reg fslib[] = {
  798. {"attributes", file_info},
  799. {"chdir", change_dir},
  800. {"currentdir", get_dir},
  801. {"dir", dir_iter_factory},
  802. {"link", make_link},
  803. {"lock", file_lock},
  804. {"mkdir", make_dir},
  805. {"rmdir", remove_dir},
  806. {"symlinkattributes", link_info},
  807. {"setmode", lfs_f_setmode},
  808. {"touch", file_utime},
  809. {"unlock", file_unlock},
  810. {"lock_dir", lfs_lock_dir},
  811. {NULL, NULL},
  812. };
  813. int luaopen_lfs (lua_State *L) {
  814. dir_create_meta (L);
  815. lock_create_meta (L);
  816. luaL_newlib (L, fslib);
  817. lua_pushvalue(L, -1);
  818. lua_setglobal(L, LFS_LIBNAME);
  819. set_info (L);
  820. return 1;
  821. }