Message ID | 20171103123009.18705-8-christian.storm@siemens.com |
---|---|
State | Accepted |
Headers | show |
Series | [01/11] Lua: expose get_tmpdir() to Lua | expand |
On 03/11/2017 13:30, Christian Storm wrote: > For C handlers, there's core/cpio_util.c's copyfile() as > a general method to extract data from the input stream and > copy it to somewhere. image:read(<callback()>) is the > analogous function exposed to Lua that reads from the input > stream and calls the callback Lua function <callback()> for > every chunk read, passing this chunk as parameter. > > Signed-off-by: Christian Storm <christian.storm@siemens.com> > --- > corelib/lua_compat.c | 39 ++++++++++++++++++++++++++ > corelib/lua_interface.c | 73 +++++++++++++++++++++++++++++++++++++++++++++++++ > include/lua_util.h | 21 ++++++++++++++ > 3 files changed, 133 insertions(+) > > diff --git a/corelib/lua_compat.c b/corelib/lua_compat.c > index 6204e8d..317f353 100644 > --- a/corelib/lua_compat.c > +++ b/corelib/lua_compat.c > @@ -25,6 +25,45 @@ > * https://github.com/keplerproject/lua-compat-5.2 > */ > #if !defined(LUA_VERSION_NUM) || LUA_VERSION_NUM == 501 > +char *luaL_prepbuffsize(luaL_Buffer_52 *B, size_t s) > +{ > + if (B->capacity - B->nelems < s) { /* needs to grow */ > + char* newptr = NULL; > + size_t newcap = B->capacity * 2; > + if (newcap - B->nelems < s) > + newcap = B->nelems + s; > + if (newcap < B->capacity) /* overflow */ > + luaL_error(B->L2, "buffer too large"); > + newptr = lua_newuserdata(B->L2, newcap); > + memcpy(newptr, B->ptr, B->nelems); > + if (B->ptr != B->b.buffer) > + lua_replace(B->L2, -2); /* remove old buffer */ > + B->ptr = newptr; > + B->capacity = newcap; > + } > + return B->ptr+B->nelems; > +} > + > +void luaL_buffinit(lua_State *L, luaL_Buffer_52 *B) > +{ > + /* make it crash if used via pointer to a 5.1-style luaL_Buffer */ > + B->b.p = NULL; > + B->b.L = NULL; > + B->b.lvl = 0; > + /* reuse the buffer from the 5.1-style luaL_Buffer though! */ > + B->ptr = B->b.buffer; > + B->capacity = LUAL_BUFFERSIZE; > + B->nelems = 0; > + B->L2 = L; > +} > + > +void luaL_pushresult(luaL_Buffer_52 *B) > +{ > + lua_pushlstring(B->L2, B->ptr, B->nelems); > + if (B->ptr != B->b.buffer) > + lua_replace(B->L2, -2); /* remove userdata buffer */ > +} > + > void luaL_setfuncs(lua_State *L, const luaL_Reg *l, int nup) > { > luaL_checkstack(L, nup+1, "too many upvalues"); > diff --git a/corelib/lua_interface.c b/corelib/lua_interface.c > index a551cde..7bb58ec 100644 > --- a/corelib/lua_interface.c > +++ b/corelib/lua_interface.c > @@ -321,6 +321,75 @@ copyfile_exit: > close(fdout); > return 2; > } > + > +static int istream_read_callback(void *out, const void *buf, unsigned int len) > +{ > + lua_State* L = (lua_State*)out; > + if (len > LUAL_BUFFERSIZE) { > + ERROR("I/O buffer size is larger than Lua's buffer size %d", LUAL_BUFFERSIZE); > + return -1; > + } > + > + luaL_checktype(L, 2, LUA_TFUNCTION); > + lua_pushvalue(L, 2); > + > + luaL_Buffer lbuffer; > + luaL_buffinit(L, &lbuffer); > + char *buffer = luaL_prepbuffsize(&lbuffer, len); > + memcpy(buffer, buf, len); > + luaL_addsize(&lbuffer, len); > + luaL_pushresult(&lbuffer); > + if (lua_pcall(L, 1, 0, 0) != LUA_OK) { > + ERROR("Lua error in callback: %s", lua_tostring(L, -1)); > + lua_pop(L, 1); > + return -1; > + } > + return 0; > +} > + > +static int l_istream_read(lua_State* L) > +{ > + luaL_checktype(L, 1, LUA_TTABLE); > + luaL_checktype(L, 2, LUA_TFUNCTION); > + > + struct img_type img = {}; > + uint32_t checksum = 0; > + > + lua_pushvalue(L, 1); > + table2image(L, &img); > + lua_pop(L, 1); > + > + int ret = copyfile(img.fdin, > + L, > + img.size, > + (unsigned long *)&img.offset, > + img.seek, > + 0, /* no skip */ > + img.compressed, > + &checksum, > + img.sha256, > + img.is_encrypted, > + istream_read_callback); > + > + lua_pop(L, 1); > + update_table(L, &img); > + lua_pop(L, 1); > + > + if (ret < 0) { > + lua_pushinteger(L, -1); > + lua_pushstring(L, strerror(errno)); > + return 2; > + } > + if ((img.checksum != 0) && (checksum != img.checksum)) { > + lua_pushinteger(L, -1); > + lua_pushfstring(L, "Checksums WRONG! Computed 0x%d, should be 0x%d\n", > + checksum, img.checksum); > + return 2; > + } > + lua_pushinteger(L, 0); > + lua_pushnil(L); > + return 2; > +} > #endif > > static void update_table(lua_State* L, struct img_type *img) > @@ -354,6 +423,10 @@ static void update_table(lua_State* L, struct img_type *img) > lua_pushstring(L, "copy2file"); > lua_pushcfunction(L, &l_copy2file); > lua_settable(L, -3); > + > + lua_pushstring(L, "read"); > + lua_pushcfunction(L, &l_istream_read); > + lua_settable(L, -3); > #endif > > lua_getfield(L, -1, "_private"); > diff --git a/include/lua_util.h b/include/lua_util.h > index 03ef8d9..5be8c8d 100644 > --- a/include/lua_util.h > +++ b/include/lua_util.h > @@ -50,6 +50,27 @@ void luaL_requiref(lua_State *L, char const* modname, lua_CFunction openf, int g > typedef struct luaL_Stream { > FILE *f; > } luaL_Stream; > + > +typedef struct luaL_Buffer_52 { > + luaL_Buffer b; /* make incorrect code crash! */ > + char *ptr; > + size_t nelems; > + size_t capacity; > + lua_State *L2; > +} luaL_Buffer_52; > +#define luaL_Buffer luaL_Buffer_52 > + > +#define luaL_prepbuffsize luaL_prepbuffsize_52 > +char *luaL_prepbuffsize(luaL_Buffer_52 *B, size_t s); > + > +#define luaL_buffinit luaL_buffinit_52 > +void luaL_buffinit(lua_State *L, luaL_Buffer_52 *B); > + > +#undef luaL_addsize > +#define luaL_addsize(B, s) ((B)->nelems += (s)) > + > +#define luaL_pushresult luaL_pushresult_52 > +void luaL_pushresult(luaL_Buffer_52 *B); > #endif > > #else > Applied to -master, thanks ! Best regards, Stefano Babic
diff --git a/corelib/lua_compat.c b/corelib/lua_compat.c index 6204e8d..317f353 100644 --- a/corelib/lua_compat.c +++ b/corelib/lua_compat.c @@ -25,6 +25,45 @@ * https://github.com/keplerproject/lua-compat-5.2 */ #if !defined(LUA_VERSION_NUM) || LUA_VERSION_NUM == 501 +char *luaL_prepbuffsize(luaL_Buffer_52 *B, size_t s) +{ + if (B->capacity - B->nelems < s) { /* needs to grow */ + char* newptr = NULL; + size_t newcap = B->capacity * 2; + if (newcap - B->nelems < s) + newcap = B->nelems + s; + if (newcap < B->capacity) /* overflow */ + luaL_error(B->L2, "buffer too large"); + newptr = lua_newuserdata(B->L2, newcap); + memcpy(newptr, B->ptr, B->nelems); + if (B->ptr != B->b.buffer) + lua_replace(B->L2, -2); /* remove old buffer */ + B->ptr = newptr; + B->capacity = newcap; + } + return B->ptr+B->nelems; +} + +void luaL_buffinit(lua_State *L, luaL_Buffer_52 *B) +{ + /* make it crash if used via pointer to a 5.1-style luaL_Buffer */ + B->b.p = NULL; + B->b.L = NULL; + B->b.lvl = 0; + /* reuse the buffer from the 5.1-style luaL_Buffer though! */ + B->ptr = B->b.buffer; + B->capacity = LUAL_BUFFERSIZE; + B->nelems = 0; + B->L2 = L; +} + +void luaL_pushresult(luaL_Buffer_52 *B) +{ + lua_pushlstring(B->L2, B->ptr, B->nelems); + if (B->ptr != B->b.buffer) + lua_replace(B->L2, -2); /* remove userdata buffer */ +} + void luaL_setfuncs(lua_State *L, const luaL_Reg *l, int nup) { luaL_checkstack(L, nup+1, "too many upvalues"); diff --git a/corelib/lua_interface.c b/corelib/lua_interface.c index a551cde..7bb58ec 100644 --- a/corelib/lua_interface.c +++ b/corelib/lua_interface.c @@ -321,6 +321,75 @@ copyfile_exit: close(fdout); return 2; } + +static int istream_read_callback(void *out, const void *buf, unsigned int len) +{ + lua_State* L = (lua_State*)out; + if (len > LUAL_BUFFERSIZE) { + ERROR("I/O buffer size is larger than Lua's buffer size %d", LUAL_BUFFERSIZE); + return -1; + } + + luaL_checktype(L, 2, LUA_TFUNCTION); + lua_pushvalue(L, 2); + + luaL_Buffer lbuffer; + luaL_buffinit(L, &lbuffer); + char *buffer = luaL_prepbuffsize(&lbuffer, len); + memcpy(buffer, buf, len); + luaL_addsize(&lbuffer, len); + luaL_pushresult(&lbuffer); + if (lua_pcall(L, 1, 0, 0) != LUA_OK) { + ERROR("Lua error in callback: %s", lua_tostring(L, -1)); + lua_pop(L, 1); + return -1; + } + return 0; +} + +static int l_istream_read(lua_State* L) +{ + luaL_checktype(L, 1, LUA_TTABLE); + luaL_checktype(L, 2, LUA_TFUNCTION); + + struct img_type img = {}; + uint32_t checksum = 0; + + lua_pushvalue(L, 1); + table2image(L, &img); + lua_pop(L, 1); + + int ret = copyfile(img.fdin, + L, + img.size, + (unsigned long *)&img.offset, + img.seek, + 0, /* no skip */ + img.compressed, + &checksum, + img.sha256, + img.is_encrypted, + istream_read_callback); + + lua_pop(L, 1); + update_table(L, &img); + lua_pop(L, 1); + + if (ret < 0) { + lua_pushinteger(L, -1); + lua_pushstring(L, strerror(errno)); + return 2; + } + if ((img.checksum != 0) && (checksum != img.checksum)) { + lua_pushinteger(L, -1); + lua_pushfstring(L, "Checksums WRONG! Computed 0x%d, should be 0x%d\n", + checksum, img.checksum); + return 2; + } + lua_pushinteger(L, 0); + lua_pushnil(L); + return 2; +} #endif static void update_table(lua_State* L, struct img_type *img) @@ -354,6 +423,10 @@ static void update_table(lua_State* L, struct img_type *img) lua_pushstring(L, "copy2file"); lua_pushcfunction(L, &l_copy2file); lua_settable(L, -3); + + lua_pushstring(L, "read"); + lua_pushcfunction(L, &l_istream_read); + lua_settable(L, -3); #endif lua_getfield(L, -1, "_private"); diff --git a/include/lua_util.h b/include/lua_util.h index 03ef8d9..5be8c8d 100644 --- a/include/lua_util.h +++ b/include/lua_util.h @@ -50,6 +50,27 @@ void luaL_requiref(lua_State *L, char const* modname, lua_CFunction openf, int g typedef struct luaL_Stream { FILE *f; } luaL_Stream; + +typedef struct luaL_Buffer_52 { + luaL_Buffer b; /* make incorrect code crash! */ + char *ptr; + size_t nelems; + size_t capacity; + lua_State *L2; +} luaL_Buffer_52; +#define luaL_Buffer luaL_Buffer_52 + +#define luaL_prepbuffsize luaL_prepbuffsize_52 +char *luaL_prepbuffsize(luaL_Buffer_52 *B, size_t s); + +#define luaL_buffinit luaL_buffinit_52 +void luaL_buffinit(lua_State *L, luaL_Buffer_52 *B); + +#undef luaL_addsize +#define luaL_addsize(B, s) ((B)->nelems += (s)) + +#define luaL_pushresult luaL_pushresult_52 +void luaL_pushresult(luaL_Buffer_52 *B); #endif #else
For C handlers, there's core/cpio_util.c's copyfile() as a general method to extract data from the input stream and copy it to somewhere. image:read(<callback()>) is the analogous function exposed to Lua that reads from the input stream and calls the callback Lua function <callback()> for every chunk read, passing this chunk as parameter. Signed-off-by: Christian Storm <christian.storm@siemens.com> --- corelib/lua_compat.c | 39 ++++++++++++++++++++++++++ corelib/lua_interface.c | 73 +++++++++++++++++++++++++++++++++++++++++++++++++ include/lua_util.h | 21 ++++++++++++++ 3 files changed, 133 insertions(+)