| 1 |
/*
|
| 2 |
* Copyright 2003-2012 Gentoo Foundation
|
| 3 |
* Distributed under the terms of the GNU General Public License v2
|
| 4 |
* $Header: /var/cvsroot/gentoo-projects/pax-utils/paxinc.c,v 1.14 2010/12/08 01:16:01 vapier Exp $
|
| 5 |
*
|
| 6 |
* Copyright 2005-2012 Ned Ludd - <solar@gentoo.org>
|
| 7 |
* Copyright 2005-2012 Mike Frysinger - <vapier@gentoo.org>
|
| 8 |
*/
|
| 9 |
|
| 10 |
/* stick common symbols here that are needed by paxinc.h */
|
| 11 |
|
| 12 |
#define IN_paxinc
|
| 13 |
#include "paxinc.h"
|
| 14 |
|
| 15 |
char do_reverse_endian;
|
| 16 |
|
| 17 |
/* some of this ar code was taken from busybox */
|
| 18 |
|
| 19 |
#define AR_MAGIC "!<arch>"
|
| 20 |
#define AR_MAGIC_SIZE (sizeof(AR_MAGIC)-1) /* dont count null byte */
|
| 21 |
archive_handle *ar_open_fd(const char *filename, int fd)
|
| 22 |
{
|
| 23 |
static archive_handle ret;
|
| 24 |
char buf[AR_MAGIC_SIZE];
|
| 25 |
|
| 26 |
ret.filename = filename;
|
| 27 |
ret.fd = fd;
|
| 28 |
ret.skip = 0;
|
| 29 |
ret.extfn = NULL;
|
| 30 |
|
| 31 |
if (read(ret.fd, buf, AR_MAGIC_SIZE) != AR_MAGIC_SIZE)
|
| 32 |
return NULL;
|
| 33 |
if (strncmp(buf, AR_MAGIC, AR_MAGIC_SIZE))
|
| 34 |
return NULL;
|
| 35 |
|
| 36 |
return &ret;
|
| 37 |
}
|
| 38 |
archive_handle *ar_open(const char *filename)
|
| 39 |
{
|
| 40 |
int fd;
|
| 41 |
archive_handle *ret;
|
| 42 |
|
| 43 |
if ((fd=open(filename, O_RDONLY)) == -1)
|
| 44 |
err("Could not open '%s'", filename);
|
| 45 |
|
| 46 |
ret = ar_open_fd(filename, fd);
|
| 47 |
if (ret == NULL)
|
| 48 |
close(fd);
|
| 49 |
|
| 50 |
return ret;
|
| 51 |
}
|
| 52 |
|
| 53 |
archive_member *ar_next(archive_handle *ar)
|
| 54 |
{
|
| 55 |
char *s;
|
| 56 |
size_t len = 0;
|
| 57 |
static archive_member ret;
|
| 58 |
|
| 59 |
if (ar->skip && lseek(ar->fd, ar->skip, SEEK_CUR) == -1) {
|
| 60 |
close_and_ret:
|
| 61 |
close(ar->fd);
|
| 62 |
return NULL;
|
| 63 |
}
|
| 64 |
|
| 65 |
if (read(ar->fd, ret.buf.raw, sizeof(ret.buf.raw)) != sizeof(ret.buf.raw))
|
| 66 |
goto close_and_ret;
|
| 67 |
|
| 68 |
/* ar header starts on an even byte (2 byte aligned)
|
| 69 |
* '\n' is used for padding */
|
| 70 |
if (ret.buf.raw[0] == '\n') {
|
| 71 |
memmove(ret.buf.raw, ret.buf.raw+1, 59);
|
| 72 |
if (read(ar->fd, ret.buf.raw+59, 1) != 1)
|
| 73 |
goto close_and_ret;
|
| 74 |
}
|
| 75 |
|
| 76 |
if ((ret.buf.formatted.magic[0] != '`') || (ret.buf.formatted.magic[1] != '\n')) {
|
| 77 |
warn("Invalid ar entry");
|
| 78 |
goto close_and_ret;
|
| 79 |
}
|
| 80 |
|
| 81 |
if (ret.buf.formatted.name[0] == '/' && ret.buf.formatted.name[1] == '/') {
|
| 82 |
if (ar->extfn != NULL) {
|
| 83 |
warn("Duplicate GNU extended filename section");
|
| 84 |
goto close_and_ret;
|
| 85 |
}
|
| 86 |
len = atoi(ret.buf.formatted.size);
|
| 87 |
/* we will leak this memory */
|
| 88 |
ar->extfn = xmalloc(sizeof(char) * (len + 1));
|
| 89 |
if (read(ar->fd, ar->extfn, len) != len)
|
| 90 |
goto close_and_ret;
|
| 91 |
ar->extfn[len--] = '\0';
|
| 92 |
for (; len > 0; len--)
|
| 93 |
if (ar->extfn[len] == '\n')
|
| 94 |
ar->extfn[len] = '\0';
|
| 95 |
ar->skip = 0;
|
| 96 |
return ar_next(ar);
|
| 97 |
}
|
| 98 |
|
| 99 |
s = ret.buf.formatted.name;
|
| 100 |
if (s[0] == '#' && s[1] == '1' && s[2] == '/') {
|
| 101 |
/* BSD extended filename, always in use on Darwin */
|
| 102 |
len = atoi(s + 3);
|
| 103 |
if (len <= sizeof(ret.buf.formatted.name)) {
|
| 104 |
if (read(ar->fd, ret.buf.formatted.name, len) != len)
|
| 105 |
goto close_and_ret;
|
| 106 |
} else {
|
| 107 |
s = alloca(sizeof(char) * len);
|
| 108 |
if (read(ar->fd, s, len) != len)
|
| 109 |
goto close_and_ret;
|
| 110 |
}
|
| 111 |
} else if (s[0] == '/' && s[1] >= '0' && s[1] <= '9') {
|
| 112 |
/* GNU extended filename */
|
| 113 |
if (ar->extfn == NULL) {
|
| 114 |
warn("GNU extended filename without special data section");
|
| 115 |
goto close_and_ret;
|
| 116 |
}
|
| 117 |
s = ar->extfn + atoi(s + 1);
|
| 118 |
}
|
| 119 |
|
| 120 |
snprintf(ret.name, sizeof(ret.name), "%s:%s", ar->filename, s);
|
| 121 |
if ((s=strchr(ret.name+strlen(ar->filename), '/')) != NULL)
|
| 122 |
*s = '\0';
|
| 123 |
ret.date = atoi(ret.buf.formatted.date);
|
| 124 |
ret.uid = atoi(ret.buf.formatted.uid);
|
| 125 |
ret.gid = atoi(ret.buf.formatted.gid);
|
| 126 |
ret.mode = strtol(ret.buf.formatted.mode, NULL, 8);
|
| 127 |
ret.size = atoi(ret.buf.formatted.size);
|
| 128 |
ar->skip = ret.size - len;
|
| 129 |
|
| 130 |
return &ret;
|
| 131 |
}
|
| 132 |
|
| 133 |
/* Convert file perms into octal string */
|
| 134 |
const char *strfileperms(const char *fname)
|
| 135 |
{
|
| 136 |
struct stat st;
|
| 137 |
static char buf[8];
|
| 138 |
|
| 139 |
if (stat(fname, &st) == -1)
|
| 140 |
return "";
|
| 141 |
|
| 142 |
snprintf(buf, sizeof(buf), "%o", st.st_mode);
|
| 143 |
|
| 144 |
return buf + 2;
|
| 145 |
}
|
| 146 |
|
| 147 |
/* Color helpers */
|
| 148 |
#define COLOR(c,b) "\e[" c ";" b "m"
|
| 149 |
const char *NORM = COLOR("00", "00");
|
| 150 |
const char *RED = COLOR("31", "01");
|
| 151 |
const char *YELLOW = COLOR("33", "01");
|
| 152 |
|
| 153 |
void color_init(bool disable)
|
| 154 |
{
|
| 155 |
if (!disable) {
|
| 156 |
const char *nocolor = getenv("NOCOLOR");
|
| 157 |
if (nocolor)
|
| 158 |
disable = !strcmp(nocolor, "yes") || !strcmp(nocolor, "true");
|
| 159 |
}
|
| 160 |
if (disable)
|
| 161 |
NORM = RED = YELLOW = "";
|
| 162 |
}
|