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