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