00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "tarfile.h"
00023 #include "data.h"
00024
00025 #include <fcntl.h>
00026 #include <errno.h>
00027 #include <string.h>
00028 #include <stdlib.h>
00029
00030 namespace reuse {
00031
00032 TarFile::TarFile(const char *filename,
00033 bool create,
00034 tartype_t *compress_ops,
00035 bool always_throw)
00036 : m_tar(0),
00037 m_throw(always_throw),
00038 m_writemode(create)
00039 {
00040
00041 int flags = 0;
00042 mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
00043
00044 if( m_writemode ) {
00045 flags = O_WRONLY | O_CREAT | O_EXCL;
00046 }
00047 else {
00048 flags = O_RDONLY;
00049 }
00050
00051
00052 if( tar_open(&m_tar, const_cast<char*>(filename),
00053 compress_ops, flags, mode, TAR_VERBOSE | TAR_GNU) == -1 ) {
00054 throw TarError(std::string("Unable to open tar file: ") + strerror(errno));
00055 }
00056 }
00057
00058 TarFile::~TarFile()
00059 {
00060 try {
00061 Close();
00062 } catch( TarError &te ) {}
00063 }
00064
00065 bool TarFile::False(const char *msg)
00066 {
00067 m_last_error = msg;
00068 if( m_throw )
00069 throw TarError(msg);
00070 else
00071 return false;
00072 }
00073
00074 bool TarFile::False(const std::string &msg, int err)
00075 {
00076 std::string str = msg;
00077 str += ": ";
00078 str += strerror(err);
00079 return False(str);
00080 }
00081
00082 bool TarFile::Close()
00083 {
00084 if( m_tar ) {
00085 if( m_writemode ) {
00086 if( tar_append_eof(m_tar) != 0 )
00087 return False("Unable to write eof", errno);
00088 }
00089
00090 if( tar_close(m_tar) != 0 ) {
00091 return False("Unable to close file", errno);
00092 }
00093 m_tar = 0;
00094 }
00095 return true;
00096 }
00097
00098
00099
00100
00101 bool TarFile::AppendFile(const char *tarpath, const std::string &data)
00102 {
00103
00104 th_set_type(m_tar, REGTYPE);
00105 th_set_mode(m_tar, 0644);
00106 th_set_path(m_tar, const_cast<char*>(tarpath));
00107 th_set_user(m_tar, 0);
00108 th_set_group(m_tar, 0);
00109 th_set_size(m_tar, data.size());
00110 th_set_mtime(m_tar, time(NULL));
00111 if( th_write(m_tar) != 0 ) {
00112 return False("Unable to write tar header", errno);
00113 }
00114
00115
00116 char block[T_BLOCKSIZE];
00117 for( size_t pos = 0; pos < data.size(); pos += T_BLOCKSIZE ) {
00118 memset(block, 0, T_BLOCKSIZE);
00119
00120 size_t size = T_BLOCKSIZE;
00121 if( data.size() - pos < T_BLOCKSIZE )
00122 size = data.size() - pos;
00123
00124 memcpy(block, data.data() + pos, size);
00125
00126 if( tar_block_write(m_tar, block) != T_BLOCKSIZE ) {
00127 return False("Unable to write block", errno);
00128 }
00129 }
00130
00131 return true;
00132 }
00133
00134
00135
00136 bool TarFile::ReadNextFile(std::string &tarpath, std::string &data)
00137 {
00138
00139 tarpath.clear();
00140 data.clear();
00141
00142
00143 do {
00144 if( th_read(m_tar) != 0 ) {
00145
00146
00147
00148 m_last_error = "";
00149 return false;
00150 }
00151 } while( TH_ISDIR(m_tar) );
00152
00153
00154 if( !TH_ISREG(m_tar) ) {
00155 return False("Only regular files are supported inside a tarball.");
00156 }
00157
00158 char *pathname = th_get_pathname(m_tar);
00159 tarpath = pathname;
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171 size_t size = th_get_size(m_tar);
00172
00173
00174 char block[T_BLOCKSIZE];
00175 for( size_t pos = 0; pos < size; pos += T_BLOCKSIZE ) {
00176 memset(block, 0, T_BLOCKSIZE);
00177
00178 size_t readsize = T_BLOCKSIZE;
00179 if( size - pos < T_BLOCKSIZE )
00180 readsize = size - pos;
00181
00182 if( tar_block_read(m_tar, block) != T_BLOCKSIZE ) {
00183 return False("Unable to read block", errno);
00184 }
00185
00186 data.append(block, readsize);
00187 }
00188
00189 return true;
00190 }
00191
00192
00193
00194
00195 bool TarFile::ReadNextFile(std::string &tarpath, Barry::Data &data)
00196 {
00197
00198 tarpath.clear();
00199 data.QuickZap();
00200
00201
00202 do {
00203 if( th_read(m_tar) != 0 ) {
00204
00205
00206
00207 m_last_error = "";
00208 return false;
00209 }
00210 } while( TH_ISDIR(m_tar) );
00211
00212
00213 if( !TH_ISREG(m_tar) ) {
00214 return False("Only regular files are supported inside a tarball.");
00215 }
00216
00217 char *pathname = th_get_pathname(m_tar);
00218 tarpath = pathname;
00219
00220
00221
00222
00223
00224
00225
00226
00227
00228
00229
00230 size_t size = th_get_size(m_tar);
00231
00232
00233 char block[T_BLOCKSIZE];
00234 for( size_t pos = 0; pos < size; pos += T_BLOCKSIZE ) {
00235 memset(block, 0, T_BLOCKSIZE);
00236
00237 size_t readsize = T_BLOCKSIZE;
00238 if( size - pos < T_BLOCKSIZE )
00239 readsize = size - pos;
00240
00241 if( tar_block_read(m_tar, block) != T_BLOCKSIZE ) {
00242 return False("Unable to read block", errno);
00243 }
00244
00245 data.Append(block, readsize);
00246 }
00247
00248 return true;
00249 }
00250
00251
00252
00253 bool TarFile::ReadNextFilenameOnly(std::string &tarpath)
00254 {
00255
00256 tarpath.clear();
00257
00258
00259 do {
00260 if( th_read(m_tar) != 0 ) {
00261
00262
00263
00264 m_last_error = "";
00265 return false;
00266 }
00267 } while( TH_ISDIR(m_tar) );
00268
00269
00270 if( !TH_ISREG(m_tar) ) {
00271 return False("Only regular files are supported inside a tarball.");
00272 }
00273
00274 char *pathname = th_get_pathname(m_tar);
00275 tarpath = pathname;
00276
00277
00278
00279 if( tar_skip_regfile(m_tar) != 0 ) {
00280 return False("Unable to skip tar file", errno);
00281 }
00282
00283 return true;
00284 }
00285
00286
00287 }
00288
00289
00290 #ifdef __TEST_MODE__
00291
00292 #include <iostream>
00293 #include <unistd.h>
00294
00295 using namespace std;
00296
00297 int main()
00298 {
00299 try {
00300 cout << "Writing test file..." << endl;
00301 reuse::TarFile output("tartest.tar.gz", true, true, true);
00302 std::string data;
00303 for( int i = 0; i < 60; i++ ) {
00304 data.append("0123456789", 10);
00305 }
00306
00307 output.AppendFile("path1/test1.txt", data);
00308 output.AppendFile("path2/test2.txt", data);
00309 output.Close();
00310
00311
00312 cout << "Reading test file..." << endl;
00313 reuse::TarFile input("tartest.tar.gz", false, true, true);
00314 std::string path, incoming;
00315
00316 while( input.ReadNextFile(path, incoming) ) {
00317 cout << "Read: " << path
00318 << " Data: "
00319 << (( data == incoming ) ? "equal" : "different")
00320 << endl;
00321 }
00322
00323 input.Close();
00324
00325 unlink("tartest.tar.gz");
00326
00327 } catch( reuse::TarFile::TarError &te ) {
00328 cerr << te.what() << endl;
00329 return 1;
00330 }
00331 }
00332
00333 #endif
00334