dpkg (1.18.25) stretch; urgency=medium
[dpkg] / dpkg-split / split.c
CommitLineData
1479465f
GJ
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 <fcntl.h>
32#include <libgen.h>
33#include <string.h>
34#include <time.h>
35#include <unistd.h>
36#include <stdint.h>
37#include <stdlib.h>
38#include <stdio.h>
39
40#include <dpkg/i18n.h>
41#include <dpkg/c-ctype.h>
42#include <dpkg/dpkg.h>
43#include <dpkg/dpkg-db.h>
44#include <dpkg/parsedump.h>
45#include <dpkg/path.h>
46#include <dpkg/string.h>
47#include <dpkg/subproc.h>
48#include <dpkg/buffer.h>
49#include <dpkg/ar.h>
50#include <dpkg/options.h>
51
52#include "dpkg-split.h"
53
54/**
55 * Parse the control file from a .deb package into a struct pkginfo.
56 */
57static struct pkginfo *
58deb_parse_control(const char *filename)
59{
60 struct parsedb_state *ps;
61 struct pkginfo *pkg;
62 pid_t pid;
63 int p[2];
64
65 m_pipe(p);
66
67 pid = subproc_fork();
68 if (pid == 0) {
69 /* Child writes to pipe. */
70 m_dup2(p[1], 1);
71 close(p[0]);
72 close(p[1]);
73
74 execlp(BACKEND, BACKEND, "--info", filename, "control", NULL);
75 ohshite(_("unable to execute %s (%s)"),
76 _("package field value extraction"), BACKEND);
77 }
78 close(p[1]);
79
80 /* Parent reads from pipe. */
81 ps = parsedb_new(_("<dpkg-deb --info pipe>"), p[0], pdb_parse_binary);
82 parsedb_load(ps);
83 parsedb_parse(ps, &pkg);
84 parsedb_close(ps);
85
86 close(p[0]);
87
88 subproc_reap(pid, _("package field value extraction"), SUBPROC_NOPIPE);
89
90 return pkg;
91}
92
93static time_t
94parse_timestamp(const char *value)
95{
96 time_t timestamp;
97 char *end;
98
99 errno = 0;
100 timestamp = strtol(value, &end, 10);
101 if (value == end || *end || errno != 0)
102 ohshite(_("unable to parse timestamp '%.255s'"), value);
103
104 return timestamp;
105}
106
107/* Cleanup filename for use in crippled msdos systems. */
108static char *
109clean_msdos_filename(char *filename)
110{
111 char *d, *s;
112
113 for (s = d = filename; *s; d++, s++) {
114 if (*s == '+')
115 *d = 'x';
116 else if (c_isupper(*s))
117 *d = c_tolower(*s);
118 else if (c_islower(*s) || c_isdigit(*s))
119 *d = *s;
120 else
121 s++;
122 }
123
124 return filename;
125}
126
127static int
128mksplit(const char *file_src, const char *prefix, off_t maxpartsize,
129 bool msdos)
130{
131 struct pkginfo *pkg;
132 struct dpkg_error err;
133 int fd_src;
134 struct stat st;
135 time_t timestamp;
136 const char *timestamp_str;
137 const char *version;
138 char hash[MD5HASHLEN + 1];
139 int nparts, curpart;
140 off_t partsize;
141 off_t cur_partsize, last_partsize;
142 char *prefixdir = NULL, *msdos_prefix = NULL;
143 struct varbuf file_dst = VARBUF_INIT;
144 struct varbuf partmagic = VARBUF_INIT;
145 struct varbuf partname = VARBUF_INIT;
146
147 fd_src = open(file_src, O_RDONLY);
148 if (fd_src < 0)
149 ohshite(_("unable to open source file '%.250s'"), file_src);
150 if (fstat(fd_src, &st))
151 ohshite(_("unable to fstat source file"));
152 if (!S_ISREG(st.st_mode))
153 ohshit(_("source file '%.250s' not a plain file"), file_src);
154
155 if (fd_md5(fd_src, hash, -1, &err) < 0)
156 ohshit(_("cannot compute MD5 hash for file '%s': %s"),
157 file_src, err.str);
158 lseek(fd_src, 0, SEEK_SET);
159
160 pkg = deb_parse_control(file_src);
161 version = versiondescribe(&pkg->available.version, vdew_nonambig);
162
163 timestamp_str = getenv("SOURCE_DATE_EPOCH");
164 if (timestamp_str)
165 timestamp = parse_timestamp(timestamp_str);
166 else
167 timestamp = time(NULL);
168
169 partsize = maxpartsize - HEADERALLOWANCE;
170 last_partsize = st.st_size % partsize;
171 if (last_partsize == 0)
172 last_partsize = partsize;
173 nparts = (st.st_size + partsize - 1) / partsize;
174
175 printf(P_("Splitting package %s into %d part: ",
176 "Splitting package %s into %d parts: ", nparts),
177 pkg->set->name, nparts);
178
179 if (msdos) {
180 char *t;
181
182 t = m_strdup(prefix);
183 prefixdir = m_strdup(dirname(t));
184 free(t);
185
186 msdos_prefix = m_strdup(path_basename(prefix));
187 prefix = clean_msdos_filename(msdos_prefix);
188 }
189
190 for (curpart = 1; curpart <= nparts; curpart++) {
191 struct dpkg_ar *ar;
192
193 varbuf_reset(&file_dst);
194 /* Generate output filename. */
195 if (msdos) {
196 char *refname;
197 int prefix_max;
198
199 refname = str_fmt("%dof%d", curpart, nparts);
200 prefix_max = max(8 - strlen(refname), 0);
201 varbuf_printf(&file_dst, "%s/%.*s%.8s.deb",
202 prefixdir, prefix_max, prefix, refname);
203 free(refname);
204 } else {
205 varbuf_printf(&file_dst, "%s.%dof%d.deb",
206 prefix, curpart, nparts);
207 }
208
209 if (curpart == nparts)
210 cur_partsize = last_partsize;
211 else
212 cur_partsize = partsize;
213
214 if (cur_partsize > maxpartsize) {
215 ohshit(_("header is too long, making part too long; "
216 "the package name or version\n"
217 "numbers must be extraordinarily long, "
218 "or something; giving up"));
219 }
220
221 /* Split the data. */
222 ar = dpkg_ar_create(file_dst.buf, 0644);
223 dpkg_ar_set_mtime(ar, timestamp);
224
225 /* Write the ar header. */
226 dpkg_ar_put_magic(ar);
227
228 /* Write the debian-split part. */
229 varbuf_printf(&partmagic,
230 "%s\n%s\n%s\n%s\n%jd\n%jd\n%d/%d\n%s\n",
231 SPLITVERSION, pkg->set->name, version, hash,
232 (intmax_t)st.st_size, (intmax_t)partsize,
233 curpart, nparts, pkg->available.arch->name);
234 dpkg_ar_member_put_mem(ar, PARTMAGIC,
235 partmagic.buf, partmagic.used);
236 varbuf_reset(&partmagic);
237
238 /* Write the data part. */
239 varbuf_printf(&partname, "data.%d", curpart);
240 dpkg_ar_member_put_file(ar, partname.buf,
241 fd_src, cur_partsize);
242 varbuf_reset(&partname);
243
244 dpkg_ar_close(ar);
245
246 printf("%d ", curpart);
247 }
248
249 varbuf_destroy(&file_dst);
250 varbuf_destroy(&partname);
251 varbuf_destroy(&partmagic);
252
253 free(prefixdir);
254 free(msdos_prefix);
255
256 close(fd_src);
257
258 printf(_("done\n"));
259
260 return 0;
261}
262
263int
264do_split(const char *const *argv)
265{
266 const char *sourcefile, *prefix;
267
268 sourcefile = *argv++;
269 if (!sourcefile)
270 badusage(_("--split needs a source filename argument"));
271 prefix = *argv++;
272 if (prefix && *argv)
273 badusage(_("--split takes at most a source filename and destination prefix"));
274 if (!prefix) {
275 size_t sourcefile_len = strlen(sourcefile);
276
277 if (str_match_end(sourcefile, DEBEXT))
278 sourcefile_len -= strlen(DEBEXT);
279
280 prefix = nfstrnsave(sourcefile, sourcefile_len);
281 }
282
283 mksplit(sourcefile, prefix, opt_maxpartsize, opt_msdos);
284
285 return 0;
286}