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)
103 : 0 : ohshit(_("unable to parse timestamp '%.255s'"), value);
104 [ - + ]: 1 : else if (errno != 0)
105 : 0 : ohshite(_("unable to parse timestamp '%.255s'"), value);
106 : :
107 : 1 : return timestamp;
108 : : }
109 : :
110 : : /* Cleanup filename for use in crippled msdos systems. */
111 : : static char *
112 : 0 : clean_msdos_filename(char *filename)
113 : : {
114 : : char *d, *s;
115 : :
116 [ # # ]: 0 : for (s = d = filename; *s; d++, s++) {
117 [ # # ]: 0 : if (*s == '+')
118 : 0 : *d = 'x';
119 [ # # ]: 0 : else if (c_isupper(*s))
120 : 0 : *d = c_tolower(*s);
121 [ # # # # ]: 0 : else if (c_islower(*s) || c_isdigit(*s))
122 : 0 : *d = *s;
123 : : else
124 : 0 : s++;
125 : : }
126 : :
127 : 0 : return filename;
128 : : }
129 : :
130 : : static int
131 : 1 : mksplit(const char *file_src, const char *prefix, off_t maxpartsize,
132 : : bool msdos)
133 : : {
134 : : struct pkginfo *pkg;
135 : : struct dpkg_error err;
136 : : int fd_src;
137 : : struct stat st;
138 : : intmax_t timestamp;
139 : : const char *timestamp_str;
140 : : const char *version;
141 : : char hash[MD5HASHLEN + 1];
142 : : int nparts, curpart;
143 : : off_t partsize;
144 : : off_t cur_partsize, last_partsize;
145 : 1 : char *prefixdir = NULL, *msdos_prefix = NULL;
146 : 1 : struct varbuf file_dst = VARBUF_INIT;
147 : 1 : struct varbuf partmagic = VARBUF_INIT;
148 : 1 : struct varbuf partname = VARBUF_INIT;
149 : :
150 : 1 : fd_src = open(file_src, O_RDONLY);
151 [ - + ]: 1 : if (fd_src < 0)
152 : 0 : ohshite(_("unable to open source file '%.250s'"), file_src);
153 [ - + ]: 1 : if (fstat(fd_src, &st))
154 : 0 : ohshite(_("unable to fstat source file"));
155 [ - + ]: 1 : if (!S_ISREG(st.st_mode))
156 : 0 : ohshit(_("source file '%.250s' not a plain file"), file_src);
157 : :
158 [ - + ]: 1 : if (fd_md5(fd_src, hash, -1, &err) < 0)
159 : 0 : ohshit(_("cannot compute MD5 digest for file '%s': %s"),
160 : : file_src, err.str);
161 : 1 : lseek(fd_src, 0, SEEK_SET);
162 : :
163 : 1 : pkg = deb_parse_control(file_src);
164 : 1 : version = versiondescribe(&pkg->available.version, vdew_nonambig);
165 : :
166 : 1 : timestamp_str = getenv("SOURCE_DATE_EPOCH");
167 [ + - ]: 1 : if (str_is_set(timestamp_str))
168 : 1 : timestamp = parse_timestamp(timestamp_str);
169 : : else
170 : 0 : timestamp = time(NULL);
171 : :
172 : 1 : partsize = maxpartsize - HEADERALLOWANCE;
173 : 1 : last_partsize = st.st_size % partsize;
174 [ - + ]: 1 : if (last_partsize == 0)
175 : 0 : last_partsize = partsize;
176 : 1 : nparts = (st.st_size + partsize - 1) / partsize;
177 : :
178 : 1 : printf(P_("Splitting package %s into %d part: ",
179 : : "Splitting package %s into %d parts: ", nparts),
180 : 1 : pkg->set->name, nparts);
181 : :
182 [ - + ]: 1 : if (msdos) {
183 : : char *t;
184 : :
185 : 0 : t = m_strdup(prefix);
186 : 0 : prefixdir = m_strdup(dirname(t));
187 : 0 : free(t);
188 : :
189 : 0 : msdos_prefix = m_strdup(path_basename(prefix));
190 : 0 : prefix = clean_msdos_filename(msdos_prefix);
191 : : }
192 : :
193 [ + + ]: 11 : for (curpart = 1; curpart <= nparts; curpart++) {
194 : : struct dpkg_ar *ar;
195 : :
196 : 10 : varbuf_reset(&file_dst);
197 : : /* Generate output filename. */
198 [ - + ]: 10 : if (msdos) {
199 : : char *refname;
200 : : int prefix_max;
201 : :
202 : 0 : refname = str_fmt("%dof%d", curpart, nparts);
203 [ # # ]: 0 : prefix_max = max(8 - strlen(refname), 0);
204 : 0 : varbuf_printf(&file_dst, "%s/%.*s%.8s" DEBEXT,
205 : : prefixdir, prefix_max, prefix, refname);
206 : 0 : free(refname);
207 : : } else {
208 : 10 : varbuf_printf(&file_dst, "%s.%dof%d" DEBEXT,
209 : : prefix, curpart, nparts);
210 : : }
211 : :
212 [ + + ]: 10 : if (curpart == nparts)
213 : 1 : cur_partsize = last_partsize;
214 : : else
215 : 9 : cur_partsize = partsize;
216 : :
217 [ - + ]: 10 : if (cur_partsize > maxpartsize) {
218 : 0 : ohshit(_("header is too long, making part too long; "
219 : : "the package name or version\n"
220 : : "numbers must be extraordinarily long, "
221 : : "or something; giving up"));
222 : : }
223 : :
224 : : /* Split the data. */
225 : 10 : ar = dpkg_ar_create(file_dst.buf, 0644);
226 : 10 : dpkg_ar_set_mtime(ar, timestamp);
227 : :
228 : : /* Write the ar header. */
229 : 10 : dpkg_ar_put_magic(ar);
230 : :
231 : : /* Write the debian-split part. */
232 : 10 : varbuf_printf(&partmagic,
233 : : "%s\n%s\n%s\n%s\n%jd\n%jd\n%d/%d\n%s\n",
234 : 10 : SPLITVERSION, pkg->set->name, version, hash,
235 : 10 : (intmax_t)st.st_size, (intmax_t)partsize,
236 : 10 : curpart, nparts, pkg->available.arch->name);
237 : 10 : dpkg_ar_member_put_mem(ar, PARTMAGIC,
238 : 10 : partmagic.buf, partmagic.used);
239 : 10 : varbuf_reset(&partmagic);
240 : :
241 : : /* Write the data part. */
242 : 10 : varbuf_printf(&partname, "data.%d", curpart);
243 : 10 : dpkg_ar_member_put_file(ar, partname.buf,
244 : : fd_src, cur_partsize);
245 : 10 : varbuf_reset(&partname);
246 : :
247 : 10 : dpkg_ar_close(ar);
248 : :
249 : 10 : printf("%d ", curpart);
250 : : }
251 : :
252 : 1 : varbuf_destroy(&file_dst);
253 : 1 : varbuf_destroy(&partname);
254 : 1 : varbuf_destroy(&partmagic);
255 : :
256 : 1 : free(prefixdir);
257 : 1 : free(msdos_prefix);
258 : :
259 : 1 : close(fd_src);
260 : :
261 : 1 : printf(_("done\n"));
262 : :
263 : 1 : return 0;
264 : : }
265 : :
266 : : int
267 : 1 : do_split(const char *const *argv)
268 : : {
269 : : const char *sourcefile, *prefix;
270 : :
271 : 1 : sourcefile = *argv++;
272 [ - + ]: 1 : if (!sourcefile)
273 : 0 : badusage(_("--split needs a source filename argument"));
274 : 1 : prefix = *argv++;
275 [ + - - + ]: 1 : if (prefix && *argv)
276 : 0 : badusage(_("--split takes at most a source filename and destination prefix"));
277 [ - + ]: 1 : if (!prefix) {
278 : 0 : size_t sourcefile_len = strlen(sourcefile);
279 : :
280 [ # # ]: 0 : if (str_match_end(sourcefile, DEBEXT))
281 : 0 : sourcefile_len -= strlen(DEBEXT);
282 : :
283 : 0 : prefix = nfstrnsave(sourcefile, sourcefile_len);
284 : : }
285 : :
286 : 1 : mksplit(sourcefile, prefix, opt_maxpartsize, opt_msdos);
287 : :
288 : 1 : return 0;
289 : : }
|