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