2 * dpkg-split - splitting and joining of multipart *.deb archives
3 * queue.c - queue management
5 * Copyright © 1995 Ian Jackson <ijackson@chiark.greenend.org.uk>
6 * Copyright © 2008-2014 Guillem Jover <guillem@debian.org>
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.
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.
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/>.
38 #include <dpkg/i18n.h>
39 #include <dpkg/dpkg.h>
40 #include <dpkg/dpkg-db.h>
42 #include <dpkg/buffer.h>
43 #include <dpkg/options.h>
45 #include "dpkg-split.h"
48 * The queue, by default located in /var/lib/dpkg/parts/, is a plain
49 * directory with one file per part.
51 * Each part is named “<md5sum>.<maxpartlen>.<thispartn>.<maxpartn>”,
52 * with all numbers in hex.
57 decompose_filename(const char *filename
, struct partqueue
*pq
)
62 if (strspn(filename
, "0123456789abcdef") != MD5HASHLEN
||
63 filename
[MD5HASHLEN
] != '.')
65 q
= nfmalloc(MD5HASHLEN
+ 1);
66 memcpy(q
, filename
, MD5HASHLEN
);
69 p
= filename
+ MD5HASHLEN
+ 1;
71 pq
->info
.maxpartlen
= strtoimax(p
, &q
, 16);
72 if (q
== p
|| *q
++ != '.' || errno
!= 0)
75 pq
->info
.thispartn
= (int)strtol(p
, &q
, 16);
76 if (q
== p
|| *q
++ != '.' || errno
!= 0)
79 pq
->info
.maxpartn
= (int)strtol(p
, &q
, 16);
80 if (q
== p
|| *q
|| errno
!= 0)
85 static struct partqueue
*
90 struct partqueue
*queue
= NULL
;
92 depot
= opendir(opt_depotdir
);
94 ohshite(_("unable to read depot directory '%.250s'"), opt_depotdir
);
95 while ((de
= readdir(depot
))) {
99 if (de
->d_name
[0] == '.') continue;
100 pq
= nfmalloc(sizeof(struct partqueue
));
101 pq
->info
.fmtversion
.major
= 0;
102 pq
->info
.fmtversion
.minor
= 0;
103 pq
->info
.package
= NULL
;
104 pq
->info
.version
= NULL
;
105 pq
->info
.arch
= NULL
;
106 pq
->info
.orglength
= pq
->info
.thispartoffset
= pq
->info
.thispartlen
= 0;
107 pq
->info
.headerlen
= 0;
108 p
= nfmalloc(strlen(opt_depotdir
) + 1 + strlen(de
->d_name
) + 1);
109 sprintf(p
, "%s/%s", opt_depotdir
, de
->d_name
);
110 pq
->info
.filename
= p
;
111 if (!decompose_filename(de
->d_name
,pq
)) {
112 pq
->info
.md5sum
= NULL
;
113 pq
->info
.maxpartlen
= pq
->info
.thispartn
= pq
->info
.maxpartn
= 0;
115 pq
->nextinqueue
= queue
;
124 partmatches(struct partinfo
*pi
, struct partinfo
*refi
)
126 return (pi
->md5sum
&&
127 strcmp(pi
->md5sum
, refi
->md5sum
) == 0 &&
128 pi
->maxpartn
== refi
->maxpartn
&&
129 pi
->maxpartlen
== refi
->maxpartlen
);
133 do_auto(const char *const *argv
)
135 const char *partfile
;
136 struct partinfo
*refi
, **partlist
, *otherthispart
;
137 struct partqueue
*queue
;
138 struct partqueue
*pq
;
139 struct dpkg_ar
*part
;
144 badusage(_("--auto requires the use of the --output option"));
146 if (partfile
== NULL
|| *argv
)
147 badusage(_("--auto requires exactly one part file argument"));
149 refi
= nfmalloc(sizeof(struct partqueue
));
150 part
= dpkg_ar_open(partfile
);
152 ohshite(_("unable to read part file '%.250s'"), partfile
);
153 if (!read_info(part
, refi
)) {
155 printf(_("File '%.250s' is not part of a multipart archive.\n"), partfile
);
156 m_output(stdout
, _("<standard output>"));
162 partlist
= nfmalloc(sizeof(struct partinfo
*)*refi
->maxpartn
);
163 for (i
= 0; i
< refi
->maxpartn
; i
++)
165 for (pq
= queue
; pq
; pq
= pq
->nextinqueue
) {
166 struct partinfo
*npi
, *pi
= &pq
->info
;
168 if (!partmatches(pi
,refi
)) continue;
169 npi
= nfmalloc(sizeof(struct partinfo
));
170 mustgetpartinfo(pi
->filename
,npi
);
171 addtopartlist(partlist
,npi
,refi
);
173 /* If we already have a copy of this version we ignore it and prefer the
174 * new one, but we still want to delete the one in the depot, so we
175 * save its partinfo (with the filename) for later. This also prevents
176 * us from accidentally deleting the source file. */
177 otherthispart
= partlist
[refi
->thispartn
-1];
178 partlist
[refi
->thispartn
-1]= refi
;
179 for (j
=refi
->maxpartn
-1; j
>=0 && partlist
[j
]; j
--);
182 struct dpkg_error err
;
187 p
= str_fmt("%s/t.%lx", opt_depotdir
, (long)getpid());
188 q
= str_fmt("%s/%s.%jx.%x.%x", opt_depotdir
, refi
->md5sum
,
189 (intmax_t)refi
->maxpartlen
, refi
->thispartn
, refi
->maxpartn
);
191 fd_src
= open(partfile
, O_RDONLY
);
193 ohshite(_("unable to reopen part file '%.250s'"), partfile
);
194 fd_dst
= creat(p
, 0644);
196 ohshite(_("unable to open new depot file '%.250s'"), p
);
198 if (fd_fd_copy(fd_src
, fd_dst
, refi
->filesize
, &err
) < 0)
199 ohshit(_("cannot extract split package part '%s': %s"),
203 ohshite(_("unable to sync file '%s'"), p
);
205 ohshite(_("unable to close file '%s'"), p
);
209 ohshite(_("unable to rename new depot file '%.250s' to '%.250s'"), p
, q
);
213 printf(_("Part %d of package %s filed (still want "),refi
->thispartn
,refi
->package
);
214 /* There are still some parts missing. */
215 for (i
=0, ap
=0; i
<refi
->maxpartn
; i
++)
217 printf("%s%d", !ap
++ ?
"" : i
== (unsigned int)j ?
_(" and ") : ", ", i
+ 1);
220 dir_sync_path(opt_depotdir
);
223 /* We have all the parts. */
224 reassemble(partlist
, opt_outputfile
);
226 /* OK, delete all the parts (except the new one, which we never copied). */
227 partlist
[refi
->thispartn
-1]= otherthispart
;
228 for (i
=0; i
<refi
->maxpartn
; i
++)
230 if (unlink(partlist
[i
]->filename
))
231 ohshite(_("unable to delete used-up depot file '%.250s'"),
232 partlist
[i
]->filename
);
236 m_output(stderr
, _("<standard error>"));
242 do_queue(const char *const *argv
)
244 struct partqueue
*queue
;
245 struct partqueue
*pq
;
251 badusage(_("--%s takes no arguments"), cipaction
->olong
);
255 head
= N_("Junk files left around in the depot directory:\n");
256 for (pq
= queue
; pq
; pq
= pq
->nextinqueue
) {
257 if (pq
->info
.md5sum
) continue;
258 fputs(gettext(head
),stdout
); head
= "";
259 if (lstat(pq
->info
.filename
,&stab
))
260 ohshit(_("unable to stat '%.250s'"), pq
->info
.filename
);
261 if (S_ISREG(stab
.st_mode
)) {
263 printf(_(" %s (%jd bytes)\n"), pq
->info
.filename
, (intmax_t)bytes
);
265 printf(_(" %s (not a plain file)\n"),pq
->info
.filename
);
268 if (!*head
) putchar('\n');
270 head
= N_("Packages not yet reassembled:\n");
271 for (pq
= queue
; pq
; pq
= pq
->nextinqueue
) {
275 if (!pq
->info
.md5sum
) continue;
276 mustgetpartinfo(pq
->info
.filename
,&ti
);
277 fputs(gettext(head
),stdout
); head
= "";
278 printf(_(" Package %s: part(s) "), ti
.package
);
280 for (i
=0; i
<ti
.maxpartn
; i
++) {
281 struct partqueue
*qq
;
284 qq
&& !(partmatches(&qq
->info
,&ti
) && qq
->info
.thispartn
== i
+1);
285 qq
= qq
->nextinqueue
);
288 if (lstat(qq
->info
.filename
,&stab
))
289 ohshite(_("unable to stat '%.250s'"), qq
->info
.filename
);
290 if (!S_ISREG(stab
.st_mode
))
291 ohshit(_("part file '%.250s' is not a plain file"), qq
->info
.filename
);
292 bytes
+= stab
.st_size
;
294 /* Don't find this package again. */
295 qq
->info
.md5sum
= NULL
;
298 printf(_("(total %jd bytes)\n"), (intmax_t)bytes
);
300 m_output(stdout
, _("<standard output>"));
307 DISCARD_PART_PACKAGE
,
312 discard_parts(struct partqueue
*queue
, enum discard_which which
,
315 struct partqueue
*pq
;
317 for (pq
= queue
; pq
; pq
= pq
->nextinqueue
) {
319 case DISCARD_PART_JUNK
:
320 if (pq
->info
.md5sum
) continue;
322 case DISCARD_PART_PACKAGE
:
323 if (!pq
->info
.md5sum
|| strcasecmp(pq
->info
.package
,package
)) continue;
325 case DISCARD_PART_ALL
:
328 internerr("unknown discard_which '%d'", which
);
330 if (unlink(pq
->info
.filename
))
331 ohshite(_("unable to discard '%.250s'"), pq
->info
.filename
);
332 printf(_("Deleted %s.\n"),pq
->info
.filename
);
337 do_discard(const char *const *argv
)
340 struct partqueue
*queue
;
341 struct partqueue
*pq
;
345 for (pq
= queue
; pq
; pq
= pq
->nextinqueue
)
347 mustgetpartinfo(pq
->info
.filename
,&pq
->info
);
348 discard_parts(queue
, DISCARD_PART_JUNK
, NULL
);
349 while ((thisarg
= *argv
++))
350 discard_parts(queue
, DISCARD_PART_PACKAGE
, thisarg
);
352 discard_parts(queue
, DISCARD_PART_ALL
, NULL
);