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