Rizin
unix-like reverse engineering framework and cli tools
ar.c File Reference
#include <stdio.h>
#include "ar.h"

Go to the source code of this file.

Classes

struct  Filetable
 

Macros

#define AR_MAGIC_HEADER   "!<arch>\n"
 
#define AR_FILE_HEADER_END   "`\n"
 
#define VERIFY_AR_NUM_FIELD(x, s)
 

Typedefs

typedef struct Filetable filetable
 

Functions

static RzArFparfp_new (RzBuffer *b, bool shared_buf)
 
bool ar_check_magic (RzBuffer *b)
 
static void arf_clean_name (RzArFp *arf)
 
static char * name_from_table (ut64 off, filetable *tbl)
 
static int ar_parse_header (RzArFp *arf, filetable *tbl, ut64 arsize)
 
RZ_API RzListar_open_all (const char *arname, int perm)
 Open specific file withen a ar/lib file. More...
 
RZ_API RzArFpar_open_file (const char *arname, int perm, const char *filename)
 Open specific file withen a ar/lib file. More...
 
RZ_API void ar_close (RzArFp *f)
 
RZ_API int ar_read_at (RzArFp *f, ut64 off, void *buf, int count)
 
RZ_API int ar_write_at (RzArFp *f, ut64 off, void *buf, int count)
 

Macro Definition Documentation

◆ AR_FILE_HEADER_END

#define AR_FILE_HEADER_END   "`\n"

Definition at line 7 of file ar.c.

◆ AR_MAGIC_HEADER

#define AR_MAGIC_HEADER   "!<arch>\n"

Definition at line 6 of file ar.c.

◆ VERIFY_AR_NUM_FIELD

#define VERIFY_AR_NUM_FIELD (   x,
  s 
)
Value:
x[sizeof(x) - 1] = '\0'; \
rz_str_trim_tail(x); \
if (x[0] != '\0' && (x[0] == '-' || !rz_str_isnumber(x))) { \
RZ_LOG_ERROR("ar: Malformed AR: bad %s in header at offset 0x%" PFMT64x "\n", s, h_off); \
return -1; \
}
int x
Definition: mipsasm.c:20
static RzSocket * s
Definition: rtr.c:28
RZ_API bool rz_str_isnumber(const char *str)
Definition: str.c:3550
#define PFMT64x
Definition: rz_types.h:393

Definition at line 67 of file ar.c.

Typedef Documentation

◆ filetable

typedef struct Filetable filetable

Function Documentation

◆ ar_check_magic()

bool ar_check_magic ( RzBuffer b)

Definition at line 28 of file ar.c.

28  {
29  char buf[sizeof(AR_MAGIC_HEADER) - 1];
30  if (rz_buf_read(b, (ut8 *)buf, sizeof(buf)) != sizeof(buf)) {
31  return false;
32  }
33  if (strncmp(buf, AR_MAGIC_HEADER, 8)) {
34  RZ_LOG_ERROR("ar: Wrong file type.\n");
35  return false;
36  }
37  return true;
38 }
#define AR_MAGIC_HEADER
Definition: ar.c:6
voidpf void * buf
Definition: ioapi.h:138
uint8_t ut8
Definition: lh5801.h:11
RZ_API st64 rz_buf_read(RZ_NONNULL RzBuffer *b, RZ_NONNULL RZ_OUT ut8 *buf, ut64 len)
#define RZ_LOG_ERROR(fmtstr,...)
Definition: rz_log.h:58
#define b(i)
Definition: sha256.c:42

References AR_MAGIC_HEADER, b, rz_buf_read(), and RZ_LOG_ERROR.

Referenced by ar_open_all(), and ar_open_file().

◆ ar_close()

RZ_API void ar_close ( RzArFp f)

Definition at line 338 of file ar.c.

338  {
339  if (!f) {
340  return;
341  }
342  free(f->name);
343  if (!f->shared_buf) {
344  rz_buf_free(f->buf);
345  }
346  free(f);
347 }
RZ_API void Ht_() free(HtName_(Ht) *ht)
Definition: ht_inc.c:130
RZ_API void rz_buf_free(RzBuffer *b)
Free all internal data hold by the buffer and the buffer.
Definition: buf.c:1253
#define f(i)
Definition: sha256.c:46

References f, free(), and rz_buf_free().

Referenced by ar_open_all(), ar_open_file(), and rz_io_ar_close().

◆ ar_open_all()

RZ_API RzList* ar_open_all ( const char *  arname,
int  perm 
)

Open specific file withen a ar/lib file.

Parameters
arnamethe name of the .a file
Returns
a list of files or NULL

Open an ar/lib and returns all the object files inside it.

Definition at line 218 of file ar.c.

218  {
219  if (!arname) {
220  rz_sys_perror(__FUNCTION__);
221  return NULL;
222  }
223 
225  if (!files) {
226  rz_sys_perror(__FUNCTION__);
227  return NULL;
228  }
229 
230  RzBuffer *b = rz_buf_new_file(arname, perm, 0);
231  if (!b) {
233  rz_sys_perror(__FUNCTION__);
234  return NULL;
235  }
236 
237  ut64 arsize = rz_buf_size(b);
238 
239  if (!ar_check_magic(b)) {
241  rz_buf_free(b);
242  return NULL;
243  }
244 
245  filetable tbl = { NULL, 0, 0 };
246  int res = -1;
247  bool shared = false;
248 
249  do {
250  shared = !rz_list_empty(files);
251  RzArFp *arf = arfp_new(b, shared);
252  if (!arf) {
254  if (!shared) {
255  rz_buf_free(b);
256  }
257  return NULL;
258  }
259  if ((res = ar_parse_header(arf, &tbl, arsize)) <= 0) {
260  // on error or when it has reached the EOF
261  free(tbl.data);
262  ar_close(arf);
263  return files;
264  }
265  if (!rz_list_append(files, arf)) {
266  free(tbl.data);
267  ar_close(arf);
269  return NULL;
270  }
271  } while (res > 0);
272 
273  // this portion should never be reached
274  free(tbl.data);
275  return files;
276 }
bool ar_check_magic(RzBuffer *b)
Definition: ar.c:28
static int ar_parse_header(RzArFp *arf, filetable *tbl, ut64 arsize)
Definition: ar.c:76
static RzArFp * arfp_new(RzBuffer *b, bool shared_buf)
Definition: ar.c:15
RZ_API void ar_close(RzArFp *f)
Definition: ar.c:338
#define NULL
Definition: cris-opc.c:27
checking print the parsed form of the magic use in n conjunction with m to debug a new magic file n before installing it n output MIME type special files
Definition: file_opts.h:46
RZ_API RZ_OWN RzList * rz_list_newf(RzListFree f)
Returns a new initialized RzList pointer and sets the free method.
Definition: list.c:248
RZ_API RZ_BORROW RzListIter * rz_list_append(RZ_NONNULL RzList *list, void *data)
Appends at the end of the list a new element.
Definition: list.c:288
RZ_API void rz_list_free(RZ_NONNULL RzList *list)
Empties the list and frees the list pointer.
Definition: list.c:137
RZ_API ut64 rz_buf_size(RZ_NONNULL RzBuffer *b)
Return the size of the buffer.
Definition: buf.c:1225
RZ_API RZ_OWN RzBuffer * rz_buf_new_file(const char *file, int perm, int mode)
Creates a new buffer from a file.
Definition: buf.c:317
void(* RzListFree)(void *ptr)
Definition: rz_list.h:11
#define rz_sys_perror(x)
Definition: rz_types.h:336
Definition: ar.c:9
char * data
Definition: ar.c:10
Definition: ar.h:7
ut64(WINAPI *w32_GetEnabledXStateFeatures)()

References ar_check_magic(), ar_close(), ar_parse_header(), arfp_new(), b, Filetable::data, files, free(), NULL, rz_buf_free(), rz_buf_new_file(), rz_buf_size(), rz_list_append(), rz_list_free(), rz_list_newf(), rz_sys_perror, and ut64().

Referenced by rz_io_ar_open_many().

◆ ar_open_file()

RZ_API RzArFp* ar_open_file ( const char *  arname,
int  perm,
const char *  filename 
)

Open specific file withen a ar/lib file.

Parameters
arnamethe name of the .a file
filenamethe name of file in the .a file that you wish to open
Returns
a handle of the internal filename or NULL

Open an ar/lib file by name.

Definition at line 286 of file ar.c.

286  {
287  if (!filename || !arname) {
288  rz_sys_perror(__FUNCTION__);
289  return NULL;
290  }
291 
292  RzBuffer *b = rz_buf_new_file(arname, perm, 0);
293  if (!b) {
294  rz_sys_perror(__FUNCTION__);
295  return NULL;
296  }
297 
298  ut64 arsize = rz_buf_size(b);
299 
300  if (!ar_check_magic(b)) {
301  rz_buf_free(b);
302  return NULL;
303  }
304 
305  RzArFp *arf = arfp_new(b, NULL);
306  if (!arf) {
307  rz_buf_free(b);
308  return NULL;
309  }
310 
311  filetable tbl = { NULL, 0, 0 };
312  int r;
313  while ((r = ar_parse_header(arf, &tbl, arsize)) > 0) {
314  if (filename) {
315  if (!strcmp(filename, arf->name)) {
316  // found the right file
317  break;
318  }
319  }
320 
321  // clean RzArFp for next loop
322  arf_clean_name(arf);
323  }
324 
325  free(tbl.data);
326 
327  if (r <= 0) {
328  if (r == 0 && filename) {
329  RZ_LOG_ERROR("ar: Cound not find file '%s' in archive '%s'\n", filename, arname);
330  }
331  ar_close(arf); // results in buf being free'd
332  return NULL;
333  }
334 
335  return arf;
336 }
static void arf_clean_name(RzArFp *arf)
Definition: ar.c:40
#define r
Definition: crypto_rc6.c:12
const char * filename
Definition: ioapi.h:137
char * name
Definition: ar.h:8

References ar_check_magic(), ar_close(), ar_parse_header(), arf_clean_name(), arfp_new(), b, Filetable::data, free(), RZARFP::name, NULL, r, rz_buf_free(), rz_buf_new_file(), rz_buf_size(), RZ_LOG_ERROR, rz_sys_perror, and ut64().

Referenced by rz_io_ar_open().

◆ ar_parse_header()

static int ar_parse_header ( RzArFp arf,
filetable tbl,
ut64  arsize 
)
static

Definition at line 76 of file ar.c.

76  {
77  rz_return_val_if_fail(arf && arf->buf && tbl, -1);
78  RzBuffer *b = arf->buf;
79 
80  ut64 h_off = rz_buf_tell(b);
81  if (h_off % 2 == 1) {
82  // headers start at even offset
83  ut8 tmp[1];
84  if (rz_buf_read(b, tmp, 1) != 1 || tmp[0] != '\n') {
85  return -1;
86  }
87  h_off++;
88  }
89 
90  struct header {
91  char name[16];
92  char timestamp[12];
93  char oid[6];
94  char gid[6];
95  char mode[8];
96  char size[10];
97  char end[2];
98  } h;
99 
100  int r = rz_buf_read(b, (ut8 *)&h, sizeof(h));
101  if (r != sizeof(h)) {
102  if (r == 0) {
103  return 0; // no more file
104  }
105  if (r < 0) {
106  RZ_LOG_ERROR("ar: io error\n");
107  } else {
108  RZ_LOG_ERROR("ar: Invalid file length\n");
109  }
110  return -1;
111  }
112 
113  if (strncmp(h.end, AR_FILE_HEADER_END, sizeof(h.end))) {
114  RZ_LOG_ERROR("ar: Invalid header at offset 0x%" PFMT64x ": bad end field\n", h_off);
115  return -1;
116  }
117 
118  // remove trailing spaces from fields and verify they are valid
119  VERIFY_AR_NUM_FIELD(h.timestamp, "timestamp")
120  VERIFY_AR_NUM_FIELD(h.oid, "oid")
121  VERIFY_AR_NUM_FIELD(h.gid, "gid")
124 
125  if (h.size[0] == '\0') {
126  RZ_LOG_ERROR("ar: Malformed AR: bad size in header at offset 0x%" PFMT64x "\n", h_off);
127  return -1;
128  }
129  ut64 size = atol(h.size);
130 
131  h.timestamp[0] = '\0'; // null terminate h.name
132  rz_str_trim_tail(h.name);
133 
134  /*
135  * handle fake files
136  */
137  if (!strcmp(h.name, "/")) {
138  // skip over symbol table
139  if (rz_buf_seek(b, size, RZ_BUF_CUR) <= 0 || rz_buf_tell(b) > arsize) {
140  RZ_LOG_ERROR("ar: Malformed ar: too short\n");
141  return -1;
142  }
143  // return next entry
144  return ar_parse_header(arf, tbl, arsize);
145  } else if (!strcmp(h.name, "//")) {
146  // table of file names
147  if (tbl->data || tbl->size != 0) {
148  RZ_LOG_ERROR("ar: invalid ar file: two filename lookup tables (at 0x%" PFMT64x ", and 0x%" PFMT64x ")\n", tbl->offset, h_off);
149  return -1;
150  }
151  tbl->data = (char *)malloc(size + 1);
152  if (!tbl->data || rz_buf_read(b, (ut8 *)tbl->data, size) != size) {
153  return -1;
154  }
155  tbl->data[size] = '\0';
156  tbl->size = size;
157  tbl->offset = h_off;
158 
159  // return next entry
160  return ar_parse_header(arf, tbl, arsize);
161  }
162 
163  /*
164  * handle real files
165  */
166  RzList *list = rz_str_split_duplist(h.name, "/", false); // don't strip spaces
167  if (rz_list_length(list) != 2) {
169  RZ_LOG_ERROR("ar: invalid ar file: invalid file name in header at: 0x%" PFMT64x "\n", h_off);
170  return -1;
171  }
172 
173  char *tmp = rz_list_pop_head(list);
174  if (tmp[0] == '\0') {
175  free(tmp);
176  tmp = rz_list_pop(list);
177  if (rz_str_isnumber(tmp)) {
178  arf->name = name_from_table(atol(tmp), tbl);
179  } else {
180  RZ_LOG_ERROR("ar: invalid ar file: invalid file name in header at: 0x%" PFMT64x "\n", h_off);
181  }
182  free(tmp);
183  } else {
184  arf->name = tmp;
185  tmp = rz_list_pop(list);
186  if (tmp[0]) {
187  arf_clean_name(arf);
188  RZ_LOG_ERROR("ar: invalid ar file: invalid file name in header at: 0x%" PFMT64x "\n", h_off);
189  }
190  free(tmp);
191  }
193 
194  if (!arf->name) {
195  return -1;
196  }
197  arf->start = rz_buf_tell(b);
198  arf->end = arf->start + size;
199 
200  // skip over file content and make sure it is all there
201  if (rz_buf_seek(b, size, RZ_BUF_CUR) <= 0 || rz_buf_tell(b) > arsize) {
202  RZ_LOG_ERROR("ar: Malformed ar: missing the end of %s (header offset: 0x%" PFMT64x ")\n", arf->name, h_off);
203  arf_clean_name(arf);
204  return -1;
205  }
206 
207  return 1;
208 }
static char * name_from_table(ut64 off, filetable *tbl)
Definition: ar.c:45
#define AR_FILE_HEADER_END
Definition: ar.c:7
#define VERIFY_AR_NUM_FIELD(x, s)
Definition: ar.c:67
voidpf void uLong size
Definition: ioapi.h:138
const char int mode
Definition: ioapi.h:137
static void list(RzEgg *egg)
Definition: rz-gg.c:52
RZ_API RZ_OWN void * rz_list_pop(RZ_NONNULL RzList *list)
Removes and returns the last element of the list.
Definition: list.c:376
RZ_API ut32 rz_list_length(RZ_NONNULL const RzList *list)
Returns the length of the list.
Definition: list.c:109
RZ_API RZ_OWN void * rz_list_pop_head(RZ_NONNULL RzList *list)
Removes and returns the first element of the list.
Definition: list.c:401
void * malloc(size_t size)
Definition: malloc.c:123
#define header(is_bt, len_min, ret_op)
#define rz_return_val_if_fail(expr, val)
Definition: rz_assert.h:108
RZ_API ut64 rz_buf_tell(RZ_NONNULL RzBuffer *b)
Return the current cursor position.
Definition: buf.c:1238
RZ_API st64 rz_buf_seek(RZ_NONNULL RzBuffer *b, st64 addr, int whence)
Modify the current cursor position in the buffer.
Definition: buf.c:1166
#define RZ_BUF_CUR
Definition: rz_buf.h:15
RZ_API RZ_BORROW char * rz_str_trim_tail(RZ_NONNULL char *str)
Removes whitespace characters (space, tab, newline etc.) from the end of a string and replaces them w...
Definition: str_trim.c:125
RZ_API RzList * rz_str_split_duplist(const char *str, const char *c, bool trim)
Split the string str according to the substring c and returns a RzList with the result.
Definition: str.c:3464
#define h(i)
Definition: sha256.c:48
ut64 offset
Definition: ar.c:12
ut64 size
Definition: ar.c:11
ut64 start
Definition: ar.h:9
ut64 end
Definition: ar.h:10
RzBuffer * buf
Definition: ar.h:11
Definition: z80asm.h:102
if(dbg->bits==RZ_SYS_BITS_64)
Definition: windows-arm64.h:4

References AR_FILE_HEADER_END, arf_clean_name(), b, RZARFP::buf, Filetable::data, test_evm::end, RZARFP::end, free(), h, header, list(), malloc(), RZARFP::name, name_from_table(), Filetable::offset, PFMT64x, r, RZ_BUF_CUR, rz_buf_read(), rz_buf_seek(), rz_buf_tell(), rz_list_free(), rz_list_length(), rz_list_pop(), rz_list_pop_head(), RZ_LOG_ERROR, rz_return_val_if_fail, rz_str_isnumber(), rz_str_split_duplist(), rz_str_trim_tail(), Filetable::size, RZARFP::start, autogen_x86imm::tmp, ut64(), and VERIFY_AR_NUM_FIELD.

Referenced by ar_open_all(), and ar_open_file().

◆ ar_read_at()

RZ_API int ar_read_at ( RzArFp f,
ut64  off,
void *  buf,
int  count 
)

Definition at line 349 of file ar.c.

349  {
350  off += f->start;
351  if (off > f->end) {
352  return -1;
353  }
354  if (count + off > f->end) {
355  count = f->end - off;
356  }
357  return rz_buf_read_at(f->buf, off, buf, count);
358 }
static static sync static getppid static getegid const char static filename char static len const char char static bufsiz static mask static vfork const void static prot static getpgrp const char static swapflags static arg static fd static protocol static who struct sockaddr static addrlen static backlog struct timeval struct timezone static tz const struct iovec static count static mode const void const struct sockaddr static tolen const char static pathname void count
Definition: sflib.h:98
int off
Definition: pal.c:13
RZ_API st64 rz_buf_read_at(RZ_NONNULL RzBuffer *b, ut64 addr, RZ_NONNULL RZ_OUT ut8 *buf, ut64 len)
Read len bytes of the buffer at the specified address.
Definition: buf.c:1136

References count, f, off, and rz_buf_read_at().

Referenced by rz_io_ar_read().

◆ ar_write_at()

RZ_API int ar_write_at ( RzArFp f,
ut64  off,
void *  buf,
int  count 
)

Definition at line 360 of file ar.c.

360  {
361  off += f->start;
362  if (off > f->end) {
363  return -1;
364  }
365  if (count + off > f->end) {
366  count = f->end - off;
367  }
368  return rz_buf_write_at(f->buf, off + f->start, buf, count);
369 }
RZ_API st64 rz_buf_write_at(RZ_NONNULL RzBuffer *b, ut64 addr, RZ_NONNULL const ut8 *buf, ut64 len)
Write len bytes of the buffer at the specified address.
Definition: buf.c:1197

References count, f, off, and rz_buf_write_at().

Referenced by rz_io_ar_write().

◆ arf_clean_name()

static void arf_clean_name ( RzArFp arf)
inlinestatic

Definition at line 40 of file ar.c.

40  {
41  free(arf->name);
42  arf->name = NULL;
43 }

References free(), RZARFP::name, and NULL.

Referenced by ar_open_file(), and ar_parse_header().

◆ arfp_new()

static RzArFp* arfp_new ( RzBuffer b,
bool  shared_buf 
)
static

Definition at line 15 of file ar.c.

15  {
17  RzArFp *f = RZ_NEW(RzArFp);
18  if (f) {
19  f->name = NULL;
20  f->shared_buf = shared_buf;
21  f->buf = b;
22  f->start = 0;
23  f->end = 0;
24  }
25  return f;
26 }
#define RZ_NEW(x)
Definition: rz_types.h:285

References b, f, NULL, RZ_NEW, and rz_return_val_if_fail.

Referenced by ar_open_all(), and ar_open_file().

◆ name_from_table()

static char* name_from_table ( ut64  off,
filetable tbl 
)
static

Definition at line 45 of file ar.c.

45  {
46  if (off > tbl->size) {
47  RZ_LOG_ERROR("ar: Malformed ar: name lookup out of bounds for header at offset 0x%" PFMT64x "\n", off);
48  return NULL;
49  }
50  // files are suppose to be line feed seperated but we also stop on invalid
51  // chars, such as '/' or '\0'
52 
53  char *buf = tbl->data;
54  ut64 i;
55  for (i = off; i < tbl->size; i++) {
56  char c = buf[i];
57  if (c == '\n' || c == '\0') {
58  break;
59  }
60  }
61  if (i == off) {
62  return NULL;
63  }
64  return rz_str_newlen(buf + off, i - off - 1);
65 }
lzma_index ** i
Definition: index.h:629
RZ_API char RZ_API char * rz_str_newlen(const char *str, int len)
Definition: str.c:871
#define c(i)
Definition: sha256.c:43

References c, Filetable::data, i, NULL, off, PFMT64x, RZ_LOG_ERROR, rz_str_newlen(), Filetable::size, and ut64().

Referenced by ar_parse_header().