diff options
Diffstat (limited to 'libs/luci-lib-nixio/src/file.c')
-rw-r--r-- | libs/luci-lib-nixio/src/file.c | 402 |
1 files changed, 402 insertions, 0 deletions
diff --git a/libs/luci-lib-nixio/src/file.c b/libs/luci-lib-nixio/src/file.c new file mode 100644 index 000000000..b86e040e1 --- /dev/null +++ b/libs/luci-lib-nixio/src/file.c @@ -0,0 +1,402 @@ +/* + * nixio - Linux I/O library for lua + * + * Copyright (C) 2009 Steven Barth <steven@midlink.org> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "nixio.h" +#include <errno.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include <fcntl.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/param.h> + + +static int nixio_open(lua_State *L) { + const char *filename = luaL_checklstring(L, 1, NULL); + int flags; + + if (lua_isnoneornil(L, 2)) { + flags = O_RDONLY; + } else if (lua_isnumber(L, 2)) { + flags = lua_tointeger(L, 2); + } else if (lua_isstring(L, 2)) { + const char *str = lua_tostring(L, 2); + if (!strcmp(str, "r")) { + flags = O_RDONLY; + } else if (!strcmp(str, "r+")) { + flags = O_RDWR; + } else if (!strcmp(str, "w")) { + flags = O_WRONLY | O_CREAT | O_TRUNC; + } else if (!strcmp(str, "w+")) { + flags = O_RDWR | O_CREAT | O_TRUNC; + } else if (!strcmp(str, "a")) { + flags = O_WRONLY | O_CREAT | O_APPEND; + } else if (!strcmp(str, "a+")) { + flags = O_RDWR | O_CREAT | O_APPEND; + } else { + return luaL_argerror(L, 2, "supported values: r, r+, w, w+, a, a+"); + } + } else { + return luaL_argerror(L, 2, "open flags or string expected"); + } + + int fd; + + do { + fd = open(filename, flags, nixio__check_mode(L, 3, 0666)); + } while (fd == -1 && errno == EINTR); + if (fd == -1) { + return nixio__perror(L); + } + + int *udata = lua_newuserdata(L, sizeof(int)); + if (!udata) { + return luaL_error(L, "out of memory"); + } + + *udata = fd; + + luaL_getmetatable(L, NIXIO_FILE_META); + lua_setmetatable(L, -2); + + return 1; +} + +static int nixio_open_flags(lua_State *L) { + int mode = 0; + const int j = lua_gettop(L); + for (int i=1; i<=j; i++) { + const char *flag = luaL_checkstring(L, i); + if (!strcmp(flag, "append")) { + mode |= O_APPEND; + } else if (!strcmp(flag, "creat")) { + mode |= O_CREAT; + } else if (!strcmp(flag, "excl")) { + mode |= O_EXCL; + } else if (!strcmp(flag, "nonblock") || !strcmp(flag, "ndelay")) { +#ifndef __WINNT__ + mode |= O_NONBLOCK; +#endif + } else if (!strcmp(flag, "sync")) { +#ifndef __WINNT__ + mode |= O_SYNC; +#endif + } else if (!strcmp(flag, "trunc")) { + mode |= O_TRUNC; + } else if (!strcmp(flag, "rdonly")) { + mode |= O_RDONLY; + } else if (!strcmp(flag, "wronly")) { + mode |= O_WRONLY; + } else if (!strcmp(flag, "rdwr")) { + mode |= O_RDWR; + } else { + return luaL_argerror(L, i, "supported values: append, creat, " + "excl, nonblock, ndelay, sync, trunc"); + } + } + lua_pushinteger(L, mode); + return 1; +} + +static int nixio_dup(lua_State *L) { + int oldfd = nixio__checkfd(L, 1); + int newfd = (lua_gettop(L) > 1) ? nixio__checkfd(L, 2) : -1; + int stat = (newfd == -1) ? dup(oldfd) : dup2(oldfd, newfd); + + if (stat == -1) { + return nixio__perror(L); + } else { + if (newfd == -1) { + int *udata = lua_newuserdata(L, sizeof(int)); + if (!udata) { + return luaL_error(L, "out of memory"); + } + + *udata = stat; + luaL_getmetatable(L, NIXIO_FILE_META); + lua_setmetatable(L, -2); + } else { + lua_pushvalue(L, 2); + } + return 1; + } +} + +static int nixio_pipe(lua_State *L) { + int pipefd[2], *udata; + if (pipe(pipefd)) { + return nixio__perror(L); + } + + luaL_getmetatable(L, NIXIO_FILE_META); + udata = lua_newuserdata(L, sizeof(int)); + if (!udata) { + return luaL_error(L, "out of memory"); + } + + *udata = pipefd[0]; + lua_pushvalue(L, -2); + lua_setmetatable(L, -2); + + + udata = lua_newuserdata(L, sizeof(int)); + if (!udata) { + return luaL_error(L, "out of memory"); + } + + *udata = pipefd[1]; + lua_pushvalue(L, -3); + lua_setmetatable(L, -2); + + return 2; +} + +static int nixio_file_write(lua_State *L) { + int fd = nixio__checkfd(L, 1); + size_t len; + ssize_t sent; + const char *data = luaL_checklstring(L, 2, &len); + + if (lua_gettop(L) > 2) { + int offset = luaL_optint(L, 3, 0); + if (offset) { + if (offset < len) { + data += offset; + len -= offset; + } else { + len = 0; + } + } + + unsigned int wlen = luaL_optint(L, 4, len); + if (wlen < len) { + len = wlen; + } + } + + do { + sent = write(fd, data, len); + } while(sent == -1 && errno == EINTR); + if (sent >= 0) { + lua_pushinteger(L, sent); + return 1; + } else { + return nixio__perror(L); + } +} + +static int nixio_file_read(lua_State *L) { + int fd = nixio__checkfd(L, 1); + char buffer[NIXIO_BUFFERSIZE]; + uint req = luaL_checkinteger(L, 2); + int readc; + + /* We limit the readsize to NIXIO_BUFFERSIZE */ + req = (req > NIXIO_BUFFERSIZE) ? NIXIO_BUFFERSIZE : req; + + do { + readc = read(fd, buffer, req); + } while (readc == -1 && errno == EINTR); + + if (readc < 0) { + return nixio__perror(L); + } else { + lua_pushlstring(L, buffer, readc); + return 1; + } +} + + +static int nixio_file_seek(lua_State *L) { + int fd = nixio__checkfd(L, 1); + off_t len = (off_t)nixio__checknumber(L, 2); + int whence; + const char *whstr = luaL_optlstring(L, 3, "set", NULL); + if (!strcmp(whstr, "set")) { + whence = SEEK_SET; + } else if (!strcmp(whstr, "cur")) { + whence = SEEK_CUR; + } else if (!strcmp(whstr, "end")) { + whence = SEEK_END; + } else { + return luaL_argerror(L, 3, "supported values: set, cur, end"); + } + len = lseek(fd, len, whence); + if (len == -1) { + return nixio__perror(L); + } else { + nixio__pushnumber(L, len); + return 1; + } +} + +static int nixio_file_tell(lua_State *L) { + int fd = nixio__checkfd(L, 1); + off_t pos = lseek(fd, 0, SEEK_CUR); + if (pos < 0) { + return nixio__perror(L); + } else { + nixio__pushnumber(L, pos); + return 1; + } +} + +static int nixio_file_stat(lua_State *L) { + nixio_stat_t buf; + if (fstat(nixio__checkfd(L, 1), &buf)) { + return nixio__perror(L); + } else { + nixio__push_stat(L, &buf); + if (lua_isstring(L, 2)) { + lua_getfield(L, -1, lua_tostring(L, 2)); + } + return 1; + } +} + +static int nixio_file_sync(lua_State *L) { + int fd = nixio__checkfd(L, 1); + int stat; +#if (!defined BSD && !defined __WINNT__) + int dataonly = lua_toboolean(L, 2); + do { + stat = (dataonly) ? fdatasync(fd) : fsync(fd); + } while (stat == -1 && errno == EINTR); + return nixio__pstatus(L, !stat); +#else + do { + stat = fsync(fd); + } while (stat == -1 && errno == EINTR); + return nixio__pstatus(L, !stat); +#endif +} + +static int nixio_file_lock(lua_State *L) { + int fd = nixio__checkfd(L, 1); + const char *flag = luaL_checkstring(L, 2); + off_t len = (off_t)nixio__optnumber(L, 3, 0); + int stat; + + int cmd = 0; + if (!strcmp(flag, "lock")) { + cmd = F_LOCK; + } else if (!strcmp(flag, "tlock")) { + cmd = F_TLOCK; + } else if (!strcmp(flag, "ulock")) { + cmd = F_ULOCK; + } else if (!strcmp(flag, "test")) { + cmd = F_TEST; + } else { + return luaL_argerror(L, 2, + "supported values: lock, tlock, ulock, test"); + } + + do { + stat = lockf(fd, cmd, len); + } while (stat == -1 && errno == EINTR); + + return nixio__pstatus(L, !stat); +} + +static int nixio_file_close(lua_State *L) { + int *fdp = luaL_checkudata(L, 1, NIXIO_FILE_META); + luaL_argcheck(L, *fdp != -1, 1, "invalid file object"); + int res; + do { + res = close(*fdp); + } while (res == -1 && errno == EINTR); + *fdp = -1; + return nixio__pstatus(L, !res); +} + +static int nixio_file__gc(lua_State *L) { + int *fdp = luaL_checkudata(L, 1, NIXIO_FILE_META); + int res; + if (*fdp > 2) { + do { + res = close(*fdp); + } while (res == -1 && errno == EINTR); + *fdp = -1; + } + return 0; +} + +/** + * string representation + */ +static int nixio_file__tostring(lua_State *L) { + lua_pushfstring(L, "nixio file %d", nixio__tofd(L, 1)); + return 1; +} + +/* method table */ +static const luaL_reg M[] = { + {"write", nixio_file_write}, + {"read", nixio_file_read}, + {"tell", nixio_file_tell}, + {"seek", nixio_file_seek}, + {"stat", nixio_file_stat}, + {"sync", nixio_file_sync}, + {"lock", nixio_file_lock}, + {"close", nixio_file_close}, + {"__gc", nixio_file__gc}, + {"__tostring", nixio_file__tostring}, + {NULL, NULL} +}; + +/* module table */ +static const luaL_reg R[] = { + {"dup", nixio_dup}, + {"open", nixio_open}, + {"open_flags", nixio_open_flags}, + {"pipe", nixio_pipe}, + {NULL, NULL} +}; + +void nixio_open_file(lua_State *L) { + luaL_register(L, NULL, R); + + luaL_newmetatable(L, NIXIO_FILE_META); + luaL_register(L, NULL, M); + lua_pushvalue(L, -1); + lua_setfield(L, -2, "__index"); + + int *uin = lua_newuserdata(L, sizeof(int)); + int *uout = lua_newuserdata(L, sizeof(int)); + int *uerr = lua_newuserdata(L, sizeof(int)); + + if (!uin || !uout || !uerr) { + luaL_error(L, "out of memory"); + } + + *uin = STDIN_FILENO; + *uout = STDOUT_FILENO; + *uerr = STDERR_FILENO; + + for (int i = -4; i < -1; i++) { + lua_pushvalue(L, -4); + lua_setmetatable(L, i); + } + + lua_setfield(L, -5, "stderr"); + lua_setfield(L, -4, "stdout"); + lua_setfield(L, -3, "stdin"); + lua_setfield(L, -2, "meta_file"); +} |