chiark / gitweb /
dpkg (1.18.25) stretch; urgency=medium
[dpkg] / dpkg-split / split.c
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  */
57 static struct pkginfo *
58 deb_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
93 static time_t
94 parse_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. */
108 static char *
109 clean_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
127 static int
128 mksplit(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
263 int
264 do_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 }