static int ar_read_destroy(lua_State *L) { struct archive** self_ref = ar_read_check(L, 1); if ( NULL == *self_ref ) return 0; // If called in destructor, we were already removed from the weak // table, so we need to re-register so that the read callback // will work. ar_registry_set(L, *self_ref); if ( ARCHIVE_OK != archive_read_close(*self_ref) ) { lua_pushfstring(L, "archive_read_close: %s", archive_error_string(*self_ref)); archive_read_finish(*self_ref); __ref_count--; *self_ref = NULL; lua_error(L); } ar_read_get_reader(L, 1); // {self}, reader if ( ! lua_isnil(L, -1) ) { lua_pushvalue(L, 1); // {self}, reader, {self} lua_pushnil(L); // {self}, reader, {self}, nil lua_call(L, 2, 1); // {self}, result } if ( ARCHIVE_OK != archive_read_finish(*self_ref) ) { luaL_error(L, "archive_read_finish: %s", archive_error_string(*self_ref)); } __ref_count--; *self_ref = NULL; return 0; }
////////////////////////////////////////////////////////////////////// // Constructor: static int ar_read(lua_State *L) { struct archive** self_ref; static named_setter format_names[] = { /* Copied from archive.h */ { "all", archive_read_support_format_all }, { "ar", archive_read_support_format_ar }, { "cpio", archive_read_support_format_cpio }, { "empty", archive_read_support_format_empty }, { "gnutar", archive_read_support_format_gnutar }, { "iso9660", archive_read_support_format_iso9660 }, { "mtree", archive_read_support_format_mtree }, { "tar", archive_read_support_format_tar }, { "zip", archive_read_support_format_zip }, { NULL, NULL } }; static named_setter compression_names[] = { { "all", archive_read_support_compression_all }, { "bzip2", archive_read_support_compression_bzip2 }, { "compress", archive_read_support_compression_compress }, { "gzip", archive_read_support_compression_gzip }, { "lzma", archive_read_support_compression_lzma }, { "none", archive_read_support_compression_none }, { "xz", archive_read_support_compression_xz }, { NULL, NULL } }; luaL_checktype(L, 1, LUA_TTABLE); self_ref = (struct archive**) lua_newuserdata(L, sizeof(struct archive*)); // {ud} *self_ref = NULL; luaL_getmetatable(L, AR_READ); // {ud}, [read] lua_setmetatable(L, -2); // {ud} __ref_count++; *self_ref = archive_read_new(); // Register it in the weak metatable: ar_registry_set(L, *self_ref); // Create an environment to store a reference to the callbacks: lua_createtable(L, 1, 0); // {ud}, {fenv} lua_getfield(L, 1, "reader"); // {ud}, {fenv}, fn if ( ! lua_isfunction(L, -1) ) err("MissingArgument: required parameter 'reader' must be a function"); lua_setfield(L, -2, "reader"); // {ud}, {fenv} lua_setfenv(L, -2); // {ud} // Do it the easy way for now... perhaps in the future we will // have a parameter to support toggling which algorithms are // supported: if ( ARCHIVE_OK != archive_read_support_compression_all(*self_ref) ) { err("archive_read_support_compression_all: %s", archive_error_string(*self_ref)); } if ( ARCHIVE_OK != archive_read_support_format_all(*self_ref) ) { err("archive_read_support_format_all: %s", archive_error_string(*self_ref)); } // Extract various fields and prepare the archive: lua_getfield(L, 1, "format"); if ( NULL == lua_tostring(L, -1) ) { lua_pop(L, 1); lua_pushliteral(L, "all"); } if ( 0 == call_setters(L, *self_ref, "archive_read_support_format_", format_names, lua_tostring(L, -1)) ) { // We will be strict for now... perhaps in the future we will // default to "all"? err("empty format='%s' is not allowed, you must specify at least one format", lua_tostring(L, -1)); } lua_pop(L, 1); lua_getfield(L, 1, "compression"); if ( NULL == lua_tostring(L, -1) ) { lua_pop(L, 1); lua_pushliteral(L, "none"); } call_setters(L, *self_ref, "archive_read_support_compression_", compression_names, lua_tostring(L, -1)); lua_pop(L, 1); lua_getfield(L, 1, "options"); if ( ! lua_isnil(L, -1) && ARCHIVE_OK != archive_read_set_options(*self_ref, lua_tostring(L, -1)) ) { err("archive_read_set_options: %s", archive_error_string(*self_ref)); } lua_pop(L, 1); if ( ARCHIVE_OK != archive_read_open(*self_ref, L, NULL, &ar_read_cb, NULL) ) { err("archive_read_open: %s", archive_error_string(*self_ref)); } return 1; }
////////////////////////////////////////////////////////////////////// // Constructor: static int ar_write(lua_State *L) { struct archive** self_ref; static struct { const char *name; int (*setter)(struct archive *); } names[] = { /* Copied from archive_write_set_format_by_name.c */ { "ar", archive_write_set_format_ar_bsd }, { "arbsd", archive_write_set_format_ar_bsd }, { "argnu", archive_write_set_format_ar_svr4 }, { "arsvr4", archive_write_set_format_ar_svr4 }, { "cpio", archive_write_set_format_cpio }, { "mtree", archive_write_set_format_mtree }, { "newc", archive_write_set_format_cpio_newc }, { "odc", archive_write_set_format_cpio }, { "pax", archive_write_set_format_pax }, { "posix", archive_write_set_format_pax }, { "shar", archive_write_set_format_shar }, { "shardump", archive_write_set_format_shar_dump }, { "ustar", archive_write_set_format_ustar }, /* New ones to more closely match the C API */ { "ar_bsd", archive_write_set_format_ar_bsd }, { "ar_svr4", archive_write_set_format_ar_svr4 }, { "cpio_newc", archive_write_set_format_cpio_newc }, { "pax_restricted", archive_write_set_format_pax_restricted }, { "shar_dump", archive_write_set_format_shar_dump }, { NULL, NULL } }; int idx = 0; const char* name; luaL_checktype(L, 1, LUA_TTABLE); self_ref = (struct archive**) lua_newuserdata(L, sizeof(struct archive*)); // {ud} luaL_getmetatable(L, AR_WRITE); // {ud}, [write] lua_setmetatable(L, -2); // {ud} __ref_count++; *self_ref = archive_write_new(); // Register it in the weak metatable: ar_registry_set(L, *self_ref); // Create an environment to store a reference to the writer: lua_createtable(L, 1, 0); // {ud}, {} lua_pushliteral(L, "writer"); // {ud}, {}, "writer" lua_rawget(L, 1); // {ud}, {}, fn if ( ! lua_isfunction(L, -1) ) { err("MissingArgument: required parameter 'writer' must be a function"); } lua_setfield(L, -2, "writer"); lua_setfenv(L, -2); // {ud} // Extract various fields and prepare the archive: lua_getfield(L, 1, "bytes_per_block"); if ( ! lua_isnil(L, -1) && ARCHIVE_OK != archive_write_set_bytes_per_block(*self_ref, lua_tointeger(L, -1)) ) { err("archive_write_set_bytes_per_block: %s", archive_error_string(*self_ref)); } lua_pop(L, 1); lua_getfield(L, 1, "bytes_in_last_block"); if ( ! lua_isnil(L, -1) && ARCHIVE_OK != archive_write_set_bytes_in_last_block(*self_ref, lua_tointeger(L, -1)) ) { err("archive_write_set_bytes_in_last_block: %s", archive_error_string(*self_ref)); } lua_pop(L, 1); lua_getfield(L, 1, "skip_file"); if ( ! lua_isnil(L, -1) ) { dev_t dev; ino_t ino; if ( LUA_TTABLE != lua_type(L, -1) ) { err("skip_file member must be a table object"); } lua_getfield(L, -1, "dev"); if ( ! lua_isnumber(L, -1) ) { err("skip_file.dev member must be a number"); } dev = (dev_t)lua_tonumber(L, -1); lua_pop(L, 1); lua_getfield(L, -1, "ino"); if ( ! lua_isnumber(L, -1) ) { err("skip_file.ino member must be a number"); } ino = (ino_t)lua_tonumber(L, -1); lua_pop(L, 1); if ( ARCHIVE_OK != archive_write_set_skip_file(*self_ref, dev, ino) ) { err("archive_write_set_skip_file: %s", archive_error_string(*self_ref)); } } lua_pop(L, 1); lua_getfield(L, 1, "format"); if ( lua_isnil(L, -1) ) { lua_pop(L, 1); lua_pushliteral(L, "posix"); } name = lua_tostring(L, -1); for ( ;; idx++ ) { if ( names[idx].name == NULL ) { err("archive_write_set_format_*: No such format '%s'", name); } if ( strcmp(name, names[idx].name) == 0 ) break; } if ( ARCHIVE_OK != (names[idx].setter)(*self_ref) ) { err("archive_write_set_format_%s: %s", name, archive_error_string(*self_ref)); } lua_pop(L, 1); lua_getfield(L, 1, "compression"); if ( ! lua_isnil(L, -1) ) { static struct { const char *name; int (*setter)(struct archive *); } names[] = { { "bzip2", archive_write_add_filter_bzip2 }, { "compress", archive_write_add_filter_compress }, { "gzip", archive_write_add_filter_gzip }, { "lzma", archive_write_add_filter_lzma }, { "xz", archive_write_add_filter_xz }, { NULL, NULL } }; int idx = 0; const char* name = lua_tostring(L, -1); for ( ;; idx++ ) { if ( names[idx].name == NULL ) { err("archive_write_set_compression_*: No such compression '%s'", name); } if ( strcmp(name, names[idx].name) == 0 ) break; } if ( ARCHIVE_OK != (names[idx].setter)(*self_ref) ) { err("archive_write_set_compression_%s: %s", name, archive_error_string(*self_ref)); } } lua_pop(L, 1); lua_getfield(L, 1, "options"); if ( ! lua_isnil(L, -1) && ARCHIVE_OK != archive_write_set_options(*self_ref, lua_tostring(L, -1)) ) { err("archive_write_set_options: %s", archive_error_string(*self_ref)); } lua_pop(L, 1); if ( ARCHIVE_OK != archive_write_open(*self_ref, L, NULL, &ar_write_cb, NULL) ) { err("archive_write_open: %s", archive_error_string(*self_ref)); } return 1; }