]> git.tdb.fi Git - builder.git/blob - source/tar.cpp
Add tarball building
[builder.git] / source / tar.cpp
1 /* $Id$
2
3 This file is part of builder
4 Copyright © 2007 Mikko Rasa, Mikkosoft Productions
5 Distributed under the LGPL
6 */
7
8 #include <iostream>
9 #include <msp/path/utils.h>
10 #include "builder.h"
11 #include "package.h"
12 #include "tar.h"
13 #include "tarball.h"
14
15 using namespace std;
16 using namespace Msp;
17
18 Tar::Tar(Builder &b, const TarBall &t):
19         Action(b),
20         tarball(t),
21         worker(0)
22 {
23         string basename=tarball.get_name().substr(tarball.get_name().rfind('/')+1);
24         announce(tarball.get_package()->get_name(), "TAR ", basename);
25         if(builder.get_verbose()>=2)
26                 cout<<"Create "<<basename<<'\n';
27         
28         if(!builder.get_dry_run())
29                 worker=new Worker(*this);
30 }
31
32 Tar::~Tar()
33 {
34         delete worker;
35 }
36
37 int Tar::check()
38 {
39         if(!worker)  // True for dry run
40         {
41                 signal_done.emit();
42                 return 0;
43         }
44         
45         if(worker->get_done())
46         {
47                 signal_done.emit();
48                 worker->join();
49                 return worker->get_error()?1:0;
50         }
51         
52         return -1;
53 }
54
55
56 Tar::Worker::Worker(Tar &t):
57         tar(t),
58         done(false),
59         error(false)
60 {
61         launch();
62 }
63
64 void Tar::Worker::main()
65 {
66         const Path::Path &pkg_src=tar.tarball.get_package()->get_source();
67         Path::Path basedir=Path::splitext(Path::basename(tar.tarball.get_name())).base;
68
69         ofstream out(tar.tarball.get_name().c_str());
70         const TargetList &deps=tar.tarball.get_depends();
71         for(TargetList::const_iterator i=deps.begin(); i!=deps.end(); ++i)
72         {
73                 char buf[4096];
74                 memset(buf, 0, 512);
75
76                 string rel_path=(basedir/relative((*i)->get_name(), pkg_src)).str();
77                 if(rel_path.size()>99)
78                 {
79                         cout<<"Can't store "<<rel_path<<" in tar archive - too long name\n";
80                         error=true;
81                         break;
82                 }
83
84                 memcpy(buf, rel_path.data(), rel_path.size());
85
86                 struct stat st;
87                 Path::stat((*i)->get_name(), st);
88                 store_number(buf+100, st.st_mode, 7);
89                 store_number(buf+108, st.st_uid, 7);
90                 store_number(buf+116, st.st_gid, 7);
91                 store_number(buf+124, st.st_size, 11);
92                 store_number(buf+136, st.st_mtime, 11);
93                 buf[156]='0';
94
95                 memset(buf+148, ' ', 8);
96                 unsigned chk=0;
97                 for(unsigned j=0; j<512; ++j)
98                         chk+=static_cast<unsigned char>(buf[j]);
99                 store_number(buf+148, chk, 7);
100                 buf[155]=0;
101
102                 out.write(buf, 512);
103                 ifstream in((*i)->get_name().c_str());
104                 for(int j=0; j<st.st_size; j+=4096)
105                 {
106                         in.read(buf, 4096);
107                         unsigned len=in.gcount();
108                         len+=((~len)+1)&0777;
109                         out.write(buf, len);
110                 }
111         }
112
113         done=true;
114 }
115
116 void Tar::Worker::store_number(char *buf, unsigned value, unsigned length)
117 {
118         for(unsigned i=length; i--;)
119         {
120                 buf[i]='0'+value%8;
121                 value/=8;
122         }
123 }