radare2/shlr/ar/ar.c

255 lines
5.3 KiB
C
Raw Normal View History

2017-08-16 08:20:21 +00:00
/* radare - LGPLv3 - Copyright 2017 - xarkes */
#include <stdio.h>
#include <r_util.h>
#include "ar.h"
2017-08-22 23:07:21 +00:00
#define BUF_SIZE 512
2017-08-16 08:20:21 +00:00
const char *AR_MAGIC_HEADER = "!<arch>\n";
const char *AR_FILE_HEADER_END = "`\n";
2017-08-24 11:37:20 +00:00
const int AR_FILENAME_LEN = 16;
2017-08-16 08:20:21 +00:00
2017-08-22 23:07:21 +00:00
/* Used to lookup filename table */
static int index_filename = -2;
/**
* Open an ar/lib file. If filename is NULL, list archive files
*/
2017-08-16 08:20:21 +00:00
R_API RBuffer *ar_open_file(const char *arname, const char *filename) {
int r;
RList *files = NULL;
RBuffer *b = r_buf_new_file (arname, O_RDWR, 0);
2017-08-16 08:20:21 +00:00
if (!b) {
r_sys_perror (__FUNCTION__);
return NULL;
}
/* Read magic header */
2017-08-23 14:45:05 +00:00
char *buffer = calloc (1, BUF_SIZE + 1);
2017-08-22 23:07:21 +00:00
if (!buffer) {
return NULL;
2017-08-16 08:20:21 +00:00
}
2017-08-22 23:07:21 +00:00
r = ar_read_header (b, buffer);
if (!r) {
goto fail;
2017-08-16 08:20:21 +00:00
}
files = r_list_new ();
2017-08-22 23:07:21 +00:00
/* Parse archive */
2017-08-24 11:37:20 +00:00
ar_read_file (b, buffer, true, NULL, NULL);
2017-08-22 23:07:21 +00:00
ar_read_filename_table (b, buffer, files, filename);
/* If b->base is set, then we found the file root in the archive */
while (r) {
2017-08-24 11:37:20 +00:00
r = ar_read_file (b, buffer, false, files, filename);
2017-08-22 23:07:21 +00:00
}
if (!filename) {
RListIter *iter;
char *name;
r_list_foreach (files, iter, name) {
printf ("%s\n", name);
2017-08-16 08:20:21 +00:00
}
2017-08-22 23:07:21 +00:00
goto fail;
}
if (!r) {
goto fail;
2017-08-16 08:20:21 +00:00
}
2017-08-22 23:07:21 +00:00
2017-08-16 08:20:21 +00:00
free (buffer);
2017-08-22 23:07:21 +00:00
r_list_free (files);
2017-08-16 08:20:21 +00:00
return b;
2017-08-22 23:07:21 +00:00
fail:
r_list_free (files);
2017-08-16 08:20:21 +00:00
free (buffer);
ar_close (b);
return NULL;
}
R_API int ar_close(RBuffer *b) {
r_buf_free (b);
return 0;
}
R_API int ar_read_at(RBuffer *b, ut64 off, void *buf, int count) {
return r_buf_read_at (b, off, buf, count);
2017-08-16 08:20:21 +00:00
}
R_API int ar_write_at(RBuffer *b, ut64 off, void *buf, int count) {
return r_buf_write_at (b, off, buf, count);
2017-08-16 08:20:21 +00:00
}
int ar_read(RBuffer *b, void *dest, int len) {
int r = r_buf_read (b, dest, len);
2017-08-16 08:20:21 +00:00
if (!r) {
return 0;
}
r_buf_seek (b, r, R_BUF_CUR);
2017-08-16 08:20:21 +00:00
return r;
}
2017-08-22 23:07:21 +00:00
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;
}
2017-08-24 11:37:20 +00:00
int ar_read_file(RBuffer *b, char *buffer, bool lookup, RList *files, const char *filename) {
2017-08-22 23:07:21 +00:00
ut64 filesize = 0;
char *tmp = NULL;
char *curfile = NULL;
ut32 index = -1;
int r;
/* File identifier */
if (lookup) {
2017-08-24 11:37:20 +00:00
ar_read (b, buffer, AR_FILENAME_LEN);
2017-08-22 23:07:21 +00:00
} else {
2017-08-24 11:37:20 +00:00
ar_read (b, buffer, 2);
/* Fix padding issues */
if (*buffer == '\n') {
buffer[0] = buffer[1];
r_buf_seek (b, -1, R_BUF_CUR);
2017-08-24 11:37:20 +00:00
ar_read (b, buffer, 2);
}
ar_read (b, buffer + 2, AR_FILENAME_LEN - 2);
2017-08-22 23:07:21 +00:00
}
2017-08-24 11:37:20 +00:00
buffer[AR_FILENAME_LEN] = '\0';
2017-08-22 23:07:21 +00:00
/* Fix some padding issues */
2017-08-24 11:37:20 +00:00
if (buffer[AR_FILENAME_LEN - 1] != '/' && buffer[AR_FILENAME_LEN - 1] != ' ') {
// Find padding offset
2017-08-23 14:45:05 +00:00
tmp = (char *)r_str_lchr (buffer, ' ');
if (!tmp) {
2017-08-24 11:37:20 +00:00
goto fail;
2017-08-23 14:45:05 +00:00
}
2017-08-22 23:07:21 +00:00
int dif = (int) (tmp - buffer);
dif = 31 - dif;
2017-08-24 11:37:20 +00:00
// Re-read the whole filename
r_buf_seek (b, -dif, R_BUF_CUR);
2017-08-24 11:37:20 +00:00
r = ar_read (b, buffer, AR_FILENAME_LEN);
2018-12-13 23:17:50 +00:00
if (r != AR_FILENAME_LEN) {
goto fail;
}
2017-08-22 23:07:21 +00:00
}
free (curfile);
curfile = strdup (buffer);
if (!curfile) {
2017-08-24 11:37:20 +00:00
goto fail;
2017-08-22 23:07:21 +00:00
}
/* 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) {
2017-08-24 11:37:20 +00:00
goto fail;
2017-08-22 23:07:21 +00:00
}
*tmp = '\0';
if (files) {
r_list_append (files, strdup (curfile));
}
}
2017-08-24 11:37:20 +00:00
/* Timestamp 12
* Owner ID 6
* Group ID 6
* File Mode 8
* File Size 10
* Header end 2 */
r = ar_read (b, buffer, 44);
if (r != 44) {
goto fail;
2017-08-22 23:07:21 +00:00
}
2017-08-24 11:37:20 +00:00
filesize = strtoull (buffer + 32, &tmp, 10);
2017-08-22 23:07:21 +00:00
/* Header end */
2017-08-24 11:37:20 +00:00
if (strncmp (buffer + 42, AR_FILE_HEADER_END, 2)) {
goto fail;
2017-08-22 23:07:21 +00:00
}
/* File content */
if (!lookup && filename) {
/* Check filename */
if (index == index_filename || !strcmp (curfile, filename)) {
r_buf_resize(b, filesize);
2017-08-23 14:45:05 +00:00
free (curfile);
return r_buf_size (b);
2017-08-22 23:07:21 +00:00
}
}
2018-12-06 16:00:08 +00:00
(void)ar_read (b, buffer, 1);
2017-08-22 23:07:21 +00:00
r_buf_seek (b, filesize - 1, R_BUF_CUR);
2017-08-23 14:45:05 +00:00
free (curfile);
2017-08-22 23:07:21 +00:00
return filesize;
2017-08-24 11:37:20 +00:00
fail:
free (curfile);
return 0;
2017-08-22 23:07:21 +00:00
}
int ar_read_filename_table(RBuffer *b, char *buffer, RList *files, const char *filename) {
2017-08-24 11:37:20 +00:00
int r = ar_read (b, buffer, AR_FILENAME_LEN);
if (r != AR_FILENAME_LEN) {
2017-08-22 23:07:21 +00:00
return 0;
}
if (strncmp (buffer, "//", 2)) {
2017-08-24 11:37:20 +00:00
// What we read was not a filename table, just go back
r_buf_seek (b, -AR_FILENAME_LEN, R_BUF_CUR);
2017-08-22 23:07:21 +00:00
return 0;
}
/* Read table size */
r_buf_seek (b, 32, R_BUF_CUR);
2017-08-22 23:07:21 +00:00
r = ar_read (b, buffer, 10);
2018-12-13 23:17:50 +00:00
if (r != 10) {
return 0;
}
2017-08-22 23:07:21 +00:00
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') */
r_buf_seek (b, 1, R_BUF_CUR);
2017-08-22 23:07:21 +00:00
index++;
}
return len;
}