Add arall:// and liball:// open_many plugins #io (#18196)
This commit is contained in:
parent
32652cbbc8
commit
528e6598a1
|
@ -205,6 +205,8 @@ R_API RList* r_io_open_many(RIO* io, const char* uri, int perm, int mode) {
|
|||
}
|
||||
}
|
||||
}
|
||||
// ensure no double free with r_list_close and r_io_free
|
||||
desc_list->free = NULL;
|
||||
return desc_list;
|
||||
}
|
||||
|
||||
|
|
|
@ -6,14 +6,34 @@
|
|||
#include "ar.h"
|
||||
|
||||
|
||||
static const char *r_io_get_individual_schema(const char *file) {
|
||||
if (r_str_startswith (file, "arall://")) {
|
||||
return "ar://";
|
||||
}
|
||||
if (r_str_startswith (file, "liball://")) {
|
||||
return "lib://";
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static bool r_io_ar_plugin_open(RIO *io, const char *file, bool many) {
|
||||
r_return_val_if_fail (io && file, NULL);
|
||||
if (many) {
|
||||
return (r_io_get_individual_schema (file) != NULL);
|
||||
}
|
||||
return !strncmp ("ar://", file, 5) || !strncmp ("lib://", file, 6);
|
||||
}
|
||||
|
||||
static int r_io_ar_close(RIODesc *fd) {
|
||||
if (!fd || !fd->data) {
|
||||
return -1;
|
||||
}
|
||||
return ar_close ((RArFp *)fd->data);
|
||||
}
|
||||
|
||||
static RIODesc *r_io_ar_open(RIO *io, const char *file, int rw, int mode) {
|
||||
RIODesc *res = NULL;
|
||||
char *url = strdup (file);
|
||||
char *arname = strstr (url, "://") + 3;
|
||||
r_return_val_if_fail (r_io_ar_plugin_open (io, file, false), NULL);
|
||||
const char *arname = strstr (file, "://") + 3;
|
||||
char *filename = strstr (arname, "//");
|
||||
if (filename) {
|
||||
*filename = 0;
|
||||
|
@ -21,16 +41,61 @@ static RIODesc *r_io_ar_open(RIO *io, const char *file, int rw, int mode) {
|
|||
}
|
||||
|
||||
RArFp *arf = ar_open_file (arname, filename);
|
||||
RIODesc *res = NULL;
|
||||
if (arf) {
|
||||
res = r_io_desc_new (io, &r_io_plugin_ar, filename, rw, mode, arf);
|
||||
res = r_io_desc_new (io, &r_io_plugin_ar, file, rw, mode, arf);
|
||||
if (res) {
|
||||
res->name = strdup (filename);
|
||||
}
|
||||
}
|
||||
free (url);
|
||||
return res;
|
||||
}
|
||||
|
||||
typedef struct ar_many_data {
|
||||
const char *schema;
|
||||
const char *arname;
|
||||
RIO *io;
|
||||
bool rw;
|
||||
int mode;
|
||||
RList *list;
|
||||
} ar_many_data;
|
||||
|
||||
static int __io_ar_list(RArFp *arf, void *user) {
|
||||
ar_many_data *data = (ar_many_data *)user;
|
||||
char *uri = r_str_newf ("%s%s//%s", data->schema, data->arname, arf->name);
|
||||
RIODesc *des = r_io_desc_new (data->io, &r_io_plugin_ar, uri, data->rw, data->mode, arf);
|
||||
free (uri);
|
||||
|
||||
if (!des) {
|
||||
ar_close (arf);
|
||||
return -1; // stop error
|
||||
}
|
||||
|
||||
des->name = strdup (arf->name);
|
||||
if (!r_list_append (data->list, des)) {
|
||||
r_io_ar_close (des);
|
||||
return -1; // stop error
|
||||
}
|
||||
return 0; // continue
|
||||
}
|
||||
|
||||
static RList *r_io_ar_open_many(RIO *io, const char *file, int rw, int mode) {
|
||||
eprintf ("Not implemented\n");
|
||||
return NULL;
|
||||
r_return_val_if_fail (io && file, NULL);
|
||||
ar_many_data data;
|
||||
if ((data.schema = r_io_get_individual_schema (file)) == NULL) {
|
||||
r_warn_if_reached ();
|
||||
return NULL;
|
||||
}
|
||||
data.io = io;
|
||||
data.rw = rw;
|
||||
data.mode = mode;
|
||||
data.arname = strstr (file, "://") + 3;
|
||||
data.list = r_list_newf ((RListFree)r_io_ar_close);
|
||||
if (data.list && ar_open_all_cb (data.arname, (RArOpenManyCB)__io_ar_list, (void *)&data) < 0) {
|
||||
r_list_free (data.list);
|
||||
return NULL;
|
||||
}
|
||||
return data.list;
|
||||
}
|
||||
|
||||
static ut64 r_io_ar_lseek(RIO *io, RIODesc *fd, ut64 offset, int whence) {
|
||||
|
@ -69,18 +134,11 @@ static int r_io_ar_write(RIO *io, RIODesc *fd, const ut8 *buf, int count) {
|
|||
return ar_write_at ((RArFp *) fd->data, io->off, (void *) buf, count);
|
||||
}
|
||||
|
||||
static int r_io_ar_close(RIODesc *fd) {
|
||||
if (!fd || !fd->data) {
|
||||
return -1;
|
||||
}
|
||||
return ar_close ((RArFp *) fd->data);
|
||||
}
|
||||
|
||||
RIOPlugin r_io_plugin_ar = {
|
||||
.name = "ar",
|
||||
.desc = "Open ar/lib files",
|
||||
.license = "LGPL3",
|
||||
.uris = "ar://,lib://",
|
||||
.uris = "ar://,lib://,arall://,liball://",
|
||||
.open = r_io_ar_open,
|
||||
.open_many = r_io_ar_open_many,
|
||||
.write = r_io_ar_write,
|
||||
|
|
147
shlr/ar/ar.c
147
shlr/ar/ar.c
|
@ -75,7 +75,7 @@ static char *name_from_table(ut64 off, filetable *tbl) {
|
|||
return -1; \
|
||||
}
|
||||
|
||||
/* -1 error, 0 end, 1 contnue */
|
||||
/* -1 error, 0 continue, 1 finished */
|
||||
static int ar_parse_header(RArFp *arf, filetable *tbl, ut64 arsize) {
|
||||
r_return_val_if_fail (arf && arf->buf && tbl, -1);
|
||||
RBuffer *b = arf->buf;
|
||||
|
@ -103,12 +103,12 @@ static int ar_parse_header(RArFp *arf, filetable *tbl, ut64 arsize) {
|
|||
int r = r_buf_read (b, (ut8 *)&h, sizeof (h));
|
||||
if (r != sizeof (h)) {
|
||||
if (r == 0) {
|
||||
return 0; // no more file
|
||||
return 1; // no more file
|
||||
}
|
||||
if (r < 0) {
|
||||
eprintf ("io_ar: io error\n");
|
||||
eprintf ("AR read io error\n");
|
||||
} else {
|
||||
eprintf ("io_ar: Invalid file length\n");
|
||||
eprintf ("Malformed AR: Invalid length while parsing header at 0x%" PFMT64x "\n", h_off);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
@ -207,12 +207,29 @@ static int ar_parse_header(RArFp *arf, filetable *tbl, ut64 arsize) {
|
|||
return -1;
|
||||
}
|
||||
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
#undef VERIFY_AR_NUM_FIELD
|
||||
|
||||
typedef struct single_file_data {
|
||||
const char *name;
|
||||
RArFp **ret;
|
||||
} single_file_data;
|
||||
|
||||
static int __ar_open_file_cb(RArFp *arf, void *user) {
|
||||
single_file_data *data = user;
|
||||
if (!data->name) {
|
||||
printf ("%s\n", arf->name);
|
||||
} else if (!strcmp (data->name, arf->name)) {
|
||||
*data->ret = arf;
|
||||
return 1; // stop success
|
||||
}
|
||||
ar_close (arf);
|
||||
return 0; // continue
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Open specific file withen a ar/lib file.
|
||||
* \brief Open specific file within a ar/lib file.
|
||||
* \param arname the name of the .a file
|
||||
* \param filename the name of file in the .a file that you wish to open
|
||||
* \return a handle of the internal filename or NULL
|
||||
|
@ -221,10 +238,64 @@ static int ar_parse_header(RArFp *arf, filetable *tbl, ut64 arsize) {
|
|||
* listed.
|
||||
*/
|
||||
R_API RArFp *ar_open_file(const char *arname, const char *filename) {
|
||||
RArFp *ret = NULL;
|
||||
single_file_data data;
|
||||
data.name = filename;
|
||||
data.ret = &ret;
|
||||
if (ar_open_all_cb (arname, (RArOpenManyCB)__ar_open_file_cb, (void *)&data) < 0) {
|
||||
ar_close (ret);
|
||||
return NULL;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __ar_open_list_cb(RArFp *arf, void *user) {
|
||||
RList *l = user;
|
||||
if (!r_list_append (l, arf)) {
|
||||
ar_close (arf);
|
||||
return -1; // stop error
|
||||
}
|
||||
return 0; // continue
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Get a RList* of handles to every file in ar
|
||||
* \param arname the name of the .a file
|
||||
* \return RList* containg a RArFp* per file
|
||||
*
|
||||
* Open an ar/lib file by name. If filename is NULL, then archive files will be
|
||||
* listed.
|
||||
*/
|
||||
R_API RList *ar_open_all(const char *arname) {
|
||||
RList *list = r_list_newf ((RListFree)ar_close);
|
||||
if (!list) {
|
||||
return NULL;
|
||||
}
|
||||
if (ar_open_all_cb (arname, (RArOpenManyCB)__ar_open_list_cb, (void *)list) > 0) {
|
||||
return list;
|
||||
}
|
||||
r_list_free (list);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Send all files in AR file to callback
|
||||
* \param arname the name of the .a file
|
||||
* \param cb callback function
|
||||
* \param user (void *) data to be passed to callback
|
||||
* \return bool success or error
|
||||
*
|
||||
* Each file in AR will be parsed into a RArFp* and sent to the callback. The
|
||||
* callback is trusted to close all the RArFp*'s it receives. Callback should
|
||||
* return an int <0 on error, 0 if the callback wants to receive more files and
|
||||
* >0 if it's done.
|
||||
*/
|
||||
R_API int ar_open_all_cb(const char *arname, RArOpenManyCB cb, void *user) {
|
||||
r_return_val_if_fail (arname, -1);
|
||||
RBuffer *b = r_buf_new_file (arname, O_RDWR, 0);
|
||||
if (!b) {
|
||||
r_sys_perror (__FUNCTION__);
|
||||
return NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
r_buf_seek (b, 0, R_BUF_END);
|
||||
|
@ -233,53 +304,59 @@ R_API RArFp *ar_open_file(const char *arname, const char *filename) {
|
|||
|
||||
if (!ar_check_magic (b)) {
|
||||
r_buf_free (b);
|
||||
return NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
RArFp *arf = arfp_new (b, NULL);
|
||||
if (!arf) {
|
||||
filetable tbl = { NULL, 0, 0 };
|
||||
|
||||
ut32 *refc = R_NEW (ut32);
|
||||
if (!refc) {
|
||||
r_buf_free (b);
|
||||
return NULL;
|
||||
free (refc);
|
||||
return -1;
|
||||
}
|
||||
/* The refcount is artificially inflated here. This allows the callback to
|
||||
* use ar_close without fear of free'ing the RBuffer. The refcounter must
|
||||
* be decremented later before returning.
|
||||
*/
|
||||
*refc = 1;
|
||||
|
||||
filetable tbl = {NULL, 0, 0};
|
||||
int r;
|
||||
while ((r = ar_parse_header (arf, &tbl, arsize)) > 0) {
|
||||
if (filename) {
|
||||
if (!strcmp (filename, arf->name)) {
|
||||
// found the right file
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
printf ("%s\n", arf->name);
|
||||
int r = 0;
|
||||
while (!r) {
|
||||
RArFp *arf = arfp_new (b, refc);
|
||||
if (!arf) {
|
||||
r = -1;
|
||||
break;
|
||||
}
|
||||
r = ar_parse_header (arf, &tbl, arsize);
|
||||
if (!r) {
|
||||
r = cb (arf, user);
|
||||
} else {
|
||||
ar_close (arf);
|
||||
}
|
||||
|
||||
// clean RArFp for next loop
|
||||
arf_clean_name (arf);
|
||||
}
|
||||
|
||||
free (tbl.data);
|
||||
|
||||
if (r <= 0) {
|
||||
if (r == 0 && filename) {
|
||||
eprintf ("Cound not find file '%s' in archive '%s'\n", filename, arname);
|
||||
}
|
||||
ar_close (arf); // results in buf being free'd
|
||||
return NULL;
|
||||
if (*refc == 1) {
|
||||
// the cb closed all the RArFp's, so we free these resources
|
||||
free (refc);
|
||||
r_buf_free (b);
|
||||
} else {
|
||||
// return recf to true value
|
||||
(*refc)--;
|
||||
}
|
||||
|
||||
return arf;
|
||||
return r;
|
||||
}
|
||||
|
||||
R_API int ar_close(RArFp *f) {
|
||||
if (f) {
|
||||
free (f->name);
|
||||
if (f->refcount) {
|
||||
(*f->refcount)--;
|
||||
}
|
||||
(*f->refcount)--;
|
||||
|
||||
// no more files open, clean underlying buffer
|
||||
if (!f->refcount || f->refcount == 0) {
|
||||
if (*f->refcount == 0) {
|
||||
free (f->refcount);
|
||||
r_buf_free (f->buf);
|
||||
}
|
||||
|
|
|
@ -10,9 +10,13 @@ typedef struct RARFP {
|
|||
ut32 *refcount;
|
||||
} RArFp;
|
||||
|
||||
typedef int (*RArOpenManyCB) (RArFp *arf, void *user);
|
||||
|
||||
/* Offset passed is always the real io->off of the inspected file,
|
||||
* the functions automatically translate it to relative offset within the archive */
|
||||
R_API RArFp *ar_open_file(const char *arname, const char *filename);
|
||||
R_API RList *ar_open_all(const char *arname);
|
||||
R_API int ar_open_all_cb(const char *arname, RArOpenManyCB cb, void *user);
|
||||
R_API int ar_close(RArFp *f);
|
||||
R_API int ar_read_at(RArFp *f, ut64 off, void *buf, int count);
|
||||
R_API int ar_write_at(RArFp *f, ut64 off, void *buf, int count);
|
||||
|
|
Loading…
Reference in New Issue