From 82c85a42b49a243a51ecc03d3afa6dbd294e0b25 Mon Sep 17 00:00:00 2001 From: Kyle Evans Date: Sat, 24 Feb 2018 02:57:24 +0000 Subject: [PATCH] liblua: Implement write support Write support (even if it only works on UFS) will be needed for nextboot functionality. Reviewed by: cem, imp Differential Revision: https://reviews.freebsd.org/D14478 --- stand/liblua/lstd.c | 40 ++++++++++++++++++++++-- stand/liblua/lstd.h | 1 + stand/liblua/lutils.c | 73 ++++++++++++++++++++++++++++++++++++++++--- stand/libsa/stand.h | 3 ++ 4 files changed, 110 insertions(+), 7 deletions(-) diff --git a/stand/liblua/lstd.c b/stand/liblua/lstd.c index b00abf203562..c71232ee1024 100644 --- a/stand/liblua/lstd.c +++ b/stand/liblua/lstd.c @@ -35,13 +35,32 @@ FILE * fopen(const char *filename, const char *mode) { struct stat st; - int fd; + int fd, m, o; FILE *f; - if (mode == NULL || mode[0] != 'r') + if (mode == NULL) return NULL; - fd = open(filename, O_RDONLY); + switch (*mode++) { + case 'r': /* open for reading */ + m = O_RDONLY; + o = 0; + break; + + case 'w': /* open for writing */ + m = O_WRONLY; + /* These are not actually implemented yet */ + o = O_CREAT | O_TRUNC; + break; + + default: /* illegal mode */ + return (NULL); + } + + if (*mode == '+') + m = O_RDWR; + + fd = open(filename, m | o); if (fd < 0) return NULL; @@ -85,6 +104,21 @@ fread(void *ptr, size_t size, size_t count, FILE *stream) return (r); } +size_t +fwrite(const void *ptr, size_t size, size_t count, FILE *stream) +{ + ssize_t w; + + if (stream == NULL || ptr == NULL) + return (0); + w = write(stream->fd, ptr, size * count); + if (w == -1) + return (0); + + stream->offset += w; + return ((size_t)w); +} + int fclose(FILE *stream) { diff --git a/stand/liblua/lstd.h b/stand/liblua/lstd.h index 5e47cff1d0c1..6f9eec2b40b9 100644 --- a/stand/liblua/lstd.h +++ b/stand/liblua/lstd.h @@ -51,6 +51,7 @@ typedef struct DIR FILE *fopen(const char *filename, const char *mode); FILE *freopen( const char *filename, const char *mode, FILE *stream); size_t fread(void *ptr, size_t size, size_t count, FILE *stream); +size_t fwrite(const void *ptr, size_t size, size_t count, FILE *stream); int fclose(FILE *stream); int ferror(FILE *stream); int feof(FILE *stream); diff --git a/stand/liblua/lutils.c b/stand/liblua/lutils.c index 3b30520d92b8..38392b039688 100644 --- a/stand/liblua/lutils.c +++ b/stand/liblua/lutils.c @@ -165,15 +165,24 @@ lua_printc(lua_State *L) static int lua_openfile(lua_State *L) { - const char *str; + const char *mode, *str; + int nargs; - if (lua_gettop(L) != 1) { + nargs = lua_gettop(L); + if (nargs < 1 || nargs > 2) { lua_pushnil(L); return 1; } str = lua_tostring(L, 1); - - FILE * f = fopen(str, "r"); + mode = "r"; + if (nargs > 1) { + mode = lua_tostring(L, 2); + if (mode == NULL) { + lua_pushnil(L); + return 1; + } + } + FILE * f = fopen(str, mode); if (f != NULL) { FILE ** ptr = (FILE**)lua_newuserdata(L, sizeof(FILE**)); *ptr = f; @@ -237,6 +246,61 @@ lua_readfile(lua_State *L) return 2; } +/* + * Implements io.write(file, ...) + * Any number of string and number arguments may be passed to it, + * and it will return the number of bytes written, or nil, an error string, and + * the errno. + */ +static int +lua_writefile(lua_State *L) +{ + FILE **f; + const char *buf; + int i, nargs; + size_t bufsz, w, wrsz; + + buf = NULL; + bufsz = 0; + w = 0; + wrsz = 0; + nargs = lua_gettop(L); + if (nargs < 2) { + errno = EINVAL; + return luaL_fileresult(L, 0, NULL); + } + + f = (FILE**)lua_touserdata(L, 1); + + if (f == NULL || *f == NULL) { + errno = EINVAL; + return luaL_fileresult(L, 0, NULL); + } + + /* Do a validation pass first */ + for (i = 0; i < nargs - 1; i++) { + /* + * With Lua's API, lua_isstring really checks if the argument + * is a string or a number. The latter will be implicitly + * converted to a string by our later call to lua_tolstring. + */ + if (!lua_isstring(L, i + 2)) { + errno = EINVAL; + return luaL_fileresult(L, 0, NULL); + } + } + for (i = 0; i < nargs - 1; i++) { + /* We've already validated; there's no chance of failure */ + buf = lua_tolstring(L, i + 2, &bufsz); + wrsz = fwrite(buf, 1, bufsz, *f); + if (wrsz < bufsz) + return luaL_fileresult(L, 0, NULL); + w += wrsz; + } + lua_pushinteger(L, w); + return 1; +} + #define REG_SIMPLE(n) { #n, lua_ ## n } static const struct luaL_Reg loaderlib[] = { REG_SIMPLE(delay), @@ -257,6 +321,7 @@ static const struct luaL_Reg iolib[] = { REG_SIMPLE(ischar), { "open", lua_openfile }, { "read", lua_readfile }, + { "write", lua_writefile }, { NULL, NULL }, }; #undef REG_SIMPLE diff --git a/stand/libsa/stand.h b/stand/libsa/stand.h index 614eaa65f67f..677aff5a1fdb 100644 --- a/stand/libsa/stand.h +++ b/stand/libsa/stand.h @@ -286,6 +286,9 @@ extern int open(const char *, int); #define O_RDONLY 0x0 #define O_WRONLY 0x1 #define O_RDWR 0x2 +/* NOT IMPLEMENTED */ +#define O_CREAT 0x0200 /* create if nonexistent */ +#define O_TRUNC 0x0400 /* truncate to zero length */ extern int close(int); extern void closeall(void); extern ssize_t read(int, void *, size_t);