]> cygwin.com Git - cygwin-apps/setup.git/blob - archive.cc
Increase buffer size in LogPrintf adaptors
[cygwin-apps/setup.git] / archive.cc
1 /*
2 * Copyright (c) 2001, Robert Collins.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * A copy of the GNU General Public License can be found at
10 * http://www.gnu.org/
11 *
12 * Written by Robert Collins <rbtcollins@hotmail.com>
13 *
14 */
15
16 /* Archive IO operations
17 */
18
19 #include "LogSingleton.h"
20
21 #include "io_stream.h"
22 #include "archive.h"
23 #include "archive_tar.h"
24
25 /* This file is the sole user of alloca(), so do this here.
26 * This will go away when this file is useing proper C++ string handling. */
27 #if HAVE_ALLOCA_H
28 #include <alloca.h>
29 #else
30 #ifndef alloca
31 #define alloca __builtin_alloca
32 #endif
33 #endif
34
35 /* In case you are wondering why the file magic is not in one place:
36 * It could be. But there is little (any?) benefit.
37 * What is important is that the file magic required for any _task_ is centralised.
38 * One such task is identifying archives
39 *
40 * to federate into each class one might add a magic parameter to the constructor, which
41 * the class could test itself.
42 */
43
44 /* GNU TAR:
45 * offset 257 string ustar\040\040\0
46 */
47
48
49 #define longest_magic 265
50
51 archive *
52 archive::extract (io_stream * original)
53 {
54 if (!original)
55 return NULL;
56 char magic[longest_magic];
57 if (original->peek (magic, longest_magic) > 0)
58 {
59 if (memcmp (&magic[257], "ustar\040\040\0", 8) == 0
60 || memcmp (&magic[257], "ustar\0", 6) == 0)
61 {
62 /* tar */
63 archive_tar *rv = new archive_tar (original);
64 if (!rv->error ())
65 return rv;
66 return NULL;
67 }
68 #if 0
69 else if (memcmp (magic, "BZh", 3) == 0)
70 {
71 archive_bz *rv = new archive_bz (original);
72 if (!rv->error ())
73 return rv;
74 return NULL;
75 }
76 #endif
77 }
78 return NULL;
79 }
80
81 archive::extract_results
82 archive::extract_file (archive * source, const std::string& prefixURL,
83 const std::string& prefixPath, std::string suffix)
84 {
85 extract_results res = extract_other;
86 if (source)
87 {
88 const std::string destfilename = prefixURL + prefixPath
89 + source->next_file_name() + suffix;
90 switch (source->next_file_type ())
91 {
92 case ARCHIVE_FILE_REGULAR:
93 {
94 /* TODO: remove in-the-way directories via mkpath_p */
95 if (io_stream::mkpath_p (PATH_TO_FILE, destfilename, 0755))
96 {
97 Log (LOG_TIMESTAMP) << "Failed to make the path for " << destfilename
98 << endLog;
99 res = extract_inuse;
100 goto out;
101 }
102 io_stream::remove (destfilename);
103 io_stream *in = source->extract_file ();
104 if (!in)
105 {
106 Log (LOG_TIMESTAMP) << "Failed to extract the file "
107 << destfilename << " from the archive"
108 << endLog;
109 res = extract_inuse;
110 goto out;
111 }
112 io_stream *tmp = io_stream::open (destfilename, "wb", in->get_mode ());
113 if (!tmp)
114 {
115 delete in;
116 Log (LOG_TIMESTAMP) << "Failed to open " << destfilename;
117 Log (LOG_TIMESTAMP) << " for writing." << endLog;
118 res = extract_inuse;
119 }
120 else if (io_stream::copy (in, tmp))
121 {
122 Log (LOG_TIMESTAMP) << "Failed to output " << destfilename
123 << endLog;
124 delete in;
125 delete tmp;
126 io_stream::remove (destfilename);
127 res = extract_other;
128 }
129 else
130 {
131 tmp->set_mtime (in->get_mtime ());
132 delete in;
133 delete tmp;
134 res = extract_ok;
135 }
136 }
137 break;
138 case ARCHIVE_FILE_SYMLINK:
139 if (io_stream::mkpath_p (PATH_TO_FILE, destfilename, 0755))
140 {
141 Log (LOG_TIMESTAMP) << "Failed to make the path for %s"
142 << destfilename << endLog;
143 res = extract_other;
144 }
145 else
146 {
147 io_stream::remove (destfilename);
148 int x = io_stream::mklink (destfilename,
149 prefixURL+ source->linktarget (),
150 IO_STREAM_SYMLINK);
151 /* FIXME: check what tar's filelength is set to for symlinks */
152 source->skip_file ();
153 res = x == 0 ? extract_ok : extract_inuse;
154 }
155 break;
156 case ARCHIVE_FILE_HARDLINK:
157 if (io_stream::mkpath_p (PATH_TO_FILE, destfilename, 0755))
158 {
159 Log (LOG_TIMESTAMP) << "Failed to make the path for %s"
160 << destfilename << endLog;
161 res = extract_other;
162 }
163 else
164 {
165 io_stream::remove (destfilename);
166 int x = io_stream::mklink (destfilename,
167 prefixURL + prefixPath + source->linktarget (),
168 IO_STREAM_HARDLINK);
169 /* FIXME: check what tar's filelength is set to for hardlinks */
170 source->skip_file ();
171 res = x == 0 ? extract_ok : extract_inuse;
172 }
173 break;
174 case ARCHIVE_FILE_DIRECTORY:
175 {
176 char *path = (char *) alloca (destfilename.size());
177 strcpy (path, destfilename.c_str());
178 while (path[0] && path[strlen (path) - 1] == '/')
179 path[strlen (path) - 1] = 0;
180 io_stream *in = source->extract_file ();
181 int x = io_stream::mkpath_p (PATH_TO_DIR, path, in->get_mode ());
182 delete in;
183 source->skip_file ();
184 res = x == 0 ? extract_ok : extract_other;
185 }
186 break;
187 case ARCHIVE_FILE_INVALID:
188 source->skip_file ();
189 break;
190 }
191 }
192 out:
193 return res;
194 }
195
196 archive::~archive () {};
197
198 #if 0
199 ssize_t archive::read (void *buffer, size_t len)
200 {
201 Log (LOG_TIMESTAMP, "archive::read called");
202 return 0;
203 }
204
205 ssize_t archive::write (void *buffer, size_t len)
206 {
207 Log (LOG_TIMESTAMP, "archive::write called");
208 return 0;
209 }
210
211 ssize_t archive::peek (void *buffer, size_t len)
212 {
213 Log (LOG_TIMESTAMP, "archive::peek called");
214 return 0;
215 }
216
217 long
218 archive::tell ()
219 {
220 Log (LOG_TIMESTAMP, "bz::tell called");
221 return 0;
222 }
223
224 int
225 archive::error ()
226 {
227 Log (LOG_TIMESTAMP, "archive::error called");
228 return 0;
229 }
230
231 const char *
232 archive::next_file_name ()
233 {
234 Log (LOG_TIMESTAMP, "archive::next_file_name called");
235 return NULL;
236 }
237
238 #endif
This page took 0.045518 seconds and 5 git commands to generate.