file.c 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435
  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 <errno.h>
  20. #include <stdlib.h>
  21. #include <stdio.h>
  22. #include <string.h>
  23. #include <unistd.h>
  24. #include <fcntl.h>
  25. #include <sys/types.h>
  26. #include <sys/stat.h>
  27. #include <sys/param.h>
  28. static int nixio_open(lua_State *L) {
  29. const char *filename = luaL_checklstring(L, 1, NULL);
  30. int flags;
  31. if (lua_isnoneornil(L, 2)) {
  32. flags = O_RDONLY;
  33. } else if (lua_isnumber(L, 2)) {
  34. flags = lua_tointeger(L, 2);
  35. } else if (lua_isstring(L, 2)) {
  36. const char *str = lua_tostring(L, 2);
  37. if (!strcmp(str, "r")) {
  38. flags = O_RDONLY;
  39. } else if (!strcmp(str, "r+")) {
  40. flags = O_RDWR;
  41. } else if (!strcmp(str, "w")) {
  42. flags = O_WRONLY | O_CREAT | O_TRUNC;
  43. } else if (!strcmp(str, "w+")) {
  44. flags = O_RDWR | O_CREAT | O_TRUNC;
  45. } else if (!strcmp(str, "a")) {
  46. flags = O_WRONLY | O_CREAT | O_APPEND;
  47. } else if (!strcmp(str, "a+")) {
  48. flags = O_RDWR | O_CREAT | O_APPEND;
  49. } else {
  50. return luaL_argerror(L, 2, "supported values: r, r+, w, w+, a, a+");
  51. }
  52. } else {
  53. return luaL_argerror(L, 2, "open flags or string expected");
  54. }
  55. int fd;
  56. do {
  57. fd = open(filename, flags, nixio__check_mode(L, 3, 0666));
  58. } while (fd == -1 && errno == EINTR);
  59. if (fd == -1) {
  60. return nixio__perror(L);
  61. }
  62. int *udata = lua_newuserdata(L, sizeof(int));
  63. if (!udata) {
  64. return luaL_error(L, "out of memory");
  65. }
  66. *udata = fd;
  67. luaL_getmetatable(L, NIXIO_FILE_META);
  68. lua_setmetatable(L, -2);
  69. return 1;
  70. }
  71. static int nixio_mkstemp(lua_State *L) {
  72. const char *intemplate = luaL_checklstring(L, 1, NULL);
  73. size_t len = lua_strlen(L, 1);
  74. char *template = (char *)lua_newuserdata(L, 13 + len);
  75. if (!template) {
  76. return luaL_error(L, "out of memory");
  77. }
  78. snprintf(template, 13 + len, "/tmp/%s.XXXXXX", intemplate);
  79. int fd;
  80. do {
  81. fd = mkstemp(template);
  82. } while (fd == -1 && errno == EINTR);
  83. if (fd == -1) {
  84. return nixio__perror(L);
  85. }
  86. unlink(template);
  87. int *udata = lua_newuserdata(L, sizeof(int));
  88. if (!udata) {
  89. return luaL_error(L, "out of memory");
  90. }
  91. *udata = fd;
  92. luaL_getmetatable(L, NIXIO_FILE_META);
  93. lua_setmetatable(L, -2);
  94. return 1;
  95. }
  96. static int nixio_open_flags(lua_State *L) {
  97. int mode = 0;
  98. const int j = lua_gettop(L);
  99. for (int i=1; i<=j; i++) {
  100. const char *flag = luaL_checkstring(L, i);
  101. if (!strcmp(flag, "append")) {
  102. mode |= O_APPEND;
  103. } else if (!strcmp(flag, "creat")) {
  104. mode |= O_CREAT;
  105. } else if (!strcmp(flag, "excl")) {
  106. mode |= O_EXCL;
  107. } else if (!strcmp(flag, "nonblock") || !strcmp(flag, "ndelay")) {
  108. #ifndef __WINNT__
  109. mode |= O_NONBLOCK;
  110. #endif
  111. } else if (!strcmp(flag, "sync")) {
  112. #ifndef __WINNT__
  113. mode |= O_SYNC;
  114. #endif
  115. } else if (!strcmp(flag, "trunc")) {
  116. mode |= O_TRUNC;
  117. } else if (!strcmp(flag, "rdonly")) {
  118. mode |= O_RDONLY;
  119. } else if (!strcmp(flag, "wronly")) {
  120. mode |= O_WRONLY;
  121. } else if (!strcmp(flag, "rdwr")) {
  122. mode |= O_RDWR;
  123. } else {
  124. return luaL_argerror(L, i, "supported values: append, creat, "
  125. "excl, nonblock, ndelay, sync, trunc");
  126. }
  127. }
  128. lua_pushinteger(L, mode);
  129. return 1;
  130. }
  131. static int nixio_dup(lua_State *L) {
  132. int oldfd = nixio__checkfd(L, 1);
  133. int newfd = (lua_gettop(L) > 1) ? nixio__checkfd(L, 2) : -1;
  134. int stat = (newfd == -1) ? dup(oldfd) : dup2(oldfd, newfd);
  135. if (stat == -1) {
  136. return nixio__perror(L);
  137. } else {
  138. if (newfd == -1) {
  139. int *udata = lua_newuserdata(L, sizeof(int));
  140. if (!udata) {
  141. return luaL_error(L, "out of memory");
  142. }
  143. *udata = stat;
  144. luaL_getmetatable(L, NIXIO_FILE_META);
  145. lua_setmetatable(L, -2);
  146. } else {
  147. lua_pushvalue(L, 2);
  148. }
  149. return 1;
  150. }
  151. }
  152. static int nixio_pipe(lua_State *L) {
  153. int pipefd[2], *udata;
  154. if (pipe(pipefd)) {
  155. return nixio__perror(L);
  156. }
  157. luaL_getmetatable(L, NIXIO_FILE_META);
  158. udata = lua_newuserdata(L, sizeof(int));
  159. if (!udata) {
  160. return luaL_error(L, "out of memory");
  161. }
  162. *udata = pipefd[0];
  163. lua_pushvalue(L, -2);
  164. lua_setmetatable(L, -2);
  165. udata = lua_newuserdata(L, sizeof(int));
  166. if (!udata) {
  167. return luaL_error(L, "out of memory");
  168. }
  169. *udata = pipefd[1];
  170. lua_pushvalue(L, -3);
  171. lua_setmetatable(L, -2);
  172. return 2;
  173. }
  174. static int nixio_file_write(lua_State *L) {
  175. int fd = nixio__checkfd(L, 1);
  176. size_t len;
  177. ssize_t sent;
  178. const char *data = luaL_checklstring(L, 2, &len);
  179. if (lua_gettop(L) > 2) {
  180. int offset = luaL_optint(L, 3, 0);
  181. if (offset) {
  182. if (offset < len) {
  183. data += offset;
  184. len -= offset;
  185. } else {
  186. len = 0;
  187. }
  188. }
  189. unsigned int wlen = luaL_optint(L, 4, len);
  190. if (wlen < len) {
  191. len = wlen;
  192. }
  193. }
  194. do {
  195. sent = write(fd, data, len);
  196. } while(sent == -1 && errno == EINTR);
  197. if (sent >= 0) {
  198. lua_pushinteger(L, sent);
  199. return 1;
  200. } else {
  201. return nixio__perror(L);
  202. }
  203. }
  204. static int nixio_file_read(lua_State *L) {
  205. int fd = nixio__checkfd(L, 1);
  206. char buffer[NIXIO_BUFFERSIZE];
  207. uint req = luaL_checkinteger(L, 2);
  208. int readc;
  209. /* We limit the readsize to NIXIO_BUFFERSIZE */
  210. req = (req > NIXIO_BUFFERSIZE) ? NIXIO_BUFFERSIZE : req;
  211. do {
  212. readc = read(fd, buffer, req);
  213. } while (readc == -1 && errno == EINTR);
  214. if (readc < 0) {
  215. return nixio__perror(L);
  216. } else {
  217. lua_pushlstring(L, buffer, readc);
  218. return 1;
  219. }
  220. }
  221. static int nixio_file_seek(lua_State *L) {
  222. int fd = nixio__checkfd(L, 1);
  223. off_t len = (off_t)nixio__checknumber(L, 2);
  224. int whence;
  225. const char *whstr = luaL_optlstring(L, 3, "set", NULL);
  226. if (!strcmp(whstr, "set")) {
  227. whence = SEEK_SET;
  228. } else if (!strcmp(whstr, "cur")) {
  229. whence = SEEK_CUR;
  230. } else if (!strcmp(whstr, "end")) {
  231. whence = SEEK_END;
  232. } else {
  233. return luaL_argerror(L, 3, "supported values: set, cur, end");
  234. }
  235. len = lseek(fd, len, whence);
  236. if (len == -1) {
  237. return nixio__perror(L);
  238. } else {
  239. nixio__pushnumber(L, len);
  240. return 1;
  241. }
  242. }
  243. static int nixio_file_tell(lua_State *L) {
  244. int fd = nixio__checkfd(L, 1);
  245. off_t pos = lseek(fd, 0, SEEK_CUR);
  246. if (pos < 0) {
  247. return nixio__perror(L);
  248. } else {
  249. nixio__pushnumber(L, pos);
  250. return 1;
  251. }
  252. }
  253. static int nixio_file_stat(lua_State *L) {
  254. nixio_stat_t buf;
  255. if (fstat(nixio__checkfd(L, 1), &buf)) {
  256. return nixio__perror(L);
  257. } else {
  258. nixio__push_stat(L, &buf);
  259. if (lua_isstring(L, 2)) {
  260. lua_getfield(L, -1, lua_tostring(L, 2));
  261. }
  262. return 1;
  263. }
  264. }
  265. static int nixio_file_sync(lua_State *L) {
  266. int fd = nixio__checkfd(L, 1);
  267. int stat;
  268. #if (!defined BSD && !defined __WINNT__)
  269. int dataonly = lua_toboolean(L, 2);
  270. do {
  271. stat = (dataonly) ? fdatasync(fd) : fsync(fd);
  272. } while (stat == -1 && errno == EINTR);
  273. return nixio__pstatus(L, !stat);
  274. #else
  275. do {
  276. stat = fsync(fd);
  277. } while (stat == -1 && errno == EINTR);
  278. return nixio__pstatus(L, !stat);
  279. #endif
  280. }
  281. static int nixio_file_lock(lua_State *L) {
  282. int fd = nixio__checkfd(L, 1);
  283. const char *flag = luaL_checkstring(L, 2);
  284. off_t len = (off_t)nixio__optnumber(L, 3, 0);
  285. int stat;
  286. int cmd = 0;
  287. if (!strcmp(flag, "lock")) {
  288. cmd = F_LOCK;
  289. } else if (!strcmp(flag, "tlock")) {
  290. cmd = F_TLOCK;
  291. } else if (!strcmp(flag, "ulock")) {
  292. cmd = F_ULOCK;
  293. } else if (!strcmp(flag, "test")) {
  294. cmd = F_TEST;
  295. } else {
  296. return luaL_argerror(L, 2,
  297. "supported values: lock, tlock, ulock, test");
  298. }
  299. do {
  300. stat = lockf(fd, cmd, len);
  301. } while (stat == -1 && errno == EINTR);
  302. return nixio__pstatus(L, !stat);
  303. }
  304. static int nixio_file_close(lua_State *L) {
  305. int *fdp = luaL_checkudata(L, 1, NIXIO_FILE_META);
  306. luaL_argcheck(L, *fdp != -1, 1, "invalid file object");
  307. int res;
  308. do {
  309. res = close(*fdp);
  310. } while (res == -1 && errno == EINTR);
  311. *fdp = -1;
  312. return nixio__pstatus(L, !res);
  313. }
  314. static int nixio_file__gc(lua_State *L) {
  315. int *fdp = luaL_checkudata(L, 1, NIXIO_FILE_META);
  316. int res;
  317. if (*fdp > 2) {
  318. do {
  319. res = close(*fdp);
  320. } while (res == -1 && errno == EINTR);
  321. *fdp = -1;
  322. }
  323. return 0;
  324. }
  325. /**
  326. * string representation
  327. */
  328. static int nixio_file__tostring(lua_State *L) {
  329. lua_pushfstring(L, "nixio file %d", nixio__tofd(L, 1));
  330. return 1;
  331. }
  332. /* method table */
  333. static const luaL_reg M[] = {
  334. {"write", nixio_file_write},
  335. {"read", nixio_file_read},
  336. {"tell", nixio_file_tell},
  337. {"seek", nixio_file_seek},
  338. {"stat", nixio_file_stat},
  339. {"sync", nixio_file_sync},
  340. {"lock", nixio_file_lock},
  341. {"close", nixio_file_close},
  342. {"__gc", nixio_file__gc},
  343. {"__tostring", nixio_file__tostring},
  344. {NULL, NULL}
  345. };
  346. /* module table */
  347. static const luaL_reg R[] = {
  348. {"dup", nixio_dup},
  349. {"open", nixio_open},
  350. {"open_flags", nixio_open_flags},
  351. {"mkstemp", nixio_mkstemp},
  352. {"pipe", nixio_pipe},
  353. {NULL, NULL}
  354. };
  355. void nixio_open_file(lua_State *L) {
  356. luaL_register(L, NULL, R);
  357. luaL_newmetatable(L, NIXIO_FILE_META);
  358. luaL_register(L, NULL, M);
  359. lua_pushvalue(L, -1);
  360. lua_setfield(L, -2, "__index");
  361. int *uin = lua_newuserdata(L, sizeof(int));
  362. int *uout = lua_newuserdata(L, sizeof(int));
  363. int *uerr = lua_newuserdata(L, sizeof(int));
  364. if (!uin || !uout || !uerr) {
  365. luaL_error(L, "out of memory");
  366. }
  367. *uin = STDIN_FILENO;
  368. *uout = STDOUT_FILENO;
  369. *uerr = STDERR_FILENO;
  370. for (int i = -4; i < -1; i++) {
  371. lua_pushvalue(L, -4);
  372. lua_setmetatable(L, i);
  373. }
  374. lua_setfield(L, -5, "stderr");
  375. lua_setfield(L, -4, "stdout");
  376. lua_setfield(L, -3, "stdin");
  377. lua_setfield(L, -2, "meta_file");
  378. }