1 //
2 // aegis - project change supervisor
3 // Copyright (C) 2002-2006, 2008, 2011, 2012 Peter Miller
4 //
5 // This program is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation; either version 3 of the License, or (at
8 // your option) any later version.
9 //
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 // General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with this program. If not, see <http://www.gnu.org/licenses/>.
17 //
18 
19 #include <common/ac/assert.h>
20 #include <common/ac/string.h>
21 
22 #include <common/now.h>
23 #include <common/trace.h>
24 #include <libaegis/sub.h>
25 
26 #include <aetar/header.h>
27 #include <aetar/output/tar_child.h>
28 
29 
~output_tar_child()30 output_tar_child::~output_tar_child()
31 {
32     trace(("output_tar_child::~output_tar_child(this = %08lX)\n{\n",
33         (long)this));
34     //
35     // Make sure all buffered data has been passed to our write_inner
36     // method.
37     //
38     flush();
39 
40     //
41     // It is a bug if the size changed.
42     //
43     if (pos != length)
44     {
45         changed_size();
46     }
47 
48     //
49     // Pad the data so that we are a multiple of 512 bytes.
50     //
51     padding();
52 
53     //
54     // DO NOT delete deeper;
55     // this is output_tar::destructor's job.
56     //
57     trace(("}\n"));
58 }
59 
60 
output_tar_child(const output::pointer & arg1,const nstring & arg2,long arg3,bool arg4)61 output_tar_child::output_tar_child(const output::pointer &arg1,
62         const nstring &arg2, long arg3, bool arg4) :
63     deeper(arg1),
64     name(arg2),
65     length(arg3),
66     executable(arg4),
67     pos(0),
68     bol(true)
69 {
70     trace(("output_tar_child::output_tar_child(this = %08lX)\n{\n",
71         (long)this));
72     // assert(length >= 0);
73     trace(("deeper pos = %ld\n", deeper->ftell()));
74     header();
75     trace(("}\n"));
76 }
77 
78 output::pointer
create(const output::pointer & a_deeper,const nstring & a_name,long a_length,bool a_exec)79 output_tar_child::create(const output::pointer &a_deeper, const nstring &a_name,
80     long a_length, bool a_exec)
81 {
82     return pointer(new output_tar_child(a_deeper, a_name, a_length, a_exec));
83 }
84 
85 
86 void
changed_size(void)87 output_tar_child::changed_size(void)
88 {
89     sub_context_ty sc;
90     sc.var_set_format
91     (
92         "File_Name",
93         "%s(%s)",
94         deeper->filename().c_str(),
95         name.c_str()
96     );
97     sc.fatal_intl(i18n("archive member $filename changed size"));
98 }
99 
100 
101 void
padding(void)102 output_tar_child::padding(void)
103 {
104     trace(("output_tar_child::padding(this = %08lX)\n{\n", (long)this));
105     int n = deeper->ftell();
106     trace(("n = %d\n", n));
107     for (;;)
108     {
109         if ((n & (TBLOCK - 1)) == 0)
110         {
111             trace(("deeper pos = %ld\n", deeper->ftell()));
112             trace(("}\n"));
113             return;
114         }
115         deeper->fputc('\n');
116         ++n;
117     }
118 }
119 
120 
121 void
header(void)122 output_tar_child::header(void)
123 {
124     trace(("output_tar_child::header(this = %08lX)\n{\n", (long)this));
125     char tblock[TBLOCK];
126     header_ty *hp = (header_ty *)tblock;
127     nstring root("root");
128 
129     //
130     // Long names get special treatment.
131     //
132     if (name.length() >= sizeof(hp->name))
133     {
134         memset(tblock, 0, sizeof(tblock));
135         strendcpy(hp->name, "././@LongLink", hp->name + sizeof(hp->name));
136         header_size_set(hp, name.length() + 1);
137         header_mode_set(hp, 0);
138         header_uid_set(hp, 0);
139         header_uname_set(hp, root);
140         header_gid_set(hp, 0);
141         header_gname_set(hp, root);
142         header_mtime_set(hp, 0);
143         header_linkflag_set(hp, LF_LONGNAME);
144         header_checksum_set(hp, header_checksum_calculate(hp));
145         deeper->write(tblock, TBLOCK);
146 
147         //
148         // This write, and the length in the header, include the
149         // terminating NUL on the end of the file name.
150         //
151         deeper->write(name.c_str(), name.length() + 1);
152         trace(("deeper pos = %ld\n", deeper->ftell()));
153         padding();
154     }
155 
156     memset(tblock, 0, sizeof(tblock));
157     header_name_set(hp, name);
158     header_size_set(hp, length);
159     header_mode_set(hp, 0100644 | (executable ? 0111 : 0));
160     header_uid_set(hp, 0);
161     header_uname_set(hp, root);
162     header_gid_set(hp, 0);
163     header_gname_set(hp, root);
164     header_mtime_set(hp, now());
165     header_linkflag_set(hp, LF_NORMAL);
166     header_checksum_set(hp, header_checksum_calculate(hp));
167     deeper->write(tblock, TBLOCK);
168     trace(("deeper pos = %ld\n", deeper->ftell()));
169     trace(("}\n"));
170 }
171 
172 
173 nstring
filename(void) const174 output_tar_child::filename(void)
175     const
176 {
177     return deeper->filename();
178 }
179 
180 
181 long
ftell_inner(void) const182 output_tar_child::ftell_inner(void)
183     const
184 {
185     return pos;
186 }
187 
188 
189 void
write_inner(const void * data,size_t len)190 output_tar_child::write_inner(const void *data, size_t len)
191 {
192     trace(("output_tar_child::write_inner(this = %08lX, data = %08lX, "
193         "len = %ld)\n{\n", (long)this, (long)data, (long)len));
194     deeper->write(data, len);
195     pos += len;
196     if (len > 0)
197         bol = (((const char *)data)[len - 1] == '\n');
198     trace(("deeper pos = %ld\n", deeper->ftell()));
199     trace(("}\n"));
200 }
201 
202 
203 void
end_of_line_inner(void)204 output_tar_child::end_of_line_inner(void)
205 {
206     trace(("output_tar_child::end_of_line_inner(this = %08lX)\n{\n",
207         (long)this));
208     if (!bol)
209         fputc('\n');
210     trace(("deeper pos = %ld\n", deeper->ftell()));
211     trace(("}\n"));
212 }
213 
214 
215 nstring
type_name(void) const216 output_tar_child::type_name(void)
217     const
218 {
219     return ("tar child > " + deeper->type_name());
220 }
221 
222 
223 // vim: set ts=8 sw=4 et :
224