nixio:
[project/luci.git] / libs / nixio / src / file.c
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
19 #include "nixio.h"
20 #include <errno.h>
21 #include <stdlib.h>
22 #include <stdio.h>
23 #include <string.h>
24 #include <unistd.h>
25 #include <fcntl.h>
26 #include <sys/types.h>
27 #include <sys/stat.h>
28
29
30 static int nixio_open(lua_State *L) {
31         const char *filename = luaL_checklstring(L, 1, NULL);
32         int flags = luaL_optint(L, 2, O_RDONLY);
33         int mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
34         int fd;
35
36         do {
37                 fd = open(filename, flags, mode);
38         } while (fd == -1 && errno == EINTR);
39         if (fd == -1) {
40                 return nixio__perror(L);
41         }
42
43         int *udata = lua_newuserdata(L, sizeof(int));
44         if (!udata) {
45                 return luaL_error(L, "out of memory");
46         }
47
48         *udata = fd;
49
50         luaL_getmetatable(L, NIXIO_FILE_META);
51         lua_setmetatable(L, -2);
52
53         return 1;
54 }
55
56 static int nixio_open_flags(lua_State *L) {
57         int mode = 0;
58         const int j = lua_gettop(L);
59         for (int i=1; i<=j; i++) {
60                 const char *flag = luaL_checkstring(L, i);
61                 if (!strcmp(flag, "append")) {
62                         mode |= O_APPEND;
63                 } else if (!strcmp(flag, "creat")) {
64                         mode |= O_CREAT;
65                 } else if (!strcmp(flag, "excl")) {
66                         mode |= O_EXCL;
67                 } else if (!strcmp(flag, "nonblock") || !strcmp(flag, "ndelay")) {
68                         mode |= O_NONBLOCK;
69                 } else if (!strcmp(flag, "sync")) {
70                         mode |= O_SYNC;
71                 } else if (!strcmp(flag, "trunc")) {
72                         mode |= O_TRUNC;
73                 } else if (!strcmp(flag, "rdonly")) {
74                         mode |= O_RDONLY;
75                 } else if (!strcmp(flag, "wronly")) {
76                         mode |= O_WRONLY;
77                 } else if (!strcmp(flag, "rdwr")) {
78                         mode |= O_RDWR;
79                 } else {
80                         return luaL_argerror(L, i, "supported values: append, creat, "
81                                         "excl, nonblock, ndelay, sync, trunc");
82                 }
83         }
84         lua_pushinteger(L, mode);
85         return 1;
86 }
87
88 static int nixio_dup(lua_State *L) {
89         int oldfd = nixio__checkfd(L, 1);
90         int newfd = (lua_gettop(L) > 1) ? nixio__checkfd(L, 2) : -1;
91         int stat  = (newfd == -1) ? dup(oldfd) : dup2(oldfd, newfd);
92
93         if (stat == -1) {
94                 return nixio__perror(L);
95         } else {
96                 int *udata = lua_newuserdata(L, sizeof(int));
97                 if (!udata) {
98                         return luaL_error(L, "out of memory");
99                 }
100
101                 *udata = stat;
102                 luaL_getmetatable(L, NIXIO_FILE_META);
103                 lua_setmetatable(L, -2);
104                 return 1;
105         }
106 }
107
108 static int nixio_pipe(lua_State *L) {
109         int pipefd[2], *udata;
110         if (pipe(pipefd)) {
111                 return nixio__perror(L);
112         }
113
114         luaL_getmetatable(L, NIXIO_FILE_META);
115         udata = lua_newuserdata(L, sizeof(int));
116         if (!udata) {
117                 return luaL_error(L, "out of memory");
118         }
119
120         *udata = pipefd[0];
121         lua_pushvalue(L, -2);
122         lua_setmetatable(L, -2);
123
124
125         udata = lua_newuserdata(L, sizeof(int));
126         if (!udata) {
127                 return luaL_error(L, "out of memory");
128         }
129
130         *udata = pipefd[1];
131         lua_pushvalue(L, -3);
132         lua_setmetatable(L, -2);
133
134         return 2;
135 }
136
137 static int nixio_file_write(lua_State *L) {
138         int fd = nixio__checkfd(L, 1);
139         size_t len;
140         ssize_t sent;
141         const char *data = luaL_checklstring(L, 2, &len);
142
143         do {
144                 sent = write(fd, data, len);
145         } while(sent == -1 && errno == EINTR);
146         if (sent >= 0) {
147                 lua_pushinteger(L, sent);
148                 return 1;
149         } else {
150                 return nixio__perror(L);
151         }
152 }
153
154 static int nixio_file_read(lua_State *L) {
155         int fd = nixio__checkfd(L, 1);
156         char buffer[NIXIO_BUFFERSIZE];
157         int req = luaL_checkinteger(L, 2);
158         int readc;
159
160         /* We limit the readsize to NIXIO_BUFFERSIZE */
161         req = (req > NIXIO_BUFFERSIZE) ? NIXIO_BUFFERSIZE : req;
162
163         do {
164                 readc = read(fd, buffer, req);
165         } while (readc == -1 && errno == EINTR);
166
167         if (readc < 0) {
168                 return nixio__perror(L);
169         } else {
170                 lua_pushlstring(L, buffer, readc);
171                 return 1;
172         }
173 }
174
175
176 static int nixio_file_seek(lua_State *L) {
177         int fd = nixio__checkfd(L, 1);
178         off_t len = (off_t)luaL_checknumber(L, 2);
179         int whence;
180         const char *whstr = luaL_optlstring(L, 3, "set", NULL);
181         if (!strcmp(whstr, "set")) {
182                 whence = SEEK_SET;
183         } else if (!strcmp(whstr, "cur")) {
184                 whence = SEEK_CUR;
185         } else if (!strcmp(whstr, "end")) {
186                 whence = SEEK_END;
187         } else {
188                 return luaL_argerror(L, 3, "supported values: set, cur, end");
189         }
190         len = lseek(fd, len, whence);
191         if (len == -1) {
192                 return nixio__perror(L);
193         } else {
194                 lua_pushnumber(L, len);
195                 return 1;
196         }
197 }
198
199 static int nixio_file_tell(lua_State *L) {
200         int fd = nixio__checkfd(L, 1);
201         off_t pos = lseek(fd, 0, SEEK_CUR);
202         if (pos < 0) {
203                 return nixio__perror(L);
204         } else {
205                 lua_pushnumber(L, pos);
206                 return 1;
207         }
208 }
209
210 static int nixio_file_sync(lua_State *L) {
211         int fd = nixio__checkfd(L, 1);
212         int meta = lua_toboolean(L, 2);
213         return nixio__pstatus(L, (meta) ? !fsync(fd) : !fdatasync(fd));
214 }
215
216 static int nixio_file_lock(lua_State *L) {
217         int fd = nixio__checkfd(L, 1);
218         const char *flag = luaL_checkstring(L, 2);
219         off_t len = (off_t)luaL_optnumber(L, 3, 0);
220         int stat;
221
222         int cmd = 0;
223         if (!strcmp(flag, "lock")) {
224                 cmd = F_LOCK;
225         } else if (!strcmp(flag, "tlock")) {
226                 cmd = F_TLOCK;
227         } else if (!strcmp(flag, "ulock")) {
228                 cmd = F_ULOCK;
229         } else if (!strcmp(flag, "test")) {
230                 cmd = F_TEST;
231         } else {
232                 return luaL_argerror(L, 2,
233                                 "supported values: lock, tlock, ulock, test");
234         }
235
236         do {
237                 stat = lockf(fd, cmd, len);
238         } while (stat == -1 && errno == EINTR);
239
240         return nixio__pstatus(L, !stat);
241 }
242
243 static int nixio_file_close(lua_State *L) {
244         int *fdp = luaL_checkudata(L, 1, NIXIO_FILE_META);
245         luaL_argcheck(L, *fdp != -1, 1, "invalid file object");
246         int res;
247         do {
248                 res = close(*fdp);
249         } while (res == -1 && errno == EINTR);
250         *fdp = -1;
251         return nixio__pstatus(L, !res);
252 }
253
254 static int nixio_file__gc(lua_State *L) {
255         int *fdp = luaL_checkudata(L, 1, NIXIO_FILE_META);
256         int res;
257         if (*fdp != -1) {
258                 do {
259                         res = close(*fdp);
260                 } while (res == -1 && errno == EINTR);
261                 *fdp = -1;
262         }
263         return 0;
264 }
265
266 /**
267  * string representation
268  */
269 static int nixio_file__tostring(lua_State *L) {
270         lua_pushfstring(L, "nixio file %d", nixio__tofd(L, 1));
271         return 1;
272 }
273
274 /* method table */
275 static const luaL_reg M[] = {
276         {"write",               nixio_file_write},
277         {"read",                nixio_file_read},
278         {"tell",                nixio_file_tell},
279         {"seek",                nixio_file_seek},
280         {"sync",                nixio_file_sync},
281         {"lock",                nixio_file_lock},
282         {"close",               nixio_file_close},
283         {"__gc",                nixio_file__gc},
284         {"__tostring",  nixio_file__tostring},
285         {NULL,                  NULL}
286 };
287
288 /* module table */
289 static const luaL_reg R[] = {
290         {"dup",                 nixio_dup},
291         {"open",                nixio_open},
292         {"open_flags",  nixio_open_flags},
293         {"pipe",                nixio_pipe},
294         {NULL,                  NULL}
295 };
296
297 void nixio_open_file(lua_State *L) {
298         luaL_register(L, NULL, R);
299
300         luaL_newmetatable(L, NIXIO_FILE_META);
301         luaL_register(L, NULL, M);
302         lua_pushvalue(L, -1);
303         lua_setfield(L, -2, "__index");
304         lua_setfield(L, -2, "meta_file");
305 }