lfs.c 25 KB

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