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