lfs.c 26 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183
  1. /*
  2. ** LuaFileSystem
  3. ** Copyright Kepler Project 2003 - 2020
  4. ** (http://keplerproject.github.io/luafilesystem)
  5. **
  6. ** File system manipulation library.
  7. ** This library offers these functions:
  8. ** lfs.attributes (filepath [, attributename | attributetable])
  9. ** lfs.chdir (path)
  10. ** lfs.currentdir ()
  11. ** lfs.dir (path)
  12. ** lfs.link (old, new[, symlink])
  13. ** lfs.lock (fh, mode)
  14. ** lfs.lock_dir (path)
  15. ** lfs.mkdir (path)
  16. ** lfs.rmdir (path)
  17. ** lfs.setmode (filepath, mode)
  18. ** lfs.symlinkattributes (filepath [, attributename])
  19. ** lfs.touch (filepath [, atime [, mtime]])
  20. ** lfs.unlock (fh)
  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. #ifdef _WIN32
  32. #define _WIN32_WINNT 0x600
  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. /* MAX_PATH seems to be 260. Seems kind of small. Is there a better one? */
  55. #define LFS_MAXPATHLEN MAX_PATH
  56. #else
  57. #include <unistd.h>
  58. #include <dirent.h>
  59. #include <fcntl.h>
  60. #include <sys/types.h>
  61. #include <utime.h>
  62. #include <sys/param.h> /* for MAXPATHLEN */
  63. #ifdef MAXPATHLEN
  64. #define LFS_MAXPATHLEN MAXPATHLEN
  65. #else
  66. #include <limits.h> /* for _POSIX_PATH_MAX */
  67. #define LFS_MAXPATHLEN _POSIX_PATH_MAX
  68. #endif
  69. #endif
  70. #include <lua.h>
  71. #include <lauxlib.h>
  72. #include <lualib.h>
  73. #include "lfs.h"
  74. #define LFS_VERSION "1.8.0"
  75. #define LFS_LIBNAME "lfs"
  76. #if LUA_VERSION_NUM >= 503 /* Lua 5.3+ */
  77. #ifndef luaL_optlong
  78. #define luaL_optlong luaL_optinteger
  79. #endif
  80. #endif
  81. #if LUA_VERSION_NUM >= 502
  82. #define new_lib(L, l) (luaL_newlib(L, l))
  83. #else
  84. #define new_lib(L, l) (lua_newtable(L), luaL_register(L, NULL, l))
  85. #endif
  86. /* Define 'strerror' for systems that do not implement it */
  87. #ifdef NO_STRERROR
  88. #define strerror(_) "System unable to describe the error"
  89. #endif
  90. #define DIR_METATABLE "directory metatable"
  91. typedef struct dir_data {
  92. int closed;
  93. #ifdef _WIN32
  94. intptr_t hFile;
  95. char pattern[MAX_PATH + 1];
  96. #else
  97. DIR *dir;
  98. #endif
  99. } dir_data;
  100. #define LOCK_METATABLE "lock metatable"
  101. #ifdef _WIN32
  102. #ifdef __BORLANDC__
  103. #define lfs_setmode(file, m) (setmode(_fileno(file), m))
  104. #define STAT_STRUCT struct stati64
  105. #else
  106. #define lfs_setmode(file, m) (_setmode(_fileno(file), m))
  107. #define STAT_STRUCT struct _stati64
  108. #endif
  109. #ifndef _S_IFLNK
  110. #define _S_IFLNK 0x400
  111. #endif
  112. #ifndef S_ISDIR
  113. #define S_ISDIR(mode) (mode&_S_IFDIR)
  114. #endif
  115. #ifndef S_ISREG
  116. #define S_ISREG(mode) (mode&_S_IFREG)
  117. #endif
  118. #ifndef S_ISLNK
  119. #define S_ISLNK(mode) (mode&_S_IFLNK)
  120. #endif
  121. #ifndef S_ISSOCK
  122. #define S_ISSOCK(mode) (0)
  123. #endif
  124. #ifndef S_ISFIFO
  125. #define S_ISFIFO(mode) (0)
  126. #endif
  127. #ifndef S_ISCHR
  128. #define S_ISCHR(mode) (mode&_S_IFCHR)
  129. #endif
  130. #ifndef S_ISBLK
  131. #define S_ISBLK(mode) (0)
  132. #endif
  133. #define STAT_FUNC _stati64
  134. #define LSTAT_FUNC lfs_win32_lstat
  135. #else
  136. #define _O_TEXT 0
  137. #define _O_BINARY 0
  138. #define lfs_setmode(file, m) ((void)file, (void)m, 0)
  139. #define STAT_STRUCT struct stat
  140. #define STAT_FUNC stat
  141. #define LSTAT_FUNC lstat
  142. #endif
  143. #ifdef _WIN32
  144. #define lfs_mkdir _mkdir
  145. #else
  146. #define lfs_mkdir(path) (mkdir((path), \
  147. S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IWGRP | S_IXGRP | S_IROTH | S_IXOTH))
  148. #endif
  149. #ifdef _WIN32
  150. int lfs_win32_pusherror(lua_State * L)
  151. {
  152. int en = GetLastError();
  153. lua_pushnil(L);
  154. if (en == ERROR_FILE_EXISTS || en == ERROR_SHARING_VIOLATION)
  155. lua_pushstring(L, "File exists");
  156. else
  157. lua_pushstring(L, strerror(en));
  158. return 2;
  159. }
  160. #define TICKS_PER_SECOND 10000000
  161. #define EPOCH_DIFFERENCE 11644473600LL
  162. time_t windowsToUnixTime(FILETIME ft)
  163. {
  164. ULARGE_INTEGER uli;
  165. uli.LowPart = ft.dwLowDateTime;
  166. uli.HighPart = ft.dwHighDateTime;
  167. return (time_t) (uli.QuadPart / TICKS_PER_SECOND - EPOCH_DIFFERENCE);
  168. }
  169. int lfs_win32_lstat(const char *path, STAT_STRUCT * buffer)
  170. {
  171. WIN32_FILE_ATTRIBUTE_DATA win32buffer;
  172. if (GetFileAttributesEx(path, GetFileExInfoStandard, &win32buffer)) {
  173. if (!(win32buffer.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) {
  174. return STAT_FUNC(path, buffer);
  175. }
  176. buffer->st_mode = _S_IFLNK;
  177. buffer->st_dev = 0;
  178. buffer->st_ino = 0;
  179. buffer->st_nlink = 0;
  180. buffer->st_uid = 0;
  181. buffer->st_gid = 0;
  182. buffer->st_rdev = 0;
  183. buffer->st_atime = windowsToUnixTime(win32buffer.ftLastAccessTime);
  184. buffer->st_mtime = windowsToUnixTime(win32buffer.ftLastWriteTime);
  185. buffer->st_ctime = windowsToUnixTime(win32buffer.ftCreationTime);
  186. buffer->st_size = 0;
  187. return 0;
  188. } else {
  189. return 1;
  190. }
  191. }
  192. #endif
  193. /*
  194. ** Utility functions
  195. */
  196. static int pusherror(lua_State * L, const char *info)
  197. {
  198. lua_pushnil(L);
  199. if (info == NULL)
  200. lua_pushstring(L, strerror(errno));
  201. else
  202. lua_pushfstring(L, "%s: %s", info, strerror(errno));
  203. lua_pushinteger(L, errno);
  204. return 3;
  205. }
  206. static int pushresult(lua_State * L, int res, const char *info)
  207. {
  208. if (res == -1) {
  209. return pusherror(L, info);
  210. } else {
  211. lua_pushboolean(L, 1);
  212. return 1;
  213. }
  214. }
  215. /*
  216. ** This function changes the working (current) directory
  217. */
  218. static int change_dir(lua_State * L)
  219. {
  220. const char *path = luaL_checkstring(L, 1);
  221. if (chdir(path)) {
  222. lua_pushnil(L);
  223. lua_pushfstring(L, "Unable to change working directory to '%s'\n%s\n",
  224. path, chdir_error);
  225. return 2;
  226. } else {
  227. lua_pushboolean(L, 1);
  228. return 1;
  229. }
  230. }
  231. /*
  232. ** This function returns the current directory
  233. ** If unable to get the current directory, it returns nil
  234. ** and a string describing the error
  235. */
  236. static int get_dir(lua_State * L)
  237. {
  238. #ifdef NO_GETCWD
  239. lua_pushnil(L);
  240. lua_pushstring(L, "Function 'getcwd' not provided by system");
  241. return 2;
  242. #else
  243. char *path = NULL;
  244. /* Passing (NULL, 0) is not guaranteed to work.
  245. Use a temp buffer and size instead. */
  246. size_t size = LFS_MAXPATHLEN; /* initial buffer size */
  247. int result;
  248. while (1) {
  249. char *path2 = realloc(path, size);
  250. if (!path2) { /* failed to allocate */
  251. result = pusherror(L, "get_dir realloc() failed");
  252. break;
  253. }
  254. path = path2;
  255. if (getcwd(path, size) != NULL) {
  256. /* success, push the path to the Lua stack */
  257. lua_pushstring(L, path);
  258. result = 1;
  259. break;
  260. }
  261. if (errno != ERANGE) { /* unexpected error */
  262. result = pusherror(L, "get_dir getcwd() failed");
  263. break;
  264. }
  265. /* ERANGE = insufficient buffer capacity, double size and retry */
  266. size *= 2;
  267. }
  268. free(path);
  269. return result;
  270. #endif
  271. }
  272. /*
  273. ** Check if the given element on the stack is a file and returns it.
  274. */
  275. static FILE *check_file(lua_State * L, int idx, const char *funcname)
  276. {
  277. #if LUA_VERSION_NUM == 501
  278. FILE **fh = (FILE **) luaL_checkudata(L, idx, "FILE*");
  279. if (*fh == NULL) {
  280. luaL_error(L, "%s: closed file", funcname);
  281. return 0;
  282. } else
  283. return *fh;
  284. #elif LUA_VERSION_NUM >= 502 && LUA_VERSION_NUM <= 504
  285. luaL_Stream *fh = (luaL_Stream *) luaL_checkudata(L, idx, "FILE*");
  286. if (fh->closef == 0 || fh->f == NULL) {
  287. luaL_error(L, "%s: closed file", funcname);
  288. return 0;
  289. } else
  290. return fh->f;
  291. #else
  292. #error unsupported Lua version
  293. #endif
  294. }
  295. /*
  296. **
  297. */
  298. static int _file_lock(lua_State * L, FILE * fh, const char *mode,
  299. const long start, long len, const char *funcname)
  300. {
  301. int code;
  302. #ifdef _WIN32
  303. /* lkmode valid values are:
  304. LK_LOCK Locks the specified bytes. If the bytes cannot be locked,
  305. the program immediately tries again after 1 second.
  306. If, after 10 attempts, the bytes cannot be locked,
  307. the constant returns an error.
  308. LK_NBLCK Locks the specified bytes. If the bytes cannot be locked,
  309. the constant returns an error.
  310. LK_NBRLCK Same as _LK_NBLCK.
  311. LK_RLCK Same as _LK_LOCK.
  312. LK_UNLCK Unlocks the specified bytes, which must have been
  313. previously locked.
  314. Regions should be locked only briefly and should be unlocked
  315. before closing a file or exiting the program.
  316. http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vclib/html/_crt__locking.asp
  317. */
  318. int lkmode;
  319. switch (*mode) {
  320. case 'r':
  321. lkmode = LK_NBLCK;
  322. break;
  323. case 'w':
  324. lkmode = LK_NBLCK;
  325. break;
  326. case 'u':
  327. lkmode = LK_UNLCK;
  328. break;
  329. default:
  330. return luaL_error(L, "%s: invalid mode", funcname);
  331. }
  332. if (!len) {
  333. fseek(fh, 0L, SEEK_END);
  334. len = ftell(fh);
  335. }
  336. fseek(fh, start, SEEK_SET);
  337. #ifdef __BORLANDC__
  338. code = locking(fileno(fh), lkmode, len);
  339. #else
  340. code = _locking(fileno(fh), lkmode, len);
  341. #endif
  342. #else
  343. struct flock f;
  344. switch (*mode) {
  345. case 'w':
  346. f.l_type = F_WRLCK;
  347. break;
  348. case 'r':
  349. f.l_type = F_RDLCK;
  350. break;
  351. case 'u':
  352. f.l_type = F_UNLCK;
  353. break;
  354. default:
  355. return luaL_error(L, "%s: invalid mode", funcname);
  356. }
  357. f.l_whence = SEEK_SET;
  358. f.l_start = (off_t) start;
  359. f.l_len = (off_t) len;
  360. code = fcntl(fileno(fh), F_SETLK, &f);
  361. #endif
  362. return (code != -1);
  363. }
  364. #ifdef _WIN32
  365. typedef struct lfs_Lock {
  366. HANDLE fd;
  367. } lfs_Lock;
  368. static int lfs_lock_dir(lua_State * L)
  369. {
  370. size_t pathl;
  371. HANDLE fd;
  372. lfs_Lock *lock;
  373. char *ln;
  374. const char *lockfile = "/lockfile.lfs";
  375. const char *path = luaL_checklstring(L, 1, &pathl);
  376. ln = (char *) malloc(pathl + strlen(lockfile) + 1);
  377. if (!ln) {
  378. lua_pushnil(L);
  379. lua_pushstring(L, strerror(errno));
  380. return 2;
  381. }
  382. strcpy(ln, path);
  383. strcat(ln, lockfile);
  384. fd = CreateFile(ln, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
  385. FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE, NULL);
  386. free(ln);
  387. if (fd == INVALID_HANDLE_VALUE) {
  388. return lfs_win32_pusherror(L);
  389. }
  390. lock = (lfs_Lock *) lua_newuserdata(L, sizeof(lfs_Lock));
  391. lock->fd = fd;
  392. luaL_getmetatable(L, LOCK_METATABLE);
  393. lua_setmetatable(L, -2);
  394. return 1;
  395. }
  396. static int lfs_unlock_dir(lua_State * L)
  397. {
  398. lfs_Lock *lock = (lfs_Lock *) luaL_checkudata(L, 1, LOCK_METATABLE);
  399. if (lock->fd != INVALID_HANDLE_VALUE) {
  400. CloseHandle(lock->fd);
  401. lock->fd = INVALID_HANDLE_VALUE;
  402. }
  403. return 0;
  404. }
  405. #else
  406. typedef struct lfs_Lock {
  407. char *ln;
  408. } lfs_Lock;
  409. static int lfs_lock_dir(lua_State * L)
  410. {
  411. lfs_Lock *lock;
  412. size_t pathl;
  413. char *ln;
  414. const char *lockfile = "/lockfile.lfs";
  415. const char *path = luaL_checklstring(L, 1, &pathl);
  416. lock = (lfs_Lock *) lua_newuserdata(L, sizeof(lfs_Lock));
  417. ln = (char *) malloc(pathl + strlen(lockfile) + 1);
  418. if (!ln) {
  419. lua_pushnil(L);
  420. lua_pushstring(L, strerror(errno));
  421. return 2;
  422. }
  423. strcpy(ln, path);
  424. strcat(ln, lockfile);
  425. if (symlink("lock", ln) == -1) {
  426. free(ln);
  427. lua_pushnil(L);
  428. lua_pushstring(L, strerror(errno));
  429. return 2;
  430. }
  431. lock->ln = ln;
  432. luaL_getmetatable(L, LOCK_METATABLE);
  433. lua_setmetatable(L, -2);
  434. return 1;
  435. }
  436. static int lfs_unlock_dir(lua_State * L)
  437. {
  438. lfs_Lock *lock = (lfs_Lock *) luaL_checkudata(L, 1, LOCK_METATABLE);
  439. if (lock->ln) {
  440. unlink(lock->ln);
  441. free(lock->ln);
  442. lock->ln = NULL;
  443. }
  444. return 0;
  445. }
  446. #endif
  447. static int lfs_g_setmode(lua_State * L, FILE * f, int arg)
  448. {
  449. static const int mode[] = { _O_BINARY, _O_TEXT };
  450. static const char *const modenames[] = { "binary", "text", NULL };
  451. int op = luaL_checkoption(L, arg, NULL, modenames);
  452. int res = lfs_setmode(f, mode[op]);
  453. if (res != -1) {
  454. int i;
  455. lua_pushboolean(L, 1);
  456. for (i = 0; modenames[i] != NULL; i++) {
  457. if (mode[i] == res) {
  458. lua_pushstring(L, modenames[i]);
  459. return 2;
  460. }
  461. }
  462. lua_pushnil(L);
  463. return 2;
  464. } else {
  465. return pusherror(L, NULL);
  466. }
  467. }
  468. static int lfs_f_setmode(lua_State * L)
  469. {
  470. return lfs_g_setmode(L, check_file(L, 1, "setmode"), 2);
  471. }
  472. /*
  473. ** Locks a file.
  474. ** @param #1 File handle.
  475. ** @param #2 String with lock mode ('w'rite, 'r'ead).
  476. ** @param #3 Number with start position (optional).
  477. ** @param #4 Number with length (optional).
  478. */
  479. static int file_lock(lua_State * L)
  480. {
  481. FILE *fh = check_file(L, 1, "lock");
  482. const char *mode = luaL_checkstring(L, 2);
  483. const long start = (long) luaL_optinteger(L, 3, 0);
  484. long len = (long) luaL_optinteger(L, 4, 0);
  485. if (_file_lock(L, fh, mode, start, len, "lock")) {
  486. lua_pushboolean(L, 1);
  487. return 1;
  488. } else {
  489. lua_pushnil(L);
  490. lua_pushfstring(L, "%s", strerror(errno));
  491. return 2;
  492. }
  493. }
  494. /*
  495. ** Unlocks a file.
  496. ** @param #1 File handle.
  497. ** @param #2 Number with start position (optional).
  498. ** @param #3 Number with length (optional).
  499. */
  500. static int file_unlock(lua_State * L)
  501. {
  502. FILE *fh = check_file(L, 1, "unlock");
  503. const long start = (long) luaL_optinteger(L, 2, 0);
  504. long len = (long) luaL_optinteger(L, 3, 0);
  505. if (_file_lock(L, fh, "u", start, len, "unlock")) {
  506. lua_pushboolean(L, 1);
  507. return 1;
  508. } else {
  509. lua_pushnil(L);
  510. lua_pushfstring(L, "%s", strerror(errno));
  511. return 2;
  512. }
  513. }
  514. /*
  515. ** Creates a link.
  516. ** @param #1 Object to link to.
  517. ** @param #2 Name of link.
  518. ** @param #3 True if link is symbolic (optional).
  519. */
  520. static int make_link(lua_State * L)
  521. {
  522. const char *oldpath = luaL_checkstring(L, 1);
  523. const char *newpath = luaL_checkstring(L, 2);
  524. #ifndef _WIN32
  525. return pushresult(L,
  526. (lua_toboolean(L, 3) ? symlink : link) (oldpath,
  527. newpath),
  528. NULL);
  529. #else
  530. int symbolic = lua_toboolean(L, 3);
  531. STAT_STRUCT oldpathinfo;
  532. int is_dir = 0;
  533. if (STAT_FUNC(oldpath, &oldpathinfo) == 0) {
  534. is_dir = S_ISDIR(oldpathinfo.st_mode) != 0;
  535. }
  536. if (!symbolic && is_dir) {
  537. lua_pushnil(L);
  538. lua_pushstring(L,
  539. "hard links to directories are not supported on Windows");
  540. return 2;
  541. }
  542. int result = symbolic ? CreateSymbolicLink(newpath, oldpath, is_dir)
  543. : CreateHardLink(newpath, oldpath, NULL);
  544. if (result) {
  545. return pushresult(L, result, NULL);
  546. } else {
  547. lua_pushnil(L);
  548. lua_pushstring(L, symbolic ? "make_link CreateSymbolicLink() failed"
  549. : "make_link CreateHardLink() failed");
  550. return 2;
  551. }
  552. #endif
  553. }
  554. /*
  555. ** Creates a directory.
  556. ** @param #1 Directory path.
  557. */
  558. static int make_dir(lua_State * L)
  559. {
  560. const char *path = luaL_checkstring(L, 1);
  561. return pushresult(L, lfs_mkdir(path), NULL);
  562. }
  563. /*
  564. ** Removes a directory.
  565. ** @param #1 Directory path.
  566. */
  567. static int remove_dir(lua_State * L)
  568. {
  569. const char *path = luaL_checkstring(L, 1);
  570. return pushresult(L, rmdir(path), NULL);
  571. }
  572. /*
  573. ** Directory iterator
  574. */
  575. static int dir_iter(lua_State * L)
  576. {
  577. #ifdef _WIN32
  578. struct _finddata_t c_file;
  579. #else
  580. struct dirent *entry;
  581. #endif
  582. dir_data *d = (dir_data *) luaL_checkudata(L, 1, DIR_METATABLE);
  583. luaL_argcheck(L, d->closed == 0, 1, "closed directory");
  584. #ifdef _WIN32
  585. if (d->hFile == 0L) { /* first entry */
  586. if ((d->hFile = _findfirst(d->pattern, &c_file)) == -1L) {
  587. lua_pushnil(L);
  588. lua_pushstring(L, strerror(errno));
  589. d->closed = 1;
  590. return 2;
  591. } else {
  592. lua_pushstring(L, c_file.name);
  593. return 1;
  594. }
  595. } else { /* next entry */
  596. if (_findnext(d->hFile, &c_file) == -1L) {
  597. /* no more entries => close directory */
  598. _findclose(d->hFile);
  599. d->closed = 1;
  600. return 0;
  601. } else {
  602. lua_pushstring(L, c_file.name);
  603. return 1;
  604. }
  605. }
  606. #else
  607. if ((entry = readdir(d->dir)) != NULL) {
  608. lua_pushstring(L, entry->d_name);
  609. return 1;
  610. } else {
  611. /* no more entries => close directory */
  612. closedir(d->dir);
  613. d->closed = 1;
  614. return 0;
  615. }
  616. #endif
  617. }
  618. /*
  619. ** Closes directory iterators
  620. */
  621. static int dir_close(lua_State * L)
  622. {
  623. dir_data *d = (dir_data *) lua_touserdata(L, 1);
  624. #ifdef _WIN32
  625. if (!d->closed && d->hFile) {
  626. _findclose(d->hFile);
  627. }
  628. #else
  629. if (!d->closed && d->dir) {
  630. closedir(d->dir);
  631. }
  632. #endif
  633. d->closed = 1;
  634. return 0;
  635. }
  636. /*
  637. ** Factory of directory iterators
  638. */
  639. static int dir_iter_factory(lua_State * L)
  640. {
  641. const char *path = luaL_checkstring(L, 1);
  642. dir_data *d;
  643. lua_pushcfunction(L, dir_iter);
  644. d = (dir_data *) lua_newuserdata(L, sizeof(dir_data));
  645. luaL_getmetatable(L, DIR_METATABLE);
  646. lua_setmetatable(L, -2);
  647. d->closed = 0;
  648. #ifdef _WIN32
  649. d->hFile = 0L;
  650. if (strlen(path) > MAX_PATH - 2)
  651. luaL_error(L, "path too long: %s", path);
  652. else
  653. sprintf(d->pattern, "%s/*", path);
  654. #else
  655. d->dir = opendir(path);
  656. if (d->dir == NULL)
  657. luaL_error(L, "cannot open %s: %s", path, strerror(errno));
  658. #endif
  659. #if LUA_VERSION_NUM >= 504
  660. lua_pushnil(L);
  661. lua_pushvalue(L, -2);
  662. return 4;
  663. #else
  664. return 2;
  665. #endif
  666. }
  667. /*
  668. ** Creates directory metatable.
  669. */
  670. static int dir_create_meta(lua_State * L)
  671. {
  672. luaL_newmetatable(L, DIR_METATABLE);
  673. /* Method table */
  674. lua_newtable(L);
  675. lua_pushcfunction(L, dir_iter);
  676. lua_setfield(L, -2, "next");
  677. lua_pushcfunction(L, dir_close);
  678. lua_setfield(L, -2, "close");
  679. /* Metamethods */
  680. lua_setfield(L, -2, "__index");
  681. lua_pushcfunction(L, dir_close);
  682. lua_setfield(L, -2, "__gc");
  683. #if LUA_VERSION_NUM >= 504
  684. lua_pushcfunction(L, dir_close);
  685. lua_setfield(L, -2, "__close");
  686. #endif
  687. return 1;
  688. }
  689. /*
  690. ** Creates lock metatable.
  691. */
  692. static int lock_create_meta(lua_State * L)
  693. {
  694. luaL_newmetatable(L, LOCK_METATABLE);
  695. /* Method table */
  696. lua_newtable(L);
  697. lua_pushcfunction(L, lfs_unlock_dir);
  698. lua_setfield(L, -2, "free");
  699. /* Metamethods */
  700. lua_setfield(L, -2, "__index");
  701. lua_pushcfunction(L, lfs_unlock_dir);
  702. lua_setfield(L, -2, "__gc");
  703. return 1;
  704. }
  705. /*
  706. ** Convert the inode protection mode to a string.
  707. */
  708. #ifdef _WIN32
  709. static const char *mode2string(unsigned short mode)
  710. {
  711. #else
  712. static const char *mode2string(mode_t mode)
  713. {
  714. #endif
  715. if (S_ISREG(mode))
  716. return "file";
  717. else if (S_ISDIR(mode))
  718. return "directory";
  719. else if (S_ISLNK(mode))
  720. return "link";
  721. else if (S_ISSOCK(mode))
  722. return "socket";
  723. else if (S_ISFIFO(mode))
  724. return "named pipe";
  725. else if (S_ISCHR(mode))
  726. return "char device";
  727. else if (S_ISBLK(mode))
  728. return "block device";
  729. else
  730. return "other";
  731. }
  732. /*
  733. ** Set access time and modification values for a file.
  734. ** @param #1 File path.
  735. ** @param #2 Access time in seconds, current time is used if missing.
  736. ** @param #3 Modification time in seconds, access time is used if missing.
  737. */
  738. static int file_utime(lua_State * L)
  739. {
  740. const char *file = luaL_checkstring(L, 1);
  741. struct utimbuf utb, *buf;
  742. if (lua_gettop(L) == 1) /* set to current date/time */
  743. buf = NULL;
  744. else {
  745. utb.actime = (time_t) luaL_optnumber(L, 2, 0);
  746. utb.modtime = (time_t) luaL_optinteger(L, 3, utb.actime);
  747. buf = &utb;
  748. }
  749. return pushresult(L, utime(file, buf), NULL);
  750. }
  751. /* inode protection mode */
  752. static void push_st_mode(lua_State * L, STAT_STRUCT * info)
  753. {
  754. lua_pushstring(L, mode2string(info->st_mode));
  755. }
  756. /* device inode resides on */
  757. static void push_st_dev(lua_State * L, STAT_STRUCT * info)
  758. {
  759. lua_pushinteger(L, (lua_Integer) info->st_dev);
  760. }
  761. /* inode's number */
  762. static void push_st_ino(lua_State * L, STAT_STRUCT * info)
  763. {
  764. lua_pushinteger(L, (lua_Integer) info->st_ino);
  765. }
  766. /* number of hard links to the file */
  767. static void push_st_nlink(lua_State * L, STAT_STRUCT * info)
  768. {
  769. lua_pushinteger(L, (lua_Integer) info->st_nlink);
  770. }
  771. /* user-id of owner */
  772. static void push_st_uid(lua_State * L, STAT_STRUCT * info)
  773. {
  774. lua_pushinteger(L, (lua_Integer) info->st_uid);
  775. }
  776. /* group-id of owner */
  777. static void push_st_gid(lua_State * L, STAT_STRUCT * info)
  778. {
  779. lua_pushinteger(L, (lua_Integer) info->st_gid);
  780. }
  781. /* device type, for special file inode */
  782. static void push_st_rdev(lua_State * L, STAT_STRUCT * info)
  783. {
  784. lua_pushinteger(L, (lua_Integer) info->st_rdev);
  785. }
  786. /* time of last access */
  787. static void push_st_atime(lua_State * L, STAT_STRUCT * info)
  788. {
  789. lua_pushinteger(L, (lua_Integer) info->st_atime);
  790. }
  791. /* time of last data modification */
  792. static void push_st_mtime(lua_State * L, STAT_STRUCT * info)
  793. {
  794. lua_pushinteger(L, (lua_Integer) info->st_mtime);
  795. }
  796. /* time of last file status change */
  797. static void push_st_ctime(lua_State * L, STAT_STRUCT * info)
  798. {
  799. lua_pushinteger(L, (lua_Integer) info->st_ctime);
  800. }
  801. /* file size, in bytes */
  802. static void push_st_size(lua_State * L, STAT_STRUCT * info)
  803. {
  804. lua_pushinteger(L, (lua_Integer) info->st_size);
  805. }
  806. #ifndef _WIN32
  807. /* blocks allocated for file */
  808. static void push_st_blocks(lua_State * L, STAT_STRUCT * info)
  809. {
  810. lua_pushinteger(L, (lua_Integer) info->st_blocks);
  811. }
  812. /* optimal file system I/O blocksize */
  813. static void push_st_blksize(lua_State * L, STAT_STRUCT * info)
  814. {
  815. lua_pushinteger(L, (lua_Integer) info->st_blksize);
  816. }
  817. #endif
  818. /*
  819. ** Convert the inode protection mode to a permission list.
  820. */
  821. #ifdef _WIN32
  822. static const char *perm2string(unsigned short mode)
  823. {
  824. static char perms[10] = "---------";
  825. int i;
  826. for (i = 0; i < 9; i++)
  827. perms[i] = '-';
  828. if (mode & _S_IREAD) {
  829. perms[0] = 'r';
  830. perms[3] = 'r';
  831. perms[6] = 'r';
  832. }
  833. if (mode & _S_IWRITE) {
  834. perms[1] = 'w';
  835. perms[4] = 'w';
  836. perms[7] = 'w';
  837. }
  838. if (mode & _S_IEXEC) {
  839. perms[2] = 'x';
  840. perms[5] = 'x';
  841. perms[8] = 'x';
  842. }
  843. return perms;
  844. }
  845. #else
  846. static const char *perm2string(mode_t mode)
  847. {
  848. static char perms[10] = "---------";
  849. int i;
  850. for (i = 0; i < 9; i++)
  851. perms[i] = '-';
  852. if (mode & S_IRUSR)
  853. perms[0] = 'r';
  854. if (mode & S_IWUSR)
  855. perms[1] = 'w';
  856. if (mode & S_IXUSR)
  857. perms[2] = 'x';
  858. if (mode & S_IRGRP)
  859. perms[3] = 'r';
  860. if (mode & S_IWGRP)
  861. perms[4] = 'w';
  862. if (mode & S_IXGRP)
  863. perms[5] = 'x';
  864. if (mode & S_IROTH)
  865. perms[6] = 'r';
  866. if (mode & S_IWOTH)
  867. perms[7] = 'w';
  868. if (mode & S_IXOTH)
  869. perms[8] = 'x';
  870. return perms;
  871. }
  872. #endif
  873. /* permssions string */
  874. static void push_st_perm(lua_State * L, STAT_STRUCT * info)
  875. {
  876. lua_pushstring(L, perm2string(info->st_mode));
  877. }
  878. typedef void (*_push_function)(lua_State * L, STAT_STRUCT * info);
  879. struct _stat_members {
  880. const char *name;
  881. _push_function push;
  882. };
  883. struct _stat_members members[] = {
  884. { "mode", push_st_mode },
  885. { "dev", push_st_dev },
  886. { "ino", push_st_ino },
  887. { "nlink", push_st_nlink },
  888. { "uid", push_st_uid },
  889. { "gid", push_st_gid },
  890. { "rdev", push_st_rdev },
  891. { "access", push_st_atime },
  892. { "modification", push_st_mtime },
  893. { "change", push_st_ctime },
  894. { "size", push_st_size },
  895. { "permissions", push_st_perm },
  896. #ifndef _WIN32
  897. { "blocks", push_st_blocks },
  898. { "blksize", push_st_blksize },
  899. #endif
  900. { NULL, NULL }
  901. };
  902. /*
  903. ** Get file or symbolic link information
  904. */
  905. static int _file_info_(lua_State * L,
  906. int (*st)(const char *, STAT_STRUCT *))
  907. {
  908. STAT_STRUCT info;
  909. const char *file = luaL_checkstring(L, 1);
  910. int i;
  911. if (st(file, &info)) {
  912. lua_pushnil(L);
  913. lua_pushfstring(L, "cannot obtain information from file '%s': %s",
  914. file, strerror(errno));
  915. lua_pushinteger(L, errno);
  916. return 3;
  917. }
  918. if (lua_isstring(L, 2)) {
  919. const char *member = lua_tostring(L, 2);
  920. for (i = 0; members[i].name; i++) {
  921. if (strcmp(members[i].name, member) == 0) {
  922. /* push member value and return */
  923. members[i].push(L, &info);
  924. return 1;
  925. }
  926. }
  927. /* member not found */
  928. return luaL_error(L, "invalid attribute name '%s'", member);
  929. }
  930. /* creates a table if none is given, removes extra arguments */
  931. lua_settop(L, 2);
  932. if (!lua_istable(L, 2)) {
  933. lua_newtable(L);
  934. }
  935. /* stores all members in table on top of the stack */
  936. for (i = 0; members[i].name; i++) {
  937. lua_pushstring(L, members[i].name);
  938. members[i].push(L, &info);
  939. lua_rawset(L, -3);
  940. }
  941. return 1;
  942. }
  943. /*
  944. ** Get file information using stat.
  945. */
  946. static int file_info(lua_State * L)
  947. {
  948. return _file_info_(L, STAT_FUNC);
  949. }
  950. /*
  951. ** Push the symlink target to the top of the stack.
  952. ** Assumes the file name is at position 1 of the stack.
  953. ** Returns 1 if successful (with the target on top of the stack),
  954. ** 0 on failure (with stack unchanged, and errno set).
  955. */
  956. static int push_link_target(lua_State * L)
  957. {
  958. const char *file = luaL_checkstring(L, 1);
  959. #ifdef _WIN32
  960. HANDLE h = CreateFile(file, GENERIC_READ,
  961. FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
  962. OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
  963. if (h == INVALID_HANDLE_VALUE) {
  964. return lfs_win32_pusherror(L);
  965. }
  966. #endif
  967. char *target = NULL;
  968. int tsize, size = 256; /* size = initial buffer capacity */
  969. int ok = 0;
  970. while (!ok) {
  971. char *target2 = realloc(target, size);
  972. if (!target2) { /* failed to allocate */
  973. break;
  974. }
  975. target = target2;
  976. #ifdef _WIN32
  977. tsize = GetFinalPathNameByHandle(h, target, size, FILE_NAME_OPENED);
  978. #else
  979. tsize = readlink(file, target, size);
  980. #endif
  981. if (tsize < 0) { /* a readlink() error occurred */
  982. break;
  983. }
  984. if (tsize < size) {
  985. #ifdef _WIN32
  986. if (tsize > 4 && strncmp(target, "\\\\?\\", 4) == 0) {
  987. memmove_s(target, tsize - 3, target + 4, tsize - 3);
  988. tsize -= 4;
  989. }
  990. #endif
  991. ok = 1;
  992. break;
  993. }
  994. /* possibly truncated readlink() result, double size and retry */
  995. size *= 2;
  996. }
  997. if (ok) {
  998. target[tsize] = '\0';
  999. lua_pushlstring(L, target, tsize);
  1000. }
  1001. #ifdef _WIN32
  1002. CloseHandle(h);
  1003. #endif
  1004. free(target);
  1005. return ok;
  1006. }
  1007. /*
  1008. ** Get symbolic link information using lstat.
  1009. */
  1010. static int link_info(lua_State * L)
  1011. {
  1012. int ret;
  1013. if (lua_isstring(L, 2) && (strcmp(lua_tostring(L, 2), "target") == 0)) {
  1014. int ok = push_link_target(L);
  1015. return ok ? 1 : pusherror(L, "could not obtain link target");
  1016. }
  1017. ret = _file_info_(L, LSTAT_FUNC);
  1018. if (ret == 1 && lua_type(L, -1) == LUA_TTABLE) {
  1019. int ok = push_link_target(L);
  1020. if (ok) {
  1021. lua_setfield(L, -2, "target");
  1022. }
  1023. }
  1024. return ret;
  1025. }
  1026. /*
  1027. ** Assumes the table is on top of the stack.
  1028. */
  1029. static void set_info(lua_State * L)
  1030. {
  1031. lua_pushliteral(L, "Copyright (C) 2003-2017 Kepler Project");
  1032. lua_setfield(L, -2, "_COPYRIGHT");
  1033. lua_pushliteral(L,
  1034. "LuaFileSystem is a Lua library developed to complement "
  1035. "the set of functions related to file systems offered by "
  1036. "the standard Lua distribution");
  1037. lua_setfield(L, -2, "_DESCRIPTION");
  1038. lua_pushliteral(L, "LuaFileSystem " LFS_VERSION);
  1039. lua_setfield(L, -2, "_VERSION");
  1040. }
  1041. static const struct luaL_Reg fslib[] = {
  1042. { "attributes", file_info },
  1043. { "chdir", change_dir },
  1044. { "currentdir", get_dir },
  1045. { "dir", dir_iter_factory },
  1046. { "link", make_link },
  1047. { "lock", file_lock },
  1048. { "mkdir", make_dir },
  1049. { "rmdir", remove_dir },
  1050. { "symlinkattributes", link_info },
  1051. { "setmode", lfs_f_setmode },
  1052. { "touch", file_utime },
  1053. { "unlock", file_unlock },
  1054. { "lock_dir", lfs_lock_dir },
  1055. { NULL, NULL },
  1056. };
  1057. LFS_EXPORT int luaopen_lfs(lua_State * L)
  1058. {
  1059. dir_create_meta(L);
  1060. lock_create_meta(L);
  1061. new_lib(L, fslib);
  1062. lua_pushvalue(L, -1);
  1063. lua_setglobal(L, LFS_LIBNAME);
  1064. set_info(L);
  1065. return 1;
  1066. }