]> git.saurik.com Git - apt.git/blame - apt-pkg/cdrom.cc
* remove all the remaining #pragma implementation
[apt.git] / apt-pkg / cdrom.cc
CommitLineData
a75c6a6e
MZ
1/*
2 */
3
a75c6a6e
MZ
4#include<apt-pkg/init.h>
5#include<apt-pkg/error.h>
6#include<apt-pkg/cdromutl.h>
7#include<apt-pkg/strutl.h>
8#include<apt-pkg/cdrom.h>
9#include<sstream>
10#include<fstream>
11#include<config.h>
12#include<apti18n.h>
13#include <sys/stat.h>
14#include <fcntl.h>
15#include <dirent.h>
16#include <unistd.h>
17#include <stdio.h>
18
19
20#include "indexcopy.h"
21
22using namespace std;
23
24// FindPackages - Find the package files on the CDROM /*{{{*/
25// ---------------------------------------------------------------------
26/* We look over the cdrom for package files. This is a recursive
27 search that short circuits when it his a package file in the dir.
28 This speeds it up greatly as the majority of the size is in the
29 binary-* sub dirs. */
30bool pkgCdrom::FindPackages(string CD,vector<string> &List,
31 vector<string> &SList, vector<string> &SigList,
32 string &InfoDir, pkgCdromStatus *log,
33 unsigned int Depth)
34{
35 static ino_t Inodes[9];
36
37 // if we have a look we "pulse" now
38 if(log)
39 log->Update();
40
41 if (Depth >= 7)
42 return true;
43
44 if (CD[CD.length()-1] != '/')
45 CD += '/';
46
47 if (chdir(CD.c_str()) != 0)
48 return _error->Errno("chdir","Unable to change to %s",CD.c_str());
49
50 // Look for a .disk subdirectory
51 struct stat Buf;
52 if (stat(".disk",&Buf) == 0)
53 {
54 if (InfoDir.empty() == true)
55 InfoDir = CD + ".disk/";
56 }
57
58 // Don't look into directories that have been marked to ingore.
59 if (stat(".aptignr",&Buf) == 0)
60 return true;
61
62
63 /* Check _first_ for a signature file as apt-cdrom assumes that all files
64 under a Packages/Source file are in control of that file and stops
65 the scanning
66 */
67 if (stat("Release.gpg",&Buf) == 0)
68 {
69 SigList.push_back(CD);
70 }
71 /* Aha! We found some package files. We assume that everything under
72 this dir is controlled by those package files so we don't look down
73 anymore */
74 if (stat("Packages",&Buf) == 0 || stat("Packages.gz",&Buf) == 0)
75 {
76 List.push_back(CD);
77
78 // Continue down if thorough is given
79 if (_config->FindB("APT::CDROM::Thorough",false) == false)
80 return true;
81 }
82 if (stat("Sources.gz",&Buf) == 0 || stat("Sources",&Buf) == 0)
83 {
84 SList.push_back(CD);
85
86 // Continue down if thorough is given
87 if (_config->FindB("APT::CDROM::Thorough",false) == false)
88 return true;
89 }
90
91 DIR *D = opendir(".");
92 if (D == 0)
93 return _error->Errno("opendir","Unable to read %s",CD.c_str());
94
95 // Run over the directory
96 for (struct dirent *Dir = readdir(D); Dir != 0; Dir = readdir(D))
97 {
98 // Skip some files..
99 if (strcmp(Dir->d_name,".") == 0 ||
100 strcmp(Dir->d_name,"..") == 0 ||
101 //strcmp(Dir->d_name,"source") == 0 ||
102 strcmp(Dir->d_name,".disk") == 0 ||
103 strcmp(Dir->d_name,"experimental") == 0 ||
104 strcmp(Dir->d_name,"binary-all") == 0 ||
105 strcmp(Dir->d_name,"debian-installer") == 0)
106 continue;
107
108 // See if the name is a sub directory
109 struct stat Buf;
110 if (stat(Dir->d_name,&Buf) != 0)
111 continue;
112
113 if (S_ISDIR(Buf.st_mode) == 0)
114 continue;
115
116 unsigned int I;
117 for (I = 0; I != Depth; I++)
118 if (Inodes[I] == Buf.st_ino)
119 break;
120 if (I != Depth)
121 continue;
122
123 // Store the inodes weve seen
124 Inodes[Depth] = Buf.st_ino;
125
126 // Descend
127 if (FindPackages(CD + Dir->d_name,List,SList,SigList,InfoDir,log,Depth+1) == false)
128 break;
129
130 if (chdir(CD.c_str()) != 0)
131 return _error->Errno("chdir","Unable to change to %s",CD.c_str());
132 };
133
134 closedir(D);
135
136 return !_error->PendingError();
137}
138
139// Score - We compute a 'score' for a path /*{{{*/
140// ---------------------------------------------------------------------
141/* Paths are scored based on how close they come to what I consider
142 normal. That is ones that have 'dist' 'stable' 'testing' will score
143 higher than ones without. */
144int pkgCdrom::Score(string Path)
145{
146 int Res = 0;
147 if (Path.find("stable/") != string::npos)
148 Res += 29;
149 if (Path.find("/binary-") != string::npos)
150 Res += 20;
151 if (Path.find("testing/") != string::npos)
152 Res += 28;
153 if (Path.find("unstable/") != string::npos)
154 Res += 27;
155 if (Path.find("/dists/") != string::npos)
156 Res += 40;
157 if (Path.find("/main/") != string::npos)
158 Res += 20;
159 if (Path.find("/contrib/") != string::npos)
160 Res += 20;
161 if (Path.find("/non-free/") != string::npos)
162 Res += 20;
163 if (Path.find("/non-US/") != string::npos)
164 Res += 20;
165 if (Path.find("/source/") != string::npos)
166 Res += 10;
167 if (Path.find("/debian/") != string::npos)
168 Res -= 10;
872b3d39
MV
169
170 // check for symlinks in the patch leading to the actual file
171 // a symlink gets a big penalty
172 struct stat Buf;
173 string statPath = flNotFile(Path);
174 string cdromPath = _config->FindDir("Acquire::cdrom::mount","/cdrom/");
175 while(statPath != cdromPath && statPath != "./") {
176 statPath.resize(statPath.size()-1); // remove the trailing '/'
177 if (lstat(statPath.c_str(),&Buf) == 0) {
178 if(S_ISLNK(Buf.st_mode)) {
179 Res -= 60;
180 break;
181 }
182 }
183 statPath = flNotFile(statPath); // descent
184 }
185
a75c6a6e
MZ
186 return Res;
187}
188
189 /*}}}*/
190// DropBinaryArch - Dump dirs with a string like /binary-<foo>/ /*{{{*/
191// ---------------------------------------------------------------------
192/* Here we drop everything that is not this machines arch */
193bool pkgCdrom::DropBinaryArch(vector<string> &List)
194{
195 char S[300];
196 snprintf(S,sizeof(S),"/binary-%s/",
197 _config->Find("Apt::Architecture").c_str());
198
199 for (unsigned int I = 0; I < List.size(); I++)
200 {
201 const char *Str = List[I].c_str();
202
203 const char *Res;
204 if ((Res = strstr(Str,"/binary-")) == 0)
205 continue;
206
207 // Weird, remove it.
208 if (strlen(Res) < strlen(S))
209 {
210 List.erase(List.begin() + I);
211 I--;
212 continue;
213 }
214
215 // See if it is our arch
216 if (stringcmp(Res,Res + strlen(S),S) == 0)
217 continue;
218
219 // Erase it
220 List.erase(List.begin() + I);
221 I--;
222 }
223
224 return true;
225}
226
227
228// DropRepeats - Drop repeated files resulting from symlinks /*{{{*/
229// ---------------------------------------------------------------------
230/* Here we go and stat every file that we found and strip dup inodes. */
231bool pkgCdrom::DropRepeats(vector<string> &List,const char *Name)
232{
233 // Get a list of all the inodes
234 ino_t *Inodes = new ino_t[List.size()];
235 for (unsigned int I = 0; I != List.size(); I++)
236 {
237 struct stat Buf;
238 if (stat((List[I] + Name).c_str(),&Buf) != 0 &&
239 stat((List[I] + Name + ".gz").c_str(),&Buf) != 0)
240 _error->Errno("stat","Failed to stat %s%s",List[I].c_str(),
241 Name);
242 Inodes[I] = Buf.st_ino;
243 }
244
245 if (_error->PendingError() == true)
246 return false;
247
248 // Look for dups
249 for (unsigned int I = 0; I != List.size(); I++)
250 {
251 for (unsigned int J = I+1; J < List.size(); J++)
252 {
253 // No match
254 if (Inodes[J] != Inodes[I])
255 continue;
256
257 // We score the two paths.. and erase one
258 int ScoreA = Score(List[I]);
259 int ScoreB = Score(List[J]);
260 if (ScoreA < ScoreB)
261 {
262 List[I] = string();
263 break;
264 }
265
266 List[J] = string();
267 }
268 }
269
270 // Wipe erased entries
271 for (unsigned int I = 0; I < List.size();)
272 {
273 if (List[I].empty() == false)
274 I++;
275 else
276 List.erase(List.begin()+I);
277 }
278
279 return true;
280}
281 /*}}}*/
282
283// ReduceSourceList - Takes the path list and reduces it /*{{{*/
284// ---------------------------------------------------------------------
285/* This takes the list of source list expressed entires and collects
286 similar ones to form a single entry for each dist */
287void pkgCdrom::ReduceSourcelist(string CD,vector<string> &List)
288{
289 sort(List.begin(),List.end());
290
291 // Collect similar entries
292 for (vector<string>::iterator I = List.begin(); I != List.end(); I++)
293 {
294 // Find a space..
295 string::size_type Space = (*I).find(' ');
296 if (Space == string::npos)
297 continue;
298 string::size_type SSpace = (*I).find(' ',Space + 1);
299 if (SSpace == string::npos)
300 continue;
301
302 string Word1 = string(*I,Space,SSpace-Space);
303 string Prefix = string(*I,0,Space);
304 for (vector<string>::iterator J = List.begin(); J != I; J++)
305 {
306 // Find a space..
307 string::size_type Space2 = (*J).find(' ');
308 if (Space2 == string::npos)
309 continue;
310 string::size_type SSpace2 = (*J).find(' ',Space2 + 1);
311 if (SSpace2 == string::npos)
312 continue;
313
314 if (string(*J,0,Space2) != Prefix)
315 continue;
316 if (string(*J,Space2,SSpace2-Space2) != Word1)
317 continue;
318
319 *J += string(*I,SSpace);
320 *I = string();
321 }
322 }
323
324 // Wipe erased entries
325 for (unsigned int I = 0; I < List.size();)
326 {
327 if (List[I].empty() == false)
328 I++;
329 else
330 List.erase(List.begin()+I);
331 }
332}
333 /*}}}*/
334// WriteDatabase - Write the CDROM Database file /*{{{*/
335// ---------------------------------------------------------------------
336/* We rewrite the configuration class associated with the cdrom database. */
337bool pkgCdrom::WriteDatabase(Configuration &Cnf)
338{
339 string DFile = _config->FindFile("Dir::State::cdroms");
340 string NewFile = DFile + ".new";
341
342 unlink(NewFile.c_str());
343 ofstream Out(NewFile.c_str());
344 if (!Out)
345 return _error->Errno("ofstream::ofstream",
346 "Failed to open %s.new",DFile.c_str());
347
348 /* Write out all of the configuration directives by walking the
349 configuration tree */
350 const Configuration::Item *Top = Cnf.Tree(0);
351 for (; Top != 0;)
352 {
353 // Print the config entry
354 if (Top->Value.empty() == false)
355 Out << Top->FullTag() + " \"" << Top->Value << "\";" << endl;
356
357 if (Top->Child != 0)
358 {
359 Top = Top->Child;
360 continue;
361 }
362
363 while (Top != 0 && Top->Next == 0)
364 Top = Top->Parent;
365 if (Top != 0)
366 Top = Top->Next;
367 }
368
369 Out.close();
370
371 rename(DFile.c_str(),string(DFile + '~').c_str());
372 if (rename(NewFile.c_str(),DFile.c_str()) != 0)
373 return _error->Errno("rename","Failed to rename %s.new to %s",
374 DFile.c_str(),DFile.c_str());
375
376 return true;
377}
378 /*}}}*/
379// WriteSourceList - Write an updated sourcelist /*{{{*/
380// ---------------------------------------------------------------------
381/* This reads the old source list and copies it into the new one. It
382 appends the new CDROM entires just after the first block of comments.
383 This places them first in the file. It also removes any old entries
384 that were the same. */
385bool pkgCdrom::WriteSourceList(string Name,vector<string> &List,bool Source)
386{
387 if (List.size() == 0)
388 return true;
389
390 string File = _config->FindFile("Dir::Etc::sourcelist");
391
392 // Open the stream for reading
393 ifstream F((FileExists(File)?File.c_str():"/dev/null"),
394 ios::in );
395 if (!F != 0)
396 return _error->Errno("ifstream::ifstream","Opening %s",File.c_str());
397
398 string NewFile = File + ".new";
399 unlink(NewFile.c_str());
400 ofstream Out(NewFile.c_str());
401 if (!Out)
402 return _error->Errno("ofstream::ofstream",
403 "Failed to open %s.new",File.c_str());
404
405 // Create a short uri without the path
406 string ShortURI = "cdrom:[" + Name + "]/";
407 string ShortURI2 = "cdrom:" + Name + "/"; // For Compatibility
408
409 string Type;
410 if (Source == true)
411 Type = "deb-src";
412 else
413 Type = "deb";
414
415 char Buffer[300];
416 int CurLine = 0;
417 bool First = true;
418 while (F.eof() == false)
419 {
420 F.getline(Buffer,sizeof(Buffer));
421 CurLine++;
13e8426f
MV
422 if (F.fail() && !F.eof())
423 return _error->Error(_("Line %u too long in source list %s."),
424 CurLine,File.c_str());
a75c6a6e
MZ
425 _strtabexpand(Buffer,sizeof(Buffer));
426 _strstrip(Buffer);
427
428 // Comment or blank
429 if (Buffer[0] == '#' || Buffer[0] == 0)
430 {
431 Out << Buffer << endl;
432 continue;
433 }
434
435 if (First == true)
436 {
437 for (vector<string>::iterator I = List.begin(); I != List.end(); I++)
438 {
439 string::size_type Space = (*I).find(' ');
440 if (Space == string::npos)
441 return _error->Error("Internal error");
442 Out << Type << " cdrom:[" << Name << "]/" << string(*I,0,Space) <<
443 " " << string(*I,Space+1) << endl;
444 }
445 }
446 First = false;
447
448 // Grok it
449 string cType;
450 string URI;
451 const char *C = Buffer;
452 if (ParseQuoteWord(C,cType) == false ||
453 ParseQuoteWord(C,URI) == false)
454 {
455 Out << Buffer << endl;
456 continue;
457 }
458
459 // Emit lines like this one
460 if (cType != Type || (string(URI,0,ShortURI.length()) != ShortURI &&
461 string(URI,0,ShortURI.length()) != ShortURI2))
462 {
463 Out << Buffer << endl;
464 continue;
465 }
466 }
467
468 // Just in case the file was empty
469 if (First == true)
470 {
471 for (vector<string>::iterator I = List.begin(); I != List.end(); I++)
472 {
473 string::size_type Space = (*I).find(' ');
474 if (Space == string::npos)
475 return _error->Error("Internal error");
476
477 Out << "deb cdrom:[" << Name << "]/" << string(*I,0,Space) <<
478 " " << string(*I,Space+1) << endl;
479 }
480 }
481
482 Out.close();
483
484 rename(File.c_str(),string(File + '~').c_str());
485 if (rename(NewFile.c_str(),File.c_str()) != 0)
486 return _error->Errno("rename","Failed to rename %s.new to %s",
487 File.c_str(),File.c_str());
488
489 return true;
490}
491
492
493bool pkgCdrom::Ident(string &ident, pkgCdromStatus *log)
494{
495 stringstream msg;
496
497 // Startup
498 string CDROM = _config->FindDir("Acquire::cdrom::mount","/cdrom/");
499 if (CDROM[0] == '.')
500 CDROM= SafeGetCWD() + '/' + CDROM;
501
502 if(log) {
503 msg.str("");
504 ioprintf(msg, _("Using CD-ROM mount point %s\nMounting CD-ROM\n"),
505 CDROM.c_str());
506 log->Update(msg.str());
507 }
508 if (MountCdrom(CDROM) == false)
509 return _error->Error("Failed to mount the cdrom.");
510
511 // Hash the CD to get an ID
512 if(log)
513 log->Update(_("Identifying.. "));
514
515
516 if (IdentCdrom(CDROM,ident) == false)
517 {
518 ident = "";
519 return false;
520 }
521
522 msg.str("");
523 ioprintf(msg, "[%s]\n",ident.c_str());
524 log->Update(msg.str());
525
526
527 // Read the database
528 Configuration Database;
529 string DFile = _config->FindFile("Dir::State::cdroms");
530 if (FileExists(DFile) == true)
531 {
532 if (ReadConfigFile(Database,DFile) == false)
533 return _error->Error("Unable to read the cdrom database %s",
534 DFile.c_str());
535 }
536 if(log) {
537 msg.str("");
db0db9fe 538 ioprintf(msg, _("Stored label: %s \n"),
a75c6a6e
MZ
539 Database.Find("CD::"+ident).c_str());
540 log->Update(msg.str());
541 }
542 return true;
543}
544
545
546bool pkgCdrom::Add(pkgCdromStatus *log)
547{
548 stringstream msg;
549
550 // Startup
551 string CDROM = _config->FindDir("Acquire::cdrom::mount","/cdrom/");
552 if (CDROM[0] == '.')
553 CDROM= SafeGetCWD() + '/' + CDROM;
554
555 if(log) {
556 log->SetTotal(STEP_LAST);
557 msg.str("");
558 ioprintf(msg, _("Using CD-ROM mount point %s\n"), CDROM.c_str());
559 log->Update(msg.str(), STEP_PREPARE);
560 }
561
562 // Read the database
563 Configuration Database;
564 string DFile = _config->FindFile("Dir::State::cdroms");
565 if (FileExists(DFile) == true)
566 {
cdadf54b 567 if (ReadConfigFile(Database,DFile) == false)
a75c6a6e
MZ
568 return _error->Error("Unable to read the cdrom database %s",
569 DFile.c_str());
570 }
571
572 // Unmount the CD and get the user to put in the one they want
573 if (_config->FindB("APT::CDROM::NoMount",false) == false)
574 {
575 if(log)
576 log->Update(_("Unmounting CD-ROM\n"), STEP_UNMOUNT);
577 UnmountCdrom(CDROM);
578
579 if(log) {
580 log->Update(_("Waiting for disc...\n"), STEP_WAIT);
581 if(!log->ChangeCdrom()) {
582 // user aborted
583 return false;
584 }
585 }
586
587 // Mount the new CDROM
588 log->Update(_("Mounting CD-ROM...\n"), STEP_MOUNT);
589 if (MountCdrom(CDROM) == false)
590 return _error->Error("Failed to mount the cdrom.");
591 }
592
593 // Hash the CD to get an ID
594 if(log)
595 log->Update(_("Identifying.. "), STEP_IDENT);
596 string ID;
597 if (IdentCdrom(CDROM,ID) == false)
598 {
599 log->Update("\n");
600 return false;
601 }
602 if(log)
603 log->Update("["+ID+"]\n");
604
605 if(log)
db0db9fe 606 log->Update(_("Scanning disc for index files..\n"),STEP_SCAN);
a75c6a6e
MZ
607
608 // Get the CD structure
609 vector<string> List;
610 vector<string> SourceList;
611 vector<string> SigList;
612 string StartDir = SafeGetCWD();
613 string InfoDir;
614 if (FindPackages(CDROM,List,SourceList, SigList,InfoDir,log) == false)
615 {
616 log->Update("\n");
617 return false;
618 }
619
620 chdir(StartDir.c_str());
621
622 if (_config->FindB("Debug::aptcdrom",false) == true)
623 {
624 cout << "I found (binary):" << endl;
625 for (vector<string>::iterator I = List.begin(); I != List.end(); I++)
626 cout << *I << endl;
627 cout << "I found (source):" << endl;
628 for (vector<string>::iterator I = SourceList.begin(); I != SourceList.end(); I++)
629 cout << *I << endl;
630 cout << "I found (Signatures):" << endl;
631 for (vector<string>::iterator I = SigList.begin(); I != SigList.end(); I++)
632 cout << *I << endl;
633 }
634
635 //log->Update(_("Cleaning package lists..."), STEP_CLEAN);
636
637 // Fix up the list
638 DropBinaryArch(List);
639 DropRepeats(List,"Packages");
640 DropRepeats(SourceList,"Sources");
641 DropRepeats(SigList,"Release.gpg");
642 if(log) {
643 msg.str("");
644 ioprintf(msg, _("Found %i package indexes, %i source indexes and "
645 "%i signatures\n"),
646 List.size(), SourceList.size(), SigList.size());
647 log->Update(msg.str(), STEP_SCAN);
648 }
649
cdadf54b
MV
650 if (List.size() == 0 && SourceList.size() == 0)
651 {
652 UnmountCdrom(CDROM);
a75c6a6e 653 return _error->Error("Unable to locate any package files, perhaps this is not a Debian Disc");
cdadf54b 654 }
a75c6a6e
MZ
655
656 // Check if the CD is in the database
657 string Name;
658 if (Database.Exists("CD::" + ID) == false ||
659 _config->FindB("APT::CDROM::Rename",false) == true)
660 {
661 // Try to use the CDs label if at all possible
662 if (InfoDir.empty() == false &&
663 FileExists(InfoDir + "/info") == true)
664 {
665 ifstream F(string(InfoDir + "/info").c_str());
666 if (!F == 0)
667 getline(F,Name);
668
669 if (Name.empty() == false)
670 {
671 // Escape special characters
672 string::iterator J = Name.begin();
673 for (; J != Name.end(); J++)
674 if (*J == '"' || *J == ']' || *J == '[')
675 *J = '_';
676
677 if(log) {
678 msg.str("");
679 ioprintf(msg, "Found label '%s'\n", Name.c_str());
680 log->Update(msg.str());
681 }
682 Database.Set("CD::" + ID + "::Label",Name);
683 }
684 }
685
686 if (_config->FindB("APT::CDROM::Rename",false) == true ||
687 Name.empty() == true)
688 {
689 if(!log)
cdadf54b
MV
690 {
691 UnmountCdrom(CDROM);
a75c6a6e 692 return _error->Error("No disc name found and no way to ask for it");
cdadf54b 693 }
a75c6a6e
MZ
694
695 while(true) {
696 if(!log->AskCdromName(Name)) {
697 // user canceld
698 return false;
699 }
700 cout << "Name: '" << Name << "'" << endl;
701
702 if (Name.empty() == false &&
703 Name.find('"') == string::npos &&
704 Name.find('[') == string::npos &&
705 Name.find(']') == string::npos)
706 break;
707 log->Update(_("That is not a valid name, try again.\n"));
708 }
709 }
710 }
711 else
712 Name = Database.Find("CD::" + ID);
713
714 // Escape special characters
715 string::iterator J = Name.begin();
716 for (; J != Name.end(); J++)
717 if (*J == '"' || *J == ']' || *J == '[')
718 *J = '_';
719
720 Database.Set("CD::" + ID,Name);
721 if(log) {
722 msg.str("");
db0db9fe 723 ioprintf(msg, _("This disc is called: \n'%s'\n"), Name.c_str());
a75c6a6e
MZ
724 log->Update(msg.str());
725 }
726
727 log->Update(_("Copying package lists..."), STEP_COPY);
728 // take care of the signatures and copy them if they are ok
729 // (we do this before PackageCopy as it modifies "List" and "SourceList")
730 SigVerify SignVerify;
731 SignVerify.CopyAndVerify(CDROM, Name, SigList, List, SourceList);
732
733 // Copy the package files to the state directory
734 PackageCopy Copy;
735 SourceCopy SrcCopy;
736 if (Copy.CopyPackages(CDROM,Name,List, log) == false ||
737 SrcCopy.CopyPackages(CDROM,Name,SourceList, log) == false)
738 return false;
739
740 // reduce the List so that it takes less space in sources.list
741 ReduceSourcelist(CDROM,List);
742 ReduceSourcelist(CDROM,SourceList);
743
744 // Write the database and sourcelist
745 if (_config->FindB("APT::cdrom::NoAct",false) == false)
746 {
747 if (WriteDatabase(Database) == false)
748 return false;
749
750 if(log) {
751 log->Update(_("Writing new source list\n"), STEP_WRITE);
752 }
753 if (WriteSourceList(Name,List,false) == false ||
754 WriteSourceList(Name,SourceList,true) == false)
755 return false;
756 }
757
758 // Print the sourcelist entries
759 if(log)
db0db9fe 760 log->Update(_("Source list entries for this disc are:\n"));
a75c6a6e
MZ
761
762 for (vector<string>::iterator I = List.begin(); I != List.end(); I++)
763 {
764 string::size_type Space = (*I).find(' ');
765 if (Space == string::npos)
cdadf54b
MV
766 {
767 UnmountCdrom(CDROM);
a75c6a6e 768 return _error->Error("Internal error");
cdadf54b 769 }
a75c6a6e
MZ
770
771 if(log) {
772 msg.str("");
773 msg << "deb cdrom:[" << Name << "]/" << string(*I,0,Space) <<
774 " " << string(*I,Space+1) << endl;
775 log->Update(msg.str());
776 }
777 }
778
779 for (vector<string>::iterator I = SourceList.begin(); I != SourceList.end(); I++)
780 {
781 string::size_type Space = (*I).find(' ');
782 if (Space == string::npos)
cdadf54b
MV
783 {
784 UnmountCdrom(CDROM);
a75c6a6e 785 return _error->Error("Internal error");
cdadf54b 786 }
a75c6a6e
MZ
787
788 if(log) {
789 msg.str("");
790 msg << "deb-src cdrom:[" << Name << "]/" << string(*I,0,Space) <<
791 " " << string(*I,Space+1) << endl;
792 log->Update(msg.str());
793 }
794 }
795
796
797
798 // Unmount and finish
799 if (_config->FindB("APT::CDROM::NoMount",false) == false) {
800 log->Update(_("Unmounting CD-ROM..."), STEP_LAST);
801 UnmountCdrom(CDROM);
802 }
803
804 return true;
805}