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