2 * nixio - Linux I/O library for lua
4 * Copyright (C) 2009 Steven Barth <steven@midlink.org>
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
10 * http://www.apache.org/licenses/LICENSE-2.0
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.
26 #include <sys/types.h>
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) {
34 } else if (lua_isstring(L, idx) && lua_objlen(L, idx) == 9) {
36 const char *modestr = lua_tostring(L, idx);
39 if (i % 3 == 0) { /* read flags */
40 if (modestr[i] == 'r') {
42 } else if (modestr[i] != '-') {
45 } else if (i % 3 == 1) { /* write flags */
46 if (modestr[i] == 'w') {
48 } else if (modestr[i] != '-') {
52 if (modestr[i] == 'x') {
54 } else if (modestr[i] == 's') {
56 } else if (modestr[i] == 'S') {
58 } else if (modestr[i] != '-') {
62 if (modestr[i] == 'x') {
64 } else if (modestr[i] == 's') {
66 } else if (modestr[i] == 'S') {
68 } else if (modestr[i] != '-') {
72 if (modestr[i] == 'x') {
74 } else if (modestr[i] == 't') {
76 } else if (modestr[i] == 'T') {
78 } else if (modestr[i] != '-') {
83 if (i == 9) { /* successfully parsed */
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);
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;
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]");
102 /* Transforms a mode into the modestring */
103 int nixio__mode_write(int mode, char *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' : '-';
119 return (mode & 00007) + ((mode & 00070) >> 3) * 10 +
120 ((mode & 00700) >> 6) * 100 + ((mode & 07000) >> 9) * 1000;
123 static int nixio_access(lua_State *L) {
124 const char *path = luaL_checkstring(L, 1);
127 for (const char *s = luaL_optstring(L, 2, "f"); *s; s++) {
130 } else if (*s == 'w') {
132 } else if (*s == 'x') {
134 } else if (*s != 'f') {
135 return luaL_argerror(L, 2, "supported values: [frwx]");
139 return nixio__pstatus(L, !access(path, mode));
142 static int nixio_basename(lua_State *L) {
143 const char *path = luaL_checkstring(L, 1);
145 base[PATH_MAX-1] = 0;
147 strncpy(base, path, PATH_MAX-1);
148 lua_pushstring(L, basename(base));
152 static int nixio_dirname(lua_State *L) {
153 const char *path = luaL_checkstring(L, 1);
155 base[PATH_MAX-1] = 0;
157 strncpy(base, path, PATH_MAX-1);
158 lua_pushstring(L, dirname(base));
162 static int nixio_realpath(lua_State *L) {
163 const char *path = luaL_checkstring(L, 1);
166 if (!realpath(path, real)) {
167 return nixio__perror(L);
169 lua_pushstring(L, real);
174 static int nixio_remove(lua_State *L) {
175 return nixio__pstatus(L, !remove(luaL_checkstring(L, 1)));
178 static int nixio_unlink(lua_State *L) {
179 return nixio__pstatus(L, !unlink(luaL_checkstring(L, 1)));
182 static int nixio_rename(lua_State *L) {
183 return nixio__pstatus(L,
184 !rename(luaL_checkstring(L, 1), luaL_checkstring(L, 2)));
187 static int nixio_rmdir(lua_State *L) {
188 return nixio__pstatus(L, !rmdir(luaL_checkstring(L, 1)));
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)));
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)));
201 static int nixio_dir__gc(lua_State *L) {
202 DIR **dirp = lua_touserdata(L, 1);
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;
217 entry = readdir(*dirp);
218 n = (entry) ? entry->d_name : NULL;
219 } while(n && n[0] == '.' && (n[1] == 0 || (n[1] == '.' && n[2] == 0)));
223 lua_pushstring(L, n);
235 static int nixio_dir(lua_State *L) {
236 const char *path = luaL_optstring(L, 1, ".");
237 DIR **dirp = lua_newuserdata(L, sizeof(DIR *));
239 *dirp = opendir(path);
241 return nixio__perror(L);
243 luaL_getmetatable(L, NIXIO_DIR_META);
244 lua_setmetatable(L, -2);
245 lua_pushcclosure(L, nixio_dir__iter, 1);
250 static int nixio_link(lua_State *L) {
251 return nixio__pstatus(L,
252 !link(luaL_checkstring(L, 1), luaL_checkstring(L, 2)));
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));
260 double atime = nixio__checknumber(L, 2);
261 double mtime = nixio__optnumber(L, 3, atime);
262 struct timeval times[2];
264 times[0].tv_sec = atime;
265 times[0].tv_usec = 0;
266 times[1].tv_sec = mtime;
267 times[1].tv_usec = 0;
269 return nixio__pstatus(L, !utimes(path, times));
273 int nixio__push_stat(lua_State *L, nixio_stat_t *buf) {
274 lua_createtable(L, 0, 15);
276 lua_pushinteger(L, buf->st_dev);
277 lua_setfield(L, -2, "dev");
279 lua_pushinteger(L, buf->st_ino);
280 lua_setfield(L, -2, "ino");
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");
297 lua_pushliteral(L, "unknown");
299 lua_setfield(L, -2, "type");
302 lua_pushinteger(L, nixio__mode_write(buf->st_mode, modestr));
303 lua_setfield(L, -2, "modedec");
305 lua_pushlstring(L, modestr, 9);
306 lua_setfield(L, -2, "modestr");
308 lua_pushinteger(L, buf->st_nlink);
309 lua_setfield(L, -2, "nlink");
311 lua_pushinteger(L, buf->st_uid);
312 lua_setfield(L, -2, "uid");
314 lua_pushinteger(L, buf->st_gid);
315 lua_setfield(L, -2, "gid");
317 lua_pushinteger(L, buf->st_rdev);
318 lua_setfield(L, -2, "rdev");
320 nixio__pushnumber(L, buf->st_size);
321 lua_setfield(L, -2, "size");
323 lua_pushinteger(L, buf->st_atime);
324 lua_setfield(L, -2, "atime");
326 lua_pushinteger(L, buf->st_mtime);
327 lua_setfield(L, -2, "mtime");
329 lua_pushinteger(L, buf->st_ctime);
330 lua_setfield(L, -2, "ctime");
333 lua_pushinteger(L, buf->st_blksize);
334 lua_setfield(L, -2, "blksize");
336 lua_pushinteger(L, buf->st_blocks);
337 lua_setfield(L, -2, "blocks");
343 static int nixio_stat(lua_State *L) {
345 if (stat(luaL_checkstring(L, 1), &buf)) {
346 return nixio__perror(L);
348 nixio__push_stat(L, &buf);
349 if (lua_isstring(L, 2)) {
350 lua_getfield(L, -1, lua_tostring(L, 2));
356 static int nixio_lstat(lua_State *L) {
358 if (stat(luaL_checkstring(L, 1), &buf)) {
359 return nixio__perror(L);
361 nixio__push_stat(L, &buf);
362 if (lua_isstring(L, 2)) {
363 lua_getfield(L, -1, lua_tostring(L, 2));
371 static int nixio_chown(lua_State *L) {
372 return nixio__pstatus(L,
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)
381 static int nixio_lchown(lua_State *L) {
382 return nixio__pstatus(L,
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)
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)));
396 static int nixio_symlink(lua_State *L) {
397 return nixio__pstatus(L,
398 !symlink(luaL_checkstring(L, 1), luaL_checkstring(L, 2)));
401 static int nixio_readlink(lua_State *L) {
403 ssize_t res = readlink(luaL_checkstring(L, 1), dest, sizeof(dest));
405 return nixio__perror(L);
407 lua_pushlstring(L, dest, res);
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)++]);
425 if (!globres->freed) {
426 globfree(&globres->gl);
434 static int nixio_glob__gc(lua_State *L) {
435 nixio_glob_t *globres = lua_touserdata(L, 1);
436 if (globres && !globres->freed) {
438 globfree(&globres->gl);
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));
447 return luaL_error(L, NIXIO_OOM);
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);
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);
467 #include <sys/statvfs.h>
469 static int nixio__push_statvfs(lua_State *L, struct statvfs *buf) {
470 lua_createtable(L, 0, 12);
472 nixio__pushnumber(L, buf->f_bavail);
473 lua_setfield(L, -2, "bavail");
475 nixio__pushnumber(L, buf->f_bfree);
476 lua_setfield(L, -2, "bfree");
478 nixio__pushnumber(L, buf->f_blocks);
479 lua_setfield(L, -2, "blocks");
481 nixio__pushnumber(L, buf->f_bsize);
482 lua_setfield(L, -2, "bsize");
484 nixio__pushnumber(L, buf->f_frsize);
485 lua_setfield(L, -2, "frsize");
487 nixio__pushnumber(L, buf->f_favail);
488 lua_setfield(L, -2, "favail");
490 nixio__pushnumber(L, buf->f_ffree);
491 lua_setfield(L, -2, "ffree");
493 nixio__pushnumber(L, buf->f_files);
494 lua_setfield(L, -2, "files");
496 nixio__pushnumber(L, buf->f_flag);
497 lua_setfield(L, -2, "flag");
499 nixio__pushnumber(L, buf->f_fsid);
500 lua_setfield(L, -2, "fsid");
502 nixio__pushnumber(L, buf->f_namemax);
503 lua_setfield(L, -2, "namemax");
508 static int nixio_statvfs(lua_State *L) {
510 if (statvfs(luaL_optstring(L, 1, "."), &buf)) {
511 return nixio__perror(L);
513 return nixio__push_statvfs(L, &buf);
517 #endif /* !__WINNT__ */
522 static const luaL_reg R[] = {
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},
532 {"chmod", nixio_chmod},
533 {"access", nixio_access},
534 {"basename", nixio_basename},
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},
550 void nixio_open_fs(lua_State *L) {
552 luaL_register(L, NULL, R);
553 lua_setfield(L, -2, "fs");
555 luaL_newmetatable(L, NIXIO_DIR_META);
556 lua_pushcfunction(L, nixio_dir__gc);
557 lua_setfield(L, -2, "__gc");
561 luaL_newmetatable(L, NIXIO_GLOB_META);
562 lua_pushcfunction(L, nixio_glob__gc);
563 lua_setfield(L, -2, "__gc");