2 * dpkg-split - splitting and joining of multipart *.deb archives
3 * queue.c - queue management
5 * Copyright © 1995 Ian Jackson <ian@chiark.greenend.org.uk>
7 * This is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
22 * Queue, in /var/lib/dpkg/parts, is a plain directory with one
26 * <md5sum>.<maxpartlen>.<thispartn>.<maxpartn>
44 #include <dpkg/i18n.h>
45 #include <dpkg/dpkg.h>
46 #include <dpkg/dpkg-db.h>
47 #include <dpkg/myopt.h>
49 #include "dpkg-split.h"
51 static int decompose_filename(const char *filename
, struct partqueue
*pq
) {
55 if (strspn(filename
, "0123456789abcdef") != MD5HASHLEN
||
56 filename
[MD5HASHLEN
] != '.')
58 q
= nfmalloc(MD5HASHLEN
+ 1);
59 memcpy(q
, filename
, MD5HASHLEN
);
62 p
= filename
+ MD5HASHLEN
+ 1;
63 pq
->info
.maxpartlen
= strtol(p
,&q
,16); if (q
==p
|| *q
++ != '.') return 0;
64 p
=q
; pq
->info
.thispartn
= (int)strtol(p
,&q
,16); if (q
==p
|| *q
++ != '.') return 0;
65 p
=q
; pq
->info
.maxpartn
= (int)strtol(p
,&q
,16); if (q
==p
|| *q
) return 0;
69 void scandepot(void) {
76 depot
= opendir(depotdir
);
77 if (!depot
) ohshite(_("unable to read depot directory `%.250s'"),depotdir
);
78 while ((de
= readdir(depot
))) {
79 if (de
->d_name
[0] == '.') continue;
80 pq
= nfmalloc(sizeof(struct partqueue
));
81 pq
->info
.fmtversion
= pq
->info
.package
= pq
->info
.version
= NULL
;
82 pq
->info
.orglength
= pq
->info
.thispartoffset
= pq
->info
.thispartlen
= 0;
83 pq
->info
.headerlen
= 0;
84 p
= nfmalloc(strlen(depotdir
)+strlen(de
->d_name
)+1);
88 if (!decompose_filename(de
->d_name
,pq
)) {
89 pq
->info
.md5sum
= NULL
;
90 pq
->info
.maxpartlen
= pq
->info
.thispartn
= pq
->info
.maxpartn
= 0;
92 pq
->nextinqueue
= queue
;
98 static int partmatches(struct partinfo
*pi
, struct partinfo
*refi
) {
100 !strcmp(pi
->md5sum
,refi
->md5sum
) &&
101 pi
->maxpartn
== refi
->maxpartn
&&
102 pi
->maxpartlen
== refi
->maxpartlen
);
105 void do_auto(const char *const *argv
) {
106 const char *partfile
;
107 struct partinfo
*pi
, *refi
, *npi
, **partlist
, *otherthispart
;
108 struct partqueue
*pq
;
116 if (!outputfile
) badusage(_("--auto requires the use of the --output option"));
117 if (!(partfile
= *argv
++) || *argv
)
118 badusage(_("--auto requires exactly one part file argument"));
120 refi
= nfmalloc(sizeof(struct partqueue
));
121 part
= fopen(partfile
,"r");
122 if (!part
) ohshite(_("unable to read part file `%.250s'"),partfile
);
123 if (!read_info(part
,partfile
,refi
)) {
125 printf(_("File `%.250s' is not part of a multipart archive.\n"),partfile
);
126 m_output(stdout
, _("<standard output>"));
131 partlist
= nfmalloc(sizeof(struct partinfo
*)*refi
->maxpartn
);
132 for (i
= 0; i
< refi
->maxpartn
; i
++)
134 for (pq
= queue
; pq
; pq
= pq
->nextinqueue
) {
136 if (!partmatches(pi
,refi
)) continue;
137 npi
= nfmalloc(sizeof(struct partinfo
));
138 mustgetpartinfo(pi
->filename
,npi
);
139 addtopartlist(partlist
,npi
,refi
);
141 /* If we already have a copy of this version we ignore it and prefer the
142 * new one, but we still want to delete the one in the depot, so we
143 * save its partinfo (with the filename) for later. This also prevents
144 * us from accidentally deleting the source file.
146 otherthispart
= partlist
[refi
->thispartn
-1];
147 partlist
[refi
->thispartn
-1]= refi
;
148 for (j
=refi
->maxpartn
-1; j
>=0 && partlist
[j
]; j
--);
152 part
= fopen(partfile
,"r");
153 if (!part
) ohshite(_("unable to reopen part file `%.250s'"),partfile
);
154 buffer
= nfmalloc(refi
->filesize
);
155 nr
= fread(buffer
,1,refi
->filesize
,part
);
156 if (nr
!= refi
->filesize
) rerreof(part
,partfile
);
157 if (getc(part
) != EOF
) ohshit(_("part file `%.250s' has trailing garbage"),partfile
);
158 if (ferror(part
)) rerr(partfile
);
160 p
= nfmalloc(strlen(depotdir
)+50);
161 q
= nfmalloc(strlen(depotdir
)+200);
162 sprintf(p
,"%st.%lx",depotdir
,(long)getpid());
163 sprintf(q
,"%s%s.%lx.%x.%x",depotdir
,refi
->md5sum
,
164 refi
->maxpartlen
,refi
->thispartn
,refi
->maxpartn
);
166 if (!part
) ohshite(_("unable to open new depot file `%.250s'"),p
);
167 nr
= fwrite(buffer
,1,refi
->filesize
,part
);
168 if (nr
!= refi
->filesize
) werr(p
);
169 if (fclose(part
)) werr(p
);
170 if (rename(p
,q
)) ohshite(_("unable to rename new depot file `%.250s' to `%.250s'"),p
,q
);
172 printf(_("Part %d of package %s filed (still want "),refi
->thispartn
,refi
->package
);
173 /* There are still some parts missing. */
174 for (i
=0, ap
=0; i
<refi
->maxpartn
; i
++)
176 printf("%s%d", !ap
++ ? "" : i
== (unsigned int)j
? _(" and ") : ", ", i
+ 1);
181 /* We have all the parts. */
182 reassemble(partlist
,outputfile
);
184 /* OK, delete all the parts (except the new one, which we never copied). */
185 partlist
[refi
->thispartn
-1]= otherthispart
;
186 for (i
=0; i
<refi
->maxpartn
; i
++)
188 if (unlink(partlist
[i
]->filename
))
189 ohshite(_("unable to delete used-up depot file `%.250s'"),partlist
[i
]->filename
);
193 m_output(stderr
, _("<standard error>"));
196 void do_queue(const char *const *argv
) {
197 struct partqueue
*pq
, *qq
;
205 badusage(_("--%s takes no arguments"), cipaction
->olong
);
208 head
= N_("Junk files left around in the depot directory:\n");
209 for (pq
= queue
; pq
; pq
= pq
->nextinqueue
) {
210 if (pq
->info
.md5sum
) continue;
211 fputs(gettext(head
),stdout
); head
= "";
212 if (lstat(pq
->info
.filename
,&stab
))
213 ohshit(_("unable to stat `%.250s'"),pq
->info
.filename
);
214 if (S_ISREG(stab
.st_mode
)) {
216 printf(_(" %s (%lu bytes)\n"),pq
->info
.filename
,bytes
);
218 printf(_(" %s (not a plain file)\n"),pq
->info
.filename
);
221 if (!*head
) putchar('\n');
223 head
= N_("Packages not yet reassembled:\n");
224 for (pq
= queue
; pq
; pq
= pq
->nextinqueue
) {
225 if (!pq
->info
.md5sum
) continue;
226 mustgetpartinfo(pq
->info
.filename
,&ti
);
227 fputs(gettext(head
),stdout
); head
= "";
228 printf(_(" Package %s: part(s) "), ti
.package
);
230 for (i
=0; i
<ti
.maxpartn
; i
++) {
232 qq
&& !(partmatches(&qq
->info
,&ti
) && qq
->info
.thispartn
== i
+1);
233 qq
= qq
->nextinqueue
);
236 if (lstat(qq
->info
.filename
,&stab
))
237 ohshite(_("unable to stat `%.250s'"),qq
->info
.filename
);
238 if (!S_ISREG(stab
.st_mode
))
239 ohshit(_("part file `%.250s' is not a plain file"),qq
->info
.filename
);
240 bytes
+= stab
.st_size
;
241 qq
->info
.md5sum
= NULL
; /* don't find this package again */
244 printf(_("(total %lu bytes)\n"),bytes
);
246 m_output(stdout
, _("<standard output>"));
249 enum discardwhich
{ ds_junk
, ds_package
, ds_all
};
251 static void discardsome(enum discardwhich which
, const char *package
) {
252 struct partqueue
*pq
;
254 for (pq
= queue
; pq
; pq
= pq
->nextinqueue
) {
257 if (pq
->info
.md5sum
) continue;
260 if (!pq
->info
.md5sum
|| strcasecmp(pq
->info
.package
,package
)) continue;
265 internerr("unknown discardwhich '%d'", which
);
267 if (unlink(pq
->info
.filename
))
268 ohshite(_("unable to discard `%.250s'"),pq
->info
.filename
);
269 printf(_("Deleted %s.\n"),pq
->info
.filename
);
273 void do_discard(const char *const *argv
) {
275 struct partqueue
*pq
;
279 for (pq
= queue
; pq
; pq
= pq
->nextinqueue
)
281 mustgetpartinfo(pq
->info
.filename
,&pq
->info
);
282 discardsome(ds_junk
,NULL
);
283 while ((thisarg
= *argv
++)) discardsome(ds_package
,thisarg
);
285 discardsome(ds_all
,NULL
);