fs.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566
  1. /*
  2. * nixio - Linux I/O library for lua
  3. *
  4. * Copyright (C) 2009 Steven Barth <steven@midlink.org>
  5. *
  6. * Licensed under the Apache License, Version 2.0 (the "License");
  7. * you may not use this file except in compliance with the License.
  8. * You may obtain a copy of the License at
  9. *
  10. * http://www.apache.org/licenses/LICENSE-2.0
  11. *
  12. * Unless required by applicable law or agreed to in writing, software
  13. * distributed under the License is distributed on an "AS IS" BASIS,
  14. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  15. * See the License for the specific language governing permissions and
  16. * limitations under the License.
  17. */
  18. #include "nixio.h"
  19. #include <libgen.h>
  20. #include <string.h>
  21. #include <unistd.h>
  22. #include <limits.h>
  23. #include <stdlib.h>
  24. #include <sys/stat.h>
  25. #include <sys/types.h>
  26. #include <sys/time.h>
  27. #include <dirent.h>
  28. /* Reads argument from given index and transforms it into a mode bitfield */
  29. int nixio__check_mode(lua_State *L, int idx, int def) {
  30. if (lua_isnoneornil(L, idx) && def > 0) {
  31. return def;
  32. } else if (lua_isstring(L, idx) && lua_objlen(L, idx) == 9) {
  33. int mode = 0;
  34. const char *modestr = lua_tostring(L, idx);
  35. int i;
  36. for (i=0; i<9; i++) {
  37. if (i % 3 == 0) { /* read flags */
  38. if (modestr[i] == 'r') {
  39. mode |= 1 << (8 - i);
  40. } else if (modestr[i] != '-') {
  41. break;
  42. }
  43. } else if (i % 3 == 1) { /* write flags */
  44. if (modestr[i] == 'w') {
  45. mode |= 1 << (8 - i);
  46. } else if (modestr[i] != '-') {
  47. break;
  48. }
  49. } else if (i == 2) {
  50. if (modestr[i] == 'x') {
  51. mode |= 00100;
  52. } else if (modestr[i] == 's') {
  53. mode |= 04100;
  54. } else if (modestr[i] == 'S') {
  55. mode |= 04000;
  56. } else if (modestr[i] != '-') {
  57. break;
  58. }
  59. } else if (i == 5) {
  60. if (modestr[i] == 'x') {
  61. mode |= 00010;
  62. } else if (modestr[i] == 's') {
  63. mode |= 02010;
  64. } else if (modestr[i] == 'S') {
  65. mode |= 02000;
  66. } else if (modestr[i] != '-') {
  67. break;
  68. }
  69. } else if (i == 8) {
  70. if (modestr[i] == 'x') {
  71. mode |= 00001;
  72. } else if (modestr[i] == 't') {
  73. mode |= 01001;
  74. } else if (modestr[i] == 'T') {
  75. mode |= 01000;
  76. } else if (modestr[i] != '-') {
  77. break;
  78. }
  79. }
  80. }
  81. if (i == 9) { /* successfully parsed */
  82. return mode;
  83. }
  84. } else if (lua_isnumber(L, idx)) {
  85. int decmode = lua_tointeger(L, idx);
  86. int s = (decmode % 10000) / 1000;
  87. int u = (decmode % 1000) / 100;
  88. int g = (decmode % 100) / 10;
  89. int o = (decmode % 10);
  90. if (s>=0 && s<=7 && u>=0 && u<=7 && g>=0 && g<=7 && o>=0 && o<=7) {
  91. return (s << 9) + (u << 6) + (g << 3) + o;
  92. }
  93. }
  94. return luaL_argerror(L, idx, "supported values: [0-7]?[0-7][0-7][0-7], "
  95. "[-r][-w][-xsS][-r][-w][-xsS][-r][-w][-xtT]");
  96. }
  97. /* Transforms a mode into the modestring */
  98. int nixio__mode_write(int mode, char *modestr) {
  99. if (modestr) {
  100. modestr[0] = (mode & 00400) ? 'r' : '-';
  101. modestr[1] = (mode & 00200) ? 'w' : '-';
  102. modestr[2] = ((mode & 04100) == 04100) ? 's' :
  103. (mode & 04000) ? 'S' : (mode & 00100) ? 'x' : '-';
  104. modestr[3] = (mode & 00040) ? 'r' : '-';
  105. modestr[4] = (mode & 00020) ? 'w' : '-';
  106. modestr[5] = ((mode & 02010) == 02010) ? 's' :
  107. (mode & 02000) ? 'S' : (mode & 00010) ? 'x' : '-';
  108. modestr[6] = (mode & 00004) ? 'r' : '-';
  109. modestr[7] = (mode & 00002) ? 'w' : '-';
  110. modestr[8] = ((mode & 01001) == 01001) ? 't' :
  111. (mode & 01000) ? 'T' : (mode & 00001) ? 'x' : '-';
  112. }
  113. return (mode & 00007) + ((mode & 00070) >> 3) * 10 +
  114. ((mode & 00700) >> 6) * 100 + ((mode & 07000) >> 9) * 1000;
  115. }
  116. static int nixio_access(lua_State *L) {
  117. const char *path = luaL_checkstring(L, 1);
  118. int mode = F_OK;
  119. for (const char *s = luaL_optstring(L, 2, "f"); *s; s++) {
  120. if (*s == 'r') {
  121. mode |= R_OK;
  122. } else if (*s == 'w') {
  123. mode |= W_OK;
  124. } else if (*s == 'x') {
  125. mode |= X_OK;
  126. } else if (*s != 'f') {
  127. return luaL_argerror(L, 2, "supported values: [frwx]");
  128. }
  129. }
  130. return nixio__pstatus(L, !access(path, mode));
  131. }
  132. static int nixio_basename(lua_State *L) {
  133. const char *path = luaL_checkstring(L, 1);
  134. char base[PATH_MAX];
  135. base[PATH_MAX-1] = 0;
  136. strncpy(base, path, PATH_MAX-1);
  137. lua_pushstring(L, basename(base));
  138. return 1;
  139. }
  140. static int nixio_dirname(lua_State *L) {
  141. const char *path = luaL_checkstring(L, 1);
  142. char base[PATH_MAX];
  143. base[PATH_MAX-1] = 0;
  144. strncpy(base, path, PATH_MAX-1);
  145. lua_pushstring(L, dirname(base));
  146. return 1;
  147. }
  148. static int nixio_realpath(lua_State *L) {
  149. const char *path = luaL_checkstring(L, 1);
  150. char real[PATH_MAX];
  151. if (!realpath(path, real)) {
  152. return nixio__perror(L);
  153. } else {
  154. lua_pushstring(L, real);
  155. return 1;
  156. }
  157. }
  158. static int nixio_remove(lua_State *L) {
  159. return nixio__pstatus(L, !remove(luaL_checkstring(L, 1)));
  160. }
  161. static int nixio_unlink(lua_State *L) {
  162. return nixio__pstatus(L, !unlink(luaL_checkstring(L, 1)));
  163. }
  164. static int nixio_rename(lua_State *L) {
  165. return nixio__pstatus(L,
  166. !rename(luaL_checkstring(L, 1), luaL_checkstring(L, 2)));
  167. }
  168. static int nixio_rmdir(lua_State *L) {
  169. return nixio__pstatus(L, !rmdir(luaL_checkstring(L, 1)));
  170. }
  171. static int nixio_mkdir(lua_State *L) {
  172. return nixio__pstatus(L,
  173. !mkdir(luaL_checkstring(L, 1), nixio__check_mode(L, 2, 0777)));
  174. }
  175. static int nixio_chmod(lua_State *L) {
  176. return nixio__pstatus(L,
  177. !chmod(luaL_checkstring(L, 1), nixio__check_mode(L, 2, -1)));
  178. }
  179. static int nixio_dir__gc(lua_State *L) {
  180. DIR **dirp = lua_touserdata(L, 1);
  181. if (dirp && *dirp) {
  182. closedir(*dirp);
  183. *dirp = NULL;
  184. }
  185. return 0;
  186. }
  187. static int nixio_dir__iter(lua_State *L) {
  188. DIR **dirp = lua_touserdata(L, lua_upvalueindex(1));
  189. struct dirent *entry;
  190. const char *n = NULL;
  191. if (*dirp) {
  192. do {
  193. entry = readdir(*dirp);
  194. n = (entry) ? entry->d_name : NULL;
  195. } while(n && n[0] == '.' && (n[1] == 0 || (n[1] == '.' && n[2] == 0)));
  196. }
  197. if (n) {
  198. lua_pushstring(L, n);
  199. } else {
  200. if (*dirp) {
  201. closedir(*dirp);
  202. *dirp = NULL;
  203. }
  204. lua_pushnil(L);
  205. }
  206. return 1;
  207. }
  208. static int nixio_dir(lua_State *L) {
  209. const char *path = luaL_optstring(L, 1, ".");
  210. DIR **dirp = lua_newuserdata(L, sizeof(DIR *));
  211. *dirp = opendir(path);
  212. if (!*dirp) {
  213. return nixio__perror(L);
  214. } else {
  215. luaL_getmetatable(L, NIXIO_DIR_META);
  216. lua_setmetatable(L, -2);
  217. lua_pushcclosure(L, nixio_dir__iter, 1);
  218. return 1;
  219. }
  220. }
  221. static int nixio_link(lua_State *L) {
  222. return nixio__pstatus(L,
  223. !link(luaL_checkstring(L, 1), luaL_checkstring(L, 2)));
  224. }
  225. static int nixio_utimes(lua_State *L) {
  226. const char *path = luaL_checkstring(L, 1);
  227. if (lua_gettop(L) < 2 || (lua_isnoneornil(L, 2) && lua_isnoneornil(L, 3))) {
  228. return nixio__pstatus(L, !utimes(path, NULL));
  229. } else {
  230. double atime = nixio__checknumber(L, 2);
  231. double mtime = nixio__optnumber(L, 3, atime);
  232. struct timeval times[2];
  233. times[0].tv_sec = atime;
  234. times[0].tv_usec = 0;
  235. times[1].tv_sec = mtime;
  236. times[1].tv_usec = 0;
  237. return nixio__pstatus(L, !utimes(path, times));
  238. }
  239. }
  240. int nixio__push_stat(lua_State *L, nixio_stat_t *buf) {
  241. lua_createtable(L, 0, 15);
  242. lua_pushinteger(L, buf->st_dev);
  243. lua_setfield(L, -2, "dev");
  244. lua_pushinteger(L, buf->st_ino);
  245. lua_setfield(L, -2, "ino");
  246. if (S_ISREG(buf->st_mode)) {
  247. lua_pushliteral(L, "reg");
  248. } else if (S_ISDIR(buf->st_mode)) {
  249. lua_pushliteral(L, "dir");
  250. } else if (S_ISCHR(buf->st_mode)) {
  251. lua_pushliteral(L, "chr");
  252. } else if (S_ISBLK(buf->st_mode)) {
  253. lua_pushliteral(L, "blk");
  254. } else if (S_ISFIFO(buf->st_mode)) {
  255. lua_pushliteral(L, "fifo");
  256. } else if (S_ISLNK(buf->st_mode)) {
  257. lua_pushliteral(L, "lnk");
  258. } else if (S_ISSOCK(buf->st_mode)) {
  259. lua_pushliteral(L, "sock");
  260. } else {
  261. lua_pushliteral(L, "unknown");
  262. }
  263. lua_setfield(L, -2, "type");
  264. char modestr[9];
  265. lua_pushinteger(L, nixio__mode_write(buf->st_mode, modestr));
  266. lua_setfield(L, -2, "modedec");
  267. lua_pushlstring(L, modestr, 9);
  268. lua_setfield(L, -2, "modestr");
  269. lua_pushinteger(L, buf->st_nlink);
  270. lua_setfield(L, -2, "nlink");
  271. lua_pushinteger(L, buf->st_uid);
  272. lua_setfield(L, -2, "uid");
  273. lua_pushinteger(L, buf->st_gid);
  274. lua_setfield(L, -2, "gid");
  275. lua_pushinteger(L, buf->st_rdev);
  276. lua_setfield(L, -2, "rdev");
  277. nixio__pushnumber(L, buf->st_size);
  278. lua_setfield(L, -2, "size");
  279. lua_pushinteger(L, buf->st_atime);
  280. lua_setfield(L, -2, "atime");
  281. lua_pushinteger(L, buf->st_mtime);
  282. lua_setfield(L, -2, "mtime");
  283. lua_pushinteger(L, buf->st_ctime);
  284. lua_setfield(L, -2, "ctime");
  285. #ifndef __WINNT__
  286. lua_pushinteger(L, buf->st_blksize);
  287. lua_setfield(L, -2, "blksize");
  288. lua_pushinteger(L, buf->st_blocks);
  289. lua_setfield(L, -2, "blocks");
  290. #endif
  291. return 1;
  292. }
  293. static int nixio_stat(lua_State *L) {
  294. nixio_stat_t buf;
  295. if (stat(luaL_checkstring(L, 1), &buf)) {
  296. return nixio__perror(L);
  297. } else {
  298. nixio__push_stat(L, &buf);
  299. if (lua_isstring(L, 2)) {
  300. lua_getfield(L, -1, lua_tostring(L, 2));
  301. }
  302. return 1;
  303. }
  304. }
  305. static int nixio_lstat(lua_State *L) {
  306. nixio_stat_t buf;
  307. if (stat(luaL_checkstring(L, 1), &buf)) {
  308. return nixio__perror(L);
  309. } else {
  310. nixio__push_stat(L, &buf);
  311. if (lua_isstring(L, 2)) {
  312. lua_getfield(L, -1, lua_tostring(L, 2));
  313. }
  314. return 1;
  315. }
  316. }
  317. #ifndef __WINNT__
  318. static int nixio_chown(lua_State *L) {
  319. return nixio__pstatus(L,
  320. !chown(
  321. luaL_checkstring(L, 1),
  322. lua_isnoneornil(L, 2) ? -1 : nixio__check_user(L, 2),
  323. lua_isnoneornil(L, 3) ? -1 : nixio__check_group(L, 3)
  324. )
  325. );
  326. }
  327. static int nixio_lchown(lua_State *L) {
  328. return nixio__pstatus(L,
  329. !lchown(
  330. luaL_checkstring(L, 1),
  331. lua_isnoneornil(L, 2) ? -1 : nixio__check_user(L, 2),
  332. lua_isnoneornil(L, 3) ? -1 : nixio__check_group(L, 3)
  333. )
  334. );
  335. }
  336. static int nixio_mkfifo(lua_State *L) {
  337. return nixio__pstatus(L,
  338. !mkfifo(luaL_checkstring(L, 1), nixio__check_mode(L, 2, -1)));
  339. }
  340. static int nixio_symlink(lua_State *L) {
  341. return nixio__pstatus(L,
  342. !symlink(luaL_checkstring(L, 1), luaL_checkstring(L, 2)));
  343. }
  344. static int nixio_readlink(lua_State *L) {
  345. char dest[PATH_MAX];
  346. ssize_t res = readlink(luaL_checkstring(L, 1), dest, sizeof(dest));
  347. if (res < 0) {
  348. return nixio__perror(L);
  349. } else {
  350. lua_pushlstring(L, dest, res);
  351. return 1;
  352. }
  353. }
  354. #include <glob.h>
  355. typedef struct {
  356. glob_t gl;
  357. size_t pos;
  358. int freed;
  359. } nixio_glob_t;
  360. static int nixio_glob__iter(lua_State *L) {
  361. nixio_glob_t *globres = lua_touserdata(L, lua_upvalueindex(1));
  362. if (!globres->freed && globres->pos < globres->gl.gl_pathc) {
  363. lua_pushstring(L, globres->gl.gl_pathv[(globres->pos)++]);
  364. } else {
  365. if (!globres->freed) {
  366. globfree(&globres->gl);
  367. globres->freed = 1;
  368. }
  369. lua_pushnil(L);
  370. }
  371. return 1;
  372. }
  373. static int nixio_glob__gc(lua_State *L) {
  374. nixio_glob_t *globres = lua_touserdata(L, 1);
  375. if (globres && !globres->freed) {
  376. globres->freed = 1;
  377. globfree(&globres->gl);
  378. }
  379. return 0;
  380. }
  381. static int nixio_glob(lua_State *L) {
  382. const char *pattern = luaL_optstring(L, 1, "*");
  383. nixio_glob_t *globres = lua_newuserdata(L, sizeof(nixio_glob_t));
  384. if (!globres) {
  385. return luaL_error(L, NIXIO_OOM);
  386. }
  387. globres->pos = 0;
  388. globres->freed = 0;
  389. int globstat = glob(pattern, 0, NULL, &globres->gl);
  390. if (globstat == GLOB_NOMATCH) {
  391. lua_pushcfunction(L, nixio__nulliter);
  392. lua_pushinteger(L, 0);
  393. } else if (globstat) {
  394. return nixio__perror(L);
  395. } else {
  396. luaL_getmetatable(L, NIXIO_GLOB_META);
  397. lua_setmetatable(L, -2);
  398. lua_pushcclosure(L, nixio_glob__iter, 1);
  399. lua_pushinteger(L, globres->gl.gl_pathc);
  400. }
  401. return 2;
  402. }
  403. #include <sys/statvfs.h>
  404. static int nixio__push_statvfs(lua_State *L, struct statvfs *buf) {
  405. lua_createtable(L, 0, 12);
  406. nixio__pushnumber(L, buf->f_bavail);
  407. lua_setfield(L, -2, "bavail");
  408. nixio__pushnumber(L, buf->f_bfree);
  409. lua_setfield(L, -2, "bfree");
  410. nixio__pushnumber(L, buf->f_blocks);
  411. lua_setfield(L, -2, "blocks");
  412. nixio__pushnumber(L, buf->f_bsize);
  413. lua_setfield(L, -2, "bsize");
  414. nixio__pushnumber(L, buf->f_frsize);
  415. lua_setfield(L, -2, "frsize");
  416. nixio__pushnumber(L, buf->f_favail);
  417. lua_setfield(L, -2, "favail");
  418. nixio__pushnumber(L, buf->f_ffree);
  419. lua_setfield(L, -2, "ffree");
  420. nixio__pushnumber(L, buf->f_files);
  421. lua_setfield(L, -2, "files");
  422. nixio__pushnumber(L, buf->f_flag);
  423. lua_setfield(L, -2, "flag");
  424. nixio__pushnumber(L, buf->f_fsid);
  425. lua_setfield(L, -2, "fsid");
  426. nixio__pushnumber(L, buf->f_namemax);
  427. lua_setfield(L, -2, "namemax");
  428. return 1;
  429. }
  430. static int nixio_statvfs(lua_State *L) {
  431. struct statvfs buf;
  432. if (statvfs(luaL_optstring(L, 1, "."), &buf)) {
  433. return nixio__perror(L);
  434. } else {
  435. return nixio__push_statvfs(L, &buf);
  436. }
  437. }
  438. #endif /* !__WINNT__ */
  439. /* module table */
  440. static const luaL_reg R[] = {
  441. #ifndef __WINNT__
  442. {"glob", nixio_glob},
  443. {"mkfifo", nixio_mkfifo},
  444. {"symlink", nixio_symlink},
  445. {"readlink", nixio_readlink},
  446. {"chown", nixio_chown},
  447. {"lchown", nixio_lchown},
  448. {"statvfs", nixio_statvfs},
  449. #endif
  450. {"chmod", nixio_chmod},
  451. {"access", nixio_access},
  452. {"basename", nixio_basename},
  453. {"dir", nixio_dir},
  454. {"dirname", nixio_dirname},
  455. {"realpath", nixio_realpath},
  456. {"mkdir", nixio_mkdir},
  457. {"rmdir", nixio_rmdir},
  458. {"link", nixio_link},
  459. {"unlink", nixio_unlink},
  460. {"utimes", nixio_utimes},
  461. {"rename", nixio_rename},
  462. {"remove", nixio_remove},
  463. {"stat", nixio_stat},
  464. {"lstat", nixio_lstat},
  465. {NULL, NULL}
  466. };
  467. void nixio_open_fs(lua_State *L) {
  468. lua_newtable(L);
  469. luaL_register(L, NULL, R);
  470. lua_setfield(L, -2, "fs");
  471. luaL_newmetatable(L, NIXIO_DIR_META);
  472. lua_pushcfunction(L, nixio_dir__gc);
  473. lua_setfield(L, -2, "__gc");
  474. lua_pop(L, 1);
  475. #ifndef __WINNT__
  476. luaL_newmetatable(L, NIXIO_GLOB_META);
  477. lua_pushcfunction(L, nixio_glob__gc);
  478. lua_setfield(L, -2, "__gc");
  479. lua_pop(L, 1);
  480. #endif
  481. }