lfs.c 24 KB

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