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
This commit is contained in:
Kyle Evans 2018-02-24 02:57:24 +00:00
parent 061577c5fe
commit 82c85a42b4
4 changed files with 110 additions and 7 deletions

View File

@ -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)
{

View File

@ -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);

View File

@ -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

View File

@ -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);