]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/elftoolchain/ar/read.c
sysctl(9): Fix a few mandoc related issues
[FreeBSD/FreeBSD.git] / contrib / elftoolchain / ar / read.c
1 /*-
2  * Copyright (c) 2007 Kai Wang
3  * Copyright (c) 2007 Tim Kientzle
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer
11  *    in this position and unchanged.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19  * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
20  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27
28 #include <sys/queue.h>
29 #include <sys/stat.h>
30
31 #include <archive.h>
32 #include <archive_entry.h>
33 #include <assert.h>
34 #include <errno.h>
35 #include <libgen.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39
40 #include "ar.h"
41
42 ELFTC_VCSID("$Id: read.c 3629 2018-09-30 19:26:28Z jkoshy $");
43
44 /*
45  * Handle read modes: 'x', 't' and 'p'.
46  *
47  * Returns EXIT_SUCCESS if all operations completed successfully or returns
48  * EXIT_FAILURE otherwise.
49  */
50 int
51 ar_read_archive(struct bsdar *bsdar, int mode)
52 {
53         FILE                     *out;
54         struct archive           *a;
55         struct archive_entry     *entry;
56         struct stat               sb;
57         struct tm                *tp;
58         const char               *bname;
59         const char               *name;
60         mode_t                    md;
61         size_t                    size;
62         time_t                    mtime;
63         uid_t                     uid;
64         gid_t                     gid;
65         char                    **av;
66         char                      buf[25];
67         int                       found;
68         int                       exitcode, i, flags, r;
69
70         assert(mode == 'p' || mode == 't' || mode == 'x');
71
72         if ((a = archive_read_new()) == NULL)
73                 bsdar_errc(bsdar, 0, "archive_read_new failed");
74         archive_read_support_format_ar(a);
75         AC(archive_read_open_filename(a, bsdar->filename, DEF_BLKSZ));
76
77         exitcode = EXIT_SUCCESS;
78         out = bsdar->output;
79
80         for (;;) {
81                 r = archive_read_next_header(a, &entry);
82                 if (r == ARCHIVE_WARN || r == ARCHIVE_RETRY ||
83                     r == ARCHIVE_FATAL)
84                         bsdar_warnc(bsdar, 0, "%s", archive_error_string(a));
85                 if (r == ARCHIVE_EOF || r == ARCHIVE_FATAL)
86                         break;
87                 if (r == ARCHIVE_RETRY) {
88                         bsdar_warnc(bsdar, 0, "Retrying...");
89                         continue;
90                 }
91
92                 if (archive_format(a) == ARCHIVE_FORMAT_AR_BSD)
93                         bsdar->options |= AR_BSD;
94                 else
95                         bsdar->options &= ~AR_BSD;
96
97                 if ((name = archive_entry_pathname(entry)) == NULL)
98                         break;
99
100                 /* Skip pseudo members. */
101                 if (bsdar_is_pseudomember(bsdar, name))
102                         continue;
103
104                 /* The ar(5) format only supports 'leaf' file names. */
105                 if (strchr(name, '/')) {
106                         bsdar_warnc(bsdar, 0, "ignoring entry: %s",
107                             name);
108                         continue;
109                 }
110
111                 /*
112                  * If we had been given a list of file names to process, check
113                  * that the current entry is present in this list.
114                  */
115                 if (bsdar->argc > 0) {
116                         found = 0;
117                         for(i = 0; i < bsdar->argc; i++) {
118                                 av = &bsdar->argv[i];
119                                 if (*av == NULL)
120                                         continue;
121                                 /*
122                                  * Per POSIX, only the basename of a file
123                                  * argument should be compared.
124                                  */
125                                 if ((bname = basename(*av)) == NULL)
126                                         bsdar_errc(bsdar, errno,
127                                             "basename failed");
128                                 if (strcmp(bname, name) != 0)
129                                         continue;
130
131                                 *av = NULL;
132                                 found = 1;
133                                 break;
134                         }
135                         if (!found)
136                                 continue;
137                 }
138
139                 if (mode == 't') {
140                         if (bsdar->options & AR_V) {
141                                 md = archive_entry_mode(entry);
142                                 uid = archive_entry_uid(entry);
143                                 gid = archive_entry_gid(entry);
144                                 size = archive_entry_size(entry);
145                                 mtime = archive_entry_mtime(entry);
146                                 (void)fprintf(out, "%s %6d/%-6d %8ju ",
147                                     bsdar_strmode(md) + 1, uid, gid,
148                                     (uintmax_t)size);
149                                 tp = localtime(&mtime);
150                                 (void)strftime(buf, sizeof(buf),
151                                     "%b %e %H:%M %Y", tp);
152                                 (void)fprintf(out, "%s %s", buf, name);
153                         } else
154                                 (void)fprintf(out, "%s", name);
155                         r = archive_read_data_skip(a);
156                         if (r == ARCHIVE_WARN || r == ARCHIVE_RETRY ||
157                             r == ARCHIVE_FATAL) {
158                                 (void)fprintf(out, "\n");
159                                 bsdar_warnc(bsdar, 0, "%s",
160                                     archive_error_string(a));
161                         }
162
163                         if (r == ARCHIVE_FATAL)
164                                 break;
165
166                         (void)fprintf(out, "\n");
167                 } else {
168                         /* mode == 'x' || mode = 'p' */
169                         if (mode == 'p') {
170                                 if (bsdar->options & AR_V) {
171                                         (void)fprintf(out, "\n<%s>\n\n",
172                                             name);
173                                         fflush(out);
174                                 }
175                                 r = archive_read_data_into_fd(a, fileno(out));
176                         } else {
177                                 /* mode == 'x' */
178                                 if (stat(name, &sb) != 0) {
179                                         if (errno != ENOENT) {
180                                                 bsdar_warnc(bsdar, errno,
181                                                     "stat %s failed",
182                                                     bsdar->filename);
183                                                 continue;
184                                         }
185                                 } else {
186                                         /* stat success, file exist */
187                                         if (bsdar->options & AR_CC)
188                                                 continue;
189                                         if (bsdar->options & AR_U &&
190                                             archive_entry_mtime(entry) <=
191                                             sb.st_mtime)
192                                                 continue;
193                                 }
194
195                                 if (bsdar->options & AR_V)
196                                         (void)fprintf(out, "x - %s\n", name);
197                                 /* Basic path security flags. */
198                                 flags = ARCHIVE_EXTRACT_SECURE_SYMLINKS |
199                                     ARCHIVE_EXTRACT_SECURE_NODOTDOT;
200                                 if (bsdar->options & AR_O)
201                                         flags |= ARCHIVE_EXTRACT_TIME;
202
203                                 r = archive_read_extract(a, entry, flags);
204                         }
205
206                         if (r) {
207                                 bsdar_warnc(bsdar, 0, "%s",
208                                     archive_error_string(a));
209                                 exitcode = EXIT_FAILURE;
210                         }
211                 }
212         }
213
214         if (r == ARCHIVE_FATAL)
215                 exitcode = EXIT_FAILURE;
216
217         AC(archive_read_close(a));
218         ACV(archive_read_free(a));
219
220         return (exitcode);
221 }