mirror of
https://github.com/radareorg/radare2.git
synced 2024-11-24 05:40:10 +00:00
Ar fixes (Added filename table)
This commit is contained in:
parent
1a406a87ef
commit
ee4f42d13e
@ -15,13 +15,9 @@ static RIODesc *r_io_ar_open(RIO *io, const char *file, int rw, int mode) {
|
||||
char *url = strdup (file);
|
||||
char *arname = strstr (url, "://") + 3;
|
||||
char *filename = strstr (arname, "//");
|
||||
*filename = 0;
|
||||
filename += 2;
|
||||
|
||||
if (!filename) {
|
||||
eprintf ("Wrong filename: use ar://lib.a//filename\n");
|
||||
free (url);
|
||||
return res;
|
||||
if (filename) {
|
||||
*filename = 0;
|
||||
filename += 2;
|
||||
}
|
||||
|
||||
RBuffer *b = ar_open_file (arname, filename);
|
||||
|
275
shlr/ar/ar.c
275
shlr/ar/ar.c
@ -3,14 +3,19 @@
|
||||
#include <r_util.h>
|
||||
#include "ar.h"
|
||||
|
||||
#define BUF_SIZE 512
|
||||
|
||||
const char *AR_MAGIC_HEADER = "!<arch>\n";
|
||||
const char *AR_FILE_HEADER_END = "`\n";
|
||||
|
||||
/* Used to lookup filename table */
|
||||
static int index_filename = -2;
|
||||
|
||||
/**
|
||||
* Open an ar/lib file. If filename is NULL, list archive files
|
||||
*/
|
||||
R_API RBuffer *ar_open_file(const char *arname, const char *filename) {
|
||||
int r;
|
||||
ut64 filesize = 0;
|
||||
char *curfile = NULL;
|
||||
char *tmp = NULL;
|
||||
RBuffer *b = r_buf_new_file (arname, 0);
|
||||
if (!b) {
|
||||
r_sys_perror (__FUNCTION__);
|
||||
@ -18,84 +23,51 @@ R_API RBuffer *ar_open_file(const char *arname, const char *filename) {
|
||||
}
|
||||
|
||||
/* Read magic header */
|
||||
char *buffer = calloc (1, 1024);
|
||||
// r = r_buf_read (b, buffer, 8);
|
||||
r = ar_read (b, buffer, 8);
|
||||
if (!r) {
|
||||
goto end;
|
||||
char *buffer = calloc (1, BUF_SIZE);
|
||||
if (!buffer) {
|
||||
return NULL;
|
||||
}
|
||||
if (strncmp (buffer, AR_MAGIC_HEADER, 8)) {
|
||||
eprintf ("Wrong file type.\n");
|
||||
goto end;
|
||||
r = ar_read_header (b, buffer);
|
||||
if (!r) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Read lookup table */
|
||||
while (true) {
|
||||
r = ar_read (b, buffer, 2);
|
||||
if (!r) {
|
||||
break;
|
||||
/* Parse archive */
|
||||
RList *files = r_list_new ();
|
||||
ar_read_file (b, buffer, true, NULL, NULL);
|
||||
ar_read_filename_table (b, buffer, files, filename);
|
||||
|
||||
/* If b->base is set, then we found the file root in the archive */
|
||||
while (r && !b->base) {
|
||||
ar_read (b, buffer, 2);
|
||||
/* Fix padding */
|
||||
if (*buffer == '\n') {
|
||||
buffer[0] = buffer[1];
|
||||
b->cur -= 1;
|
||||
ar_read (b, buffer, 2);
|
||||
}
|
||||
/* "//" denotes the start of a filename table */
|
||||
// if (*buffer == '/' && *(buffer + 1) != '/') {
|
||||
/* File identifier */
|
||||
r = ar_read (b, buffer + 2, 14);
|
||||
free (curfile);
|
||||
curfile = strdup (buffer);
|
||||
if (!curfile) {
|
||||
goto end;
|
||||
}
|
||||
tmp = strchr (curfile, '/');
|
||||
if (!tmp) {
|
||||
goto end;
|
||||
}
|
||||
*tmp = '\0';
|
||||
if (r != 14) {
|
||||
goto end;
|
||||
}
|
||||
/* File timestamp */
|
||||
r = ar_read (b, buffer, 12);
|
||||
if (r != 12) {
|
||||
goto end;
|
||||
}
|
||||
/* Owner id */
|
||||
r = ar_read (b, buffer, 6);
|
||||
if (r != 6) {
|
||||
goto end;
|
||||
}
|
||||
/* Group id */
|
||||
r = ar_read (b, buffer, 6);
|
||||
if (r != 6) {
|
||||
goto end;
|
||||
}
|
||||
/* File mode */
|
||||
r = ar_read (b, buffer, 8);
|
||||
if (r != 8) {
|
||||
goto end;
|
||||
}
|
||||
/* File size */
|
||||
r = ar_read (b, buffer, 10);
|
||||
filesize = strtoull (buffer, &tmp, 10);
|
||||
if (r != 10) {
|
||||
goto end;
|
||||
}
|
||||
/* Header end */
|
||||
r = ar_read (b, buffer, 2);
|
||||
if (strncmp (buffer, AR_FILE_HEADER_END, 2)) {
|
||||
goto end;
|
||||
}
|
||||
/* File content */
|
||||
if (!strcmp (curfile, filename)) {
|
||||
break;
|
||||
}
|
||||
b->cur += filesize;
|
||||
// if (fseek (f, filesize, SEEK_CUR)) goto end;
|
||||
// }
|
||||
r = ar_read_file (b, buffer, false, files, filename);
|
||||
}
|
||||
|
||||
if (!filename) {
|
||||
RListIter *iter;
|
||||
char *name;
|
||||
puts ("Available files:\n");
|
||||
r_list_foreach (files, iter, name) {
|
||||
printf ("%s\n", name);
|
||||
}
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!r) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
free (buffer);
|
||||
b->length = filesize;
|
||||
b->base = b->cur;
|
||||
r_list_free (files);
|
||||
return b;
|
||||
end:
|
||||
fail:
|
||||
r_list_free (files);
|
||||
free (buffer);
|
||||
ar_close (b);
|
||||
return NULL;
|
||||
@ -122,3 +94,158 @@ int ar_read(RBuffer *b, void *dest, int len) {
|
||||
b->cur += r;
|
||||
return r;
|
||||
}
|
||||
|
||||
int ar_read_until_slash(RBuffer *b, char *buffer, int limit) {
|
||||
ut32 i = 0;
|
||||
ut32 lim = (limit && limit < BUF_SIZE)? limit: BUF_SIZE;
|
||||
while (i < lim) {
|
||||
ar_read (b, buffer + i, 1);
|
||||
if (buffer[i] == '/') {
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
buffer[i] = '\0';
|
||||
return i;
|
||||
}
|
||||
|
||||
int ar_read_header(RBuffer *b, char *buffer) {
|
||||
int r = ar_read (b, buffer, 8);
|
||||
if (!r) {
|
||||
return 0;
|
||||
}
|
||||
if (strncmp (buffer, AR_MAGIC_HEADER, 8)) {
|
||||
eprintf ("Wrong file type.\n");
|
||||
return 0;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
int ar_read_file(RBuffer *b, char *buffer, bool lookup, RList *files, const char *filename) {
|
||||
ut64 filesize = 0;
|
||||
char *tmp = NULL;
|
||||
char *curfile = NULL;
|
||||
ut32 index = -1;
|
||||
int r;
|
||||
|
||||
/* File identifier */
|
||||
if (lookup) {
|
||||
r = ar_read (b, buffer, 16);
|
||||
} else {
|
||||
r = ar_read (b, buffer + 2, 14);
|
||||
}
|
||||
/* Fix some padding issues */
|
||||
if (buffer[15] != '/' && buffer[15] != ' ') {
|
||||
tmp = strrchr (buffer, ' ');
|
||||
int dif = (int) (tmp - buffer);
|
||||
dif = 31 - dif;
|
||||
b->cur -= dif;
|
||||
r = ar_read (b, buffer, 16);
|
||||
}
|
||||
free (curfile);
|
||||
curfile = strdup (buffer);
|
||||
if (!curfile) {
|
||||
return 0;
|
||||
}
|
||||
/* If /XX then refer to filename table later */
|
||||
if (curfile[0] == '/' && curfile[1] >= '0' && curfile[1] <= '9') {
|
||||
index = strtoul (buffer + 1, NULL, 10);
|
||||
} else if (curfile[0] != '/') {
|
||||
/* Read filename */
|
||||
tmp = strchr (curfile, '/');
|
||||
if (!tmp) {
|
||||
return 0;
|
||||
}
|
||||
*tmp = '\0';
|
||||
if (files) {
|
||||
r_list_append (files, strdup (curfile));
|
||||
}
|
||||
}
|
||||
/* File timestamp */
|
||||
r = ar_read (b, buffer, 12);
|
||||
if (r != 12) {
|
||||
return 0;
|
||||
}
|
||||
/* Owner id */
|
||||
r = ar_read (b, buffer, 6);
|
||||
if (r != 6) {
|
||||
return 0;
|
||||
}
|
||||
/* Group id */
|
||||
r = ar_read (b, buffer, 6);
|
||||
if (r != 6) {
|
||||
return 0;
|
||||
}
|
||||
/* File mode */
|
||||
r = ar_read (b, buffer, 8);
|
||||
if (r != 8) {
|
||||
return 0;
|
||||
}
|
||||
/* File size */
|
||||
r = ar_read (b, buffer, 10);
|
||||
filesize = strtoull (buffer, &tmp, 10);
|
||||
if (r != 10) {
|
||||
return 0;
|
||||
}
|
||||
/* Header end */
|
||||
r = ar_read (b, buffer, 2);
|
||||
if (strncmp (buffer, AR_FILE_HEADER_END, 2)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* File content */
|
||||
if (!lookup && filename) {
|
||||
/* Check filename */
|
||||
if (index == index_filename || !strcmp (curfile, filename)) {
|
||||
b->length = filesize;
|
||||
b->base = b->cur;
|
||||
return b->length;
|
||||
}
|
||||
}
|
||||
r = ar_read (b, buffer, 1);
|
||||
|
||||
b->cur += filesize - 1;
|
||||
return filesize;
|
||||
}
|
||||
|
||||
int ar_read_filename_table(RBuffer *b, char *buffer, RList *files, const char *filename) {
|
||||
int r = ar_read (b, buffer, 16);
|
||||
if (r != 16) {
|
||||
return 0;
|
||||
}
|
||||
if (strncmp (buffer, "//", 2)) {
|
||||
b->cur -= 16;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Read table size */
|
||||
b->cur += 32;
|
||||
r = ar_read (b, buffer, 10);
|
||||
ut64 tablesize = strtoull (buffer, NULL, 10);
|
||||
|
||||
/* Header end */
|
||||
r = ar_read (b, buffer, 2);
|
||||
if (strncmp (buffer, AR_FILE_HEADER_END, 2)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Read table */
|
||||
ut64 len = 0;
|
||||
ut32 index = 0;
|
||||
while (r && len < tablesize) {
|
||||
r = ar_read_until_slash (b, buffer, tablesize - len);
|
||||
if (filename && !strcmp (filename, (char *) buffer)) {
|
||||
index_filename = index;
|
||||
}
|
||||
if (*(char *) buffer == '\n') {
|
||||
break;
|
||||
}
|
||||
r_list_append (files, strdup ((char *) buffer));
|
||||
/* End slash plus separation character ("/\n") */
|
||||
len += r + 2;
|
||||
/* Separation character (not always '\n') */
|
||||
b->cur += 1;
|
||||
index++;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
11
shlr/ar/ar.h
11
shlr/ar/ar.h
@ -2,11 +2,16 @@
|
||||
#ifndef _AR_H
|
||||
#define _AR_H
|
||||
|
||||
/* Offset passed is always the real io->off, the functions automatically
|
||||
* translate it to relative offset within the archive */
|
||||
/* 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 RBuffer *ar_open_file(const char *arname, const char *filename);
|
||||
R_API int ar_close(RBuffer *b);
|
||||
R_API int ar_read_at(RBuffer *b, ut64 off, void *buf, int count);
|
||||
R_API int ar_write_at(RBuffer *b, ut64 off, void *buf, int count);
|
||||
|
||||
int ar_read(RBuffer *b, void *dest, int len);
|
||||
#endif // _AR_H
|
||||
int ar_read_until_slash(RBuffer *b, char *buffer, int limit);
|
||||
int ar_read_header(RBuffer *b, char *buffer);
|
||||
int ar_read_file(RBuffer *b, char *buffer, bool lookup, RList *files, const char *filename);
|
||||
int ar_read_filename_table(RBuffer *b, char *buffer, RList *files, const char *filename);
|
||||
#endif // _AR_H
|
||||
|
Loading…
Reference in New Issue
Block a user