split merge test into two tests
[dpkg/seanius.git] / dpkg-split / queue.c
blobed114e61e73fdd19c3d3a025fe06eabfe15500c9
1 /*
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
23 * file per part.
25 * parts are named
26 * <md5sum>.<maxpartlen>.<thispartn>.<maxpartn>
27 * all numbers in hex
30 #include <config.h>
31 #include <compat.h>
33 #include <sys/stat.h>
35 #include <assert.h>
36 #include <limits.h>
37 #include <string.h>
38 #include <fcntl.h>
39 #include <dirent.h>
40 #include <unistd.h>
41 #include <stdlib.h>
42 #include <stdio.h>
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) {
52 const char *p;
53 char *q;
55 if (strspn(filename, "0123456789abcdef") != MD5HASHLEN ||
56 filename[MD5HASHLEN] != '.')
57 return 0;
58 q = nfmalloc(MD5HASHLEN + 1);
59 memcpy(q, filename, MD5HASHLEN);
60 q[MD5HASHLEN] = '\0';
61 pq->info.md5sum= q;
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;
66 return 1;
69 void scandepot(void) {
70 DIR *depot;
71 struct dirent *de;
72 struct partqueue *pq;
73 char *p;
75 assert(!queue);
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);
85 strcpy(p,depotdir);
86 strcat(p,de->d_name);
87 pq->info.filename= p;
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;
93 queue= pq;
95 closedir(depot);
98 static int partmatches(struct partinfo *pi, struct partinfo *refi) {
99 return (pi->md5sum &&
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;
109 unsigned int i;
110 int j, ap;
111 long nr;
112 FILE *part;
113 void *buffer;
114 char *p, *q;
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)) {
124 if (!npquiet)
125 printf(_("File `%.250s' is not part of a multipart archive.\n"),partfile);
126 m_output(stdout, _("<standard output>"));
127 exit(1);
129 fclose(part);
130 scandepot();
131 partlist= nfmalloc(sizeof(struct partinfo*)*refi->maxpartn);
132 for (i = 0; i < refi->maxpartn; i++)
133 partlist[i] = NULL;
134 for (pq= queue; pq; pq= pq->nextinqueue) {
135 pi= &pq->info;
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--);
150 if (j>=0) {
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);
159 fclose(part);
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);
165 part= fopen(p,"w");
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++)
175 if (!partlist[i])
176 printf("%s%d", !ap++ ? "" : i == (unsigned int)j ? _(" and ") : ", ", i + 1);
177 printf(").\n");
179 } else {
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++)
187 if (partlist[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;
198 struct partinfo ti;
199 const char *head;
200 struct stat stab;
201 unsigned long bytes;
202 unsigned int i;
204 if (*argv)
205 badusage(_("--%s takes no arguments"), cipaction->olong);
206 scandepot();
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)) {
215 bytes= stab.st_size;
216 printf(_(" %s (%lu bytes)\n"),pq->info.filename,bytes);
217 } else {
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);
229 bytes= 0;
230 for (i=0; i<ti.maxpartn; i++) {
231 for (qq= pq;
232 qq && !(partmatches(&qq->info,&ti) && qq->info.thispartn == i+1);
233 qq= qq->nextinqueue);
234 if (qq) {
235 printf("%d ",i+1);
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) {
255 switch (which) {
256 case ds_junk:
257 if (pq->info.md5sum) continue;
258 break;
259 case ds_package:
260 if (!pq->info.md5sum || strcasecmp(pq->info.package,package)) continue;
261 break;
262 case ds_all:
263 break;
264 default:
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) {
274 const char *thisarg;
275 struct partqueue *pq;
277 scandepot();
278 if (*argv) {
279 for (pq= queue; pq; pq= pq->nextinqueue)
280 if (pq->info.md5sum)
281 mustgetpartinfo(pq->info.filename,&pq->info);
282 discardsome(ds_junk,NULL);
283 while ((thisarg= *argv++)) discardsome(ds_package,thisarg);
284 } else {
285 discardsome(ds_all,NULL);