Ar fixes (Added filename table)

This commit is contained in:
xarkes 2017-08-23 01:07:21 +02:00 committed by radare
parent 1a406a87ef
commit ee4f42d13e
3 changed files with 212 additions and 84 deletions

View File

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

View File

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

View File

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