aboutsummaryrefslogtreecommitdiff
path: root/libbb/extract_archive.c
diff options
context:
space:
mode:
Diffstat (limited to 'libbb/extract_archive.c')
-rw-r--r--libbb/extract_archive.c132
1 files changed, 132 insertions, 0 deletions
diff --git a/libbb/extract_archive.c b/libbb/extract_archive.c
new file mode 100644
index 000000000..f22cbb619
--- /dev/null
+++ b/libbb/extract_archive.c
@@ -0,0 +1,132 @@
1/*
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU Library General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
15 */
16
17#include <stdlib.h>
18#include <string.h>
19#include <time.h>
20#include <unistd.h>
21#include <utime.h>
22#include "libbb.h"
23
24/* Extract files in the linear linked list 'extract_headers' to either
25 * filesystem, stdout or buffer depending on the value of 'function' which is
26 * described in extract_files.h
27 *
28 * prefix doesnt have to be just a directory, it may prefix the filename as well.
29 *
30 * e.g. '/var/lib/dpkg/info/dpkg.' will extract all files to the base bath
31 * '/var/lib/dpkg/info/' and all files/dirs created in that dir will have
32 * 'dpkg.' as their prefix
33 *
34 * For this reason if prefix does point to a dir then it must end with a
35 * trailing '/' or else the last dir will be assumed to be the file prefix
36 */
37
38char *extract_archive(FILE *src_stream, FILE *out_stream, file_headers_t *extract_headers, int function, const char *prefix)
39{
40 FILE *dst_stream = NULL;
41 char *full_name = NULL;
42 char *buffer = NULL;
43 size_t uncompressed_count = 0;
44 struct utimbuf t;
45
46 /* find files to extract or display */
47 while (extract_headers != NULL) {
48 /* prefix doesnt have to be a proper path it may prepend
49 * the filename as well */
50 if (prefix != NULL) {
51 /* strip leading '/' in filename to extract as prefix may not be dir */
52 char *tmp_str = strchr(extract_headers->name, '/');
53 if (tmp_str == NULL) {
54 tmp_str = extract_headers->name;
55 } else {
56 tmp_str++;
57 }
58 /* Cant use concat_path_file here as prefix might not be a directory */
59 full_name = xmalloc(strlen(prefix) + strlen(tmp_str) + 1);
60 strcpy(full_name, prefix);
61 strcat(full_name, tmp_str);
62 } else {
63 full_name = extract_headers->name;
64 }
65
66 /* Seek to start of file, have to use fgetc as src_stream may be a pipe
67 * you cant [lf]seek on pipes */
68 while (uncompressed_count < extract_headers->offset) {
69 fgetc(src_stream);
70 uncompressed_count++;
71 }
72
73 if (S_ISREG(extract_headers->mode)) {
74 if (function & extract_to_stdout) {
75 copy_file_chunk(src_stream, out_stream, extract_headers->size);
76 uncompressed_count += extract_headers->size;
77 }
78 else if (function & extract_all_to_fs) {
79 dst_stream = wfopen(full_name, "w");
80 copy_file_chunk(src_stream, dst_stream, extract_headers->size);
81 uncompressed_count += extract_headers->size;
82 fclose(dst_stream);
83 }
84 else if (function & extract_one_to_buffer) {
85 buffer = (char *) xmalloc(extract_headers->size + 1);
86 fread(buffer, 1, extract_headers->size, src_stream);
87 break;
88 }
89 }
90#if defined BB_DPKG | defined BB_DPKG_DEB
91 else if (S_ISDIR(extract_headers->mode)) {
92 if (function & extract_all_to_fs) {
93 if (create_path(full_name, extract_headers->mode) == FALSE) {
94 perror_msg("Cannot mkdir %s", extract_headers->name);
95 return NULL;
96 }
97 }
98 }
99 else if (S_ISLNK(extract_headers->mode)) {
100 if (function & extract_all_to_fs) {
101 if (symlink(extract_headers->link_name, full_name) < 0) {
102 perror_msg("Cannot create hard link from %s to '%s'", extract_headers->name, extract_headers->link_name);
103 return NULL;
104 }
105 }
106 }
107#endif
108 if (function & extract_verbose_list) {
109 fprintf(out_stream, "%s %d/%d %8d %s ", mode_string(extract_headers->mode),
110 extract_headers->uid, extract_headers->gid,
111 (int) extract_headers->size, time_string(extract_headers->mtime));
112 }
113
114 if ((function & extract_list) || (function & extract_verbose_list)){
115 /* fputs doesnt add a trailing \n, so use fprintf */
116 fprintf(out_stream, "%s\n", extract_headers->name);
117 }
118
119 if (function & extract_preserve_date) {
120 t.actime = extract_headers->mtime;
121 t.modtime = extract_headers->mtime;
122 utime(full_name, &t);
123 }
124 chmod(full_name, extract_headers->mode);
125 free(full_name);
126
127 extract_headers = extract_headers->next;
128 }
129
130 return(buffer);
131}
132