1da0c48c4Sopenharmony_ci/* Create, modify, and extract from archives. 2da0c48c4Sopenharmony_ci Copyright (C) 2005-2012, 2016, 2017 Red Hat, Inc. 3da0c48c4Sopenharmony_ci This file is part of elfutils. 4da0c48c4Sopenharmony_ci Written by Ulrich Drepper <drepper@redhat.com>, 2005. 5da0c48c4Sopenharmony_ci 6da0c48c4Sopenharmony_ci This file is free software; you can redistribute it and/or modify 7da0c48c4Sopenharmony_ci it under the terms of the GNU General Public License as published by 8da0c48c4Sopenharmony_ci the Free Software Foundation; either version 3 of the License, or 9da0c48c4Sopenharmony_ci (at your option) any later version. 10da0c48c4Sopenharmony_ci 11da0c48c4Sopenharmony_ci elfutils is distributed in the hope that it will be useful, but 12da0c48c4Sopenharmony_ci WITHOUT ANY WARRANTY; without even the implied warranty of 13da0c48c4Sopenharmony_ci MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14da0c48c4Sopenharmony_ci GNU General Public License for more details. 15da0c48c4Sopenharmony_ci 16da0c48c4Sopenharmony_ci You should have received a copy of the GNU General Public License 17da0c48c4Sopenharmony_ci along with this program. If not, see <http://www.gnu.org/licenses/>. */ 18da0c48c4Sopenharmony_ci 19da0c48c4Sopenharmony_ci#ifdef HAVE_CONFIG_H 20da0c48c4Sopenharmony_ci# include <config.h> 21da0c48c4Sopenharmony_ci#endif 22da0c48c4Sopenharmony_ci 23da0c48c4Sopenharmony_ci#include <argp.h> 24da0c48c4Sopenharmony_ci#include <assert.h> 25da0c48c4Sopenharmony_ci#include <fcntl.h> 26da0c48c4Sopenharmony_ci#include <gelf.h> 27da0c48c4Sopenharmony_ci#include <limits.h> 28da0c48c4Sopenharmony_ci#include <locale.h> 29da0c48c4Sopenharmony_ci#include <search.h> 30da0c48c4Sopenharmony_ci#include <stdbool.h> 31da0c48c4Sopenharmony_ci#include <stdlib.h> 32da0c48c4Sopenharmony_ci#include <stdio.h> 33da0c48c4Sopenharmony_ci#include <stdio_ext.h> 34da0c48c4Sopenharmony_ci#include <string.h> 35da0c48c4Sopenharmony_ci#include <time.h> 36da0c48c4Sopenharmony_ci#include <unistd.h> 37da0c48c4Sopenharmony_ci#include <sys/mman.h> 38da0c48c4Sopenharmony_ci#include <sys/stat.h> 39da0c48c4Sopenharmony_ci#include <sys/time.h> 40da0c48c4Sopenharmony_ci 41da0c48c4Sopenharmony_ci#include <system.h> 42da0c48c4Sopenharmony_ci#include <printversion.h> 43da0c48c4Sopenharmony_ci 44da0c48c4Sopenharmony_ci#include "arlib.h" 45da0c48c4Sopenharmony_ci 46da0c48c4Sopenharmony_ci 47da0c48c4Sopenharmony_ci/* Name and version of program. */ 48da0c48c4Sopenharmony_ciARGP_PROGRAM_VERSION_HOOK_DEF = print_version; 49da0c48c4Sopenharmony_ci 50da0c48c4Sopenharmony_ci/* Prototypes for local functions. */ 51da0c48c4Sopenharmony_cistatic int do_oper_extract (int oper, const char *arfname, char **argv, 52da0c48c4Sopenharmony_ci int argc, long int instance); 53da0c48c4Sopenharmony_cistatic int do_oper_delete (const char *arfname, char **argv, int argc, 54da0c48c4Sopenharmony_ci long int instance); 55da0c48c4Sopenharmony_cistatic int do_oper_insert (int oper, const char *arfname, char **argv, 56da0c48c4Sopenharmony_ci int argc, const char *member); 57da0c48c4Sopenharmony_ci 58da0c48c4Sopenharmony_ci 59da0c48c4Sopenharmony_ci/* Bug report address. */ 60da0c48c4Sopenharmony_ciARGP_PROGRAM_BUG_ADDRESS_DEF = PACKAGE_BUGREPORT; 61da0c48c4Sopenharmony_ci 62da0c48c4Sopenharmony_ci 63da0c48c4Sopenharmony_ci/* Definitions of arguments for argp functions. */ 64da0c48c4Sopenharmony_cistatic const struct argp_option options[] = 65da0c48c4Sopenharmony_ci{ 66da0c48c4Sopenharmony_ci { NULL, 0, NULL, 0, N_("Commands:"), 1 }, 67da0c48c4Sopenharmony_ci { NULL, 'd', NULL, 0, N_("Delete files from archive."), 0 }, 68da0c48c4Sopenharmony_ci { NULL, 'm', NULL, 0, N_("Move files in archive."), 0 }, 69da0c48c4Sopenharmony_ci { NULL, 'p', NULL, 0, N_("Print files in archive."), 0 }, 70da0c48c4Sopenharmony_ci { NULL, 'q', NULL, 0, N_("Quick append files to archive."), 0 }, 71da0c48c4Sopenharmony_ci { NULL, 'r', NULL, 0, 72da0c48c4Sopenharmony_ci N_("Replace existing or insert new file into archive."), 0 }, 73da0c48c4Sopenharmony_ci { NULL, 't', NULL, 0, N_("Display content of archive."), 0 }, 74da0c48c4Sopenharmony_ci { NULL, 'x', NULL, 0, N_("Extract files from archive."), 0 }, 75da0c48c4Sopenharmony_ci 76da0c48c4Sopenharmony_ci { NULL, 0, NULL, 0, N_("Command Modifiers:"), 2 }, 77da0c48c4Sopenharmony_ci { NULL, 'o', NULL, 0, N_("Preserve original dates."), 0 }, 78da0c48c4Sopenharmony_ci { NULL, 'N', NULL, 0, N_("Use instance [COUNT] of name."), 0 }, 79da0c48c4Sopenharmony_ci { NULL, 'C', NULL, 0, 80da0c48c4Sopenharmony_ci N_("Do not replace existing files with extracted files."), 0 }, 81da0c48c4Sopenharmony_ci { NULL, 'T', NULL, 0, N_("Allow filename to be truncated if necessary."), 82da0c48c4Sopenharmony_ci 0 }, 83da0c48c4Sopenharmony_ci { NULL, 'v', NULL, 0, N_("Provide verbose output."), 0 }, 84da0c48c4Sopenharmony_ci { NULL, 's', NULL, 0, N_("Force regeneration of symbol table."), 0 }, 85da0c48c4Sopenharmony_ci { NULL, 'a', NULL, 0, N_("Insert file after [MEMBER]."), 0 }, 86da0c48c4Sopenharmony_ci { NULL, 'b', NULL, 0, N_("Insert file before [MEMBER]."), 0 }, 87da0c48c4Sopenharmony_ci { NULL, 'i', NULL, 0, N_("Same as -b."), 0 }, 88da0c48c4Sopenharmony_ci { NULL, 'c', NULL, 0, N_("Suppress message when library has to be created."), 89da0c48c4Sopenharmony_ci 0 }, 90da0c48c4Sopenharmony_ci { NULL, 'P', NULL, 0, N_("Use full path for file matching."), 0 }, 91da0c48c4Sopenharmony_ci { NULL, 'u', NULL, 0, N_("Update only older files in archive."), 0 }, 92da0c48c4Sopenharmony_ci 93da0c48c4Sopenharmony_ci { NULL, 0, NULL, 0, NULL, 0 } 94da0c48c4Sopenharmony_ci}; 95da0c48c4Sopenharmony_ci 96da0c48c4Sopenharmony_ci/* Short description of program. */ 97da0c48c4Sopenharmony_cistatic const char doc[] = N_("Create, modify, and extract from archives."); 98da0c48c4Sopenharmony_ci 99da0c48c4Sopenharmony_ci/* Strings for arguments in help texts. */ 100da0c48c4Sopenharmony_cistatic const char args_doc[] = N_("[MEMBER] [COUNT] ARCHIVE [FILE...]"); 101da0c48c4Sopenharmony_ci 102da0c48c4Sopenharmony_ci/* Prototype for option handler. */ 103da0c48c4Sopenharmony_cistatic error_t parse_opt (int key, char *arg, struct argp_state *state); 104da0c48c4Sopenharmony_ci 105da0c48c4Sopenharmony_ci/* Data structure to communicate with argp functions. */ 106da0c48c4Sopenharmony_cistatic struct argp argp = 107da0c48c4Sopenharmony_ci{ 108da0c48c4Sopenharmony_ci options, parse_opt, args_doc, doc, arlib_argp_children, NULL, NULL 109da0c48c4Sopenharmony_ci}; 110da0c48c4Sopenharmony_ci 111da0c48c4Sopenharmony_ci 112da0c48c4Sopenharmony_ci/* What operation to perform. */ 113da0c48c4Sopenharmony_cistatic enum 114da0c48c4Sopenharmony_ci { 115da0c48c4Sopenharmony_ci oper_none, 116da0c48c4Sopenharmony_ci oper_delete, 117da0c48c4Sopenharmony_ci oper_move, 118da0c48c4Sopenharmony_ci oper_print, 119da0c48c4Sopenharmony_ci oper_qappend, 120da0c48c4Sopenharmony_ci oper_replace, 121da0c48c4Sopenharmony_ci oper_list, 122da0c48c4Sopenharmony_ci oper_extract 123da0c48c4Sopenharmony_ci } operation; 124da0c48c4Sopenharmony_ci 125da0c48c4Sopenharmony_ci/* Modifiers. */ 126da0c48c4Sopenharmony_cistatic bool verbose; 127da0c48c4Sopenharmony_cistatic bool preserve_dates; 128da0c48c4Sopenharmony_cistatic bool instance_specifed; 129da0c48c4Sopenharmony_cistatic bool dont_replace_existing; 130da0c48c4Sopenharmony_cistatic bool allow_truncate_fname; 131da0c48c4Sopenharmony_cistatic bool force_symtab; 132da0c48c4Sopenharmony_cistatic bool suppress_create_msg; 133da0c48c4Sopenharmony_cistatic bool full_path; 134da0c48c4Sopenharmony_cistatic bool update_newer; 135da0c48c4Sopenharmony_cistatic enum { ipos_none, ipos_before, ipos_after } ipos; 136da0c48c4Sopenharmony_ci 137da0c48c4Sopenharmony_ci 138da0c48c4Sopenharmony_ciint 139da0c48c4Sopenharmony_cimain (int argc, char *argv[]) 140da0c48c4Sopenharmony_ci{ 141da0c48c4Sopenharmony_ci /* We use no threads here which can interfere with handling a stream. */ 142da0c48c4Sopenharmony_ci (void) __fsetlocking (stdin, FSETLOCKING_BYCALLER); 143da0c48c4Sopenharmony_ci (void) __fsetlocking (stdout, FSETLOCKING_BYCALLER); 144da0c48c4Sopenharmony_ci (void) __fsetlocking (stderr, FSETLOCKING_BYCALLER); 145da0c48c4Sopenharmony_ci 146da0c48c4Sopenharmony_ci /* Set locale. */ 147da0c48c4Sopenharmony_ci (void) setlocale (LC_ALL, ""); 148da0c48c4Sopenharmony_ci 149da0c48c4Sopenharmony_ci /* Make sure the message catalog can be found. */ 150da0c48c4Sopenharmony_ci (void) bindtextdomain (PACKAGE_TARNAME, LOCALEDIR); 151da0c48c4Sopenharmony_ci 152da0c48c4Sopenharmony_ci /* Initialize the message catalog. */ 153da0c48c4Sopenharmony_ci (void) textdomain (PACKAGE_TARNAME); 154da0c48c4Sopenharmony_ci 155da0c48c4Sopenharmony_ci /* For historical reasons the options in the first parameter need 156da0c48c4Sopenharmony_ci not be preceded by a dash. Add it now if necessary. */ 157da0c48c4Sopenharmony_ci if (argc > 1 && argv[1][0] != '-') 158da0c48c4Sopenharmony_ci { 159da0c48c4Sopenharmony_ci size_t len = strlen (argv[1]) + 1; 160da0c48c4Sopenharmony_ci char *newp = alloca (len + 1); 161da0c48c4Sopenharmony_ci newp[0] = '-'; 162da0c48c4Sopenharmony_ci memcpy (&newp[1], argv[1], len); 163da0c48c4Sopenharmony_ci argv[1] = newp; 164da0c48c4Sopenharmony_ci } 165da0c48c4Sopenharmony_ci 166da0c48c4Sopenharmony_ci /* Parse and process arguments. */ 167da0c48c4Sopenharmony_ci int remaining; 168da0c48c4Sopenharmony_ci (void) argp_parse (&argp, argc, argv, ARGP_IN_ORDER, &remaining, NULL); 169da0c48c4Sopenharmony_ci 170da0c48c4Sopenharmony_ci /* Tell the library which version we are expecting. */ 171da0c48c4Sopenharmony_ci (void) elf_version (EV_CURRENT); 172da0c48c4Sopenharmony_ci 173da0c48c4Sopenharmony_ci /* Handle the [MEMBER] parameter. */ 174da0c48c4Sopenharmony_ci const char *member = NULL; 175da0c48c4Sopenharmony_ci if (ipos != ipos_none) 176da0c48c4Sopenharmony_ci { 177da0c48c4Sopenharmony_ci /* Only valid for certain operations. */ 178da0c48c4Sopenharmony_ci if (operation != oper_move && operation != oper_replace) 179da0c48c4Sopenharmony_ci error (1, 0, _("\ 180da0c48c4Sopenharmony_ci'a', 'b', and 'i' are only allowed with the 'm' and 'r' options")); 181da0c48c4Sopenharmony_ci 182da0c48c4Sopenharmony_ci if (remaining == argc) 183da0c48c4Sopenharmony_ci { 184da0c48c4Sopenharmony_ci error (0, 0, _("\ 185da0c48c4Sopenharmony_ciMEMBER parameter required for 'a', 'b', and 'i' modifiers")); 186da0c48c4Sopenharmony_ci argp_help (&argp, stderr, ARGP_HELP_USAGE | ARGP_HELP_SEE, 187da0c48c4Sopenharmony_ci program_invocation_short_name); 188da0c48c4Sopenharmony_ci exit (EXIT_FAILURE); 189da0c48c4Sopenharmony_ci } 190da0c48c4Sopenharmony_ci 191da0c48c4Sopenharmony_ci member = argv[remaining++]; 192da0c48c4Sopenharmony_ci } 193da0c48c4Sopenharmony_ci 194da0c48c4Sopenharmony_ci /* Handle the [COUNT] parameter. */ 195da0c48c4Sopenharmony_ci long int instance = -1; 196da0c48c4Sopenharmony_ci if (instance_specifed) 197da0c48c4Sopenharmony_ci { 198da0c48c4Sopenharmony_ci /* Only valid for certain operations. */ 199da0c48c4Sopenharmony_ci if (operation != oper_extract && operation != oper_delete) 200da0c48c4Sopenharmony_ci error (1, 0, _("\ 201da0c48c4Sopenharmony_ci'N' is only meaningful with the 'x' and 'd' options")); 202da0c48c4Sopenharmony_ci 203da0c48c4Sopenharmony_ci if (remaining == argc) 204da0c48c4Sopenharmony_ci { 205da0c48c4Sopenharmony_ci error (0, 0, _("COUNT parameter required")); 206da0c48c4Sopenharmony_ci argp_help (&argp, stderr, ARGP_HELP_SEE, 207da0c48c4Sopenharmony_ci program_invocation_short_name); 208da0c48c4Sopenharmony_ci exit (EXIT_FAILURE); 209da0c48c4Sopenharmony_ci } 210da0c48c4Sopenharmony_ci 211da0c48c4Sopenharmony_ci char *endp; 212da0c48c4Sopenharmony_ci errno = 0; 213da0c48c4Sopenharmony_ci if (((instance = strtol (argv[remaining], &endp, 10)) == LONG_MAX 214da0c48c4Sopenharmony_ci && errno == ERANGE) 215da0c48c4Sopenharmony_ci || instance <= 0 216da0c48c4Sopenharmony_ci || *endp != '\0') 217da0c48c4Sopenharmony_ci error (1, 0, _("invalid COUNT parameter %s"), argv[remaining]); 218da0c48c4Sopenharmony_ci 219da0c48c4Sopenharmony_ci ++remaining; 220da0c48c4Sopenharmony_ci } 221da0c48c4Sopenharmony_ci 222da0c48c4Sopenharmony_ci if ((dont_replace_existing || allow_truncate_fname) 223da0c48c4Sopenharmony_ci && unlikely (operation != oper_extract)) 224da0c48c4Sopenharmony_ci error (1, 0, _("'%c' is only meaningful with the 'x' option"), 225da0c48c4Sopenharmony_ci dont_replace_existing ? 'C' : 'T'); 226da0c48c4Sopenharmony_ci 227da0c48c4Sopenharmony_ci /* There must at least be one more parameter specifying the archive. */ 228da0c48c4Sopenharmony_ci if (remaining == argc) 229da0c48c4Sopenharmony_ci { 230da0c48c4Sopenharmony_ci error (0, 0, _("archive name required")); 231da0c48c4Sopenharmony_ci argp_help (&argp, stderr, ARGP_HELP_SEE, program_invocation_short_name); 232da0c48c4Sopenharmony_ci exit (EXIT_FAILURE); 233da0c48c4Sopenharmony_ci } 234da0c48c4Sopenharmony_ci 235da0c48c4Sopenharmony_ci const char *arfname = argv[remaining++]; 236da0c48c4Sopenharmony_ci argv += remaining; 237da0c48c4Sopenharmony_ci argc -= remaining; 238da0c48c4Sopenharmony_ci 239da0c48c4Sopenharmony_ci int status; 240da0c48c4Sopenharmony_ci switch (operation) 241da0c48c4Sopenharmony_ci { 242da0c48c4Sopenharmony_ci case oper_none: 243da0c48c4Sopenharmony_ci error (0, 0, _("command option required")); 244da0c48c4Sopenharmony_ci argp_help (&argp, stderr, ARGP_HELP_STD_ERR, 245da0c48c4Sopenharmony_ci program_invocation_short_name); 246da0c48c4Sopenharmony_ci status = 1; 247da0c48c4Sopenharmony_ci break; 248da0c48c4Sopenharmony_ci 249da0c48c4Sopenharmony_ci case oper_list: 250da0c48c4Sopenharmony_ci case oper_print: 251da0c48c4Sopenharmony_ci status = do_oper_extract (operation, arfname, argv, argc, -1); 252da0c48c4Sopenharmony_ci break; 253da0c48c4Sopenharmony_ci 254da0c48c4Sopenharmony_ci case oper_extract: 255da0c48c4Sopenharmony_ci status = do_oper_extract (operation, arfname, argv, argc, instance); 256da0c48c4Sopenharmony_ci break; 257da0c48c4Sopenharmony_ci 258da0c48c4Sopenharmony_ci case oper_delete: 259da0c48c4Sopenharmony_ci status = do_oper_delete (arfname, argv, argc, instance); 260da0c48c4Sopenharmony_ci break; 261da0c48c4Sopenharmony_ci 262da0c48c4Sopenharmony_ci case oper_move: 263da0c48c4Sopenharmony_ci case oper_qappend: 264da0c48c4Sopenharmony_ci case oper_replace: 265da0c48c4Sopenharmony_ci status = do_oper_insert (operation, arfname, argv, argc, member); 266da0c48c4Sopenharmony_ci break; 267da0c48c4Sopenharmony_ci 268da0c48c4Sopenharmony_ci default: 269da0c48c4Sopenharmony_ci assert (! "should not happen"); 270da0c48c4Sopenharmony_ci status = 1; 271da0c48c4Sopenharmony_ci break; 272da0c48c4Sopenharmony_ci } 273da0c48c4Sopenharmony_ci 274da0c48c4Sopenharmony_ci return status; 275da0c48c4Sopenharmony_ci} 276da0c48c4Sopenharmony_ci 277da0c48c4Sopenharmony_ci 278da0c48c4Sopenharmony_ci/* Handle program arguments. */ 279da0c48c4Sopenharmony_cistatic error_t 280da0c48c4Sopenharmony_ciparse_opt (int key, char *arg __attribute__ ((unused)), 281da0c48c4Sopenharmony_ci struct argp_state *state __attribute__ ((unused))) 282da0c48c4Sopenharmony_ci{ 283da0c48c4Sopenharmony_ci switch (key) 284da0c48c4Sopenharmony_ci { 285da0c48c4Sopenharmony_ci case 'd': 286da0c48c4Sopenharmony_ci case 'm': 287da0c48c4Sopenharmony_ci case 'p': 288da0c48c4Sopenharmony_ci case 'q': 289da0c48c4Sopenharmony_ci case 'r': 290da0c48c4Sopenharmony_ci case 't': 291da0c48c4Sopenharmony_ci case 'x': 292da0c48c4Sopenharmony_ci if (operation != oper_none) 293da0c48c4Sopenharmony_ci { 294da0c48c4Sopenharmony_ci error (0, 0, _("More than one operation specified")); 295da0c48c4Sopenharmony_ci argp_help (&argp, stderr, ARGP_HELP_SEE, 296da0c48c4Sopenharmony_ci program_invocation_short_name); 297da0c48c4Sopenharmony_ci exit (EXIT_FAILURE); 298da0c48c4Sopenharmony_ci } 299da0c48c4Sopenharmony_ci 300da0c48c4Sopenharmony_ci switch (key) 301da0c48c4Sopenharmony_ci { 302da0c48c4Sopenharmony_ci case 'd': 303da0c48c4Sopenharmony_ci operation = oper_delete; 304da0c48c4Sopenharmony_ci break; 305da0c48c4Sopenharmony_ci case 'm': 306da0c48c4Sopenharmony_ci operation = oper_move; 307da0c48c4Sopenharmony_ci break; 308da0c48c4Sopenharmony_ci case 'p': 309da0c48c4Sopenharmony_ci operation = oper_print; 310da0c48c4Sopenharmony_ci break; 311da0c48c4Sopenharmony_ci case 'q': 312da0c48c4Sopenharmony_ci operation = oper_qappend; 313da0c48c4Sopenharmony_ci break; 314da0c48c4Sopenharmony_ci case 'r': 315da0c48c4Sopenharmony_ci operation = oper_replace; 316da0c48c4Sopenharmony_ci break; 317da0c48c4Sopenharmony_ci case 't': 318da0c48c4Sopenharmony_ci operation = oper_list; 319da0c48c4Sopenharmony_ci break; 320da0c48c4Sopenharmony_ci case 'x': 321da0c48c4Sopenharmony_ci operation = oper_extract; 322da0c48c4Sopenharmony_ci break; 323da0c48c4Sopenharmony_ci } 324da0c48c4Sopenharmony_ci break; 325da0c48c4Sopenharmony_ci 326da0c48c4Sopenharmony_ci case 'a': 327da0c48c4Sopenharmony_ci ipos = ipos_after; 328da0c48c4Sopenharmony_ci break; 329da0c48c4Sopenharmony_ci 330da0c48c4Sopenharmony_ci case 'b': 331da0c48c4Sopenharmony_ci case 'i': 332da0c48c4Sopenharmony_ci ipos = ipos_before; 333da0c48c4Sopenharmony_ci break; 334da0c48c4Sopenharmony_ci 335da0c48c4Sopenharmony_ci case 'c': 336da0c48c4Sopenharmony_ci suppress_create_msg = true; 337da0c48c4Sopenharmony_ci break; 338da0c48c4Sopenharmony_ci 339da0c48c4Sopenharmony_ci case 'C': 340da0c48c4Sopenharmony_ci dont_replace_existing = true; 341da0c48c4Sopenharmony_ci break; 342da0c48c4Sopenharmony_ci 343da0c48c4Sopenharmony_ci case 'N': 344da0c48c4Sopenharmony_ci instance_specifed = true; 345da0c48c4Sopenharmony_ci break; 346da0c48c4Sopenharmony_ci 347da0c48c4Sopenharmony_ci case 'o': 348da0c48c4Sopenharmony_ci preserve_dates = true; 349da0c48c4Sopenharmony_ci break; 350da0c48c4Sopenharmony_ci 351da0c48c4Sopenharmony_ci case 'P': 352da0c48c4Sopenharmony_ci full_path = true; 353da0c48c4Sopenharmony_ci break; 354da0c48c4Sopenharmony_ci 355da0c48c4Sopenharmony_ci case 's': 356da0c48c4Sopenharmony_ci force_symtab = true; 357da0c48c4Sopenharmony_ci break; 358da0c48c4Sopenharmony_ci 359da0c48c4Sopenharmony_ci case 'T': 360da0c48c4Sopenharmony_ci allow_truncate_fname = true; 361da0c48c4Sopenharmony_ci break; 362da0c48c4Sopenharmony_ci 363da0c48c4Sopenharmony_ci case 'u': 364da0c48c4Sopenharmony_ci update_newer = true; 365da0c48c4Sopenharmony_ci break; 366da0c48c4Sopenharmony_ci 367da0c48c4Sopenharmony_ci case 'v': 368da0c48c4Sopenharmony_ci verbose = true; 369da0c48c4Sopenharmony_ci break; 370da0c48c4Sopenharmony_ci 371da0c48c4Sopenharmony_ci default: 372da0c48c4Sopenharmony_ci return ARGP_ERR_UNKNOWN; 373da0c48c4Sopenharmony_ci } 374da0c48c4Sopenharmony_ci return 0; 375da0c48c4Sopenharmony_ci} 376da0c48c4Sopenharmony_ci 377da0c48c4Sopenharmony_ci 378da0c48c4Sopenharmony_cistatic int 379da0c48c4Sopenharmony_ciopen_archive (const char *arfname, int flags, int mode, Elf **elf, 380da0c48c4Sopenharmony_ci struct stat *st, bool miss_allowed) 381da0c48c4Sopenharmony_ci{ 382da0c48c4Sopenharmony_ci int fd = open (arfname, flags, mode); 383da0c48c4Sopenharmony_ci if (fd == -1) 384da0c48c4Sopenharmony_ci { 385da0c48c4Sopenharmony_ci if (miss_allowed) 386da0c48c4Sopenharmony_ci return -1; 387da0c48c4Sopenharmony_ci 388da0c48c4Sopenharmony_ci error_exit (errno, _("cannot open archive '%s'"), 389da0c48c4Sopenharmony_ci arfname); 390da0c48c4Sopenharmony_ci } 391da0c48c4Sopenharmony_ci 392da0c48c4Sopenharmony_ci if (elf != NULL) 393da0c48c4Sopenharmony_ci { 394da0c48c4Sopenharmony_ci Elf_Cmd cmd = flags == O_RDONLY ? ELF_C_READ_MMAP : ELF_C_RDWR_MMAP; 395da0c48c4Sopenharmony_ci 396da0c48c4Sopenharmony_ci *elf = elf_begin (fd, cmd, NULL); 397da0c48c4Sopenharmony_ci if (*elf == NULL) 398da0c48c4Sopenharmony_ci error_exit (0, _("cannot open archive '%s': %s"), 399da0c48c4Sopenharmony_ci arfname, elf_errmsg (-1)); 400da0c48c4Sopenharmony_ci 401da0c48c4Sopenharmony_ci if (flags == O_RDONLY && elf_kind (*elf) != ELF_K_AR) 402da0c48c4Sopenharmony_ci error_exit (0, _("%s: not an archive file"), arfname); 403da0c48c4Sopenharmony_ci } 404da0c48c4Sopenharmony_ci 405da0c48c4Sopenharmony_ci if (st != NULL && fstat (fd, st) != 0) 406da0c48c4Sopenharmony_ci error_exit (errno, _("cannot stat archive '%s'"), 407da0c48c4Sopenharmony_ci arfname); 408da0c48c4Sopenharmony_ci 409da0c48c4Sopenharmony_ci return fd; 410da0c48c4Sopenharmony_ci} 411da0c48c4Sopenharmony_ci 412da0c48c4Sopenharmony_ci 413da0c48c4Sopenharmony_cistatic void 414da0c48c4Sopenharmony_cinot_found (int argc, char *argv[argc], bool found[argc]) 415da0c48c4Sopenharmony_ci{ 416da0c48c4Sopenharmony_ci for (int i = 0; i < argc; ++i) 417da0c48c4Sopenharmony_ci if (!found[i]) 418da0c48c4Sopenharmony_ci printf (_("no entry %s in archive\n"), argv[i]); 419da0c48c4Sopenharmony_ci} 420da0c48c4Sopenharmony_ci 421da0c48c4Sopenharmony_ci 422da0c48c4Sopenharmony_cistatic int 423da0c48c4Sopenharmony_cicopy_content (Elf *elf, int newfd, off_t off, size_t n) 424da0c48c4Sopenharmony_ci{ 425da0c48c4Sopenharmony_ci size_t len; 426da0c48c4Sopenharmony_ci char *rawfile = elf_rawfile (elf, &len); 427da0c48c4Sopenharmony_ci 428da0c48c4Sopenharmony_ci assert (off + n <= len); 429da0c48c4Sopenharmony_ci 430da0c48c4Sopenharmony_ci /* Tell the kernel we will read all the pages sequentially. */ 431da0c48c4Sopenharmony_ci size_t ps = sysconf (_SC_PAGESIZE); 432da0c48c4Sopenharmony_ci if (n > 2 * ps) 433da0c48c4Sopenharmony_ci posix_madvise (rawfile + (off & ~(ps - 1)), n, POSIX_MADV_SEQUENTIAL); 434da0c48c4Sopenharmony_ci 435da0c48c4Sopenharmony_ci return write_retry (newfd, rawfile + off, n) != (ssize_t) n; 436da0c48c4Sopenharmony_ci} 437da0c48c4Sopenharmony_ci 438da0c48c4Sopenharmony_cistatic inline bool 439da0c48c4Sopenharmony_cishould_truncate_fname (size_t *name_max) 440da0c48c4Sopenharmony_ci{ 441da0c48c4Sopenharmony_ci if (errno == ENAMETOOLONG && allow_truncate_fname) 442da0c48c4Sopenharmony_ci { 443da0c48c4Sopenharmony_ci if (*name_max == 0) 444da0c48c4Sopenharmony_ci { 445da0c48c4Sopenharmony_ci long int len = pathconf (".", _PC_NAME_MAX); 446da0c48c4Sopenharmony_ci if (len > 0) 447da0c48c4Sopenharmony_ci *name_max = len; 448da0c48c4Sopenharmony_ci } 449da0c48c4Sopenharmony_ci return *name_max != 0; 450da0c48c4Sopenharmony_ci } 451da0c48c4Sopenharmony_ci return false; 452da0c48c4Sopenharmony_ci} 453da0c48c4Sopenharmony_ci 454da0c48c4Sopenharmony_cistatic int 455da0c48c4Sopenharmony_cido_oper_extract (int oper, const char *arfname, char **argv, int argc, 456da0c48c4Sopenharmony_ci long int instance) 457da0c48c4Sopenharmony_ci{ 458da0c48c4Sopenharmony_ci bool found[argc > 0 ? argc : 1]; 459da0c48c4Sopenharmony_ci memset (found, '\0', sizeof (found)); 460da0c48c4Sopenharmony_ci 461da0c48c4Sopenharmony_ci size_t name_max = 0; 462da0c48c4Sopenharmony_ci off_t index_off = -1; 463da0c48c4Sopenharmony_ci size_t index_size = 0; 464da0c48c4Sopenharmony_ci off_t cur_off = SARMAG; 465da0c48c4Sopenharmony_ci 466da0c48c4Sopenharmony_ci int status = 0; 467da0c48c4Sopenharmony_ci Elf *elf; 468da0c48c4Sopenharmony_ci int fd = open_archive (arfname, O_RDONLY, 0, &elf, NULL, false); 469da0c48c4Sopenharmony_ci 470da0c48c4Sopenharmony_ci if (hcreate (2 * argc) == 0) 471da0c48c4Sopenharmony_ci error_exit (errno, _("cannot create hash table")); 472da0c48c4Sopenharmony_ci 473da0c48c4Sopenharmony_ci for (int cnt = 0; cnt < argc; ++cnt) 474da0c48c4Sopenharmony_ci { 475da0c48c4Sopenharmony_ci ENTRY entry = { .key = argv[cnt], .data = &argv[cnt] }; 476da0c48c4Sopenharmony_ci if (hsearch (entry, ENTER) == NULL) 477da0c48c4Sopenharmony_ci error_exit (errno, _("cannot insert into hash table")); 478da0c48c4Sopenharmony_ci } 479da0c48c4Sopenharmony_ci 480da0c48c4Sopenharmony_ci struct stat st; 481da0c48c4Sopenharmony_ci if (force_symtab) 482da0c48c4Sopenharmony_ci { 483da0c48c4Sopenharmony_ci if (fstat (fd, &st) != 0) 484da0c48c4Sopenharmony_ci { 485da0c48c4Sopenharmony_ci error (0, errno, _("cannot stat '%s'"), arfname); 486da0c48c4Sopenharmony_ci close (fd); 487da0c48c4Sopenharmony_ci return 1; 488da0c48c4Sopenharmony_ci } 489da0c48c4Sopenharmony_ci arlib_init (); 490da0c48c4Sopenharmony_ci } 491da0c48c4Sopenharmony_ci 492da0c48c4Sopenharmony_ci Elf_Cmd cmd = ELF_C_READ_MMAP; 493da0c48c4Sopenharmony_ci Elf *subelf; 494da0c48c4Sopenharmony_ci while ((subelf = elf_begin (fd, cmd, elf)) != NULL) 495da0c48c4Sopenharmony_ci { 496da0c48c4Sopenharmony_ci Elf_Arhdr *arhdr = elf_getarhdr (subelf); 497da0c48c4Sopenharmony_ci 498da0c48c4Sopenharmony_ci if (strcmp (arhdr->ar_name, "/") == 0) 499da0c48c4Sopenharmony_ci { 500da0c48c4Sopenharmony_ci index_off = elf_getaroff (subelf); 501da0c48c4Sopenharmony_ci index_size = arhdr->ar_size; 502da0c48c4Sopenharmony_ci goto next; 503da0c48c4Sopenharmony_ci } 504da0c48c4Sopenharmony_ci if (strcmp (arhdr->ar_name, "//") == 0) 505da0c48c4Sopenharmony_ci goto next; 506da0c48c4Sopenharmony_ci 507da0c48c4Sopenharmony_ci if (force_symtab) 508da0c48c4Sopenharmony_ci { 509da0c48c4Sopenharmony_ci arlib_add_symbols (elf, arfname, arhdr->ar_name, cur_off); 510da0c48c4Sopenharmony_ci cur_off += (((arhdr->ar_size + 1) & ~((off_t) 1)) 511da0c48c4Sopenharmony_ci + sizeof (struct ar_hdr)); 512da0c48c4Sopenharmony_ci } 513da0c48c4Sopenharmony_ci 514da0c48c4Sopenharmony_ci bool do_extract = argc <= 0; 515da0c48c4Sopenharmony_ci if (!do_extract) 516da0c48c4Sopenharmony_ci { 517da0c48c4Sopenharmony_ci ENTRY entry; 518da0c48c4Sopenharmony_ci entry.key = arhdr->ar_name; 519da0c48c4Sopenharmony_ci ENTRY *res = hsearch (entry, FIND); 520da0c48c4Sopenharmony_ci if (res != NULL && (instance < 0 || --instance == 0) 521da0c48c4Sopenharmony_ci && !found[(char **) res->data - argv]) 522da0c48c4Sopenharmony_ci found[(char **) res->data - argv] = do_extract = true; 523da0c48c4Sopenharmony_ci } 524da0c48c4Sopenharmony_ci 525da0c48c4Sopenharmony_ci if (do_extract) 526da0c48c4Sopenharmony_ci { 527da0c48c4Sopenharmony_ci if (verbose) 528da0c48c4Sopenharmony_ci { 529da0c48c4Sopenharmony_ci if (oper == oper_print) 530da0c48c4Sopenharmony_ci { 531da0c48c4Sopenharmony_ci printf ("\n<%s>\n\n", arhdr->ar_name); 532da0c48c4Sopenharmony_ci 533da0c48c4Sopenharmony_ci /* We have to flush now because now we use the descriptor 534da0c48c4Sopenharmony_ci directly. */ 535da0c48c4Sopenharmony_ci fflush (stdout); 536da0c48c4Sopenharmony_ci } 537da0c48c4Sopenharmony_ci else if (oper == oper_list) 538da0c48c4Sopenharmony_ci { 539da0c48c4Sopenharmony_ci char datestr[100]; 540da0c48c4Sopenharmony_ci struct tm *tp = localtime (&arhdr->ar_date); 541da0c48c4Sopenharmony_ci if (tp == NULL) 542da0c48c4Sopenharmony_ci { 543da0c48c4Sopenharmony_ci time_t time = 0; 544da0c48c4Sopenharmony_ci tp = localtime (&time); 545da0c48c4Sopenharmony_ci } 546da0c48c4Sopenharmony_ci 547da0c48c4Sopenharmony_ci strftime (datestr, sizeof (datestr), "%b %e %H:%M %Y", tp); 548da0c48c4Sopenharmony_ci 549da0c48c4Sopenharmony_ci printf ("%c%c%c%c%c%c%c%c%c %u/%u %6ju %s %s\n", 550da0c48c4Sopenharmony_ci (arhdr->ar_mode & S_IRUSR) ? 'r' : '-', 551da0c48c4Sopenharmony_ci (arhdr->ar_mode & S_IWUSR) ? 'w' : '-', 552da0c48c4Sopenharmony_ci (arhdr->ar_mode & S_IXUSR) 553da0c48c4Sopenharmony_ci ? ((arhdr->ar_mode & S_ISUID) ? 's' : 'x') 554da0c48c4Sopenharmony_ci : ((arhdr->ar_mode & S_ISUID) ? 'S' : '-'), 555da0c48c4Sopenharmony_ci (arhdr->ar_mode & S_IRGRP) ? 'r' : '-', 556da0c48c4Sopenharmony_ci (arhdr->ar_mode & S_IWGRP) ? 'w' : '-', 557da0c48c4Sopenharmony_ci (arhdr->ar_mode & S_IXGRP) 558da0c48c4Sopenharmony_ci ? ((arhdr->ar_mode & S_ISGID) ? 's' : 'x') 559da0c48c4Sopenharmony_ci : ((arhdr->ar_mode & S_ISGID) ? 'S' : '-'), 560da0c48c4Sopenharmony_ci (arhdr->ar_mode & S_IROTH) ? 'r' : '-', 561da0c48c4Sopenharmony_ci (arhdr->ar_mode & S_IWOTH) ? 'w' : '-', 562da0c48c4Sopenharmony_ci (arhdr->ar_mode & S_IXOTH) 563da0c48c4Sopenharmony_ci ? ((arhdr->ar_mode & S_ISVTX) ? 't' : 'x') 564da0c48c4Sopenharmony_ci : ((arhdr->ar_mode & S_ISVTX) ? 'T' : '-'), 565da0c48c4Sopenharmony_ci arhdr->ar_uid, 566da0c48c4Sopenharmony_ci arhdr->ar_gid, 567da0c48c4Sopenharmony_ci (uintmax_t) arhdr->ar_size, 568da0c48c4Sopenharmony_ci datestr, 569da0c48c4Sopenharmony_ci arhdr->ar_name); 570da0c48c4Sopenharmony_ci } 571da0c48c4Sopenharmony_ci else 572da0c48c4Sopenharmony_ci printf ("x - %s\n", arhdr->ar_name); 573da0c48c4Sopenharmony_ci } 574da0c48c4Sopenharmony_ci 575da0c48c4Sopenharmony_ci if (oper == oper_list) 576da0c48c4Sopenharmony_ci { 577da0c48c4Sopenharmony_ci if (!verbose) 578da0c48c4Sopenharmony_ci puts (arhdr->ar_name); 579da0c48c4Sopenharmony_ci 580da0c48c4Sopenharmony_ci goto next; 581da0c48c4Sopenharmony_ci } 582da0c48c4Sopenharmony_ci 583da0c48c4Sopenharmony_ci size_t nleft; 584da0c48c4Sopenharmony_ci char *data = elf_rawfile (subelf, &nleft); 585da0c48c4Sopenharmony_ci if (data == NULL) 586da0c48c4Sopenharmony_ci { 587da0c48c4Sopenharmony_ci error (0, 0, _("cannot read content of %s: %s"), 588da0c48c4Sopenharmony_ci arhdr->ar_name, elf_errmsg (-1)); 589da0c48c4Sopenharmony_ci status = 1; 590da0c48c4Sopenharmony_ci goto next; 591da0c48c4Sopenharmony_ci } 592da0c48c4Sopenharmony_ci 593da0c48c4Sopenharmony_ci int xfd; 594da0c48c4Sopenharmony_ci char tempfname[] = "XXXXXX"; 595da0c48c4Sopenharmony_ci bool use_mkstemp = true; 596da0c48c4Sopenharmony_ci 597da0c48c4Sopenharmony_ci if (oper == oper_print) 598da0c48c4Sopenharmony_ci xfd = STDOUT_FILENO; 599da0c48c4Sopenharmony_ci else 600da0c48c4Sopenharmony_ci { 601da0c48c4Sopenharmony_ci xfd = mkstemp (tempfname); 602da0c48c4Sopenharmony_ci if (unlikely (xfd == -1)) 603da0c48c4Sopenharmony_ci { 604da0c48c4Sopenharmony_ci /* We cannot create a temporary file. Try to overwrite 605da0c48c4Sopenharmony_ci the file or create it if it does not exist. */ 606da0c48c4Sopenharmony_ci int flags = O_WRONLY | O_CREAT; 607da0c48c4Sopenharmony_ci if (dont_replace_existing) 608da0c48c4Sopenharmony_ci flags |= O_EXCL; 609da0c48c4Sopenharmony_ci else 610da0c48c4Sopenharmony_ci flags |= O_TRUNC; 611da0c48c4Sopenharmony_ci xfd = open (arhdr->ar_name, flags, 0600); 612da0c48c4Sopenharmony_ci if (unlikely (xfd == -1)) 613da0c48c4Sopenharmony_ci { 614da0c48c4Sopenharmony_ci int printlen = INT_MAX; 615da0c48c4Sopenharmony_ci 616da0c48c4Sopenharmony_ci if (should_truncate_fname (&name_max)) 617da0c48c4Sopenharmony_ci { 618da0c48c4Sopenharmony_ci /* Try to truncate the name. First find out by how 619da0c48c4Sopenharmony_ci much. */ 620da0c48c4Sopenharmony_ci printlen = name_max; 621da0c48c4Sopenharmony_ci char truncfname[name_max + 1]; 622da0c48c4Sopenharmony_ci *((char *) mempcpy (truncfname, arhdr->ar_name, 623da0c48c4Sopenharmony_ci name_max)) = '\0'; 624da0c48c4Sopenharmony_ci 625da0c48c4Sopenharmony_ci xfd = open (truncfname, flags, 0600); 626da0c48c4Sopenharmony_ci } 627da0c48c4Sopenharmony_ci 628da0c48c4Sopenharmony_ci if (xfd == -1) 629da0c48c4Sopenharmony_ci { 630da0c48c4Sopenharmony_ci error (0, errno, _("cannot open %.*s"), 631da0c48c4Sopenharmony_ci (int) printlen, arhdr->ar_name); 632da0c48c4Sopenharmony_ci status = 1; 633da0c48c4Sopenharmony_ci goto next; 634da0c48c4Sopenharmony_ci } 635da0c48c4Sopenharmony_ci } 636da0c48c4Sopenharmony_ci 637da0c48c4Sopenharmony_ci use_mkstemp = false; 638da0c48c4Sopenharmony_ci } 639da0c48c4Sopenharmony_ci } 640da0c48c4Sopenharmony_ci 641da0c48c4Sopenharmony_ci ssize_t n; 642da0c48c4Sopenharmony_ci while ((n = TEMP_FAILURE_RETRY (write (xfd, data, nleft))) != -1) 643da0c48c4Sopenharmony_ci { 644da0c48c4Sopenharmony_ci nleft -= n; 645da0c48c4Sopenharmony_ci if (nleft == 0) 646da0c48c4Sopenharmony_ci break; 647da0c48c4Sopenharmony_ci data += n; 648da0c48c4Sopenharmony_ci } 649da0c48c4Sopenharmony_ci 650da0c48c4Sopenharmony_ci if (unlikely (n == -1)) 651da0c48c4Sopenharmony_ci { 652da0c48c4Sopenharmony_ci error (0, errno, _("failed to write %s"), arhdr->ar_name); 653da0c48c4Sopenharmony_ci status = 1; 654da0c48c4Sopenharmony_ci unlink (tempfname); 655da0c48c4Sopenharmony_ci close (xfd); 656da0c48c4Sopenharmony_ci goto next; 657da0c48c4Sopenharmony_ci } 658da0c48c4Sopenharmony_ci 659da0c48c4Sopenharmony_ci if (oper != oper_print) 660da0c48c4Sopenharmony_ci { 661da0c48c4Sopenharmony_ci /* Fix up the mode. */ 662da0c48c4Sopenharmony_ci if (unlikely (fchmod (xfd, arhdr->ar_mode) != 0)) 663da0c48c4Sopenharmony_ci { 664da0c48c4Sopenharmony_ci error (0, errno, _("cannot change mode of %s"), 665da0c48c4Sopenharmony_ci arhdr->ar_name); 666da0c48c4Sopenharmony_ci status = 0; 667da0c48c4Sopenharmony_ci } 668da0c48c4Sopenharmony_ci 669da0c48c4Sopenharmony_ci if (preserve_dates) 670da0c48c4Sopenharmony_ci { 671da0c48c4Sopenharmony_ci struct timespec tv[2]; 672da0c48c4Sopenharmony_ci tv[0].tv_sec = arhdr->ar_date; 673da0c48c4Sopenharmony_ci tv[0].tv_nsec = 0; 674da0c48c4Sopenharmony_ci tv[1].tv_sec = arhdr->ar_date; 675da0c48c4Sopenharmony_ci tv[1].tv_nsec = 0; 676da0c48c4Sopenharmony_ci 677da0c48c4Sopenharmony_ci if (unlikely (futimens (xfd, tv) != 0)) 678da0c48c4Sopenharmony_ci { 679da0c48c4Sopenharmony_ci error (0, errno, 680da0c48c4Sopenharmony_ci _("cannot change modification time of %s"), 681da0c48c4Sopenharmony_ci arhdr->ar_name); 682da0c48c4Sopenharmony_ci status = 1; 683da0c48c4Sopenharmony_ci } 684da0c48c4Sopenharmony_ci } 685da0c48c4Sopenharmony_ci 686da0c48c4Sopenharmony_ci /* If we used a temporary file, move it do the right 687da0c48c4Sopenharmony_ci name now. */ 688da0c48c4Sopenharmony_ci if (use_mkstemp) 689da0c48c4Sopenharmony_ci { 690da0c48c4Sopenharmony_ci int r; 691da0c48c4Sopenharmony_ci 692da0c48c4Sopenharmony_ci if (dont_replace_existing) 693da0c48c4Sopenharmony_ci { 694da0c48c4Sopenharmony_ci r = link (tempfname, arhdr->ar_name); 695da0c48c4Sopenharmony_ci if (likely (r == 0)) 696da0c48c4Sopenharmony_ci unlink (tempfname); 697da0c48c4Sopenharmony_ci } 698da0c48c4Sopenharmony_ci else 699da0c48c4Sopenharmony_ci r = rename (tempfname, arhdr->ar_name); 700da0c48c4Sopenharmony_ci 701da0c48c4Sopenharmony_ci if (unlikely (r) != 0) 702da0c48c4Sopenharmony_ci { 703da0c48c4Sopenharmony_ci int printlen = INT_MAX; 704da0c48c4Sopenharmony_ci 705da0c48c4Sopenharmony_ci if (should_truncate_fname (&name_max)) 706da0c48c4Sopenharmony_ci { 707da0c48c4Sopenharmony_ci /* Try to truncate the name. First find out by how 708da0c48c4Sopenharmony_ci much. */ 709da0c48c4Sopenharmony_ci printlen = name_max; 710da0c48c4Sopenharmony_ci char truncfname[name_max + 1]; 711da0c48c4Sopenharmony_ci *((char *) mempcpy (truncfname, arhdr->ar_name, 712da0c48c4Sopenharmony_ci name_max)) = '\0'; 713da0c48c4Sopenharmony_ci 714da0c48c4Sopenharmony_ci if (dont_replace_existing) 715da0c48c4Sopenharmony_ci { 716da0c48c4Sopenharmony_ci r = link (tempfname, truncfname); 717da0c48c4Sopenharmony_ci if (likely (r == 0)) 718da0c48c4Sopenharmony_ci unlink (tempfname); 719da0c48c4Sopenharmony_ci } 720da0c48c4Sopenharmony_ci else 721da0c48c4Sopenharmony_ci r = rename (tempfname, truncfname); 722da0c48c4Sopenharmony_ci } 723da0c48c4Sopenharmony_ci 724da0c48c4Sopenharmony_ci if (r != 0) 725da0c48c4Sopenharmony_ci { 726da0c48c4Sopenharmony_ci error (0, errno, _("\ 727da0c48c4Sopenharmony_cicannot rename temporary file to %.*s"), 728da0c48c4Sopenharmony_ci printlen, arhdr->ar_name); 729da0c48c4Sopenharmony_ci unlink (tempfname); 730da0c48c4Sopenharmony_ci status = 1; 731da0c48c4Sopenharmony_ci } 732da0c48c4Sopenharmony_ci } 733da0c48c4Sopenharmony_ci } 734da0c48c4Sopenharmony_ci 735da0c48c4Sopenharmony_ci close (xfd); 736da0c48c4Sopenharmony_ci } 737da0c48c4Sopenharmony_ci } 738da0c48c4Sopenharmony_ci 739da0c48c4Sopenharmony_ci next: 740da0c48c4Sopenharmony_ci cmd = elf_next (subelf); 741da0c48c4Sopenharmony_ci if (elf_end (subelf) != 0) 742da0c48c4Sopenharmony_ci error (1, 0, "%s: %s", arfname, elf_errmsg (-1)); 743da0c48c4Sopenharmony_ci } 744da0c48c4Sopenharmony_ci 745da0c48c4Sopenharmony_ci hdestroy (); 746da0c48c4Sopenharmony_ci 747da0c48c4Sopenharmony_ci if (force_symtab) 748da0c48c4Sopenharmony_ci { 749da0c48c4Sopenharmony_ci arlib_finalize (); 750da0c48c4Sopenharmony_ci 751da0c48c4Sopenharmony_ci if (symtab.symsnamelen != 0 752da0c48c4Sopenharmony_ci /* We have to rewrite the file also if it initially had an index 753da0c48c4Sopenharmony_ci but now does not need one anymore. */ 754da0c48c4Sopenharmony_ci || (symtab.symsnamelen == 0 && index_size != 0)) 755da0c48c4Sopenharmony_ci { 756da0c48c4Sopenharmony_ci char tmpfname[strlen (arfname) + 7]; 757da0c48c4Sopenharmony_ci strcpy (stpcpy (tmpfname, arfname), "XXXXXX"); 758da0c48c4Sopenharmony_ci int newfd = mkstemp (tmpfname); 759da0c48c4Sopenharmony_ci if (unlikely (newfd == -1)) 760da0c48c4Sopenharmony_ci { 761da0c48c4Sopenharmony_ci nonew: 762da0c48c4Sopenharmony_ci error (0, errno, _("cannot create new file")); 763da0c48c4Sopenharmony_ci status = 1; 764da0c48c4Sopenharmony_ci } 765da0c48c4Sopenharmony_ci else 766da0c48c4Sopenharmony_ci { 767da0c48c4Sopenharmony_ci /* Create the header. */ 768da0c48c4Sopenharmony_ci if (unlikely (write_retry (newfd, ARMAG, SARMAG) != SARMAG)) 769da0c48c4Sopenharmony_ci { 770da0c48c4Sopenharmony_ci // XXX Use /prof/self/fd/%d ??? 771da0c48c4Sopenharmony_ci nonew_unlink: 772da0c48c4Sopenharmony_ci unlink (tmpfname); 773da0c48c4Sopenharmony_ci if (newfd != -1) 774da0c48c4Sopenharmony_ci close (newfd); 775da0c48c4Sopenharmony_ci goto nonew; 776da0c48c4Sopenharmony_ci } 777da0c48c4Sopenharmony_ci 778da0c48c4Sopenharmony_ci /* Create the new file. There are three parts as far we are 779da0c48c4Sopenharmony_ci concerned: 1. original context before the index, 2. the 780da0c48c4Sopenharmony_ci new index, 3. everything after the new index. */ 781da0c48c4Sopenharmony_ci off_t rest_off; 782da0c48c4Sopenharmony_ci if (index_off != -1) 783da0c48c4Sopenharmony_ci rest_off = (index_off + sizeof (struct ar_hdr) 784da0c48c4Sopenharmony_ci + ((index_size + 1) & ~1ul)); 785da0c48c4Sopenharmony_ci else 786da0c48c4Sopenharmony_ci rest_off = SARMAG; 787da0c48c4Sopenharmony_ci 788da0c48c4Sopenharmony_ci if (symtab.symsnamelen != 0 789da0c48c4Sopenharmony_ci && ((write_retry (newfd, symtab.symsoff, 790da0c48c4Sopenharmony_ci symtab.symsofflen) 791da0c48c4Sopenharmony_ci != (ssize_t) symtab.symsofflen) 792da0c48c4Sopenharmony_ci || (write_retry (newfd, symtab.symsname, 793da0c48c4Sopenharmony_ci symtab.symsnamelen) 794da0c48c4Sopenharmony_ci != (ssize_t) symtab.symsnamelen))) 795da0c48c4Sopenharmony_ci goto nonew_unlink; 796da0c48c4Sopenharmony_ci /* Even if the original file had content before the 797da0c48c4Sopenharmony_ci symbol table, we write it in the correct order. */ 798da0c48c4Sopenharmony_ci if ((index_off != SARMAG 799da0c48c4Sopenharmony_ci && copy_content (elf, newfd, SARMAG, index_off - SARMAG)) 800da0c48c4Sopenharmony_ci || copy_content (elf, newfd, rest_off, st.st_size - rest_off)) 801da0c48c4Sopenharmony_ci goto nonew_unlink; 802da0c48c4Sopenharmony_ci 803da0c48c4Sopenharmony_ci /* Never complain about fchown failing. */ 804da0c48c4Sopenharmony_ci if (fchown (newfd, st.st_uid, st.st_gid) != 0) { ; } 805da0c48c4Sopenharmony_ci /* Set the mode of the new file to the same values the 806da0c48c4Sopenharmony_ci original file has. */ 807da0c48c4Sopenharmony_ci if (fchmod (newfd, st.st_mode & ALLPERMS) != 0 808da0c48c4Sopenharmony_ci || close (newfd) != 0) 809da0c48c4Sopenharmony_ci goto nonew_unlink; 810da0c48c4Sopenharmony_ci newfd = -1; 811da0c48c4Sopenharmony_ci if (rename (tmpfname, arfname) != 0) 812da0c48c4Sopenharmony_ci goto nonew_unlink; 813da0c48c4Sopenharmony_ci } 814da0c48c4Sopenharmony_ci } 815da0c48c4Sopenharmony_ci } 816da0c48c4Sopenharmony_ci 817da0c48c4Sopenharmony_ci elf_end (elf); 818da0c48c4Sopenharmony_ci 819da0c48c4Sopenharmony_ci close (fd); 820da0c48c4Sopenharmony_ci 821da0c48c4Sopenharmony_ci not_found (argc, argv, found); 822da0c48c4Sopenharmony_ci 823da0c48c4Sopenharmony_ci return status; 824da0c48c4Sopenharmony_ci} 825da0c48c4Sopenharmony_ci 826da0c48c4Sopenharmony_ci 827da0c48c4Sopenharmony_cistruct armem 828da0c48c4Sopenharmony_ci{ 829da0c48c4Sopenharmony_ci off_t off; 830da0c48c4Sopenharmony_ci off_t old_off; 831da0c48c4Sopenharmony_ci size_t size; 832da0c48c4Sopenharmony_ci long int long_name_off; 833da0c48c4Sopenharmony_ci struct armem *next; 834da0c48c4Sopenharmony_ci void *mem; 835da0c48c4Sopenharmony_ci time_t sec; 836da0c48c4Sopenharmony_ci uid_t uid; 837da0c48c4Sopenharmony_ci gid_t gid; 838da0c48c4Sopenharmony_ci mode_t mode; 839da0c48c4Sopenharmony_ci const char *name; 840da0c48c4Sopenharmony_ci Elf *elf; 841da0c48c4Sopenharmony_ci}; 842da0c48c4Sopenharmony_ci 843da0c48c4Sopenharmony_ci 844da0c48c4Sopenharmony_cistatic int 845da0c48c4Sopenharmony_ciwrite_member (struct armem *memb, off_t *startp, off_t *lenp, Elf *elf, 846da0c48c4Sopenharmony_ci off_t end_off, int newfd) 847da0c48c4Sopenharmony_ci{ 848da0c48c4Sopenharmony_ci struct ar_hdr arhdr; 849da0c48c4Sopenharmony_ci /* The ar_name is not actually zero terminated, but we need that for 850da0c48c4Sopenharmony_ci snprintf. Also if the name is too long, then the string starts 851da0c48c4Sopenharmony_ci with '/' plus an index off number (decimal). */ 852da0c48c4Sopenharmony_ci char tmpbuf[sizeof (arhdr.ar_name) + 2]; 853da0c48c4Sopenharmony_ci 854da0c48c4Sopenharmony_ci bool changed_header = memb->long_name_off != -1; 855da0c48c4Sopenharmony_ci if (changed_header) 856da0c48c4Sopenharmony_ci { 857da0c48c4Sopenharmony_ci /* In case of a long file name we assume the archive header 858da0c48c4Sopenharmony_ci changed and we write it here. */ 859da0c48c4Sopenharmony_ci memcpy (&arhdr, elf_rawfile (elf, NULL) + *startp, sizeof (arhdr)); 860da0c48c4Sopenharmony_ci 861da0c48c4Sopenharmony_ci snprintf (tmpbuf, sizeof (tmpbuf), "/%-*ld", 862da0c48c4Sopenharmony_ci (int) sizeof (arhdr.ar_name), memb->long_name_off); 863da0c48c4Sopenharmony_ci changed_header = memcmp (arhdr.ar_name, tmpbuf, 864da0c48c4Sopenharmony_ci sizeof (arhdr.ar_name)) != 0; 865da0c48c4Sopenharmony_ci } 866da0c48c4Sopenharmony_ci 867da0c48c4Sopenharmony_ci /* If the files are adjacent in the old file extend the range. */ 868da0c48c4Sopenharmony_ci if (*startp != -1 && !changed_header && *startp + *lenp == memb->old_off) 869da0c48c4Sopenharmony_ci { 870da0c48c4Sopenharmony_ci /* Extend the current range. */ 871da0c48c4Sopenharmony_ci *lenp += (memb->next != NULL 872da0c48c4Sopenharmony_ci ? memb->next->off : end_off) - memb->off; 873da0c48c4Sopenharmony_ci return 0; 874da0c48c4Sopenharmony_ci } 875da0c48c4Sopenharmony_ci 876da0c48c4Sopenharmony_ci /* Write out the old range. */ 877da0c48c4Sopenharmony_ci if (*startp != -1 && copy_content (elf, newfd, *startp, *lenp)) 878da0c48c4Sopenharmony_ci return -1; 879da0c48c4Sopenharmony_ci 880da0c48c4Sopenharmony_ci *startp = memb->old_off; 881da0c48c4Sopenharmony_ci *lenp = (memb->next != NULL ? memb->next->off : end_off) - memb->off; 882da0c48c4Sopenharmony_ci 883da0c48c4Sopenharmony_ci if (changed_header) 884da0c48c4Sopenharmony_ci { 885da0c48c4Sopenharmony_ci memcpy (arhdr.ar_name, tmpbuf, sizeof (arhdr.ar_name)); 886da0c48c4Sopenharmony_ci 887da0c48c4Sopenharmony_ci if (unlikely (write_retry (newfd, &arhdr, sizeof (arhdr)) 888da0c48c4Sopenharmony_ci != sizeof (arhdr))) 889da0c48c4Sopenharmony_ci return -1; 890da0c48c4Sopenharmony_ci 891da0c48c4Sopenharmony_ci *startp += sizeof (struct ar_hdr); 892da0c48c4Sopenharmony_ci assert ((size_t) *lenp >= sizeof (struct ar_hdr)); 893da0c48c4Sopenharmony_ci *lenp -= sizeof (struct ar_hdr); 894da0c48c4Sopenharmony_ci } 895da0c48c4Sopenharmony_ci 896da0c48c4Sopenharmony_ci return 0; 897da0c48c4Sopenharmony_ci} 898da0c48c4Sopenharmony_ci 899da0c48c4Sopenharmony_ci/* Store the name in the long name table if necessary. 900da0c48c4Sopenharmony_ci Record its offset or -1 if we did not need to use the table. */ 901da0c48c4Sopenharmony_cistatic void 902da0c48c4Sopenharmony_ciremember_long_name (struct armem *mem, const char *name, size_t namelen) 903da0c48c4Sopenharmony_ci{ 904da0c48c4Sopenharmony_ci mem->long_name_off = (namelen > MAX_AR_NAME_LEN 905da0c48c4Sopenharmony_ci ? arlib_add_long_name (name, namelen) 906da0c48c4Sopenharmony_ci : -1l); 907da0c48c4Sopenharmony_ci} 908da0c48c4Sopenharmony_ci 909da0c48c4Sopenharmony_cistatic int 910da0c48c4Sopenharmony_cido_oper_delete (const char *arfname, char **argv, int argc, 911da0c48c4Sopenharmony_ci long int instance) 912da0c48c4Sopenharmony_ci{ 913da0c48c4Sopenharmony_ci bool *found = alloca (sizeof (bool) * argc); 914da0c48c4Sopenharmony_ci memset (found, '\0', sizeof (bool) * argc); 915da0c48c4Sopenharmony_ci 916da0c48c4Sopenharmony_ci /* List of the files we keep. */ 917da0c48c4Sopenharmony_ci struct armem *to_copy = NULL; 918da0c48c4Sopenharmony_ci 919da0c48c4Sopenharmony_ci int status = 0; 920da0c48c4Sopenharmony_ci Elf *elf; 921da0c48c4Sopenharmony_ci struct stat st; 922da0c48c4Sopenharmony_ci int fd = open_archive (arfname, O_RDONLY, 0, &elf, &st, false); 923da0c48c4Sopenharmony_ci 924da0c48c4Sopenharmony_ci if (hcreate (2 * argc) == 0) 925da0c48c4Sopenharmony_ci error_exit (errno, _("cannot create hash table")); 926da0c48c4Sopenharmony_ci 927da0c48c4Sopenharmony_ci for (int cnt = 0; cnt < argc; ++cnt) 928da0c48c4Sopenharmony_ci { 929da0c48c4Sopenharmony_ci ENTRY entry = { .key = argv[cnt], .data = &argv[cnt] }; 930da0c48c4Sopenharmony_ci if (hsearch (entry, ENTER) == NULL) 931da0c48c4Sopenharmony_ci error_exit (errno, _("cannot insert into hash table")); 932da0c48c4Sopenharmony_ci } 933da0c48c4Sopenharmony_ci 934da0c48c4Sopenharmony_ci arlib_init (); 935da0c48c4Sopenharmony_ci 936da0c48c4Sopenharmony_ci off_t cur_off = SARMAG; 937da0c48c4Sopenharmony_ci Elf_Cmd cmd = ELF_C_READ_MMAP; 938da0c48c4Sopenharmony_ci Elf *subelf; 939da0c48c4Sopenharmony_ci while ((subelf = elf_begin (fd, cmd, elf)) != NULL) 940da0c48c4Sopenharmony_ci { 941da0c48c4Sopenharmony_ci Elf_Arhdr *arhdr = elf_getarhdr (subelf); 942da0c48c4Sopenharmony_ci 943da0c48c4Sopenharmony_ci /* Ignore the symbol table and the long file name table here. */ 944da0c48c4Sopenharmony_ci if (strcmp (arhdr->ar_name, "/") == 0 945da0c48c4Sopenharmony_ci || strcmp (arhdr->ar_name, "//") == 0) 946da0c48c4Sopenharmony_ci goto next; 947da0c48c4Sopenharmony_ci 948da0c48c4Sopenharmony_ci bool do_delete = argc <= 0; 949da0c48c4Sopenharmony_ci if (!do_delete) 950da0c48c4Sopenharmony_ci { 951da0c48c4Sopenharmony_ci ENTRY entry; 952da0c48c4Sopenharmony_ci entry.key = arhdr->ar_name; 953da0c48c4Sopenharmony_ci ENTRY *res = hsearch (entry, FIND); 954da0c48c4Sopenharmony_ci if (res != NULL && (instance < 0 || --instance == 0) 955da0c48c4Sopenharmony_ci && !found[(char **) res->data - argv]) 956da0c48c4Sopenharmony_ci found[(char **) res->data - argv] = do_delete = true; 957da0c48c4Sopenharmony_ci } 958da0c48c4Sopenharmony_ci 959da0c48c4Sopenharmony_ci if (do_delete) 960da0c48c4Sopenharmony_ci { 961da0c48c4Sopenharmony_ci if (verbose) 962da0c48c4Sopenharmony_ci printf ("d - %s\n", arhdr->ar_name); 963da0c48c4Sopenharmony_ci } 964da0c48c4Sopenharmony_ci else 965da0c48c4Sopenharmony_ci { 966da0c48c4Sopenharmony_ci struct armem *newp = alloca (sizeof (struct armem)); 967da0c48c4Sopenharmony_ci newp->old_off = elf_getaroff (subelf); 968da0c48c4Sopenharmony_ci newp->off = cur_off; 969da0c48c4Sopenharmony_ci 970da0c48c4Sopenharmony_ci cur_off += (((arhdr->ar_size + 1) & ~((off_t) 1)) 971da0c48c4Sopenharmony_ci + sizeof (struct ar_hdr)); 972da0c48c4Sopenharmony_ci 973da0c48c4Sopenharmony_ci if (to_copy == NULL) 974da0c48c4Sopenharmony_ci to_copy = newp->next = newp; 975da0c48c4Sopenharmony_ci else 976da0c48c4Sopenharmony_ci { 977da0c48c4Sopenharmony_ci newp->next = to_copy->next; 978da0c48c4Sopenharmony_ci to_copy = to_copy->next = newp; 979da0c48c4Sopenharmony_ci } 980da0c48c4Sopenharmony_ci 981da0c48c4Sopenharmony_ci /* If we recreate the symbol table read the file's symbol 982da0c48c4Sopenharmony_ci table now. */ 983da0c48c4Sopenharmony_ci arlib_add_symbols (subelf, arfname, arhdr->ar_name, newp->off); 984da0c48c4Sopenharmony_ci 985da0c48c4Sopenharmony_ci /* Remember long file names. */ 986da0c48c4Sopenharmony_ci remember_long_name (newp, arhdr->ar_name, strlen (arhdr->ar_name)); 987da0c48c4Sopenharmony_ci } 988da0c48c4Sopenharmony_ci 989da0c48c4Sopenharmony_ci next: 990da0c48c4Sopenharmony_ci cmd = elf_next (subelf); 991da0c48c4Sopenharmony_ci if (elf_end (subelf) != 0) 992da0c48c4Sopenharmony_ci error (1, 0, "%s: %s", arfname, elf_errmsg (-1)); 993da0c48c4Sopenharmony_ci } 994da0c48c4Sopenharmony_ci 995da0c48c4Sopenharmony_ci arlib_finalize (); 996da0c48c4Sopenharmony_ci 997da0c48c4Sopenharmony_ci hdestroy (); 998da0c48c4Sopenharmony_ci 999da0c48c4Sopenharmony_ci /* Create a new, temporary file in the same directory as the 1000da0c48c4Sopenharmony_ci original file. */ 1001da0c48c4Sopenharmony_ci char tmpfname[strlen (arfname) + 7]; 1002da0c48c4Sopenharmony_ci strcpy (stpcpy (tmpfname, arfname), "XXXXXX"); 1003da0c48c4Sopenharmony_ci int newfd = mkstemp (tmpfname); 1004da0c48c4Sopenharmony_ci if (unlikely (newfd == -1)) 1005da0c48c4Sopenharmony_ci goto nonew; 1006da0c48c4Sopenharmony_ci 1007da0c48c4Sopenharmony_ci /* Create the header. */ 1008da0c48c4Sopenharmony_ci if (unlikely (write_retry (newfd, ARMAG, SARMAG) != SARMAG)) 1009da0c48c4Sopenharmony_ci { 1010da0c48c4Sopenharmony_ci // XXX Use /prof/self/fd/%d ??? 1011da0c48c4Sopenharmony_ci nonew_unlink: 1012da0c48c4Sopenharmony_ci unlink (tmpfname); 1013da0c48c4Sopenharmony_ci if (newfd != -1) 1014da0c48c4Sopenharmony_ci close (newfd); 1015da0c48c4Sopenharmony_ci nonew: 1016da0c48c4Sopenharmony_ci error (0, errno, _("cannot create new file")); 1017da0c48c4Sopenharmony_ci status = 1; 1018da0c48c4Sopenharmony_ci goto errout; 1019da0c48c4Sopenharmony_ci } 1020da0c48c4Sopenharmony_ci 1021da0c48c4Sopenharmony_ci /* If the archive is empty that is all we have to do. */ 1022da0c48c4Sopenharmony_ci if (likely (to_copy != NULL)) 1023da0c48c4Sopenharmony_ci { 1024da0c48c4Sopenharmony_ci /* Write the symbol table or the long file name table or both. */ 1025da0c48c4Sopenharmony_ci if (symtab.symsnamelen != 0 1026da0c48c4Sopenharmony_ci && ((write_retry (newfd, symtab.symsoff, symtab.symsofflen) 1027da0c48c4Sopenharmony_ci != (ssize_t) symtab.symsofflen) 1028da0c48c4Sopenharmony_ci || (write_retry (newfd, symtab.symsname, symtab.symsnamelen) 1029da0c48c4Sopenharmony_ci != (ssize_t) symtab.symsnamelen))) 1030da0c48c4Sopenharmony_ci goto nonew_unlink; 1031da0c48c4Sopenharmony_ci 1032da0c48c4Sopenharmony_ci if (symtab.longnameslen > sizeof (struct ar_hdr) 1033da0c48c4Sopenharmony_ci && (write_retry (newfd, symtab.longnames, symtab.longnameslen) 1034da0c48c4Sopenharmony_ci != (ssize_t) symtab.longnameslen)) 1035da0c48c4Sopenharmony_ci goto nonew_unlink; 1036da0c48c4Sopenharmony_ci 1037da0c48c4Sopenharmony_ci /* NULL-terminate the list of files to copy. */ 1038da0c48c4Sopenharmony_ci struct armem *last = to_copy; 1039da0c48c4Sopenharmony_ci to_copy = to_copy->next; 1040da0c48c4Sopenharmony_ci last->next = NULL; 1041da0c48c4Sopenharmony_ci 1042da0c48c4Sopenharmony_ci off_t start = -1; 1043da0c48c4Sopenharmony_ci off_t len = -1; 1044da0c48c4Sopenharmony_ci 1045da0c48c4Sopenharmony_ci do 1046da0c48c4Sopenharmony_ci if (write_member (to_copy, &start, &len, elf, cur_off, newfd) != 0) 1047da0c48c4Sopenharmony_ci goto nonew_unlink; 1048da0c48c4Sopenharmony_ci while ((to_copy = to_copy->next) != NULL); 1049da0c48c4Sopenharmony_ci 1050da0c48c4Sopenharmony_ci /* Write the last part. */ 1051da0c48c4Sopenharmony_ci if (copy_content (elf, newfd, start, len)) 1052da0c48c4Sopenharmony_ci goto nonew_unlink; 1053da0c48c4Sopenharmony_ci } 1054da0c48c4Sopenharmony_ci 1055da0c48c4Sopenharmony_ci /* Set the mode of the new file to the same values the original file 1056da0c48c4Sopenharmony_ci has. Never complain about fchown failing. But do it before 1057da0c48c4Sopenharmony_ci setting the mode (which might be reset/ignored if the owner is 1058da0c48c4Sopenharmony_ci wrong. */ 1059da0c48c4Sopenharmony_ci if (fchown (newfd, st.st_uid, st.st_gid) != 0) { ; } 1060da0c48c4Sopenharmony_ci if (fchmod (newfd, st.st_mode & ALLPERMS) != 0 1061da0c48c4Sopenharmony_ci || close (newfd) != 0) 1062da0c48c4Sopenharmony_ci goto nonew_unlink; 1063da0c48c4Sopenharmony_ci newfd = -1; 1064da0c48c4Sopenharmony_ci if (rename (tmpfname, arfname) != 0) 1065da0c48c4Sopenharmony_ci goto nonew_unlink; 1066da0c48c4Sopenharmony_ci 1067da0c48c4Sopenharmony_ci errout: 1068da0c48c4Sopenharmony_ci elf_end (elf); 1069da0c48c4Sopenharmony_ci 1070da0c48c4Sopenharmony_ci arlib_fini (); 1071da0c48c4Sopenharmony_ci 1072da0c48c4Sopenharmony_ci close (fd); 1073da0c48c4Sopenharmony_ci 1074da0c48c4Sopenharmony_ci not_found (argc, argv, found); 1075da0c48c4Sopenharmony_ci 1076da0c48c4Sopenharmony_ci return status; 1077da0c48c4Sopenharmony_ci} 1078da0c48c4Sopenharmony_ci 1079da0c48c4Sopenharmony_ci 1080da0c48c4Sopenharmony_ci/* Prints the given value in the given buffer without a trailing zero char. 1081da0c48c4Sopenharmony_ci Returns false if the given value doesn't fit in the given buffer. */ 1082da0c48c4Sopenharmony_cistatic bool 1083da0c48c4Sopenharmony_cino0print (bool ofmt, char *buf, int bufsize, long int val) 1084da0c48c4Sopenharmony_ci{ 1085da0c48c4Sopenharmony_ci char tmpbuf[bufsize + 1]; 1086da0c48c4Sopenharmony_ci int ret = snprintf (tmpbuf, sizeof (tmpbuf), ofmt ? "%-*lo" : "%-*ld", 1087da0c48c4Sopenharmony_ci bufsize, val); 1088da0c48c4Sopenharmony_ci if (ret >= (int) sizeof (tmpbuf)) 1089da0c48c4Sopenharmony_ci return false; 1090da0c48c4Sopenharmony_ci memcpy (buf, tmpbuf, bufsize); 1091da0c48c4Sopenharmony_ci return true; 1092da0c48c4Sopenharmony_ci} 1093da0c48c4Sopenharmony_ci 1094da0c48c4Sopenharmony_ci 1095da0c48c4Sopenharmony_cistatic int 1096da0c48c4Sopenharmony_cido_oper_insert (int oper, const char *arfname, char **argv, int argc, 1097da0c48c4Sopenharmony_ci const char *member) 1098da0c48c4Sopenharmony_ci{ 1099da0c48c4Sopenharmony_ci int status = 0; 1100da0c48c4Sopenharmony_ci Elf *elf = NULL; 1101da0c48c4Sopenharmony_ci struct stat st; 1102da0c48c4Sopenharmony_ci int fd = open_archive (arfname, O_RDONLY, 0, &elf, &st, oper != oper_move); 1103da0c48c4Sopenharmony_ci 1104da0c48c4Sopenharmony_ci /* List of the files we keep. */ 1105da0c48c4Sopenharmony_ci struct armem *all = NULL; 1106da0c48c4Sopenharmony_ci struct armem *after_memberelem = NULL; 1107da0c48c4Sopenharmony_ci struct armem **found = alloca (sizeof (*found) * argc); 1108da0c48c4Sopenharmony_ci memset (found, '\0', sizeof (*found) * argc); 1109da0c48c4Sopenharmony_ci 1110da0c48c4Sopenharmony_ci arlib_init (); 1111da0c48c4Sopenharmony_ci 1112da0c48c4Sopenharmony_ci /* Initialize early for no_old case. */ 1113da0c48c4Sopenharmony_ci off_t cur_off = SARMAG; 1114da0c48c4Sopenharmony_ci 1115da0c48c4Sopenharmony_ci if (fd == -1) 1116da0c48c4Sopenharmony_ci { 1117da0c48c4Sopenharmony_ci if (!suppress_create_msg) 1118da0c48c4Sopenharmony_ci fprintf (stderr, "%s: creating %s\n", 1119da0c48c4Sopenharmony_ci program_invocation_short_name, arfname); 1120da0c48c4Sopenharmony_ci 1121da0c48c4Sopenharmony_ci goto no_old; 1122da0c48c4Sopenharmony_ci } 1123da0c48c4Sopenharmony_ci 1124da0c48c4Sopenharmony_ci /* Store the names of all files from the command line in a hash 1125da0c48c4Sopenharmony_ci table so that we can match it. Note that when no file name is 1126da0c48c4Sopenharmony_ci given we are basically doing nothing except recreating the 1127da0c48c4Sopenharmony_ci index. */ 1128da0c48c4Sopenharmony_ci if (oper != oper_qappend) 1129da0c48c4Sopenharmony_ci { 1130da0c48c4Sopenharmony_ci if (hcreate (2 * argc) == 0) 1131da0c48c4Sopenharmony_ci error_exit (errno, _("cannot create hash table")); 1132da0c48c4Sopenharmony_ci 1133da0c48c4Sopenharmony_ci for (int cnt = 0; cnt < argc; ++cnt) 1134da0c48c4Sopenharmony_ci { 1135da0c48c4Sopenharmony_ci ENTRY entry; 1136da0c48c4Sopenharmony_ci entry.key = full_path ? argv[cnt] : basename (argv[cnt]); 1137da0c48c4Sopenharmony_ci entry.data = &argv[cnt]; 1138da0c48c4Sopenharmony_ci if (hsearch (entry, ENTER) == NULL) 1139da0c48c4Sopenharmony_ci error_exit (errno, _("cannot insert into hash table")); 1140da0c48c4Sopenharmony_ci } 1141da0c48c4Sopenharmony_ci } 1142da0c48c4Sopenharmony_ci 1143da0c48c4Sopenharmony_ci /* While iterating over the current content of the archive we must 1144da0c48c4Sopenharmony_ci determine a number of things: which archive members to keep, 1145da0c48c4Sopenharmony_ci which are replaced, and where to insert the new members. */ 1146da0c48c4Sopenharmony_ci Elf_Cmd cmd = ELF_C_READ_MMAP; 1147da0c48c4Sopenharmony_ci Elf *subelf; 1148da0c48c4Sopenharmony_ci while ((subelf = elf_begin (fd, cmd, elf)) != NULL) 1149da0c48c4Sopenharmony_ci { 1150da0c48c4Sopenharmony_ci Elf_Arhdr *arhdr = elf_getarhdr (subelf); 1151da0c48c4Sopenharmony_ci 1152da0c48c4Sopenharmony_ci /* Ignore the symbol table and the long file name table here. */ 1153da0c48c4Sopenharmony_ci if (strcmp (arhdr->ar_name, "/") == 0 1154da0c48c4Sopenharmony_ci || strcmp (arhdr->ar_name, "//") == 0) 1155da0c48c4Sopenharmony_ci goto next; 1156da0c48c4Sopenharmony_ci 1157da0c48c4Sopenharmony_ci struct armem *newp = alloca (sizeof (struct armem)); 1158da0c48c4Sopenharmony_ci newp->old_off = elf_getaroff (subelf); 1159da0c48c4Sopenharmony_ci newp->size = arhdr->ar_size; 1160da0c48c4Sopenharmony_ci newp->sec = arhdr->ar_date; 1161da0c48c4Sopenharmony_ci newp->mem = NULL; 1162da0c48c4Sopenharmony_ci 1163da0c48c4Sopenharmony_ci /* Remember long file names. */ 1164da0c48c4Sopenharmony_ci remember_long_name (newp, arhdr->ar_name, strlen (arhdr->ar_name)); 1165da0c48c4Sopenharmony_ci 1166da0c48c4Sopenharmony_ci /* Check whether this is a file we are looking for. */ 1167da0c48c4Sopenharmony_ci if (oper != oper_qappend) 1168da0c48c4Sopenharmony_ci { 1169da0c48c4Sopenharmony_ci /* Check whether this is the member used as the insert point. */ 1170da0c48c4Sopenharmony_ci if (member != NULL && strcmp (arhdr->ar_name, member) == 0) 1171da0c48c4Sopenharmony_ci { 1172da0c48c4Sopenharmony_ci /* Note that all == NULL means insert at the beginning. */ 1173da0c48c4Sopenharmony_ci if (ipos == ipos_before) 1174da0c48c4Sopenharmony_ci after_memberelem = all; 1175da0c48c4Sopenharmony_ci else 1176da0c48c4Sopenharmony_ci after_memberelem = newp; 1177da0c48c4Sopenharmony_ci member = NULL; 1178da0c48c4Sopenharmony_ci } 1179da0c48c4Sopenharmony_ci 1180da0c48c4Sopenharmony_ci ENTRY entry; 1181da0c48c4Sopenharmony_ci entry.key = arhdr->ar_name; 1182da0c48c4Sopenharmony_ci ENTRY *res = hsearch (entry, FIND); 1183da0c48c4Sopenharmony_ci if (res != NULL && found[(char **) res->data - argv] == NULL) 1184da0c48c4Sopenharmony_ci { 1185da0c48c4Sopenharmony_ci found[(char **) res->data - argv] = newp; 1186da0c48c4Sopenharmony_ci 1187da0c48c4Sopenharmony_ci /* If we insert before or after a certain element move 1188da0c48c4Sopenharmony_ci all files to a special list. */ 1189da0c48c4Sopenharmony_ci if (unlikely (ipos != ipos_none || oper == oper_move)) 1190da0c48c4Sopenharmony_ci { 1191da0c48c4Sopenharmony_ci if (after_memberelem == newp) 1192da0c48c4Sopenharmony_ci /* Since we remove this element even though we should 1193da0c48c4Sopenharmony_ci insert everything after it, we in fact insert 1194da0c48c4Sopenharmony_ci everything after the previous element. */ 1195da0c48c4Sopenharmony_ci after_memberelem = all; 1196da0c48c4Sopenharmony_ci 1197da0c48c4Sopenharmony_ci goto next; 1198da0c48c4Sopenharmony_ci } 1199da0c48c4Sopenharmony_ci } 1200da0c48c4Sopenharmony_ci } 1201da0c48c4Sopenharmony_ci 1202da0c48c4Sopenharmony_ci if (all == NULL) 1203da0c48c4Sopenharmony_ci all = newp->next = newp; 1204da0c48c4Sopenharmony_ci else 1205da0c48c4Sopenharmony_ci { 1206da0c48c4Sopenharmony_ci newp->next = all->next; 1207da0c48c4Sopenharmony_ci all = all->next = newp; 1208da0c48c4Sopenharmony_ci } 1209da0c48c4Sopenharmony_ci 1210da0c48c4Sopenharmony_ci next: 1211da0c48c4Sopenharmony_ci cmd = elf_next (subelf); 1212da0c48c4Sopenharmony_ci if (elf_end (subelf) != 0) 1213da0c48c4Sopenharmony_ci error_exit (0, "%s: %s", arfname, elf_errmsg (-1)); 1214da0c48c4Sopenharmony_ci } 1215da0c48c4Sopenharmony_ci 1216da0c48c4Sopenharmony_ci if (oper != oper_qappend) 1217da0c48c4Sopenharmony_ci hdestroy (); 1218da0c48c4Sopenharmony_ci 1219da0c48c4Sopenharmony_ci no_old: 1220da0c48c4Sopenharmony_ci if (member != NULL) 1221da0c48c4Sopenharmony_ci error_exit (0, _("position member %s not found"), 1222da0c48c4Sopenharmony_ci member); 1223da0c48c4Sopenharmony_ci 1224da0c48c4Sopenharmony_ci if (oper == oper_move) 1225da0c48c4Sopenharmony_ci { 1226da0c48c4Sopenharmony_ci /* Make sure all requested elements are found in the archive. */ 1227da0c48c4Sopenharmony_ci for (int cnt = 0; cnt < argc; ++cnt) 1228da0c48c4Sopenharmony_ci { 1229da0c48c4Sopenharmony_ci if (found[cnt] == NULL) 1230da0c48c4Sopenharmony_ci { 1231da0c48c4Sopenharmony_ci fprintf (stderr, _("%s: no entry %s in archive!\n"), 1232da0c48c4Sopenharmony_ci program_invocation_short_name, argv[cnt]); 1233da0c48c4Sopenharmony_ci status = 1; 1234da0c48c4Sopenharmony_ci } 1235da0c48c4Sopenharmony_ci 1236da0c48c4Sopenharmony_ci if (verbose) 1237da0c48c4Sopenharmony_ci printf ("m - %s\n", argv[cnt]); 1238da0c48c4Sopenharmony_ci } 1239da0c48c4Sopenharmony_ci } 1240da0c48c4Sopenharmony_ci else 1241da0c48c4Sopenharmony_ci { 1242da0c48c4Sopenharmony_ci /* Open all the new files, get their sizes and add all symbols. */ 1243da0c48c4Sopenharmony_ci for (int cnt = 0; cnt < argc; ++cnt) 1244da0c48c4Sopenharmony_ci { 1245da0c48c4Sopenharmony_ci const char *bname = basename (argv[cnt]); 1246da0c48c4Sopenharmony_ci size_t bnamelen = strlen (bname); 1247da0c48c4Sopenharmony_ci if (found[cnt] == NULL) 1248da0c48c4Sopenharmony_ci { 1249da0c48c4Sopenharmony_ci found[cnt] = alloca (sizeof (struct armem)); 1250da0c48c4Sopenharmony_ci found[cnt]->old_off = -1; 1251da0c48c4Sopenharmony_ci 1252da0c48c4Sopenharmony_ci remember_long_name (found[cnt], bname, bnamelen); 1253da0c48c4Sopenharmony_ci } 1254da0c48c4Sopenharmony_ci 1255da0c48c4Sopenharmony_ci struct stat newst; 1256da0c48c4Sopenharmony_ci Elf *newelf; 1257da0c48c4Sopenharmony_ci int newfd = open (argv[cnt], O_RDONLY); 1258da0c48c4Sopenharmony_ci if (newfd == -1) 1259da0c48c4Sopenharmony_ci { 1260da0c48c4Sopenharmony_ci error (0, errno, _("cannot open %s"), argv[cnt]); 1261da0c48c4Sopenharmony_ci status = 1; 1262da0c48c4Sopenharmony_ci } 1263da0c48c4Sopenharmony_ci else if (fstat (newfd, &newst) == -1) 1264da0c48c4Sopenharmony_ci { 1265da0c48c4Sopenharmony_ci error (0, errno, _("cannot stat %s"), argv[cnt]); 1266da0c48c4Sopenharmony_ci close (newfd); 1267da0c48c4Sopenharmony_ci status = 1; 1268da0c48c4Sopenharmony_ci } 1269da0c48c4Sopenharmony_ci else if (!S_ISREG (newst.st_mode)) 1270da0c48c4Sopenharmony_ci { 1271da0c48c4Sopenharmony_ci error (0, errno, _("%s is no regular file"), argv[cnt]); 1272da0c48c4Sopenharmony_ci close (newfd); 1273da0c48c4Sopenharmony_ci status = 1; 1274da0c48c4Sopenharmony_ci } 1275da0c48c4Sopenharmony_ci else if (update_newer 1276da0c48c4Sopenharmony_ci && found[cnt]->old_off != -1l 1277da0c48c4Sopenharmony_ci && found[cnt]->sec > st.st_mtime) 1278da0c48c4Sopenharmony_ci /* Do nothing, the file in the archive is younger. */ 1279da0c48c4Sopenharmony_ci close (newfd); 1280da0c48c4Sopenharmony_ci else if ((newelf = elf_begin (newfd, ELF_C_READ_MMAP, NULL)) 1281da0c48c4Sopenharmony_ci == NULL) 1282da0c48c4Sopenharmony_ci { 1283da0c48c4Sopenharmony_ci fprintf (stderr, 1284da0c48c4Sopenharmony_ci _("cannot get ELF descriptor for %s: %s\n"), 1285da0c48c4Sopenharmony_ci argv[cnt], elf_errmsg (-1)); 1286da0c48c4Sopenharmony_ci status = 1; 1287da0c48c4Sopenharmony_ci } 1288da0c48c4Sopenharmony_ci else 1289da0c48c4Sopenharmony_ci { 1290da0c48c4Sopenharmony_ci if (verbose) 1291da0c48c4Sopenharmony_ci printf ("%c - %s\n", 1292da0c48c4Sopenharmony_ci found[cnt]->old_off == -1l ? 'a' : 'r', argv[cnt]); 1293da0c48c4Sopenharmony_ci 1294da0c48c4Sopenharmony_ci found[cnt]->elf = newelf; 1295da0c48c4Sopenharmony_ci found[cnt]->sec = arlib_deterministic_output ? 0 : newst.st_mtime; 1296da0c48c4Sopenharmony_ci found[cnt]->uid = arlib_deterministic_output ? 0 : newst.st_uid; 1297da0c48c4Sopenharmony_ci found[cnt]->gid = arlib_deterministic_output ? 0 : newst.st_gid; 1298da0c48c4Sopenharmony_ci found[cnt]->mode = newst.st_mode; 1299da0c48c4Sopenharmony_ci found[cnt]->name = bname; 1300da0c48c4Sopenharmony_ci 1301da0c48c4Sopenharmony_ci found[cnt]->mem = elf_rawfile (newelf, &found[cnt]->size); 1302da0c48c4Sopenharmony_ci if (found[cnt]->mem == NULL 1303da0c48c4Sopenharmony_ci || elf_cntl (newelf, ELF_C_FDDONE) != 0) 1304da0c48c4Sopenharmony_ci error_exit (0, _("cannot read %s: %s"), 1305da0c48c4Sopenharmony_ci argv[cnt], elf_errmsg (-1)); 1306da0c48c4Sopenharmony_ci 1307da0c48c4Sopenharmony_ci close (newfd); 1308da0c48c4Sopenharmony_ci 1309da0c48c4Sopenharmony_ci if (found[cnt]->old_off != -1l) 1310da0c48c4Sopenharmony_ci /* Remember long file names. */ 1311da0c48c4Sopenharmony_ci remember_long_name (found[cnt], bname, bnamelen); 1312da0c48c4Sopenharmony_ci } 1313da0c48c4Sopenharmony_ci } 1314da0c48c4Sopenharmony_ci } 1315da0c48c4Sopenharmony_ci 1316da0c48c4Sopenharmony_ci if (status != 0) 1317da0c48c4Sopenharmony_ci { 1318da0c48c4Sopenharmony_ci elf_end (elf); 1319da0c48c4Sopenharmony_ci 1320da0c48c4Sopenharmony_ci arlib_fini (); 1321da0c48c4Sopenharmony_ci 1322da0c48c4Sopenharmony_ci close (fd); 1323da0c48c4Sopenharmony_ci 1324da0c48c4Sopenharmony_ci return status; 1325da0c48c4Sopenharmony_ci } 1326da0c48c4Sopenharmony_ci 1327da0c48c4Sopenharmony_ci /* If we have no entry point so far add at the end. AFTER_MEMBERELEM 1328da0c48c4Sopenharmony_ci being NULL when adding before an entry means add at the beginning. */ 1329da0c48c4Sopenharmony_ci if (ipos != ipos_before && after_memberelem == NULL) 1330da0c48c4Sopenharmony_ci after_memberelem = all; 1331da0c48c4Sopenharmony_ci 1332da0c48c4Sopenharmony_ci /* Convert the circular list into a normal list first. */ 1333da0c48c4Sopenharmony_ci if (all != NULL) 1334da0c48c4Sopenharmony_ci { 1335da0c48c4Sopenharmony_ci struct armem *tmp = all; 1336da0c48c4Sopenharmony_ci all = all->next; 1337da0c48c4Sopenharmony_ci tmp->next = NULL; 1338da0c48c4Sopenharmony_ci } 1339da0c48c4Sopenharmony_ci 1340da0c48c4Sopenharmony_ci struct armem *last_added = after_memberelem; 1341da0c48c4Sopenharmony_ci for (int cnt = 0; cnt < argc; ++cnt) 1342da0c48c4Sopenharmony_ci if (oper != oper_replace || found[cnt]->old_off == -1) 1343da0c48c4Sopenharmony_ci { 1344da0c48c4Sopenharmony_ci if (last_added == NULL) 1345da0c48c4Sopenharmony_ci { 1346da0c48c4Sopenharmony_ci found[cnt]->next = all; 1347da0c48c4Sopenharmony_ci last_added = all = found[cnt]; 1348da0c48c4Sopenharmony_ci } 1349da0c48c4Sopenharmony_ci else 1350da0c48c4Sopenharmony_ci { 1351da0c48c4Sopenharmony_ci found[cnt]->next = last_added->next; 1352da0c48c4Sopenharmony_ci last_added = last_added->next = found[cnt]; 1353da0c48c4Sopenharmony_ci } 1354da0c48c4Sopenharmony_ci } 1355da0c48c4Sopenharmony_ci 1356da0c48c4Sopenharmony_ci /* Finally compute the offset and add the symbols for the files 1357da0c48c4Sopenharmony_ci after the insert point. */ 1358da0c48c4Sopenharmony_ci if (likely (all != NULL)) 1359da0c48c4Sopenharmony_ci for (struct armem *memp = all; memp != NULL; memp = memp->next) 1360da0c48c4Sopenharmony_ci { 1361da0c48c4Sopenharmony_ci memp->off = cur_off; 1362da0c48c4Sopenharmony_ci 1363da0c48c4Sopenharmony_ci if (memp->mem == NULL) 1364da0c48c4Sopenharmony_ci { 1365da0c48c4Sopenharmony_ci Elf_Arhdr *arhdr; 1366da0c48c4Sopenharmony_ci /* Fake initializing arhdr and subelf to keep gcc calm. */ 1367da0c48c4Sopenharmony_ci asm ("" : "=m" (arhdr), "=m" (subelf)); 1368da0c48c4Sopenharmony_ci if (elf_rand (elf, memp->old_off) == 0 1369da0c48c4Sopenharmony_ci || (subelf = elf_begin (fd, ELF_C_READ_MMAP, elf)) == NULL 1370da0c48c4Sopenharmony_ci || (arhdr = elf_getarhdr (subelf)) == NULL) 1371da0c48c4Sopenharmony_ci /* This should never happen since we already looked at the 1372da0c48c4Sopenharmony_ci archive content. But who knows... */ 1373da0c48c4Sopenharmony_ci error_exit (0, "%s: %s", arfname, elf_errmsg (-1)); 1374da0c48c4Sopenharmony_ci 1375da0c48c4Sopenharmony_ci arlib_add_symbols (subelf, arfname, arhdr->ar_name, cur_off); 1376da0c48c4Sopenharmony_ci 1377da0c48c4Sopenharmony_ci elf_end (subelf); 1378da0c48c4Sopenharmony_ci } 1379da0c48c4Sopenharmony_ci else 1380da0c48c4Sopenharmony_ci arlib_add_symbols (memp->elf, arfname, memp->name, cur_off); 1381da0c48c4Sopenharmony_ci 1382da0c48c4Sopenharmony_ci cur_off += (((memp->size + 1) & ~((off_t) 1)) 1383da0c48c4Sopenharmony_ci + sizeof (struct ar_hdr)); 1384da0c48c4Sopenharmony_ci } 1385da0c48c4Sopenharmony_ci 1386da0c48c4Sopenharmony_ci /* Now we have all the information for the symbol table and long 1387da0c48c4Sopenharmony_ci file name table. Construct the final layout. */ 1388da0c48c4Sopenharmony_ci arlib_finalize (); 1389da0c48c4Sopenharmony_ci 1390da0c48c4Sopenharmony_ci /* Create a new, temporary file in the same directory as the 1391da0c48c4Sopenharmony_ci original file. */ 1392da0c48c4Sopenharmony_ci char tmpfname[strlen (arfname) + 7]; 1393da0c48c4Sopenharmony_ci strcpy (stpcpy (tmpfname, arfname), "XXXXXX"); 1394da0c48c4Sopenharmony_ci int newfd; 1395da0c48c4Sopenharmony_ci if (fd != -1) 1396da0c48c4Sopenharmony_ci newfd = mkstemp (tmpfname); 1397da0c48c4Sopenharmony_ci else 1398da0c48c4Sopenharmony_ci { 1399da0c48c4Sopenharmony_ci newfd = open (arfname, O_RDWR | O_CREAT | O_EXCL, DEFFILEMODE); 1400da0c48c4Sopenharmony_ci if (newfd == -1 && errno == EEXIST) 1401da0c48c4Sopenharmony_ci /* Bah, first the file did not exist, now it does. Restart. */ 1402da0c48c4Sopenharmony_ci return do_oper_insert (oper, arfname, argv, argc, member); 1403da0c48c4Sopenharmony_ci } 1404da0c48c4Sopenharmony_ci if (unlikely (newfd == -1)) 1405da0c48c4Sopenharmony_ci goto nonew; 1406da0c48c4Sopenharmony_ci 1407da0c48c4Sopenharmony_ci /* Create the header. */ 1408da0c48c4Sopenharmony_ci if (unlikely (write_retry (newfd, ARMAG, SARMAG) != SARMAG)) 1409da0c48c4Sopenharmony_ci { 1410da0c48c4Sopenharmony_ci nonew_unlink: 1411da0c48c4Sopenharmony_ci if (fd != -1) 1412da0c48c4Sopenharmony_ci { 1413da0c48c4Sopenharmony_ci // XXX Use /prof/self/fd/%d ??? 1414da0c48c4Sopenharmony_ci unlink (tmpfname); 1415da0c48c4Sopenharmony_ci if (newfd != -1) 1416da0c48c4Sopenharmony_ci close (newfd); 1417da0c48c4Sopenharmony_ci } 1418da0c48c4Sopenharmony_ci nonew: 1419da0c48c4Sopenharmony_ci error (0, errno, _("cannot create new file")); 1420da0c48c4Sopenharmony_ci status = 1; 1421da0c48c4Sopenharmony_ci goto errout; 1422da0c48c4Sopenharmony_ci } 1423da0c48c4Sopenharmony_ci 1424da0c48c4Sopenharmony_ci /* If the new archive is not empty we actually have something to do. */ 1425da0c48c4Sopenharmony_ci if (likely (all != NULL)) 1426da0c48c4Sopenharmony_ci { 1427da0c48c4Sopenharmony_ci /* Write the symbol table or the long file name table or both. */ 1428da0c48c4Sopenharmony_ci if (symtab.symsnamelen != 0 1429da0c48c4Sopenharmony_ci && ((write_retry (newfd, symtab.symsoff, symtab.symsofflen) 1430da0c48c4Sopenharmony_ci != (ssize_t) symtab.symsofflen) 1431da0c48c4Sopenharmony_ci || (write_retry (newfd, symtab.symsname, symtab.symsnamelen) 1432da0c48c4Sopenharmony_ci != (ssize_t) symtab.symsnamelen))) 1433da0c48c4Sopenharmony_ci goto nonew_unlink; 1434da0c48c4Sopenharmony_ci 1435da0c48c4Sopenharmony_ci if (symtab.longnameslen > sizeof (struct ar_hdr) 1436da0c48c4Sopenharmony_ci && (write_retry (newfd, symtab.longnames, symtab.longnameslen) 1437da0c48c4Sopenharmony_ci != (ssize_t) symtab.longnameslen)) 1438da0c48c4Sopenharmony_ci goto nonew_unlink; 1439da0c48c4Sopenharmony_ci 1440da0c48c4Sopenharmony_ci off_t start = -1; 1441da0c48c4Sopenharmony_ci off_t len = -1; 1442da0c48c4Sopenharmony_ci 1443da0c48c4Sopenharmony_ci while (all != NULL) 1444da0c48c4Sopenharmony_ci { 1445da0c48c4Sopenharmony_ci if (all->mem != NULL) 1446da0c48c4Sopenharmony_ci { 1447da0c48c4Sopenharmony_ci /* This is a new file. If there is anything from the 1448da0c48c4Sopenharmony_ci archive left to be written do it now. */ 1449da0c48c4Sopenharmony_ci if (start != -1 && copy_content (elf, newfd, start, len)) 1450da0c48c4Sopenharmony_ci goto nonew_unlink; 1451da0c48c4Sopenharmony_ci 1452da0c48c4Sopenharmony_ci start = -1; 1453da0c48c4Sopenharmony_ci len = -1; 1454da0c48c4Sopenharmony_ci 1455da0c48c4Sopenharmony_ci /* Create the header. */ 1456da0c48c4Sopenharmony_ci struct ar_hdr arhdr; 1457da0c48c4Sopenharmony_ci /* The ar_name is not actually zero terminated, but we 1458da0c48c4Sopenharmony_ci need that for snprintf. Also if the name is too 1459da0c48c4Sopenharmony_ci long, then the string starts with '/' plus an index 1460da0c48c4Sopenharmony_ci off number (decimal). */ 1461da0c48c4Sopenharmony_ci char tmpbuf[sizeof (arhdr.ar_name) + 2]; 1462da0c48c4Sopenharmony_ci if (all->long_name_off == -1) 1463da0c48c4Sopenharmony_ci { 1464da0c48c4Sopenharmony_ci size_t namelen = strlen (all->name); 1465da0c48c4Sopenharmony_ci char *p = mempcpy (arhdr.ar_name, all->name, namelen); 1466da0c48c4Sopenharmony_ci *p++ = '/'; 1467da0c48c4Sopenharmony_ci memset (p, ' ', sizeof (arhdr.ar_name) - namelen - 1); 1468da0c48c4Sopenharmony_ci } 1469da0c48c4Sopenharmony_ci else 1470da0c48c4Sopenharmony_ci { 1471da0c48c4Sopenharmony_ci snprintf (tmpbuf, sizeof (tmpbuf), "/%-*ld", 1472da0c48c4Sopenharmony_ci (int) sizeof (arhdr.ar_name), all->long_name_off); 1473da0c48c4Sopenharmony_ci memcpy (arhdr.ar_name, tmpbuf, sizeof (arhdr.ar_name)); 1474da0c48c4Sopenharmony_ci } 1475da0c48c4Sopenharmony_ci 1476da0c48c4Sopenharmony_ci if (! no0print (false, arhdr.ar_date, sizeof (arhdr.ar_date), 1477da0c48c4Sopenharmony_ci all->sec)) 1478da0c48c4Sopenharmony_ci { 1479da0c48c4Sopenharmony_ci error (0, errno, _("cannot represent ar_date")); 1480da0c48c4Sopenharmony_ci goto nonew_unlink; 1481da0c48c4Sopenharmony_ci } 1482da0c48c4Sopenharmony_ci if (! no0print (false, arhdr.ar_uid, sizeof (arhdr.ar_uid), 1483da0c48c4Sopenharmony_ci all->uid)) 1484da0c48c4Sopenharmony_ci { 1485da0c48c4Sopenharmony_ci error (0, errno, _("cannot represent ar_uid")); 1486da0c48c4Sopenharmony_ci goto nonew_unlink; 1487da0c48c4Sopenharmony_ci } 1488da0c48c4Sopenharmony_ci if (! no0print (false, arhdr.ar_gid, sizeof (arhdr.ar_gid), 1489da0c48c4Sopenharmony_ci all->gid)) 1490da0c48c4Sopenharmony_ci { 1491da0c48c4Sopenharmony_ci error (0, errno, _("cannot represent ar_gid")); 1492da0c48c4Sopenharmony_ci goto nonew_unlink; 1493da0c48c4Sopenharmony_ci } 1494da0c48c4Sopenharmony_ci if (! no0print (true, arhdr.ar_mode, sizeof (arhdr.ar_mode), 1495da0c48c4Sopenharmony_ci all->mode)) 1496da0c48c4Sopenharmony_ci { 1497da0c48c4Sopenharmony_ci error (0, errno, _("cannot represent ar_mode")); 1498da0c48c4Sopenharmony_ci goto nonew_unlink; 1499da0c48c4Sopenharmony_ci } 1500da0c48c4Sopenharmony_ci if (! no0print (false, arhdr.ar_size, sizeof (arhdr.ar_size), 1501da0c48c4Sopenharmony_ci all->size)) 1502da0c48c4Sopenharmony_ci { 1503da0c48c4Sopenharmony_ci error (0, errno, _("cannot represent ar_size")); 1504da0c48c4Sopenharmony_ci goto nonew_unlink; 1505da0c48c4Sopenharmony_ci } 1506da0c48c4Sopenharmony_ci memcpy (arhdr.ar_fmag, ARFMAG, sizeof (arhdr.ar_fmag)); 1507da0c48c4Sopenharmony_ci 1508da0c48c4Sopenharmony_ci if (unlikely (write_retry (newfd, &arhdr, sizeof (arhdr)) 1509da0c48c4Sopenharmony_ci != sizeof (arhdr))) 1510da0c48c4Sopenharmony_ci goto nonew_unlink; 1511da0c48c4Sopenharmony_ci 1512da0c48c4Sopenharmony_ci /* Now the file itself. */ 1513da0c48c4Sopenharmony_ci if (unlikely (write_retry (newfd, all->mem, all->size) 1514da0c48c4Sopenharmony_ci != (off_t) all->size)) 1515da0c48c4Sopenharmony_ci goto nonew_unlink; 1516da0c48c4Sopenharmony_ci 1517da0c48c4Sopenharmony_ci /* Pad the file if its size is odd. */ 1518da0c48c4Sopenharmony_ci if ((all->size & 1) != 0) 1519da0c48c4Sopenharmony_ci if (unlikely (write_retry (newfd, "\n", 1) != 1)) 1520da0c48c4Sopenharmony_ci goto nonew_unlink; 1521da0c48c4Sopenharmony_ci } 1522da0c48c4Sopenharmony_ci else 1523da0c48c4Sopenharmony_ci { 1524da0c48c4Sopenharmony_ci /* This is a member from the archive. */ 1525da0c48c4Sopenharmony_ci if (write_member (all, &start, &len, elf, cur_off, newfd) 1526da0c48c4Sopenharmony_ci != 0) 1527da0c48c4Sopenharmony_ci goto nonew_unlink; 1528da0c48c4Sopenharmony_ci } 1529da0c48c4Sopenharmony_ci 1530da0c48c4Sopenharmony_ci all = all->next; 1531da0c48c4Sopenharmony_ci } 1532da0c48c4Sopenharmony_ci 1533da0c48c4Sopenharmony_ci /* Write the last part. */ 1534da0c48c4Sopenharmony_ci if (start != -1 && copy_content (elf, newfd, start, len)) 1535da0c48c4Sopenharmony_ci goto nonew_unlink; 1536da0c48c4Sopenharmony_ci } 1537da0c48c4Sopenharmony_ci 1538da0c48c4Sopenharmony_ci /* Set the mode of the new file to the same values the original file 1539da0c48c4Sopenharmony_ci has. */ 1540da0c48c4Sopenharmony_ci if (fd != -1) 1541da0c48c4Sopenharmony_ci { 1542da0c48c4Sopenharmony_ci /* Never complain about fchown failing. But do it before 1543da0c48c4Sopenharmony_ci setting the modes, or they might be reset/ignored if the 1544da0c48c4Sopenharmony_ci owner is wrong. */ 1545da0c48c4Sopenharmony_ci if (fchown (newfd, st.st_uid, st.st_gid) != 0) { ; } 1546da0c48c4Sopenharmony_ci if (fchmod (newfd, st.st_mode & ALLPERMS) != 0 1547da0c48c4Sopenharmony_ci || close (newfd) != 0) 1548da0c48c4Sopenharmony_ci goto nonew_unlink; 1549da0c48c4Sopenharmony_ci newfd = -1; 1550da0c48c4Sopenharmony_ci if (rename (tmpfname, arfname) != 0) 1551da0c48c4Sopenharmony_ci goto nonew_unlink; 1552da0c48c4Sopenharmony_ci } 1553da0c48c4Sopenharmony_ci 1554da0c48c4Sopenharmony_ci errout: 1555da0c48c4Sopenharmony_ci for (int cnt = 0; cnt < argc; ++cnt) 1556da0c48c4Sopenharmony_ci elf_end (found[cnt]->elf); 1557da0c48c4Sopenharmony_ci 1558da0c48c4Sopenharmony_ci elf_end (elf); 1559da0c48c4Sopenharmony_ci 1560da0c48c4Sopenharmony_ci arlib_fini (); 1561da0c48c4Sopenharmony_ci 1562da0c48c4Sopenharmony_ci if (fd != -1) 1563da0c48c4Sopenharmony_ci close (fd); 1564da0c48c4Sopenharmony_ci 1565da0c48c4Sopenharmony_ci if (newfd != -1) 1566da0c48c4Sopenharmony_ci close (newfd); 1567da0c48c4Sopenharmony_ci 1568da0c48c4Sopenharmony_ci return status; 1569da0c48c4Sopenharmony_ci} 1570da0c48c4Sopenharmony_ci 1571da0c48c4Sopenharmony_ci 1572da0c48c4Sopenharmony_ci#include "debugpred.h" 1573