lfs.c 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942
  1. /*
  2. ** LuaFileSystem
  3. ** Copyright Kepler Project 2003 - 2017 (http://keplerproject.github.io/luafilesystem)
  4. **
  5. ** File system manipulation library.
  6. ** This library offers these functions:
  7. ** lfs.attributes (filepath [, attributename | attributetable])
  8. ** lfs.chdir (path)
  9. ** lfs.currentdir ()
  10. ** lfs.dir (path)
  11. ** lfs.link (old, new[, symlink])
  12. ** lfs.lock (fh, mode)
  13. ** lfs.lock_dir (path)
  14. ** lfs.mkdir (path)
  15. ** lfs.rmdir (path)
  16. ** lfs.setmode (filepath, mode)
  17. ** lfs.symlinkattributes (filepath [, attributename])
  18. ** lfs.touch (filepath [, atime [, mtime]])
  19. ** lfs.unlock (fh)
  20. */
  21. #ifndef LFS_DO_NOT_USE_LARGE_FILE
  22. #ifndef _WIN32
  23. #ifndef _AIX
  24. #define _FILE_OFFSET_BITS 64 /* Linux, Solaris and HP-UX */
  25. #else
  26. #define _LARGE_FILES 1 /* AIX */
  27. #endif
  28. #endif
  29. #endif
  30. #ifndef LFS_DO_NOT_USE_LARGE_FILE
  31. #define _LARGEFILE64_SOURCE
  32. #endif
  33. #include <errno.h>
  34. #include <stdio.h>
  35. #include <string.h>
  36. #include <stdlib.h>
  37. #include <time.h>
  38. #include <sys/stat.h>
  39. #ifdef _WIN32
  40. #include <direct.h>
  41. #include <windows.h>
  42. #include <io.h>
  43. #include <sys/locking.h>
  44. #ifdef __BORLANDC__
  45. #include <utime.h>
  46. #else
  47. #include <sys/utime.h>
  48. #endif
  49. #include <fcntl.h>
  50. /* MAX_PATH seems to be 260. Seems kind of small. Is there a better one? */
  51. #define LFS_MAXPATHLEN MAX_PATH
  52. #else
  53. #include <unistd.h>
  54. #include <dirent.h>
  55. #include <fcntl.h>
  56. #include <sys/types.h>
  57. #include <utime.h>
  58. #include <sys/param.h> /* for MAXPATHLEN */
  59. #define LFS_MAXPATHLEN MAXPATHLEN
  60. #endif
  61. #include <lua.h>
  62. #include <lauxlib.h>
  63. #include <lualib.h>
  64. #include "lfs.h"
  65. #define LFS_VERSION "1.7.0"
  66. #define LFS_LIBNAME "lfs"
  67. #if LUA_VERSION_NUM >= 503 /* Lua 5.3 */
  68. #ifndef luaL_optlong
  69. #define luaL_optlong luaL_optinteger
  70. #endif
  71. #endif
  72. #if LUA_VERSION_NUM >= 502
  73. # define new_lib(L, l) (luaL_newlib(L, l))
  74. #else
  75. # define new_lib(L, l) (lua_newtable(L), luaL_register(L, NULL, l))
  76. #endif
  77. /* Define 'strerror' for systems that do not implement it */
  78. #ifdef NO_STRERROR
  79. #define strerror(_) "System unable to describe the error"
  80. #endif
  81. #define DIR_METATABLE "directory metatable"
  82. typedef struct dir_data {
  83. int closed;
  84. #ifdef _WIN32
  85. intptr_t hFile;
  86. char pattern[MAX_PATH+1];
  87. #else
  88. DIR *dir;
  89. #endif
  90. } dir_data;
  91. #define LOCK_METATABLE "lock metatable"
  92. #ifdef _WIN32
  93. #ifdef __BORLANDC__
  94. #define lfs_setmode(file, m) (setmode(_fileno(file), m))
  95. #define STAT_STRUCT struct stati64
  96. #else
  97. #define lfs_setmode(file, m) (_setmode(_fileno(file), m))
  98. #define STAT_STRUCT struct _stati64
  99. #endif
  100. #define STAT_FUNC _stati64
  101. #define LSTAT_FUNC STAT_FUNC
  102. #else
  103. #define _O_TEXT 0
  104. #define _O_BINARY 0
  105. #define lfs_setmode(file, m) ((void)file, (void)m, 0)
  106. #define STAT_STRUCT struct stat
  107. #define STAT_FUNC stat
  108. #define LSTAT_FUNC lstat
  109. #endif
  110. #ifdef _WIN32
  111. #define lfs_mkdir _mkdir
  112. #else
  113. #define lfs_mkdir(path) (mkdir((path), \
  114. S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IWGRP | S_IXGRP | S_IROTH | S_IXOTH))
  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 res, const char *info) {
  130. if (res == -1) {
  131. return pusherror(L, info);
  132. } else {
  133. lua_pushboolean(L, 1);
  134. return 1;
  135. }
  136. }
  137. /*
  138. ** This function changes the working (current) directory
  139. */
  140. static int change_dir (lua_State *L) {
  141. const char *path = luaL_checkstring(L, 1);
  142. if (chdir(path)) {
  143. lua_pushnil (L);
  144. lua_pushfstring (L,"Unable to change working directory to '%s'\n%s\n",
  145. path, chdir_error);
  146. return 2;
  147. } else {
  148. lua_pushboolean (L, 1);
  149. return 1;
  150. }
  151. }
  152. /*
  153. ** This function returns the current directory
  154. ** If unable to get the current directory, it returns nil
  155. ** and a string describing the error
  156. */
  157. static int get_dir (lua_State *L) {
  158. #ifdef NO_GETCWD
  159. lua_pushnil(L);
  160. lua_pushstring(L, "Function 'getcwd' not provided by system");
  161. return 2;
  162. #else
  163. char *path = NULL;
  164. /* Passing (NULL, 0) is not guaranteed to work. Use a temp buffer and size instead. */
  165. size_t size = LFS_MAXPATHLEN; /* initial buffer size */
  166. int result;
  167. while (1) {
  168. path = realloc(path, size);
  169. if (!path) /* failed to allocate */
  170. return pusherror(L, "get_dir realloc() failed");
  171. if (getcwd(path, size) != NULL) {
  172. /* success, push the path to the Lua stack */
  173. lua_pushstring(L, path);
  174. result = 1;
  175. break;
  176. }
  177. if (errno != ERANGE) { /* unexpected error */
  178. result = pusherror(L, "get_dir getcwd() failed");
  179. break;
  180. }
  181. /* ERANGE = insufficient buffer capacity, double size and retry */
  182. size *= 2;
  183. }
  184. free(path);
  185. return result;
  186. #endif
  187. }
  188. /*
  189. ** Check if the given element on the stack is a file and returns it.
  190. */
  191. static FILE *check_file (lua_State *L, int idx, const char *funcname) {
  192. #if LUA_VERSION_NUM == 501
  193. FILE **fh = (FILE **)luaL_checkudata (L, idx, "FILE*");
  194. if (*fh == NULL) {
  195. luaL_error (L, "%s: closed file", funcname);
  196. return 0;
  197. } else
  198. return *fh;
  199. #elif LUA_VERSION_NUM >= 502 && LUA_VERSION_NUM <= 503
  200. luaL_Stream *fh = (luaL_Stream *)luaL_checkudata (L, idx, "FILE*");
  201. if (fh->closef == 0 || fh->f == NULL) {
  202. luaL_error (L, "%s: closed file", funcname);
  203. return 0;
  204. } else
  205. return fh->f;
  206. #else
  207. #error unsupported Lua version
  208. #endif
  209. }
  210. /*
  211. **
  212. */
  213. static int _file_lock (lua_State *L, FILE *fh, const char *mode, const long start, long len, const char *funcname) {
  214. int code;
  215. #ifdef _WIN32
  216. /* lkmode valid values are:
  217. 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.
  218. LK_NBLCK Locks the specified bytes. If the bytes cannot be locked, the constant returns an error.
  219. LK_NBRLCK Same as _LK_NBLCK.
  220. LK_RLCK Same as _LK_LOCK.
  221. LK_UNLCK Unlocks the specified bytes, which must have been previously locked.
  222. Regions should be locked only briefly and should be unlocked before closing a file or exiting the program.
  223. http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vclib/html/_crt__locking.asp
  224. */
  225. int lkmode;
  226. switch (*mode) {
  227. case 'r': lkmode = LK_NBLCK; break;
  228. case 'w': lkmode = LK_NBLCK; break;
  229. case 'u': lkmode = LK_UNLCK; break;
  230. default : return luaL_error (L, "%s: invalid mode", funcname);
  231. }
  232. if (!len) {
  233. fseek (fh, 0L, SEEK_END);
  234. len = ftell (fh);
  235. }
  236. fseek (fh, start, SEEK_SET);
  237. #ifdef __BORLANDC__
  238. code = locking (fileno(fh), lkmode, len);
  239. #else
  240. code = _locking (fileno(fh), lkmode, len);
  241. #endif
  242. #else
  243. struct flock f;
  244. switch (*mode) {
  245. case 'w': f.l_type = F_WRLCK; break;
  246. case 'r': f.l_type = F_RDLCK; break;
  247. case 'u': f.l_type = F_UNLCK; break;
  248. default : return luaL_error (L, "%s: invalid mode", funcname);
  249. }
  250. f.l_whence = SEEK_SET;
  251. f.l_start = (off_t)start;
  252. f.l_len = (off_t)len;
  253. code = fcntl (fileno(fh), F_SETLK, &f);
  254. #endif
  255. return (code != -1);
  256. }
  257. #ifdef _WIN32
  258. typedef struct lfs_Lock {
  259. HANDLE fd;
  260. } lfs_Lock;
  261. static int lfs_lock_dir(lua_State *L) {
  262. size_t pathl; HANDLE fd;
  263. lfs_Lock *lock;
  264. char *ln;
  265. const char *lockfile = "/lockfile.lfs";
  266. const char *path = luaL_checklstring(L, 1, &pathl);
  267. ln = (char*)malloc(pathl + strlen(lockfile) + 1);
  268. if(!ln) {
  269. lua_pushnil(L); lua_pushstring(L, strerror(errno)); return 2;
  270. }
  271. strcpy(ln, path); strcat(ln, lockfile);
  272. if((fd = CreateFile(ln, GENERIC_WRITE, 0, NULL, CREATE_NEW,
  273. FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE, NULL)) == INVALID_HANDLE_VALUE) {
  274. int en = GetLastError();
  275. free(ln); lua_pushnil(L);
  276. if(en == ERROR_FILE_EXISTS || en == ERROR_SHARING_VIOLATION)
  277. lua_pushstring(L, "File exists");
  278. else
  279. lua_pushstring(L, strerror(en));
  280. return 2;
  281. }
  282. free(ln);
  283. lock = (lfs_Lock*)lua_newuserdata(L, sizeof(lfs_Lock));
  284. lock->fd = fd;
  285. luaL_getmetatable (L, LOCK_METATABLE);
  286. lua_setmetatable (L, -2);
  287. return 1;
  288. }
  289. static int lfs_unlock_dir(lua_State *L) {
  290. lfs_Lock *lock = (lfs_Lock *)luaL_checkudata(L, 1, LOCK_METATABLE);
  291. if(lock->fd != INVALID_HANDLE_VALUE) {
  292. CloseHandle(lock->fd);
  293. lock->fd=INVALID_HANDLE_VALUE;
  294. }
  295. return 0;
  296. }
  297. #else
  298. typedef struct lfs_Lock {
  299. char *ln;
  300. } lfs_Lock;
  301. static int lfs_lock_dir(lua_State *L) {
  302. lfs_Lock *lock;
  303. size_t pathl;
  304. char *ln;
  305. const char *lockfile = "/lockfile.lfs";
  306. const char *path = luaL_checklstring(L, 1, &pathl);
  307. lock = (lfs_Lock*)lua_newuserdata(L, sizeof(lfs_Lock));
  308. ln = (char*)malloc(pathl + strlen(lockfile) + 1);
  309. if(!ln) {
  310. lua_pushnil(L); lua_pushstring(L, strerror(errno)); return 2;
  311. }
  312. strcpy(ln, path); strcat(ln, lockfile);
  313. if(symlink("lock", ln) == -1) {
  314. free(ln); lua_pushnil(L);
  315. lua_pushstring(L, strerror(errno)); return 2;
  316. }
  317. lock->ln = ln;
  318. luaL_getmetatable (L, LOCK_METATABLE);
  319. lua_setmetatable (L, -2);
  320. return 1;
  321. }
  322. static int lfs_unlock_dir(lua_State *L) {
  323. lfs_Lock *lock = (lfs_Lock *)luaL_checkudata(L, 1, LOCK_METATABLE);
  324. if(lock->ln) {
  325. unlink(lock->ln);
  326. free(lock->ln);
  327. lock->ln = NULL;
  328. }
  329. return 0;
  330. }
  331. #endif
  332. static int lfs_g_setmode (lua_State *L, FILE *f, int arg) {
  333. static const int mode[] = {_O_BINARY, _O_TEXT};
  334. static const char *const modenames[] = {"binary", "text", NULL};
  335. int op = luaL_checkoption(L, arg, NULL, modenames);
  336. int res = lfs_setmode(f, mode[op]);
  337. if (res != -1) {
  338. int i;
  339. lua_pushboolean(L, 1);
  340. for (i = 0; modenames[i] != NULL; i++) {
  341. if (mode[i] == res) {
  342. lua_pushstring(L, modenames[i]);
  343. return 2;
  344. }
  345. }
  346. lua_pushnil(L);
  347. return 2;
  348. } else {
  349. return pusherror(L, NULL);
  350. }
  351. }
  352. static int lfs_f_setmode(lua_State *L) {
  353. return lfs_g_setmode(L, check_file(L, 1, "setmode"), 2);
  354. }
  355. /*
  356. ** Locks a file.
  357. ** @param #1 File handle.
  358. ** @param #2 String with lock mode ('w'rite, 'r'ead).
  359. ** @param #3 Number with start position (optional).
  360. ** @param #4 Number with length (optional).
  361. */
  362. static int file_lock (lua_State *L) {
  363. FILE *fh = check_file (L, 1, "lock");
  364. const char *mode = luaL_checkstring (L, 2);
  365. const long start = (long) luaL_optinteger (L, 3, 0);
  366. long len = (long) luaL_optinteger (L, 4, 0);
  367. if (_file_lock (L, fh, mode, start, len, "lock")) {
  368. lua_pushboolean (L, 1);
  369. return 1;
  370. } else {
  371. lua_pushnil (L);
  372. lua_pushfstring (L, "%s", strerror(errno));
  373. return 2;
  374. }
  375. }
  376. /*
  377. ** Unlocks a file.
  378. ** @param #1 File handle.
  379. ** @param #2 Number with start position (optional).
  380. ** @param #3 Number with length (optional).
  381. */
  382. static int file_unlock (lua_State *L) {
  383. FILE *fh = check_file (L, 1, "unlock");
  384. const long start = (long) luaL_optinteger (L, 2, 0);
  385. long len = (long) luaL_optinteger (L, 3, 0);
  386. if (_file_lock (L, fh, "u", start, len, "unlock")) {
  387. lua_pushboolean (L, 1);
  388. return 1;
  389. } else {
  390. lua_pushnil (L);
  391. lua_pushfstring (L, "%s", strerror(errno));
  392. return 2;
  393. }
  394. }
  395. /*
  396. ** Creates a link.
  397. ** @param #1 Object to link to.
  398. ** @param #2 Name of link.
  399. ** @param #3 True if link is symbolic (optional).
  400. */
  401. static int make_link (lua_State *L) {
  402. #ifndef _WIN32
  403. const char *oldpath = luaL_checkstring(L, 1);
  404. const char *newpath = luaL_checkstring(L, 2);
  405. int res = (lua_toboolean(L,3) ? symlink : link)(oldpath, newpath);
  406. if (res == -1) {
  407. return pusherror(L, NULL);
  408. } else {
  409. lua_pushinteger(L, 0);
  410. return 1;
  411. }
  412. #else
  413. errno = ENOSYS; /* = "Function not implemented" */
  414. return pushresult(L, -1, "make_link is not supported on Windows");
  415. #endif
  416. }
  417. /*
  418. ** Creates a directory.
  419. ** @param #1 Directory path.
  420. */
  421. static int make_dir (lua_State *L) {
  422. const char *path = luaL_checkstring(L, 1);
  423. return pushresult(L, lfs_mkdir(path), NULL);
  424. }
  425. /*
  426. ** Removes a directory.
  427. ** @param #1 Directory path.
  428. */
  429. static int remove_dir (lua_State *L) {
  430. const char *path = luaL_checkstring(L, 1);
  431. return pushresult(L, rmdir(path), NULL);
  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 a file.
  601. ** @param #1 File path.
  602. ** @param #2 Access time in seconds, current time is used if missing.
  603. ** @param #3 Modification time in seconds, access time is used if missing.
  604. */
  605. static int file_utime (lua_State *L) {
  606. const char *file = luaL_checkstring(L, 1);
  607. struct utimbuf utb, *buf;
  608. if (lua_gettop (L) == 1) /* set to current date/time */
  609. buf = NULL;
  610. else {
  611. utb.actime = (time_t) luaL_optnumber(L, 2, 0);
  612. utb.modtime = (time_t) luaL_optinteger(L, 3, utb.actime);
  613. buf = &utb;
  614. }
  615. return pushresult(L, utime(file, buf), NULL);
  616. }
  617. /* inode protection mode */
  618. static void push_st_mode (lua_State *L, STAT_STRUCT *info) {
  619. lua_pushstring (L, mode2string (info->st_mode));
  620. }
  621. /* device inode resides on */
  622. static void push_st_dev (lua_State *L, STAT_STRUCT *info) {
  623. lua_pushinteger (L, (lua_Integer) info->st_dev);
  624. }
  625. /* inode's number */
  626. static void push_st_ino (lua_State *L, STAT_STRUCT *info) {
  627. lua_pushinteger (L, (lua_Integer) info->st_ino);
  628. }
  629. /* number of hard links to the file */
  630. static void push_st_nlink (lua_State *L, STAT_STRUCT *info) {
  631. lua_pushinteger (L, (lua_Integer)info->st_nlink);
  632. }
  633. /* user-id of owner */
  634. static void push_st_uid (lua_State *L, STAT_STRUCT *info) {
  635. lua_pushinteger (L, (lua_Integer)info->st_uid);
  636. }
  637. /* group-id of owner */
  638. static void push_st_gid (lua_State *L, STAT_STRUCT *info) {
  639. lua_pushinteger (L, (lua_Integer)info->st_gid);
  640. }
  641. /* device type, for special file inode */
  642. static void push_st_rdev (lua_State *L, STAT_STRUCT *info) {
  643. lua_pushinteger (L, (lua_Integer) info->st_rdev);
  644. }
  645. /* time of last access */
  646. static void push_st_atime (lua_State *L, STAT_STRUCT *info) {
  647. lua_pushinteger (L, (lua_Integer) info->st_atime);
  648. }
  649. /* time of last data modification */
  650. static void push_st_mtime (lua_State *L, STAT_STRUCT *info) {
  651. lua_pushinteger (L, (lua_Integer) info->st_mtime);
  652. }
  653. /* time of last file status change */
  654. static void push_st_ctime (lua_State *L, STAT_STRUCT *info) {
  655. lua_pushinteger (L, (lua_Integer) info->st_ctime);
  656. }
  657. /* file size, in bytes */
  658. static void push_st_size (lua_State *L, STAT_STRUCT *info) {
  659. lua_pushinteger (L, (lua_Integer)info->st_size);
  660. }
  661. #ifndef _WIN32
  662. /* blocks allocated for file */
  663. static void push_st_blocks (lua_State *L, STAT_STRUCT *info) {
  664. lua_pushinteger (L, (lua_Integer)info->st_blocks);
  665. }
  666. /* optimal file system I/O blocksize */
  667. static void push_st_blksize (lua_State *L, STAT_STRUCT *info) {
  668. lua_pushinteger (L, (lua_Integer)info->st_blksize);
  669. }
  670. #endif
  671. /*
  672. ** Convert the inode protection mode to a permission list.
  673. */
  674. #ifdef _WIN32
  675. static const char *perm2string (unsigned short mode) {
  676. static char perms[10] = "---------";
  677. int i;
  678. for (i=0;i<9;i++) perms[i]='-';
  679. if (mode & _S_IREAD)
  680. { perms[0] = 'r'; perms[3] = 'r'; perms[6] = 'r'; }
  681. if (mode & _S_IWRITE)
  682. { perms[1] = 'w'; perms[4] = 'w'; perms[7] = 'w'; }
  683. if (mode & _S_IEXEC)
  684. { perms[2] = 'x'; perms[5] = 'x'; perms[8] = 'x'; }
  685. return perms;
  686. }
  687. #else
  688. static const char *perm2string (mode_t mode) {
  689. static char perms[10] = "---------";
  690. int i;
  691. for (i=0;i<9;i++) perms[i]='-';
  692. if (mode & S_IRUSR) perms[0] = 'r';
  693. if (mode & S_IWUSR) perms[1] = 'w';
  694. if (mode & S_IXUSR) perms[2] = 'x';
  695. if (mode & S_IRGRP) perms[3] = 'r';
  696. if (mode & S_IWGRP) perms[4] = 'w';
  697. if (mode & S_IXGRP) perms[5] = 'x';
  698. if (mode & S_IROTH) perms[6] = 'r';
  699. if (mode & S_IWOTH) perms[7] = 'w';
  700. if (mode & S_IXOTH) perms[8] = 'x';
  701. return perms;
  702. }
  703. #endif
  704. /* permssions string */
  705. static void push_st_perm (lua_State *L, STAT_STRUCT *info) {
  706. lua_pushstring (L, perm2string (info->st_mode));
  707. }
  708. typedef void (*_push_function) (lua_State *L, STAT_STRUCT *info);
  709. struct _stat_members {
  710. const char *name;
  711. _push_function push;
  712. };
  713. struct _stat_members members[] = {
  714. { "mode", push_st_mode },
  715. { "dev", push_st_dev },
  716. { "ino", push_st_ino },
  717. { "nlink", push_st_nlink },
  718. { "uid", push_st_uid },
  719. { "gid", push_st_gid },
  720. { "rdev", push_st_rdev },
  721. { "access", push_st_atime },
  722. { "modification", push_st_mtime },
  723. { "change", push_st_ctime },
  724. { "size", push_st_size },
  725. { "permissions", push_st_perm },
  726. #ifndef _WIN32
  727. { "blocks", push_st_blocks },
  728. { "blksize", push_st_blksize },
  729. #endif
  730. { NULL, NULL }
  731. };
  732. /*
  733. ** Get file or symbolic link information
  734. */
  735. static int _file_info_ (lua_State *L, int (*st)(const char*, STAT_STRUCT*)) {
  736. STAT_STRUCT info;
  737. const char *file = luaL_checkstring (L, 1);
  738. int i;
  739. if (st(file, &info)) {
  740. lua_pushnil(L);
  741. lua_pushfstring(L, "cannot obtain information from file '%s': %s", file, strerror(errno));
  742. lua_pushinteger(L, errno);
  743. return 3;
  744. }
  745. if (lua_isstring (L, 2)) {
  746. const char *member = lua_tostring (L, 2);
  747. for (i = 0; members[i].name; i++) {
  748. if (strcmp(members[i].name, member) == 0) {
  749. /* push member value and return */
  750. members[i].push (L, &info);
  751. return 1;
  752. }
  753. }
  754. /* member not found */
  755. return luaL_error(L, "invalid attribute name '%s'", member);
  756. }
  757. /* creates a table if none is given, removes extra arguments */
  758. lua_settop(L, 2);
  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. ** Push the symlink target to the top of the stack.
  778. ** Assumes the file name is at position 1 of the stack.
  779. ** Returns 1 if successful (with the target on top of the stack),
  780. ** 0 on failure (with stack unchanged, and errno set).
  781. */
  782. static int push_link_target(lua_State *L) {
  783. #ifdef _WIN32
  784. errno = ENOSYS;
  785. return 0;
  786. #else
  787. const char *file = luaL_checkstring(L, 1);
  788. char *target = NULL;
  789. int tsize, size = 256; /* size = initial buffer capacity */
  790. while (1) {
  791. target = realloc(target, size);
  792. if (!target) /* failed to allocate */
  793. return 0;
  794. tsize = readlink(file, target, size);
  795. if (tsize < 0) { /* a readlink() error occurred */
  796. free(target);
  797. return 0;
  798. }
  799. if (tsize < size)
  800. break;
  801. /* possibly truncated readlink() result, double size and retry */
  802. size *= 2;
  803. }
  804. target[tsize] = '\0';
  805. lua_pushlstring(L, target, tsize);
  806. free(target);
  807. return 1;
  808. #endif
  809. }
  810. /*
  811. ** Get symbolic link information using lstat.
  812. */
  813. static int link_info (lua_State *L) {
  814. int ret;
  815. if (lua_isstring (L, 2) && (strcmp(lua_tostring(L, 2), "target") == 0)) {
  816. int ok = push_link_target(L);
  817. return ok ? 1 : pusherror(L, "could not obtain link target");
  818. }
  819. ret = _file_info_ (L, LSTAT_FUNC);
  820. if (ret == 1 && lua_type(L, -1) == LUA_TTABLE) {
  821. int ok = push_link_target(L);
  822. if (ok) {
  823. lua_setfield(L, -2, "target");
  824. }
  825. }
  826. return ret;
  827. }
  828. /*
  829. ** Assumes the table is on top of the stack.
  830. */
  831. static void set_info (lua_State *L) {
  832. lua_pushliteral(L, "Copyright (C) 2003-2017 Kepler Project");
  833. lua_setfield(L, -2, "_COPYRIGHT");
  834. 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");
  835. lua_setfield(L, -2, "_DESCRIPTION");
  836. lua_pushliteral(L, "LuaFileSystem " LFS_VERSION);
  837. lua_setfield(L, -2, "_VERSION");
  838. }
  839. static const struct luaL_Reg fslib[] = {
  840. {"attributes", file_info},
  841. {"chdir", change_dir},
  842. {"currentdir", get_dir},
  843. {"dir", dir_iter_factory},
  844. {"link", make_link},
  845. {"lock", file_lock},
  846. {"mkdir", make_dir},
  847. {"rmdir", remove_dir},
  848. {"symlinkattributes", link_info},
  849. {"setmode", lfs_f_setmode},
  850. {"touch", file_utime},
  851. {"unlock", file_unlock},
  852. {"lock_dir", lfs_lock_dir},
  853. {NULL, NULL},
  854. };
  855. LFS_EXPORT int luaopen_lfs (lua_State *L) {
  856. dir_create_meta (L);
  857. lock_create_meta (L);
  858. new_lib (L, fslib);
  859. lua_pushvalue(L, -1);
  860. lua_setglobal(L, LFS_LIBNAME);
  861. set_info (L);
  862. return 1;
  863. }