Branch data Line data Source code
1 : : /*
2 : : * dpkg-split - splitting and joining of multipart *.deb archives
3 : : * split.c - splitting archives
4 : : *
5 : : * Copyright © 1995 Ian Jackson <ijackson@chiark.greenend.org.uk>
6 : : * Copyright © 2008-2015 Guillem Jover <guillem@debian.org>
7 : : *
8 : : * This is free software; you can redistribute it and/or modify
9 : : * it under the terms of the GNU General Public License as published by
10 : : * the Free Software Foundation; either version 2 of the License, or
11 : : * (at your option) any later version.
12 : : *
13 : : * This is distributed in the hope that it will be useful,
14 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 : : * GNU General Public License for more details.
17 : : *
18 : : * You should have received a copy of the GNU General Public License
19 : : * along with this program. If not, see <https://www.gnu.org/licenses/>.
20 : : */
21 : :
22 : : #include <config.h>
23 : : #include <compat.h>
24 : :
25 : : #include <sys/types.h>
26 : : #include <sys/stat.h>
27 : : #include <sys/wait.h>
28 : :
29 : : #include <errno.h>
30 : : #include <limits.h>
31 : : #include <inttypes.h>
32 : : #include <fcntl.h>
33 : : #include <libgen.h>
34 : : #include <string.h>
35 : : #include <time.h>
36 : : #include <unistd.h>
37 : : #include <stdint.h>
38 : : #include <stdlib.h>
39 : : #include <stdio.h>
40 : :
41 : : #include <dpkg/i18n.h>
42 : : #include <dpkg/c-ctype.h>
43 : : #include <dpkg/dpkg.h>
44 : : #include <dpkg/dpkg-db.h>
45 : : #include <dpkg/parsedump.h>
46 : : #include <dpkg/path.h>
47 : : #include <dpkg/string.h>
48 : : #include <dpkg/subproc.h>
49 : : #include <dpkg/buffer.h>
50 : : #include <dpkg/ar.h>
51 : : #include <dpkg/options.h>
52 : :
53 : : #include "dpkg-split.h"
54 : :
55 : : /**
56 : : * Parse the control file from a .deb package into a struct pkginfo.
57 : : */
58 : : static struct pkginfo *
59 : 1 : deb_parse_control(const char *filename)
60 : : {
61 : : struct parsedb_state *ps;
62 : : struct pkginfo *pkg;
63 : : pid_t pid;
64 : : int p[2];
65 : :
66 : 1 : m_pipe(p);
67 : :
68 : 1 : pid = subproc_fork();
69 [ + + ]: 2 : if (pid == 0) {
70 : : /* Child writes to pipe. */
71 : 1 : m_dup2(p[1], 1);
72 : 1 : close(p[0]);
73 : 1 : close(p[1]);
74 : :
75 : 1 : execlp(BACKEND, BACKEND, "--info", filename, "control", NULL);
76 : 1 : ohshite(_("unable to execute %s (%s)"),
77 : : _("package field value extraction"), BACKEND);
78 : : }
79 : 1 : close(p[1]);
80 : :
81 : : /* Parent reads from pipe. */
82 : 1 : ps = parsedb_new(_("<dpkg-deb --info pipe>"), p[0], pdb_parse_binary);
83 : 1 : parsedb_load(ps);
84 : 1 : parsedb_parse(ps, &pkg);
85 : 1 : parsedb_close(ps);
86 : :
87 : 1 : close(p[0]);
88 : :
89 : 1 : subproc_reap(pid, _("package field value extraction"), SUBPROC_NOPIPE);
90 : :
91 : 1 : return pkg;
92 : : }
93 : :
94 : : static intmax_t
95 : 1 : parse_timestamp(const char *value)
96 : : {
97 : : intmax_t timestamp;
98 : : char *end;
99 : :
100 : 1 : errno = 0;
101 : 1 : timestamp = strtoimax(value, &end, 10);
102 [ + - + - : 1 : if (value == end || *end || errno != 0)
- + ]
103 : 0 : ohshite(_("unable to parse timestamp '%.255s'"), value);
104 : :
105 : 1 : return timestamp;
106 : : }
107 : :
108 : : /* Cleanup filename for use in crippled msdos systems. */
109 : : static char *
110 : 0 : clean_msdos_filename(char *filename)
111 : : {
112 : : char *d, *s;
113 : :
114 [ # # ]: 0 : for (s = d = filename; *s; d++, s++) {
115 [ # # ]: 0 : if (*s == '+')
116 : 0 : *d = 'x';
117 [ # # ]: 0 : else if (c_isupper(*s))
118 : 0 : *d = c_tolower(*s);
119 [ # # # # ]: 0 : else if (c_islower(*s) || c_isdigit(*s))
120 : 0 : *d = *s;
121 : : else
122 : 0 : s++;
123 : : }
124 : :
125 : 0 : return filename;
126 : : }
127 : :
128 : : static int
129 : 1 : mksplit(const char *file_src, const char *prefix, off_t maxpartsize,
130 : : bool msdos)
131 : : {
132 : : struct pkginfo *pkg;
133 : : struct dpkg_error err;
134 : : int fd_src;
135 : : struct stat st;
136 : : intmax_t timestamp;
137 : : const char *timestamp_str;
138 : : const char *version;
139 : : char hash[MD5HASHLEN + 1];
140 : : int nparts, curpart;
141 : : off_t partsize;
142 : : off_t cur_partsize, last_partsize;
143 : 1 : char *prefixdir = NULL, *msdos_prefix = NULL;
144 : 1 : struct varbuf file_dst = VARBUF_INIT;
145 : 1 : struct varbuf partmagic = VARBUF_INIT;
146 : 1 : struct varbuf partname = VARBUF_INIT;
147 : :
148 : 1 : fd_src = open(file_src, O_RDONLY);
149 [ - + ]: 1 : if (fd_src < 0)
150 : 0 : ohshite(_("unable to open source file '%.250s'"), file_src);
151 [ - + ]: 1 : if (fstat(fd_src, &st))
152 : 0 : ohshite(_("unable to fstat source file"));
153 [ - + ]: 1 : if (!S_ISREG(st.st_mode))
154 : 0 : ohshit(_("source file '%.250s' not a plain file"), file_src);
155 : :
156 [ - + ]: 1 : if (fd_md5(fd_src, hash, -1, &err) < 0)
157 : 0 : ohshit(_("cannot compute MD5 digest for file '%s': %s"),
158 : : file_src, err.str);
159 : 1 : lseek(fd_src, 0, SEEK_SET);
160 : :
161 : 1 : pkg = deb_parse_control(file_src);
162 : 1 : version = versiondescribe(&pkg->available.version, vdew_nonambig);
163 : :
164 : 1 : timestamp_str = getenv("SOURCE_DATE_EPOCH");
165 [ + - ]: 1 : if (timestamp_str)
166 : 1 : timestamp = parse_timestamp(timestamp_str);
167 : : else
168 : 0 : timestamp = time(NULL);
169 : :
170 : 1 : partsize = maxpartsize - HEADERALLOWANCE;
171 : 1 : last_partsize = st.st_size % partsize;
172 [ - + ]: 1 : if (last_partsize == 0)
173 : 0 : last_partsize = partsize;
174 : 1 : nparts = (st.st_size + partsize - 1) / partsize;
175 : :
176 : 1 : printf(P_("Splitting package %s into %d part: ",
177 : : "Splitting package %s into %d parts: ", nparts),
178 : 1 : pkg->set->name, nparts);
179 : :
180 [ - + ]: 1 : if (msdos) {
181 : : char *t;
182 : :
183 : 0 : t = m_strdup(prefix);
184 : 0 : prefixdir = m_strdup(dirname(t));
185 : 0 : free(t);
186 : :
187 : 0 : msdos_prefix = m_strdup(path_basename(prefix));
188 : 0 : prefix = clean_msdos_filename(msdos_prefix);
189 : : }
190 : :
191 [ + + ]: 11 : for (curpart = 1; curpart <= nparts; curpart++) {
192 : : struct dpkg_ar *ar;
193 : :
194 : 10 : varbuf_reset(&file_dst);
195 : : /* Generate output filename. */
196 [ - + ]: 10 : if (msdos) {
197 : : char *refname;
198 : : int prefix_max;
199 : :
200 : 0 : refname = str_fmt("%dof%d", curpart, nparts);
201 [ # # ]: 0 : prefix_max = max(8 - strlen(refname), 0);
202 : 0 : varbuf_printf(&file_dst, "%s/%.*s%.8s.deb",
203 : : prefixdir, prefix_max, prefix, refname);
204 : 0 : free(refname);
205 : : } else {
206 : 10 : varbuf_printf(&file_dst, "%s.%dof%d.deb",
207 : : prefix, curpart, nparts);
208 : : }
209 : :
210 [ + + ]: 10 : if (curpart == nparts)
211 : 1 : cur_partsize = last_partsize;
212 : : else
213 : 9 : cur_partsize = partsize;
214 : :
215 [ - + ]: 10 : if (cur_partsize > maxpartsize) {
216 : 0 : ohshit(_("header is too long, making part too long; "
217 : : "the package name or version\n"
218 : : "numbers must be extraordinarily long, "
219 : : "or something; giving up"));
220 : : }
221 : :
222 : : /* Split the data. */
223 : 10 : ar = dpkg_ar_create(file_dst.buf, 0644);
224 : 10 : dpkg_ar_set_mtime(ar, timestamp);
225 : :
226 : : /* Write the ar header. */
227 : 10 : dpkg_ar_put_magic(ar);
228 : :
229 : : /* Write the debian-split part. */
230 : 10 : varbuf_printf(&partmagic,
231 : : "%s\n%s\n%s\n%s\n%jd\n%jd\n%d/%d\n%s\n",
232 : 10 : SPLITVERSION, pkg->set->name, version, hash,
233 : 10 : (intmax_t)st.st_size, (intmax_t)partsize,
234 : 10 : curpart, nparts, pkg->available.arch->name);
235 : 10 : dpkg_ar_member_put_mem(ar, PARTMAGIC,
236 : 10 : partmagic.buf, partmagic.used);
237 : 10 : varbuf_reset(&partmagic);
238 : :
239 : : /* Write the data part. */
240 : 10 : varbuf_printf(&partname, "data.%d", curpart);
241 : 10 : dpkg_ar_member_put_file(ar, partname.buf,
242 : : fd_src, cur_partsize);
243 : 10 : varbuf_reset(&partname);
244 : :
245 : 10 : dpkg_ar_close(ar);
246 : :
247 : 10 : printf("%d ", curpart);
248 : : }
249 : :
250 : 1 : varbuf_destroy(&file_dst);
251 : 1 : varbuf_destroy(&partname);
252 : 1 : varbuf_destroy(&partmagic);
253 : :
254 : 1 : free(prefixdir);
255 : 1 : free(msdos_prefix);
256 : :
257 : 1 : close(fd_src);
258 : :
259 : 1 : printf(_("done\n"));
260 : :
261 : 1 : return 0;
262 : : }
263 : :
264 : : int
265 : 1 : do_split(const char *const *argv)
266 : : {
267 : : const char *sourcefile, *prefix;
268 : :
269 : 1 : sourcefile = *argv++;
270 [ - + ]: 1 : if (!sourcefile)
271 : 0 : badusage(_("--split needs a source filename argument"));
272 : 1 : prefix = *argv++;
273 [ + - - + ]: 1 : if (prefix && *argv)
274 : 0 : badusage(_("--split takes at most a source filename and destination prefix"));
275 [ - + ]: 1 : if (!prefix) {
276 : 0 : size_t sourcefile_len = strlen(sourcefile);
277 : :
278 [ # # ]: 0 : if (str_match_end(sourcefile, DEBEXT))
279 : 0 : sourcefile_len -= strlen(DEBEXT);
280 : :
281 : 0 : prefix = nfstrnsave(sourcefile, sourcefile_len);
282 : : }
283 : :
284 : 1 : mksplit(sourcefile, prefix, opt_maxpartsize, opt_msdos);
285 : :
286 : 1 : return 0;
287 : : }
|