root/luci/branches/luci-0.9/libs/nixio/src/fs.c @ 4891

Revision 4891, 13.3 KB (checked in by jow, 4 years ago)

luci-0.9: merge r4886-r4890

Line 
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 */
31int 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 */
103int 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
123static 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
142static 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
152static 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
162static 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
174static int nixio_remove(lua_State *L) {
175    return nixio__pstatus(L, !remove(luaL_checkstring(L, 1)));
176}
177
178static int nixio_unlink(lua_State *L) {
179    return nixio__pstatus(L, !unlink(luaL_checkstring(L, 1)));
180}
181
182static int nixio_rename(lua_State *L) {
183    return nixio__pstatus(L,
184            !rename(luaL_checkstring(L, 1), luaL_checkstring(L, 2)));
185}
186
187static int nixio_rmdir(lua_State *L) {
188    return nixio__pstatus(L, !rmdir(luaL_checkstring(L, 1)));
189}
190
191static 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
196static 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
201static 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
210static 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
235static 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
250static int nixio_link(lua_State *L) {
251    return nixio__pstatus(L,
252            !link(luaL_checkstring(L, 1), luaL_checkstring(L, 2)));
253}
254
255static 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 = luaL_checknumber(L, 2);
261        double mtime = luaL_optnumber(L, 3, atime);
262        struct timeval times[2];
263
264        times[0].tv_sec = atime;
265        times[0].tv_usec = (long)((atime - (int64_t)atime) * 1000000);
266        times[1].tv_sec = mtime;
267        times[1].tv_usec = (long)((mtime - (int64_t)mtime) * 1000000);
268
269        return nixio__pstatus(L, !utimes(path, times));
270    }
271}
272
273int 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    lua_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
343static 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
356static 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
371static 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
381static 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
391static 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
396static int nixio_symlink(lua_State *L) {
397    return nixio__pstatus(L,
398            !symlink(luaL_checkstring(L, 1), luaL_checkstring(L, 2)));
399}
400
401static 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
414typedef struct {
415    glob_t gl;
416    size_t pos;
417    int freed;
418} nixio_glob_t;
419
420static 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
434static 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
443static 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
469static int nixio__push_statvfs(lua_State *L, struct statvfs *buf) {
470    lua_createtable(L, 0, 12);
471
472    lua_pushnumber(L, buf->f_bavail);
473    lua_setfield(L, -2, "bavail");
474
475    lua_pushnumber(L, buf->f_bfree);
476    lua_setfield(L, -2, "bfree");
477
478    lua_pushnumber(L, buf->f_blocks);
479    lua_setfield(L, -2, "blocks");
480
481    lua_pushnumber(L, buf->f_bsize);
482    lua_setfield(L, -2, "bsize");
483
484    lua_pushnumber(L, buf->f_frsize);
485    lua_setfield(L, -2, "frsize");
486
487    lua_pushnumber(L, buf->f_favail);
488    lua_setfield(L, -2, "favail");
489
490    lua_pushnumber(L, buf->f_ffree);
491    lua_setfield(L, -2, "ffree");
492
493    lua_pushnumber(L, buf->f_files);
494    lua_setfield(L, -2, "files");
495
496    lua_pushnumber(L, buf->f_flag);
497    lua_setfield(L, -2, "flag");
498
499    lua_pushnumber(L, buf->f_fsid);
500    lua_setfield(L, -2, "fsid");
501
502    lua_pushnumber(L, buf->f_namemax);
503    lua_setfield(L, -2, "namemax");
504
505    return 1;
506}
507
508static 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 */
522static 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
550void 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}
Note: See TracBrowser for help on using the browser.