libs/web: remove debugging code
[project/luci.git] / libs / nixio / src / fs.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 <libgen.h>
21 #include <string.h>
22 #include <unistd.h>
23 #include <limits.h>
24 #include <stdlib.h>
25 #include <sys/stat.h>
26 #include <sys/types.h>
27 #include <sys/time.h>
28 #include <dirent.h>
29
30 /* Reads argument from given index and transforms it into a mode bitfield */
31 int nixio__check_mode(lua_State *L, int idx, int def) {
32 if (lua_isnoneornil(L, idx) && def > 0) {
33 return def;
34 } else if (lua_isstring(L, idx) && lua_objlen(L, idx) == 9) {
35 int mode = 0;
36 const char *modestr = lua_tostring(L, idx);
37 int i;
38 for (i=0; i<9; i++) {
39 if (i % 3 == 0) { /* read flags */
40 if (modestr[i] == 'r') {
41 mode |= 1 << (8 - i);
42 } else if (modestr[i] != '-') {
43 break;
44 }
45 } else if (i % 3 == 1) { /* write flags */
46 if (modestr[i] == 'w') {
47 mode |= 1 << (8 - i);
48 } else if (modestr[i] != '-') {
49 break;
50 }
51 } else if (i == 2) {
52 if (modestr[i] == 'x') {
53 mode |= 00100;
54 } else if (modestr[i] == 's') {
55 mode |= 04100;
56 } else if (modestr[i] == 'S') {
57 mode |= 04000;
58 } else if (modestr[i] != '-') {
59 break;
60 }
61 } else if (i == 5) {
62 if (modestr[i] == 'x') {
63 mode |= 00010;
64 } else if (modestr[i] == 's') {
65 mode |= 02010;
66 } else if (modestr[i] == 'S') {
67 mode |= 02000;
68 } else if (modestr[i] != '-') {
69 break;
70 }
71 } else if (i == 8) {
72 if (modestr[i] == 'x') {
73 mode |= 00001;
74 } else if (modestr[i] == 't') {
75 mode |= 01001;
76 } else if (modestr[i] == 'T') {
77 mode |= 01000;
78 } else if (modestr[i] != '-') {
79 break;
80 }
81 }
82 }
83 if (i == 9) { /* successfully parsed */
84 return mode;
85 }
86 } else if (lua_isnumber(L, idx)) {
87 int decmode = lua_tointeger(L, idx);
88 int s = (decmode % 10000) / 1000;
89 int u = (decmode % 1000) / 100;
90 int g = (decmode % 100) / 10;
91 int o = (decmode % 10);
92
93 if (s>=0 && s<=7 && u>=0 && u<=7 && g>=0 && g<=7 && o>=0 && o<=7) {
94 return (s << 9) + (u << 6) + (g << 3) + o;
95 }
96 }
97
98 return luaL_argerror(L, idx, "supported values: [0-7]?[0-7][0-7][0-7], "
99 "[-r][-w][-xsS][-r][-w][-xsS][-r][-w][-xtT]");
100 }
101
102 /* Transforms a mode into the modestring */
103 int nixio__mode_write(int mode, char *modestr) {
104 if (modestr) {
105 modestr[0] = (mode & 00400) ? 'r' : '-';
106 modestr[1] = (mode & 00200) ? 'w' : '-';
107 modestr[2] = ((mode & 04100) == 04100) ? 's' :
108 (mode & 04000) ? 'S' : (mode & 00100) ? 'x' : '-';
109 modestr[3] = (mode & 00040) ? 'r' : '-';
110 modestr[4] = (mode & 00020) ? 'w' : '-';
111 modestr[5] = ((mode & 02010) == 02010) ? 's' :
112 (mode & 02000) ? 'S' : (mode & 00010) ? 'x' : '-';
113 modestr[6] = (mode & 00004) ? 'r' : '-';
114 modestr[7] = (mode & 00002) ? 'w' : '-';
115 modestr[8] = ((mode & 01001) == 01001) ? 't' :
116 (mode & 01000) ? 'T' : (mode & 00001) ? 'x' : '-';
117 }
118
119 return (mode & 00007) + ((mode & 00070) >> 3) * 10 +
120 ((mode & 00700) >> 6) * 100 + ((mode & 07000) >> 9) * 1000;
121 }
122
123 static int nixio_access(lua_State *L) {
124 const char *path = luaL_checkstring(L, 1);
125 int mode = F_OK;
126
127 for (const char *s = luaL_optstring(L, 2, "f"); *s; s++) {
128 if (*s == 'r') {
129 mode |= R_OK;
130 } else if (*s == 'w') {
131 mode |= W_OK;
132 } else if (*s == 'x') {
133 mode |= X_OK;
134 } else if (*s != 'f') {
135 return luaL_argerror(L, 2, "supported values: [frwx]");
136 }
137 }
138
139 return nixio__pstatus(L, !access(path, mode));
140 }
141
142 static int nixio_basename(lua_State *L) {
143 const char *path = luaL_checkstring(L, 1);
144 char base[PATH_MAX];
145 base[PATH_MAX-1] = 0;
146
147 strncpy(base, path, PATH_MAX-1);
148 lua_pushstring(L, basename(base));
149 return 1;
150 }
151
152 static int nixio_dirname(lua_State *L) {
153 const char *path = luaL_checkstring(L, 1);
154 char base[PATH_MAX];
155 base[PATH_MAX-1] = 0;
156
157 strncpy(base, path, PATH_MAX-1);
158 lua_pushstring(L, dirname(base));
159 return 1;
160 }
161
162 static int nixio_realpath(lua_State *L) {
163 const char *path = luaL_checkstring(L, 1);
164 char real[PATH_MAX];
165
166 if (!realpath(path, real)) {
167 return nixio__perror(L);
168 } else {
169 lua_pushstring(L, real);
170 return 1;
171 }
172 }
173
174 static int nixio_remove(lua_State *L) {
175 return nixio__pstatus(L, !remove(luaL_checkstring(L, 1)));
176 }
177
178 static int nixio_unlink(lua_State *L) {
179 return nixio__pstatus(L, !unlink(luaL_checkstring(L, 1)));
180 }
181
182 static int nixio_rename(lua_State *L) {
183 return nixio__pstatus(L,
184 !rename(luaL_checkstring(L, 1), luaL_checkstring(L, 2)));
185 }
186
187 static int nixio_rmdir(lua_State *L) {
188 return nixio__pstatus(L, !rmdir(luaL_checkstring(L, 1)));
189 }
190
191 static int nixio_mkdir(lua_State *L) {
192 return nixio__pstatus(L,
193 !mkdir(luaL_checkstring(L, 1), nixio__check_mode(L, 2, 0777)));
194 }
195
196 static int nixio_chmod(lua_State *L) {
197 return nixio__pstatus(L,
198 !chmod(luaL_checkstring(L, 1), nixio__check_mode(L, 2, -1)));
199 }
200
201 static int nixio_dir__gc(lua_State *L) {
202 DIR **dirp = lua_touserdata(L, 1);
203 if (dirp && *dirp) {
204 closedir(*dirp);
205 *dirp = NULL;
206 }
207 return 0;
208 }
209
210 static int nixio_dir__iter(lua_State *L) {
211 DIR **dirp = lua_touserdata(L, lua_upvalueindex(1));
212 struct dirent *entry;
213 const char *n = NULL;
214
215 if (*dirp) {
216 do {
217 entry = readdir(*dirp);
218 n = (entry) ? entry->d_name : NULL;
219 } while(n && n[0] == '.' && (n[1] == 0 || (n[1] == '.' && n[2] == 0)));
220 }
221
222 if (n) {
223 lua_pushstring(L, n);
224 } else {
225 if (*dirp) {
226 closedir(*dirp);
227 *dirp = NULL;
228 }
229 lua_pushnil(L);
230 }
231
232 return 1;
233 }
234
235 static int nixio_dir(lua_State *L) {
236 const char *path = luaL_optstring(L, 1, ".");
237 DIR **dirp = lua_newuserdata(L, sizeof(DIR *));
238
239 *dirp = opendir(path);
240 if (!*dirp) {
241 return nixio__perror(L);
242 } else {
243 luaL_getmetatable(L, NIXIO_DIR_META);
244 lua_setmetatable(L, -2);
245 lua_pushcclosure(L, nixio_dir__iter, 1);
246 return 1;
247 }
248 }
249
250 static int nixio_link(lua_State *L) {
251 return nixio__pstatus(L,
252 !link(luaL_checkstring(L, 1), luaL_checkstring(L, 2)));
253 }
254
255 static int nixio_utimes(lua_State *L) {
256 const char *path = luaL_checkstring(L, 1);
257 if (lua_gettop(L) < 2 || (lua_isnoneornil(L, 2) && lua_isnoneornil(L, 3))) {
258 return nixio__pstatus(L, !utimes(path, NULL));
259 } else {
260 double atime = nixio__checknumber(L, 2);
261 double mtime = nixio__optnumber(L, 3, atime);
262 struct timeval times[2];
263
264 times[0].tv_sec = atime;
265 times[0].tv_usec = 0;
266 times[1].tv_sec = mtime;
267 times[1].tv_usec = 0;
268
269 return nixio__pstatus(L, !utimes(path, times));
270 }
271 }
272
273 int nixio__push_stat(lua_State *L, nixio_stat_t *buf) {
274 lua_createtable(L, 0, 15);
275
276 lua_pushinteger(L, buf->st_dev);
277 lua_setfield(L, -2, "dev");
278
279 lua_pushinteger(L, buf->st_ino);
280 lua_setfield(L, -2, "ino");
281
282 if (S_ISREG(buf->st_mode)) {
283 lua_pushliteral(L, "reg");
284 } else if (S_ISDIR(buf->st_mode)) {
285 lua_pushliteral(L, "dir");
286 } else if (S_ISCHR(buf->st_mode)) {
287 lua_pushliteral(L, "chr");
288 } else if (S_ISBLK(buf->st_mode)) {
289 lua_pushliteral(L, "blk");
290 } else if (S_ISFIFO(buf->st_mode)) {
291 lua_pushliteral(L, "fifo");
292 } else if (S_ISLNK(buf->st_mode)) {
293 lua_pushliteral(L, "lnk");
294 } else if (S_ISSOCK(buf->st_mode)) {
295 lua_pushliteral(L, "sock");
296 } else {
297 lua_pushliteral(L, "unknown");
298 }
299 lua_setfield(L, -2, "type");
300
301 char modestr[9];
302 lua_pushinteger(L, nixio__mode_write(buf->st_mode, modestr));
303 lua_setfield(L, -2, "modedec");
304
305 lua_pushlstring(L, modestr, 9);
306 lua_setfield(L, -2, "modestr");
307
308 lua_pushinteger(L, buf->st_nlink);
309 lua_setfield(L, -2, "nlink");
310
311 lua_pushinteger(L, buf->st_uid);
312 lua_setfield(L, -2, "uid");
313
314 lua_pushinteger(L, buf->st_gid);
315 lua_setfield(L, -2, "gid");
316
317 lua_pushinteger(L, buf->st_rdev);
318 lua_setfield(L, -2, "rdev");
319
320 nixio__pushnumber(L, buf->st_size);
321 lua_setfield(L, -2, "size");
322
323 lua_pushinteger(L, buf->st_atime);
324 lua_setfield(L, -2, "atime");
325
326 lua_pushinteger(L, buf->st_mtime);
327 lua_setfield(L, -2, "mtime");
328
329 lua_pushinteger(L, buf->st_ctime);
330 lua_setfield(L, -2, "ctime");
331
332 #ifndef __WINNT__
333 lua_pushinteger(L, buf->st_blksize);
334 lua_setfield(L, -2, "blksize");
335
336 lua_pushinteger(L, buf->st_blocks);
337 lua_setfield(L, -2, "blocks");
338 #endif
339
340 return 1;
341 }
342
343 static int nixio_stat(lua_State *L) {
344 nixio_stat_t buf;
345 if (stat(luaL_checkstring(L, 1), &buf)) {
346 return nixio__perror(L);
347 } else {
348 nixio__push_stat(L, &buf);
349 if (lua_isstring(L, 2)) {
350 lua_getfield(L, -1, lua_tostring(L, 2));
351 }
352 return 1;
353 }
354 }
355
356 static int nixio_lstat(lua_State *L) {
357 nixio_stat_t buf;
358 if (stat(luaL_checkstring(L, 1), &buf)) {
359 return nixio__perror(L);
360 } else {
361 nixio__push_stat(L, &buf);
362 if (lua_isstring(L, 2)) {
363 lua_getfield(L, -1, lua_tostring(L, 2));
364 }
365 return 1;
366 }
367 }
368
369 #ifndef __WINNT__
370
371 static int nixio_chown(lua_State *L) {
372 return nixio__pstatus(L,
373 !chown(
374 luaL_checkstring(L, 1),
375 lua_isnoneornil(L, 2) ? -1 : nixio__check_user(L, 2),
376 lua_isnoneornil(L, 3) ? -1 : nixio__check_group(L, 3)
377 )
378 );
379 }
380
381 static int nixio_lchown(lua_State *L) {
382 return nixio__pstatus(L,
383 !lchown(
384 luaL_checkstring(L, 1),
385 lua_isnoneornil(L, 2) ? -1 : nixio__check_user(L, 2),
386 lua_isnoneornil(L, 3) ? -1 : nixio__check_group(L, 3)
387 )
388 );
389 }
390
391 static int nixio_mkfifo(lua_State *L) {
392 return nixio__pstatus(L,
393 !mkfifo(luaL_checkstring(L, 1), nixio__check_mode(L, 2, -1)));
394 }
395
396 static int nixio_symlink(lua_State *L) {
397 return nixio__pstatus(L,
398 !symlink(luaL_checkstring(L, 1), luaL_checkstring(L, 2)));
399 }
400
401 static int nixio_readlink(lua_State *L) {
402 char dest[PATH_MAX];
403 ssize_t res = readlink(luaL_checkstring(L, 1), dest, sizeof(dest));
404 if (res < 0) {
405 return nixio__perror(L);
406 } else {
407 lua_pushlstring(L, dest, res);
408 return 1;
409 }
410 }
411
412 #include <glob.h>
413
414 typedef struct {
415 glob_t gl;
416 size_t pos;
417 int freed;
418 } nixio_glob_t;
419
420 static int nixio_glob__iter(lua_State *L) {
421 nixio_glob_t *globres = lua_touserdata(L, lua_upvalueindex(1));
422 if (!globres->freed && globres->pos < globres->gl.gl_pathc) {
423 lua_pushstring(L, globres->gl.gl_pathv[(globres->pos)++]);
424 } else {
425 if (!globres->freed) {
426 globfree(&globres->gl);
427 globres->freed = 1;
428 }
429 lua_pushnil(L);
430 }
431 return 1;
432 }
433
434 static int nixio_glob__gc(lua_State *L) {
435 nixio_glob_t *globres = lua_touserdata(L, 1);
436 if (globres && !globres->freed) {
437 globres->freed = 1;
438 globfree(&globres->gl);
439 }
440 return 0;
441 }
442
443 static int nixio_glob(lua_State *L) {
444 const char *pattern = luaL_optstring(L, 1, "*");
445 nixio_glob_t *globres = lua_newuserdata(L, sizeof(nixio_glob_t));
446 if (!globres) {
447 return luaL_error(L, NIXIO_OOM);
448 }
449 globres->pos = 0;
450 globres->freed = 0;
451
452 int globstat = glob(pattern, 0, NULL, &globres->gl);
453 if (globstat == GLOB_NOMATCH) {
454 lua_pushcfunction(L, nixio__nulliter);
455 lua_pushinteger(L, 0);
456 } else if (globstat) {
457 return nixio__perror(L);
458 } else {
459 luaL_getmetatable(L, NIXIO_GLOB_META);
460 lua_setmetatable(L, -2);
461 lua_pushcclosure(L, nixio_glob__iter, 1);
462 lua_pushinteger(L, globres->gl.gl_pathc);
463 }
464 return 2;
465 }
466
467 #include <sys/statvfs.h>
468
469 static int nixio__push_statvfs(lua_State *L, struct statvfs *buf) {
470 lua_createtable(L, 0, 12);
471
472 nixio__pushnumber(L, buf->f_bavail);
473 lua_setfield(L, -2, "bavail");
474
475 nixio__pushnumber(L, buf->f_bfree);
476 lua_setfield(L, -2, "bfree");
477
478 nixio__pushnumber(L, buf->f_blocks);
479 lua_setfield(L, -2, "blocks");
480
481 nixio__pushnumber(L, buf->f_bsize);
482 lua_setfield(L, -2, "bsize");
483
484 nixio__pushnumber(L, buf->f_frsize);
485 lua_setfield(L, -2, "frsize");
486
487 nixio__pushnumber(L, buf->f_favail);
488 lua_setfield(L, -2, "favail");
489
490 nixio__pushnumber(L, buf->f_ffree);
491 lua_setfield(L, -2, "ffree");
492
493 nixio__pushnumber(L, buf->f_files);
494 lua_setfield(L, -2, "files");
495
496 nixio__pushnumber(L, buf->f_flag);
497 lua_setfield(L, -2, "flag");
498
499 nixio__pushnumber(L, buf->f_fsid);
500 lua_setfield(L, -2, "fsid");
501
502 nixio__pushnumber(L, buf->f_namemax);
503 lua_setfield(L, -2, "namemax");
504
505 return 1;
506 }
507
508 static int nixio_statvfs(lua_State *L) {
509 struct statvfs buf;
510 if (statvfs(luaL_optstring(L, 1, "."), &buf)) {
511 return nixio__perror(L);
512 } else {
513 return nixio__push_statvfs(L, &buf);
514 }
515 }
516
517 #endif /* !__WINNT__ */
518
519
520
521 /* module table */
522 static const luaL_reg R[] = {
523 #ifndef __WINNT__
524 {"glob", nixio_glob},
525 {"mkfifo", nixio_mkfifo},
526 {"symlink", nixio_symlink},
527 {"readlink", nixio_readlink},
528 {"chown", nixio_chown},
529 {"lchown", nixio_lchown},
530 {"statvfs", nixio_statvfs},
531 #endif
532 {"chmod", nixio_chmod},
533 {"access", nixio_access},
534 {"basename", nixio_basename},
535 {"dir", nixio_dir},
536 {"dirname", nixio_dirname},
537 {"realpath", nixio_realpath},
538 {"mkdir", nixio_mkdir},
539 {"rmdir", nixio_rmdir},
540 {"link", nixio_link},
541 {"unlink", nixio_unlink},
542 {"utimes", nixio_utimes},
543 {"rename", nixio_rename},
544 {"remove", nixio_remove},
545 {"stat", nixio_stat},
546 {"lstat", nixio_lstat},
547 {NULL, NULL}
548 };
549
550 void nixio_open_fs(lua_State *L) {
551 lua_newtable(L);
552 luaL_register(L, NULL, R);
553 lua_setfield(L, -2, "fs");
554
555 luaL_newmetatable(L, NIXIO_DIR_META);
556 lua_pushcfunction(L, nixio_dir__gc);
557 lua_setfield(L, -2, "__gc");
558 lua_pop(L, 1);
559
560 #ifndef __WINNT__
561 luaL_newmetatable(L, NIXIO_GLOB_META);
562 lua_pushcfunction(L, nixio_glob__gc);
563 lua_setfield(L, -2, "__gc");
564 lua_pop(L, 1);
565 #endif
566 }