2 * Copyright (c) 2001, Robert Collins.
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.
9 * A copy of the GNU General Public License can be found at
12 * Written by Robert Collins <rbtcollins@hotmail.com>
16 /* Archive IO operations
19 #include "LogSingleton.h"
21 #include "io_stream.h"
23 #include "archive_tar.h"
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. */
31 #define alloca __builtin_alloca
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
40 * to federate into each class one might add a magic parameter to the constructor, which
41 * the class could test itself.
45 * offset 257 string ustar\040\040\0
48 #define longest_magic 265
51 archive::extract (io_stream
* original
)
55 char magic
[longest_magic
];
56 if (original
->peek (magic
, longest_magic
) > 0)
58 if (memcmp (&magic
[257], "ustar\040\040\0", 8) == 0
59 || memcmp (&magic
[257], "ustar\0", 6) == 0)
62 archive_tar
*rv
= new archive_tar (original
);
71 archive::extract_results
72 archive::extract_file (archive
* source
, const std::string
& prefixURL
,
73 const std::string
& prefixPath
, std::string suffix
)
75 extract_results res
= extract_other
;
78 const std::string destfilename
= prefixURL
+ prefixPath
79 + source
->next_file_name() + suffix
;
80 switch (source
->next_file_type ())
82 case ARCHIVE_FILE_REGULAR
:
84 /* TODO: remove in-the-way directories via mkpath_p */
85 if (io_stream::mkpath_p (PATH_TO_FILE
, destfilename
, 0755))
87 Log (LOG_TIMESTAMP
) << "Failed to make the path for " << destfilename
92 io_stream::remove (destfilename
);
93 io_stream
*in
= source
->extract_file ();
96 Log (LOG_TIMESTAMP
) << "Failed to extract the file "
97 << destfilename
<< " from the archive"
102 io_stream
*tmp
= io_stream::open (destfilename
, "wb", in
->get_mode ());
106 Log (LOG_TIMESTAMP
) << "Failed to open " << destfilename
;
107 Log (LOG_TIMESTAMP
) << " for writing." << endLog
;
110 else if (io_stream::copy (in
, tmp
))
112 Log (LOG_TIMESTAMP
) << "Failed to output " << destfilename
116 io_stream::remove (destfilename
);
121 tmp
->set_mtime (in
->get_mtime ());
128 case ARCHIVE_FILE_SYMLINK
:
129 if (io_stream::mkpath_p (PATH_TO_FILE
, destfilename
, 0755))
131 Log (LOG_TIMESTAMP
) << "Failed to make the path for %s"
132 << destfilename
<< endLog
;
137 io_stream::remove (destfilename
);
138 int x
= io_stream::mklink (destfilename
,
139 prefixURL
+ source
->linktarget (),
141 /* FIXME: check what tar's filelength is set to for symlinks */
142 source
->skip_file ();
143 res
= x
== 0 ? extract_ok
: extract_inuse
;
146 case ARCHIVE_FILE_HARDLINK
:
147 if (io_stream::mkpath_p (PATH_TO_FILE
, destfilename
, 0755))
149 Log (LOG_TIMESTAMP
) << "Failed to make the path for %s"
150 << destfilename
<< endLog
;
155 io_stream::remove (destfilename
);
156 int x
= io_stream::mklink (destfilename
,
157 prefixURL
+ prefixPath
+ source
->linktarget (),
159 /* FIXME: check what tar's filelength is set to for hardlinks */
160 source
->skip_file ();
161 res
= x
== 0 ? extract_ok
: extract_inuse
;
164 case ARCHIVE_FILE_DIRECTORY
:
166 char *path
= (char *) alloca (destfilename
.size() + 1);
167 strcpy (path
, destfilename
.c_str());
168 while (path
[0] && path
[strlen (path
) - 1] == '/')
169 path
[strlen (path
) - 1] = 0;
170 io_stream
*in
= source
->extract_file ();
171 int x
= io_stream::mkpath_p (PATH_TO_DIR
, path
, in
->get_mode ());
173 source
->skip_file ();
174 res
= x
== 0 ? extract_ok
: extract_other
;
177 case ARCHIVE_FILE_INVALID
:
178 source
->skip_file ();
186 archive::~archive () {};