1a85fe12eSEd Maste /*- 2a85fe12eSEd Maste * Copyright (c) 2007-2009 Kai Wang 3a85fe12eSEd Maste * All rights reserved. 4a85fe12eSEd Maste * 5a85fe12eSEd Maste * Redistribution and use in source and binary forms, with or without 6a85fe12eSEd Maste * modification, are permitted provided that the following conditions 7a85fe12eSEd Maste * are met: 8a85fe12eSEd Maste * 1. Redistributions of source code must retain the above copyright 9a85fe12eSEd Maste * notice, this list of conditions and the following disclaimer. 10a85fe12eSEd Maste * 2. Redistributions in binary form must reproduce the above copyright 11a85fe12eSEd Maste * notice, this list of conditions and the following disclaimer in the 12a85fe12eSEd Maste * documentation and/or other materials provided with the distribution. 13a85fe12eSEd Maste * 14a85fe12eSEd Maste * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15a85fe12eSEd Maste * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16a85fe12eSEd Maste * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17a85fe12eSEd Maste * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18a85fe12eSEd Maste * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19a85fe12eSEd Maste * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20a85fe12eSEd Maste * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21a85fe12eSEd Maste * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22a85fe12eSEd Maste * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23a85fe12eSEd Maste * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24a85fe12eSEd Maste * SUCH DAMAGE. 25a85fe12eSEd Maste */ 26a85fe12eSEd Maste 27a85fe12eSEd Maste #include <sys/param.h> 28a85fe12eSEd Maste #include <sys/stat.h> 29a85fe12eSEd Maste #include <err.h> 30a85fe12eSEd Maste #include <stdlib.h> 31a85fe12eSEd Maste #include <string.h> 32a85fe12eSEd Maste #include <unistd.h> 33a85fe12eSEd Maste 34a85fe12eSEd Maste #ifndef LIBELF_AR 35a85fe12eSEd Maste #include <archive.h> 36a85fe12eSEd Maste #include <archive_entry.h> 37a85fe12eSEd Maste #endif /* ! LIBELF_AR */ 38a85fe12eSEd Maste 39a85fe12eSEd Maste #include "elfcopy.h" 40a85fe12eSEd Maste 41b6d812d2SEd Maste ELFTC_VCSID("$Id: archive.c 3490 2016-08-31 00:12:22Z emaste $"); 42a85fe12eSEd Maste 43a85fe12eSEd Maste #define _ARMAG_LEN 8 /* length of ar magic string */ 44a85fe12eSEd Maste #define _ARHDR_LEN 60 /* length of ar header */ 45a85fe12eSEd Maste #define _INIT_AS_CAP 128 /* initial archive string table size */ 46a85fe12eSEd Maste #define _INIT_SYMOFF_CAP (256*(sizeof(uint32_t))) /* initial so table size */ 47a85fe12eSEd Maste #define _INIT_SYMNAME_CAP 1024 /* initial sn table size */ 48a85fe12eSEd Maste #define _MAXNAMELEN_SVR4 15 /* max member name length in svr4 variant */ 49a85fe12eSEd Maste 50a85fe12eSEd Maste #ifndef LIBELF_AR 51a85fe12eSEd Maste static void ac_read_objs(struct elfcopy *ecp, int ifd); 52a85fe12eSEd Maste static void ac_write_cleanup(struct elfcopy *ecp); 53a85fe12eSEd Maste static void ac_write_data(struct archive *a, const void *buf, size_t s); 54a85fe12eSEd Maste static void ac_write_objs(struct elfcopy *ecp, int ofd); 55a85fe12eSEd Maste #endif /* ! LIBELF_AR */ 56a85fe12eSEd Maste static void add_to_ar_str_table(struct elfcopy *elfcopy, const char *name); 57a85fe12eSEd Maste static void add_to_ar_sym_table(struct elfcopy *ecp, const char *name); 58a85fe12eSEd Maste static void extract_arsym(struct elfcopy *ecp); 59a85fe12eSEd Maste static void process_ar_obj(struct elfcopy *ecp, struct ar_obj *obj); 60a85fe12eSEd Maste static void sync_ar(struct elfcopy *ecp); 61a85fe12eSEd Maste 62a85fe12eSEd Maste 63a85fe12eSEd Maste static void 64a85fe12eSEd Maste process_ar_obj(struct elfcopy *ecp, struct ar_obj *obj) 65a85fe12eSEd Maste { 66a85fe12eSEd Maste struct stat sb; 67a85fe12eSEd Maste char *tempfile; 68a85fe12eSEd Maste int fd; 69a85fe12eSEd Maste 70a85fe12eSEd Maste /* Output to a temporary file. */ 71*1e4896b1SDimitry Andric create_tempfile(NULL, &tempfile, &fd); 72a85fe12eSEd Maste if ((ecp->eout = elf_begin(fd, ELF_C_WRITE, NULL)) == NULL) 73a85fe12eSEd Maste errx(EXIT_FAILURE, "elf_begin() failed: %s", 74a85fe12eSEd Maste elf_errmsg(-1)); 75a85fe12eSEd Maste elf_flagelf(ecp->eout, ELF_C_SET, ELF_F_LAYOUT); 76a85fe12eSEd Maste create_elf(ecp); 77a85fe12eSEd Maste elf_end(ecp->ein); 78a85fe12eSEd Maste elf_end(ecp->eout); 79a85fe12eSEd Maste free(obj->buf); 80a85fe12eSEd Maste obj->buf = NULL; 81a85fe12eSEd Maste 82a85fe12eSEd Maste /* Extract archive symbols. */ 83a85fe12eSEd Maste if (lseek(fd, 0, SEEK_SET) < 0) 84a85fe12eSEd Maste err(EXIT_FAILURE, "lseek failed for '%s'", tempfile); 85a85fe12eSEd Maste if ((ecp->eout = elf_begin(fd, ELF_C_READ, NULL)) == NULL) 86a85fe12eSEd Maste errx(EXIT_FAILURE, "elf_begin() failed: %s", 87a85fe12eSEd Maste elf_errmsg(-1)); 88a85fe12eSEd Maste extract_arsym(ecp); 89a85fe12eSEd Maste elf_end(ecp->eout); 90a85fe12eSEd Maste 91a85fe12eSEd Maste if (fstat(fd, &sb) == -1) 92a85fe12eSEd Maste err(EXIT_FAILURE, "fstat %s failed", tempfile); 93a85fe12eSEd Maste if (lseek(fd, 0, SEEK_SET) < 0) 94a85fe12eSEd Maste err(EXIT_FAILURE, "lseek %s failed", tempfile); 95a85fe12eSEd Maste obj->size = sb.st_size; 96a85fe12eSEd Maste if ((obj->maddr = malloc(obj->size)) == NULL) 97a85fe12eSEd Maste err(EXIT_FAILURE, "memory allocation failed for '%s'", 98a85fe12eSEd Maste tempfile); 99a85fe12eSEd Maste if ((size_t) read(fd, obj->maddr, obj->size) != obj->size) 100a85fe12eSEd Maste err(EXIT_FAILURE, "read failed for '%s'", tempfile); 101a85fe12eSEd Maste if (unlink(tempfile)) 102a85fe12eSEd Maste err(EXIT_FAILURE, "unlink %s failed", tempfile); 103a85fe12eSEd Maste free(tempfile); 104a85fe12eSEd Maste close(fd); 105a85fe12eSEd Maste if (strlen(obj->name) > _MAXNAMELEN_SVR4) 106a85fe12eSEd Maste add_to_ar_str_table(ecp, obj->name); 107a85fe12eSEd Maste ecp->rela_off += _ARHDR_LEN + obj->size + obj->size % 2; 108a85fe12eSEd Maste STAILQ_INSERT_TAIL(&ecp->v_arobj, obj, objs); 109a85fe12eSEd Maste } 110a85fe12eSEd Maste 111a85fe12eSEd Maste /* 112a85fe12eSEd Maste * Append to the archive string table buffer. 113a85fe12eSEd Maste */ 114a85fe12eSEd Maste static void 115a85fe12eSEd Maste add_to_ar_str_table(struct elfcopy *ecp, const char *name) 116a85fe12eSEd Maste { 117a85fe12eSEd Maste 118a85fe12eSEd Maste if (ecp->as == NULL) { 119a85fe12eSEd Maste ecp->as_cap = _INIT_AS_CAP; 120a85fe12eSEd Maste ecp->as_sz = 0; 121a85fe12eSEd Maste if ((ecp->as = malloc(ecp->as_cap)) == NULL) 122a85fe12eSEd Maste err(EXIT_FAILURE, "malloc failed"); 123a85fe12eSEd Maste } 124a85fe12eSEd Maste 125a85fe12eSEd Maste /* 126a85fe12eSEd Maste * The space required for holding one member name in as table includes: 127a85fe12eSEd Maste * strlen(name) + (1 for '/') + (1 for '\n') + (possibly 1 for padding). 128a85fe12eSEd Maste */ 129a85fe12eSEd Maste while (ecp->as_sz + strlen(name) + 3 > ecp->as_cap) { 130a85fe12eSEd Maste ecp->as_cap *= 2; 131a85fe12eSEd Maste ecp->as = realloc(ecp->as, ecp->as_cap); 132a85fe12eSEd Maste if (ecp->as == NULL) 133a85fe12eSEd Maste err(EXIT_FAILURE, "realloc failed"); 134a85fe12eSEd Maste } 135a85fe12eSEd Maste strncpy(&ecp->as[ecp->as_sz], name, strlen(name)); 136a85fe12eSEd Maste ecp->as_sz += strlen(name); 137a85fe12eSEd Maste ecp->as[ecp->as_sz++] = '/'; 138a85fe12eSEd Maste ecp->as[ecp->as_sz++] = '\n'; 139a85fe12eSEd Maste } 140a85fe12eSEd Maste 141a85fe12eSEd Maste /* 142a85fe12eSEd Maste * Append to the archive symbol table buffer. 143a85fe12eSEd Maste */ 144a85fe12eSEd Maste static void 145a85fe12eSEd Maste add_to_ar_sym_table(struct elfcopy *ecp, const char *name) 146a85fe12eSEd Maste { 147a85fe12eSEd Maste 148a85fe12eSEd Maste if (ecp->s_so == NULL) { 149a85fe12eSEd Maste if ((ecp->s_so = malloc(_INIT_SYMOFF_CAP)) == NULL) 150a85fe12eSEd Maste err(EXIT_FAILURE, "malloc failed"); 151a85fe12eSEd Maste ecp->s_so_cap = _INIT_SYMOFF_CAP; 152a85fe12eSEd Maste ecp->s_cnt = 0; 153a85fe12eSEd Maste } 154a85fe12eSEd Maste 155a85fe12eSEd Maste if (ecp->s_sn == NULL) { 156a85fe12eSEd Maste if ((ecp->s_sn = malloc(_INIT_SYMNAME_CAP)) == NULL) 157a85fe12eSEd Maste err(EXIT_FAILURE, "malloc failed"); 158a85fe12eSEd Maste ecp->s_sn_cap = _INIT_SYMNAME_CAP; 159a85fe12eSEd Maste ecp->s_sn_sz = 0; 160a85fe12eSEd Maste } 161a85fe12eSEd Maste 162a85fe12eSEd Maste if (ecp->s_cnt * sizeof(uint32_t) >= ecp->s_so_cap) { 163a85fe12eSEd Maste ecp->s_so_cap *= 2; 164a85fe12eSEd Maste ecp->s_so = realloc(ecp->s_so, ecp->s_so_cap); 165a85fe12eSEd Maste if (ecp->s_so == NULL) 166a85fe12eSEd Maste err(EXIT_FAILURE, "realloc failed"); 167a85fe12eSEd Maste } 168a85fe12eSEd Maste ecp->s_so[ecp->s_cnt] = ecp->rela_off; 169a85fe12eSEd Maste ecp->s_cnt++; 170a85fe12eSEd Maste 171a85fe12eSEd Maste /* 172a85fe12eSEd Maste * The space required for holding one symbol name in sn table includes: 173a85fe12eSEd Maste * strlen(name) + (1 for '\n') + (possibly 1 for padding). 174a85fe12eSEd Maste */ 175a85fe12eSEd Maste while (ecp->s_sn_sz + strlen(name) + 2 > ecp->s_sn_cap) { 176a85fe12eSEd Maste ecp->s_sn_cap *= 2; 177a85fe12eSEd Maste ecp->s_sn = realloc(ecp->s_sn, ecp->s_sn_cap); 178a85fe12eSEd Maste if (ecp->s_sn == NULL) 179a85fe12eSEd Maste err(EXIT_FAILURE, "realloc failed"); 180a85fe12eSEd Maste } 181a85fe12eSEd Maste strncpy(&ecp->s_sn[ecp->s_sn_sz], name, strlen(name)); 182a85fe12eSEd Maste ecp->s_sn_sz += strlen(name); 183a85fe12eSEd Maste ecp->s_sn[ecp->s_sn_sz++] = '\0'; 184a85fe12eSEd Maste } 185a85fe12eSEd Maste 186a85fe12eSEd Maste static void 187a85fe12eSEd Maste sync_ar(struct elfcopy *ecp) 188a85fe12eSEd Maste { 189a85fe12eSEd Maste size_t s_sz; /* size of archive symbol table. */ 190a85fe12eSEd Maste size_t pm_sz; /* size of pseudo members */ 191a85fe12eSEd Maste int i; 192a85fe12eSEd Maste 193a85fe12eSEd Maste /* 194a85fe12eSEd Maste * Pad the symbol name string table. It is treated specially because 195a85fe12eSEd Maste * symbol name table should be padded by a '\0', not the common '\n' 196a85fe12eSEd Maste * for other members. The size of sn table includes the pad bit. 197a85fe12eSEd Maste */ 198a85fe12eSEd Maste if (ecp->s_cnt != 0 && ecp->s_sn_sz % 2 != 0) 199a85fe12eSEd Maste ecp->s_sn[ecp->s_sn_sz++] = '\0'; 200a85fe12eSEd Maste 201a85fe12eSEd Maste /* 202a85fe12eSEd Maste * Archive string table is padded by a "\n" as the normal members. 203a85fe12eSEd Maste * The difference is that the size of archive string table counts 204a85fe12eSEd Maste * in the pad bit, while normal members' size fileds do not. 205a85fe12eSEd Maste */ 206a85fe12eSEd Maste if (ecp->as != NULL && ecp->as_sz % 2 != 0) 207a85fe12eSEd Maste ecp->as[ecp->as_sz++] = '\n'; 208a85fe12eSEd Maste 209a85fe12eSEd Maste /* 210a85fe12eSEd Maste * If there is a symbol table, calculate the size of pseudo members, 211a85fe12eSEd Maste * convert previously stored relative offsets to absolute ones, and 212a85fe12eSEd Maste * then make them Big Endian. 213a85fe12eSEd Maste * 214a85fe12eSEd Maste * absolute_offset = htobe32(relative_offset + size_of_pseudo_members) 215a85fe12eSEd Maste */ 216a85fe12eSEd Maste 217a85fe12eSEd Maste if (ecp->s_cnt != 0) { 218a85fe12eSEd Maste s_sz = (ecp->s_cnt + 1) * sizeof(uint32_t) + ecp->s_sn_sz; 219a85fe12eSEd Maste pm_sz = _ARMAG_LEN + (_ARHDR_LEN + s_sz); 220a85fe12eSEd Maste if (ecp->as != NULL) 221a85fe12eSEd Maste pm_sz += _ARHDR_LEN + ecp->as_sz; 222a85fe12eSEd Maste for (i = 0; (size_t)i < ecp->s_cnt; i++) 223a85fe12eSEd Maste *(ecp->s_so + i) = htobe32(*(ecp->s_so + i) + 224a85fe12eSEd Maste pm_sz); 225a85fe12eSEd Maste } 226a85fe12eSEd Maste } 227a85fe12eSEd Maste 228a85fe12eSEd Maste /* 229a85fe12eSEd Maste * Extract global symbols from archive members. 230a85fe12eSEd Maste */ 231a85fe12eSEd Maste static void 232a85fe12eSEd Maste extract_arsym(struct elfcopy *ecp) 233a85fe12eSEd Maste { 234a85fe12eSEd Maste Elf_Scn *scn; 235a85fe12eSEd Maste GElf_Shdr shdr; 236a85fe12eSEd Maste GElf_Sym sym; 237a85fe12eSEd Maste Elf_Data *data; 238a85fe12eSEd Maste char *name; 239a85fe12eSEd Maste size_t n, shstrndx; 240a85fe12eSEd Maste int elferr, tabndx, len, i; 241a85fe12eSEd Maste 242a85fe12eSEd Maste if (elf_kind(ecp->eout) != ELF_K_ELF) { 243a85fe12eSEd Maste warnx("internal: cannot extract symbols from non-elf object"); 244a85fe12eSEd Maste return; 245a85fe12eSEd Maste } 246a85fe12eSEd Maste if (elf_getshstrndx(ecp->eout, &shstrndx) == 0) { 247a85fe12eSEd Maste warnx("elf_getshstrndx failed: %s", elf_errmsg(-1)); 248a85fe12eSEd Maste return; 249a85fe12eSEd Maste } 250a85fe12eSEd Maste 251a85fe12eSEd Maste tabndx = -1; 252a85fe12eSEd Maste scn = NULL; 253a85fe12eSEd Maste while ((scn = elf_nextscn(ecp->eout, scn)) != NULL) { 254a85fe12eSEd Maste if (gelf_getshdr(scn, &shdr) != &shdr) { 255a85fe12eSEd Maste warnx("elf_getshdr failed: %s", elf_errmsg(-1)); 256a85fe12eSEd Maste continue; 257a85fe12eSEd Maste } 258a85fe12eSEd Maste if ((name = elf_strptr(ecp->eout, shstrndx, shdr.sh_name)) == 259a85fe12eSEd Maste NULL) { 260a85fe12eSEd Maste warnx("elf_strptr failed: %s", elf_errmsg(-1)); 261a85fe12eSEd Maste continue; 262a85fe12eSEd Maste } 263a85fe12eSEd Maste if (strcmp(name, ".strtab") == 0) { 264a85fe12eSEd Maste tabndx = elf_ndxscn(scn); 265a85fe12eSEd Maste break; 266a85fe12eSEd Maste } 267a85fe12eSEd Maste } 268a85fe12eSEd Maste elferr = elf_errno(); 269a85fe12eSEd Maste if (elferr != 0) 270a85fe12eSEd Maste warnx("elf_nextscn failed: %s", elf_errmsg(elferr)); 271a85fe12eSEd Maste 272a85fe12eSEd Maste /* Ignore members without symbol table. */ 273a85fe12eSEd Maste if (tabndx == -1) 274a85fe12eSEd Maste return; 275a85fe12eSEd Maste 276a85fe12eSEd Maste scn = NULL; 277a85fe12eSEd Maste while ((scn = elf_nextscn(ecp->eout, scn)) != NULL) { 278a85fe12eSEd Maste if (gelf_getshdr(scn, &shdr) != &shdr) { 279a85fe12eSEd Maste warnx("elf_getshdr failed: %s", elf_errmsg(-1)); 280a85fe12eSEd Maste continue; 281a85fe12eSEd Maste } 282a85fe12eSEd Maste if (shdr.sh_type != SHT_SYMTAB) 283a85fe12eSEd Maste continue; 284a85fe12eSEd Maste 285a85fe12eSEd Maste data = NULL; 286a85fe12eSEd Maste n = 0; 287a85fe12eSEd Maste while (n < shdr.sh_size && 288a85fe12eSEd Maste (data = elf_getdata(scn, data)) != NULL) { 289a85fe12eSEd Maste len = data->d_size / shdr.sh_entsize; 290a85fe12eSEd Maste for (i = 0; i < len; i++) { 291a85fe12eSEd Maste if (gelf_getsym(data, i, &sym) != &sym) { 292a85fe12eSEd Maste warnx("gelf_getsym failed: %s", 293a85fe12eSEd Maste elf_errmsg(-1)); 294a85fe12eSEd Maste continue; 295a85fe12eSEd Maste } 296a85fe12eSEd Maste 297a85fe12eSEd Maste /* keep only global or weak symbols */ 298a85fe12eSEd Maste if (GELF_ST_BIND(sym.st_info) != STB_GLOBAL && 299a85fe12eSEd Maste GELF_ST_BIND(sym.st_info) != STB_WEAK) 300a85fe12eSEd Maste continue; 301a85fe12eSEd Maste 302a85fe12eSEd Maste /* keep only defined symbols */ 303a85fe12eSEd Maste if (sym.st_shndx == SHN_UNDEF) 304a85fe12eSEd Maste continue; 305a85fe12eSEd Maste 306a85fe12eSEd Maste if ((name = elf_strptr(ecp->eout, tabndx, 307a85fe12eSEd Maste sym.st_name)) == NULL) { 308a85fe12eSEd Maste warnx("elf_strptr failed: %s", 309a85fe12eSEd Maste elf_errmsg(-1)); 310a85fe12eSEd Maste continue; 311a85fe12eSEd Maste } 312a85fe12eSEd Maste 313a85fe12eSEd Maste add_to_ar_sym_table(ecp, name); 314a85fe12eSEd Maste } 315a85fe12eSEd Maste } 316a85fe12eSEd Maste } 317a85fe12eSEd Maste elferr = elf_errno(); 318a85fe12eSEd Maste if (elferr != 0) 319a85fe12eSEd Maste warnx("elf_nextscn failed: %s", elf_errmsg(elferr)); 320a85fe12eSEd Maste } 321a85fe12eSEd Maste 322a85fe12eSEd Maste #ifndef LIBELF_AR 323a85fe12eSEd Maste 324a85fe12eSEd Maste /* 325a85fe12eSEd Maste * Convenient wrapper for general libarchive error handling. 326a85fe12eSEd Maste */ 327a85fe12eSEd Maste #define AC(CALL) do { \ 328a85fe12eSEd Maste if ((CALL)) \ 329a85fe12eSEd Maste errx(EXIT_FAILURE, "%s", archive_error_string(a)); \ 330a85fe12eSEd Maste } while (0) 331a85fe12eSEd Maste 332a85fe12eSEd Maste /* Earlier versions of libarchive had some functions that returned 'void'. */ 333a85fe12eSEd Maste #if ARCHIVE_VERSION_NUMBER >= 2000000 334a85fe12eSEd Maste #define ACV(CALL) AC(CALL) 335a85fe12eSEd Maste #else 336a85fe12eSEd Maste #define ACV(CALL) do { \ 337a85fe12eSEd Maste (CALL); \ 338a85fe12eSEd Maste } while (0) 339a85fe12eSEd Maste #endif 340a85fe12eSEd Maste 341a85fe12eSEd Maste int 342a85fe12eSEd Maste ac_detect_ar(int ifd) 343a85fe12eSEd Maste { 344a85fe12eSEd Maste struct archive *a; 345a85fe12eSEd Maste struct archive_entry *entry; 346a85fe12eSEd Maste int r; 347a85fe12eSEd Maste 348a85fe12eSEd Maste r = -1; 349a85fe12eSEd Maste if ((a = archive_read_new()) == NULL) 350a85fe12eSEd Maste return (0); 351a85fe12eSEd Maste archive_read_support_format_ar(a); 352a85fe12eSEd Maste if (archive_read_open_fd(a, ifd, 10240) == ARCHIVE_OK) 353a85fe12eSEd Maste r = archive_read_next_header(a, &entry); 354a85fe12eSEd Maste archive_read_close(a); 355257d0ddaSEd Maste archive_read_free(a); 356a85fe12eSEd Maste 357a85fe12eSEd Maste return (r == ARCHIVE_OK); 358a85fe12eSEd Maste } 359a85fe12eSEd Maste 360a85fe12eSEd Maste void 361a85fe12eSEd Maste ac_create_ar(struct elfcopy *ecp, int ifd, int ofd) 362a85fe12eSEd Maste { 363a85fe12eSEd Maste 364a85fe12eSEd Maste ac_read_objs(ecp, ifd); 365a85fe12eSEd Maste sync_ar(ecp); 366a85fe12eSEd Maste ac_write_objs(ecp, ofd); 367a85fe12eSEd Maste ac_write_cleanup(ecp); 368a85fe12eSEd Maste } 369a85fe12eSEd Maste 370a85fe12eSEd Maste static void 371a85fe12eSEd Maste ac_read_objs(struct elfcopy *ecp, int ifd) 372a85fe12eSEd Maste { 373a85fe12eSEd Maste struct archive *a; 374a85fe12eSEd Maste struct archive_entry *entry; 375a85fe12eSEd Maste struct ar_obj *obj; 376a85fe12eSEd Maste const char *name; 377a85fe12eSEd Maste char *buff; 378a85fe12eSEd Maste size_t size; 379a85fe12eSEd Maste int r; 380a85fe12eSEd Maste 381a85fe12eSEd Maste ecp->rela_off = 0; 382a85fe12eSEd Maste if (lseek(ifd, 0, SEEK_SET) == -1) 383a85fe12eSEd Maste err(EXIT_FAILURE, "lseek failed"); 384a85fe12eSEd Maste if ((a = archive_read_new()) == NULL) 385839529caSEd Maste errx(EXIT_FAILURE, "archive_read_new failed"); 386a85fe12eSEd Maste archive_read_support_format_ar(a); 387a85fe12eSEd Maste AC(archive_read_open_fd(a, ifd, 10240)); 388a85fe12eSEd Maste for(;;) { 389a85fe12eSEd Maste r = archive_read_next_header(a, &entry); 390a85fe12eSEd Maste if (r == ARCHIVE_FATAL) 391a85fe12eSEd Maste errx(EXIT_FAILURE, "%s", archive_error_string(a)); 392a85fe12eSEd Maste if (r == ARCHIVE_EOF) 393a85fe12eSEd Maste break; 394a85fe12eSEd Maste if (r == ARCHIVE_WARN || r == ARCHIVE_RETRY) 395a85fe12eSEd Maste warnx("%s", archive_error_string(a)); 396a85fe12eSEd Maste if (r == ARCHIVE_RETRY) 397a85fe12eSEd Maste continue; 398a85fe12eSEd Maste 399a85fe12eSEd Maste name = archive_entry_pathname(entry); 400a85fe12eSEd Maste 401a85fe12eSEd Maste /* skip pseudo members. */ 402a85fe12eSEd Maste if (strcmp(name, "/") == 0 || strcmp(name, "//") == 0) 403a85fe12eSEd Maste continue; 404a85fe12eSEd Maste 405a85fe12eSEd Maste size = archive_entry_size(entry); 406a85fe12eSEd Maste 407a85fe12eSEd Maste if (size > 0) { 408a85fe12eSEd Maste if ((buff = malloc(size)) == NULL) 409a85fe12eSEd Maste err(EXIT_FAILURE, "malloc failed"); 410a85fe12eSEd Maste if (archive_read_data(a, buff, size) != (ssize_t)size) { 411a85fe12eSEd Maste warnx("%s", archive_error_string(a)); 412a85fe12eSEd Maste free(buff); 413a85fe12eSEd Maste continue; 414a85fe12eSEd Maste } 415a85fe12eSEd Maste if ((obj = malloc(sizeof(*obj))) == NULL) 416a85fe12eSEd Maste err(EXIT_FAILURE, "malloc failed"); 417a85fe12eSEd Maste if ((obj->name = strdup(name)) == NULL) 418a85fe12eSEd Maste err(EXIT_FAILURE, "strdup failed"); 419a85fe12eSEd Maste obj->buf = buff; 420a85fe12eSEd Maste obj->uid = archive_entry_uid(entry); 421a85fe12eSEd Maste obj->gid = archive_entry_gid(entry); 422a85fe12eSEd Maste obj->md = archive_entry_mode(entry); 423a85fe12eSEd Maste obj->mtime = archive_entry_mtime(entry); 424a85fe12eSEd Maste if ((ecp->ein = elf_memory(buff, size)) == NULL) 425a85fe12eSEd Maste errx(EXIT_FAILURE, "elf_memory() failed: %s", 426a85fe12eSEd Maste elf_errmsg(-1)); 427a85fe12eSEd Maste if (elf_kind(ecp->ein) != ELF_K_ELF) 428a85fe12eSEd Maste errx(EXIT_FAILURE, 429a85fe12eSEd Maste "file format not recognized"); 430a85fe12eSEd Maste process_ar_obj(ecp, obj); 431a85fe12eSEd Maste } 432a85fe12eSEd Maste } 433a85fe12eSEd Maste AC(archive_read_close(a)); 434257d0ddaSEd Maste ACV(archive_read_free(a)); 435a85fe12eSEd Maste } 436a85fe12eSEd Maste 437a85fe12eSEd Maste static void 438a85fe12eSEd Maste ac_write_objs(struct elfcopy *ecp, int ofd) 439a85fe12eSEd Maste { 440a85fe12eSEd Maste struct archive *a; 441a85fe12eSEd Maste struct archive_entry *entry; 442a85fe12eSEd Maste struct ar_obj *obj; 443b6d812d2SEd Maste time_t timestamp; 444a85fe12eSEd Maste int nr; 445a85fe12eSEd Maste 446a85fe12eSEd Maste if ((a = archive_write_new()) == NULL) 447839529caSEd Maste errx(EXIT_FAILURE, "archive_write_new failed"); 448a85fe12eSEd Maste archive_write_set_format_ar_svr4(a); 449a85fe12eSEd Maste AC(archive_write_open_fd(a, ofd)); 450a85fe12eSEd Maste 451a85fe12eSEd Maste /* Write the archive symbol table, even if it's empty. */ 452a85fe12eSEd Maste entry = archive_entry_new(); 453a85fe12eSEd Maste archive_entry_copy_pathname(entry, "/"); 454b6d812d2SEd Maste if (elftc_timestamp(×tamp) != 0) 455b6d812d2SEd Maste err(EXIT_FAILURE, "elftc_timestamp"); 456b6d812d2SEd Maste archive_entry_set_mtime(entry, timestamp, 0); 457a85fe12eSEd Maste archive_entry_set_size(entry, (ecp->s_cnt + 1) * sizeof(uint32_t) + 458a85fe12eSEd Maste ecp->s_sn_sz); 459a85fe12eSEd Maste AC(archive_write_header(a, entry)); 460a85fe12eSEd Maste nr = htobe32(ecp->s_cnt); 461a85fe12eSEd Maste ac_write_data(a, &nr, sizeof(uint32_t)); 462a85fe12eSEd Maste ac_write_data(a, ecp->s_so, sizeof(uint32_t) * ecp->s_cnt); 463a85fe12eSEd Maste ac_write_data(a, ecp->s_sn, ecp->s_sn_sz); 464a85fe12eSEd Maste archive_entry_free(entry); 465a85fe12eSEd Maste 466a85fe12eSEd Maste /* Write the archive string table, if exist. */ 467a85fe12eSEd Maste if (ecp->as != NULL) { 468a85fe12eSEd Maste entry = archive_entry_new(); 469a85fe12eSEd Maste archive_entry_copy_pathname(entry, "//"); 470a85fe12eSEd Maste archive_entry_set_size(entry, ecp->as_sz); 471a85fe12eSEd Maste AC(archive_write_header(a, entry)); 472a85fe12eSEd Maste ac_write_data(a, ecp->as, ecp->as_sz); 473a85fe12eSEd Maste archive_entry_free(entry); 474a85fe12eSEd Maste } 475a85fe12eSEd Maste 476a85fe12eSEd Maste /* Write normal members. */ 477a85fe12eSEd Maste STAILQ_FOREACH(obj, &ecp->v_arobj, objs) { 478a85fe12eSEd Maste entry = archive_entry_new(); 479a85fe12eSEd Maste archive_entry_copy_pathname(entry, obj->name); 480a85fe12eSEd Maste archive_entry_set_uid(entry, obj->uid); 481a85fe12eSEd Maste archive_entry_set_gid(entry, obj->gid); 482a85fe12eSEd Maste archive_entry_set_mode(entry, obj->md); 483a85fe12eSEd Maste archive_entry_set_size(entry, obj->size); 484a85fe12eSEd Maste archive_entry_set_mtime(entry, obj->mtime, 0); 485a85fe12eSEd Maste archive_entry_set_filetype(entry, AE_IFREG); 486a85fe12eSEd Maste AC(archive_write_header(a, entry)); 487a85fe12eSEd Maste ac_write_data(a, obj->maddr, obj->size); 488a85fe12eSEd Maste archive_entry_free(entry); 489a85fe12eSEd Maste } 490a85fe12eSEd Maste 491a85fe12eSEd Maste AC(archive_write_close(a)); 492257d0ddaSEd Maste ACV(archive_write_free(a)); 493a85fe12eSEd Maste } 494a85fe12eSEd Maste 495a85fe12eSEd Maste static void 496a85fe12eSEd Maste ac_write_cleanup(struct elfcopy *ecp) 497a85fe12eSEd Maste { 498a85fe12eSEd Maste struct ar_obj *obj, *obj_temp; 499a85fe12eSEd Maste 500a85fe12eSEd Maste STAILQ_FOREACH_SAFE(obj, &ecp->v_arobj, objs, obj_temp) { 501a85fe12eSEd Maste STAILQ_REMOVE(&ecp->v_arobj, obj, ar_obj, objs); 502a85fe12eSEd Maste if (obj->maddr != NULL) 503a85fe12eSEd Maste free(obj->maddr); 504a85fe12eSEd Maste free(obj->name); 505a85fe12eSEd Maste free(obj); 506a85fe12eSEd Maste } 507a85fe12eSEd Maste 508a85fe12eSEd Maste free(ecp->as); 509a85fe12eSEd Maste free(ecp->s_so); 510a85fe12eSEd Maste free(ecp->s_sn); 511a85fe12eSEd Maste ecp->as = NULL; 512a85fe12eSEd Maste ecp->s_so = NULL; 513a85fe12eSEd Maste ecp->s_sn = NULL; 514a85fe12eSEd Maste } 515a85fe12eSEd Maste 516a85fe12eSEd Maste /* 517a85fe12eSEd Maste * Wrapper for archive_write_data(). 518a85fe12eSEd Maste */ 519a85fe12eSEd Maste static void 520a85fe12eSEd Maste ac_write_data(struct archive *a, const void *buf, size_t s) 521a85fe12eSEd Maste { 522a85fe12eSEd Maste if (archive_write_data(a, buf, s) != (ssize_t)s) 523a85fe12eSEd Maste errx(EXIT_FAILURE, "%s", archive_error_string(a)); 524a85fe12eSEd Maste } 525a85fe12eSEd Maste 526a85fe12eSEd Maste #endif /* ! LIBELF_AR */ 527