This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
libbfd problem
- From: Laszlo Papp <djszapi at archlinux dot us>
- To: binutils at sourceware dot org
- Date: Mon, 25 Oct 2010 12:45:30 +0300
- Subject: libbfd problem
Hello,
I have just attached my 'ar' like program. The purpose is that to
extract a debian package, but it seems to not work on my armv7. It
works perfectly on i686, x86_64 host linux distributions.
When I try to run it on armv7, I get empty or unreasonable files... I
use libbfd library for this task, please help me :)
Best Regards,
Laszlo Papp
#include <bfd.h>
#include <stdio.h>
#include <stdlib.h>
#include <linux/limits.h>
#include <sys/stat.h>
#include <errno.h>
#include <ctype.h>
#include <string.h>
#include <stdbool.h>
#include <unistd.h>
#define REDIRECT_STDERR_TO_STDOUT " 2>&1"
#define CONTROL_FILE_DEBIAN "control.tar.gz"
#define DATA_FILE_DEBIAN "data.tar.gz"
#define DEBIAN_BINARY "debian-binary"
#define BUFSIZE 8192
void list_matching_formats(char **p)
{
fprintf(stderr, "Matching formats:");
while (*p)
fprintf (stderr, " %s", *p++);
fputc ('\n', stderr);
}
void bfd_nonfatal(const char *string)
{
const char *errmsg = bfd_errmsg(bfd_get_error());
if (string)
fprintf(stderr, "%s: %s\n", string, errmsg);
else
fprintf(stderr, "%s\n", errmsg);
}
void bfd_fatal(const char *string)
{
bfd_nonfatal(string);
exit(1);
}
bfd *open_inarch(const char *archive_filename, const char *file)
{
const char *target = 0;
bfd **last_one = 0;
bfd *next_one = 0;
struct stat sbuf;
bfd *arch = 0;
char **matching = 0;
const char *output_filename = 0;
bfd_set_error(bfd_error_no_error);
target = 0;
printf("TESTP0\r\n");
if (stat(archive_filename, &sbuf)) {
printf("TESTP1\r\n");
/* Try to figure out the target to use for the archive from the
first object on the list. */
if (file) {
bfd *obj;
obj = bfd_openr(file, 0);
if (obj) {
if (bfd_check_format (obj, bfd_object))
target = bfd_get_target (obj);
(void) bfd_close (obj);
}
}
/* Create an empty archive. */
arch = bfd_openw(archive_filename, target);
if (arch == 0 || !bfd_set_format(arch, bfd_archive) || !bfd_close(arch))
bfd_fatal(archive_filename);
/* If we die creating a new archive, don't leave it around. */
output_filename = archive_filename;
}
arch = bfd_openr(archive_filename, target);
if (arch == 0) {
printf("TESTP2\r\n");
bloser:
bfd_fatal(archive_filename);
}
if (!bfd_check_format_matches(arch, bfd_archive, &matching)) {
printf("TESTP3\r\n");
bfd_nonfatal(archive_filename);
if (bfd_get_error() == bfd_error_file_ambiguously_recognized) {
list_matching_formats (matching);
free(matching);
}
exit(1);
}
last_one = &(arch->archive_next);
/* Read all the contents right away, regardless. */
for (next_one = bfd_openr_next_archived_file(arch, 0);
next_one;
next_one = bfd_openr_next_archived_file(arch, next_one)) {
/* PROGRESS (1); */
*last_one = next_one;
last_one = &next_one->archive_next;
}
*last_one = (bfd *)0;
if (bfd_get_error() != bfd_error_no_more_archived_files)
goto bloser;
printf("TESTP4\r\n");
return arch;
}
/* Normalize a file name specified on the command line into a file
name which we will use in an archive. */
static const char *normalize(const char *file, bfd *abfd)
{
const char *filename;
filename = strrchr (file, '/');
if (filename != (char *)0)
++filename;
else
filename = file;
return filename;
}
/* Extract a member of the archive into its own file.
* We defer opening the new file until after we have read a BUFSIZ chunk of the
* old one, since we know we have just read the archive header for the old
* one. Since most members are shorter than BUFSIZ, this means we will read
* the old header, read the old data, write a new inode for the new file, and
* write the new data, and be done. This 'optimization' is what comes from
* sitting next to a bare disk and hearing it every time it seeks. -- Gnu
* Gilmore
*/
void extract_file(bfd *abfd)
{
FILE *ostream;
char *cbuf = 0;
size_t nread, tocopy;
size_t ncopied = 0;
size_t size;
struct stat buf;
const char *output_filename = 0;
static FILE *output_file = 0;
cbuf = (char *)malloc(BUFSIZE);
printf("FN: %s\r\n", abfd->filename);
if (bfd_stat_arch_elt(abfd, &buf))
/* xgettext:c-format */
printf("internal stat error on %s", bfd_get_filename(abfd));
size = buf.st_size;
printf("SIZE: %i\r\n", buf.st_size);
bfd_seek(abfd, (file_ptr)0, SEEK_SET);
ostream = 0;
if (size == 0) {
/* Seems like an abstraction violation, eh? Well it's OK! */
output_filename = bfd_get_filename(abfd);
ostream = fopen(output_filename, "wb");
if (ostream == 0) {
printf("ERR1\r\n");
perror(output_filename);
exit(1);
}
output_file = ostream;
} else {
while (ncopied < size) {
tocopy = size - ncopied;
if (tocopy > BUFSIZE)
tocopy = BUFSIZE;
nread = bfd_bread(cbuf, (bfd_size_type) tocopy, abfd);
if (nread != tocopy)
/* xgettext:c-format */
// printf("%s is not a valid archive",
//bfd_get_filename(bfd_my_archive(abfd)));
/* See comment above; this saves disk arm motion */
if (ostream == 0) {
/* Seems like an abstraction violation, eh? Well it's OK! */
output_filename = bfd_get_filename(abfd);
ostream = fopen(output_filename, "wb");
if (ostream == 0) {
perror(output_filename);
exit(1);
}
output_file = ostream;
}
/* fwrite in mingw32 may return int instead of size_t. Cast
the return value to size_t to avoid comparison between
signed and unsigned values. */
if ((size_t)fwrite(cbuf, 1, nread, ostream) != nread)
printf("%s: %s", output_filename, strerror(errno)); ncopied += tocopy;
}
}
if (ostream)
fclose(ostream);
output_file = 0;
output_filename = 0;
chmod(bfd_get_filename(abfd), buf.st_mode);
free(cbuf);
cbuf = 0;
}
/* If COUNT is 0, then FUNCTION is called once on each entry. If nonzero,
COUNT is the length of the FILES chain; FUNCTION is called on each entry
whose name matches one in FILES. */
static void map_over_members(bfd *arch, void (*function)(bfd *), char **files, int count)
{
bfd *head;
int match_count;
printf("COUNT: %i\r\n", count);
if (count == 0) {
for (head = arch->archive_next; head; head = head->archive_next) {
/* PROGRESS (1); */
function(head);
}
return;
}
/* This may appear to be a baroque way of accomplishing what we want.
However we have to iterate over the filenames in order to notice where
a filename is requested but does not exist in the archive. Ditto
mapping over each file each time -- we want to hack multiple
references. */
for (; count > 0; ++files, --count) {
bfd_boolean found = FALSE;
match_count = 0;
for (head = arch->archive_next; head; head = head->archive_next) {
const char *filename;
/* PROGRESS(1); */
filename = head->filename;
printf("MOM_FN: %s\r\n", filename);
if (filename == 0) {
/* Some archive formats don't get the filenames filled in
until the elements are opened. */
struct stat buf;
bfd_stat_arch_elt(head, &buf);
// } else if (bfd_is_thin_archive(arch)) {
// /* Thin archives store full pathnames. Need to normalize. */
// filename = normalize(filename, arch);
// printf("THIN_NORM_FN: %s\r\n", filename);
}
if (filename && (!strcmp(normalize(*files, arch), filename))) {
++match_count;
found = TRUE;
printf("NORM_FN: %s\r\n", filename);
function(head);
}
}
if (!found)
// xgettext:c-format
fprintf(stderr, "no entry %s in archive\n", *files);
}
}
int main(int argc, char **argv)
{
char *extracted_files[] = {DEBIAN_BINARY, CONTROL_FILE_DEBIAN, DATA_FILE_DEBIAN, 0};
bfd *arch = 0;
arch = open_inarch(argv[1], extracted_files[0]);
map_over_members(arch, extract_file, extracted_files, sizeof(extracted_files)/sizeof(extracted_files[0])-1);
return 0;
}