nixio: Fixes, use POSIX calls for file i/o
[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 <sys/file.h>
26
27
28 static int nixio_file(lua_State *L) {
29         const char *filename = luaL_checklstring(L, 1, NULL);
30         const char *mode = luaL_optlstring(L, 2, "r", NULL);
31
32         FILE *file = fopen(filename, mode);
33         if (!file) {
34                 return nixio__perror(L);
35         }
36
37         FILE **udata = lua_newuserdata(L, sizeof(FILE*));
38         if (!udata) {
39                 return luaL_error(L, "out of memory");
40         }
41
42         *udata = file;
43
44         luaL_getmetatable(L, NIXIO_FILE_META);
45         lua_setmetatable(L, -2);
46
47         return 1;
48 }
49
50 static int nixio_pipe(lua_State *L) {
51         int pipefd[2];
52         FILE **udata;
53         if (pipe(pipefd)) {
54                 return nixio__perror(L);
55         }
56
57         luaL_getmetatable(L, NIXIO_FILE_META);
58         udata = lua_newuserdata(L, sizeof(FILE*));
59         if (!udata) {
60                 return luaL_error(L, "out of memory");
61         }
62
63         if (!(*udata = fdopen(pipefd[0], "r"))) {
64                 return nixio__perror(L);
65         }
66         lua_pushvalue(L, -2);
67         lua_setmetatable(L, -2);
68
69
70         udata = lua_newuserdata(L, sizeof(FILE**));
71         if (!(*udata = fdopen(pipefd[1], "w"))) {
72                 return nixio__perror(L);
73         }
74         lua_pushvalue(L, -3);
75         lua_setmetatable(L, -2);
76
77         return 2;
78 }
79
80 static int nixio_file_write(lua_State *L) {
81         int fd = nixio__checkfd(L, 1);
82         size_t len;
83         ssize_t sent;
84         const char *data = luaL_checklstring(L, 2, &len);
85
86         do {
87                 sent = write(fd, data, len);
88         } while(sent == -1 && errno == EINTR);
89         if (sent >= 0) {
90                 lua_pushinteger(L, sent);
91                 return 1;
92         } else {
93                 return nixio__perror(L);
94         }
95 }
96
97 static int nixio_file_read(lua_State *L) {
98         int fd = nixio__checkfd(L, 1);
99         char buffer[NIXIO_BUFFERSIZE];
100         int req = luaL_checkinteger(L, 2);
101         int readc;
102
103         /* We limit the readsize to NIXIO_BUFFERSIZE */
104         req = (req > NIXIO_BUFFERSIZE) ? NIXIO_BUFFERSIZE : req;
105
106         do {
107                 readc = read(fd, buffer, req);
108         } while (readc == -1 && errno == EINTR);
109
110         if (readc < 0) {
111                 return nixio__perror(L);
112         } else {
113                 lua_pushlstring(L, buffer, readc);
114                 return 1;
115         }
116 }
117
118
119 static int nixio_file_seek(lua_State *L) {
120         FILE *f = nixio__checkfile(L);
121         off_t len = (off_t)luaL_checknumber(L, 2);
122         int whence;
123         const char *whstr = luaL_optlstring(L, 3, "set", NULL);
124         if (!strcmp(whstr, "set")) {
125                 whence = SEEK_SET;
126         } else if (!strcmp(whstr, "cur")) {
127                 whence = SEEK_CUR;
128         } else if (!strcmp(whstr, "end")) {
129                 whence = SEEK_END;
130         } else {
131                 return luaL_argerror(L, 3, "supported values: set, cur, end");
132         }
133         return nixio__pstatus(L, !fseeko(f, len, whence));
134 }
135
136 static int nixio_file_tell(lua_State *L) {
137         FILE *f = nixio__checkfile(L);
138         off_t pos = ftello(f);
139         if (pos < 0) {
140                 return nixio__perror(L);
141         } else {
142                 lua_pushnumber(L, (lua_Number)pos);
143                 return 1;
144         }
145 }
146
147 static int nixio_file_flush(lua_State *L) {
148         FILE *f = nixio__checkfile(L);
149         return nixio__pstatus(L, !fflush(f));
150 }
151
152 static int nixio_file_lock(lua_State *L) {
153         int fd = fileno(nixio__checkfile(L));
154
155         const int j = lua_gettop(L);
156         int flags = 0;
157         for (int i=2; i<=j; i++) {
158                 const char *flag = luaL_checkstring(L, i);
159                 if (!strcmp(flag, "sh")) {
160                         flags |= LOCK_SH;
161                 } else if (!strcmp(flag, "ex")) {
162                         flags |= LOCK_EX;
163                 } else if (!strcmp(flag, "un")) {
164                         flags |= LOCK_UN;
165                 } else if (!strcmp(flag, "nb")) {
166                         flags |= LOCK_NB;
167                 } else {
168                         return luaL_argerror(L, i, "supported values: sh, ex, un, nb");
169                 }
170         }
171
172         return nixio__pstatus(L, !flock(fd, flags));
173 }
174
175 static int nixio_file_close(lua_State *L) {
176         FILE **fpp = (FILE**)luaL_checkudata(L, 1, NIXIO_FILE_META);
177         luaL_argcheck(L, *fpp, 1, "invalid file object");
178         int res = fclose(*fpp);
179         *fpp = NULL;
180         return nixio__pstatus(L, !res);
181 }
182
183 static int nixio_file__gc(lua_State *L) {
184         FILE **fpp = (FILE**)luaL_checkudata(L, 1, NIXIO_FILE_META);
185         if (*fpp) {
186                 fclose(*fpp);
187                 *fpp = NULL;
188         }
189         return 0;
190 }
191
192 /**
193  * string representation
194  */
195 static int nixio_file__tostring(lua_State *L) {
196         lua_pushfstring(L, "nixio file %d", nixio__tofd(L, 1));
197         return 1;
198 }
199
200 /* method table */
201 static const luaL_reg M[] = {
202         {"write",               nixio_file_write},
203         {"read",                nixio_file_read},
204         {"tell",                nixio_file_tell},
205         {"seek",                nixio_file_seek},
206         {"flush",               nixio_file_flush},
207         {"lock",                nixio_file_lock},
208         {"close",               nixio_file_close},
209         {"__gc",                nixio_file__gc},
210         {"__tostring",  nixio_file__tostring},
211         {NULL,                  NULL}
212 };
213
214 /* module table */
215 static const luaL_reg R[] = {
216         {"open",                nixio_file},
217         {"pipe",                nixio_pipe},
218         {NULL,                  NULL}
219 };
220
221 void nixio_open_file(lua_State *L) {
222         luaL_register(L, NULL, R);
223
224         luaL_newmetatable(L, NIXIO_FILE_META);
225         luaL_register(L, NULL, M);
226         lua_pushvalue(L, -1);
227         lua_setfield(L, -2, "__index");
228         lua_setfield(L, -2, "meta_file");
229 }