* fix error in AutocleanInterval, closes: #319339
[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
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 if (F.fail() && !F.eof())
450 return _error->Error(_("Line %u too long in source list %s."),
451 CurLine,File.c_str());
452 _strtabexpand(Buffer,sizeof(Buffer));
453 _strstrip(Buffer);
454
455 // Comment or blank
456 if (Buffer[0] == '#' || Buffer[0] == 0)
457 {
458 Out << Buffer << endl;
459 continue;
460 }
461
462 if (First == true)
463 {
464 for (vector<string>::iterator I = List.begin(); I != List.end(); I++)
465 {
466 string::size_type Space = (*I).find(' ');
467 if (Space == string::npos)
468 return _error->Error("Internal error");
469 Out << Type << " cdrom:[" << Name << "]/" << string(*I,0,Space) <<
470 " " << string(*I,Space+1) << endl;
471 }
472 }
473 First = false;
474
475 // Grok it
476 string cType;
477 string URI;
478 const char *C = Buffer;
479 if (ParseQuoteWord(C,cType) == false ||
480 ParseQuoteWord(C,URI) == false)
481 {
482 Out << Buffer << endl;
483 continue;
484 }
485
486 // Emit lines like this one
487 if (cType != Type || (string(URI,0,ShortURI.length()) != ShortURI &&
488 string(URI,0,ShortURI.length()) != ShortURI2))
489 {
490 Out << Buffer << endl;
491 continue;
492 }
493 }
494
495 // Just in case the file was empty
496 if (First == true)
497 {
498 for (vector<string>::iterator I = List.begin(); I != List.end(); I++)
499 {
500 string::size_type Space = (*I).find(' ');
501 if (Space == string::npos)
502 return _error->Error("Internal error");
503
504 Out << "deb cdrom:[" << Name << "]/" << string(*I,0,Space) <<
505 " " << string(*I,Space+1) << endl;
506 }
507 }
508
509 Out.close();
510
511 rename(File.c_str(),string(File + '~').c_str());
512 if (rename(NewFile.c_str(),File.c_str()) != 0)
513 return _error->Errno("rename","Failed to rename %s.new to %s",
514 File.c_str(),File.c_str());
515
516 return true;
517 }
518
519
520 bool pkgCdrom::Ident(string &ident, pkgCdromStatus *log)
521 {
522 stringstream msg;
523
524 // Startup
525 string CDROM = _config->FindDir("Acquire::cdrom::mount","/cdrom/");
526 if (CDROM[0] == '.')
527 CDROM= SafeGetCWD() + '/' + CDROM;
528
529 if(log) {
530 msg.str("");
531 ioprintf(msg, _("Using CD-ROM mount point %s\nMounting CD-ROM\n"),
532 CDROM.c_str());
533 log->Update(msg.str());
534 }
535 if (MountCdrom(CDROM) == false)
536 return _error->Error("Failed to mount the cdrom.");
537
538 // Hash the CD to get an ID
539 if(log)
540 log->Update(_("Identifying.. "));
541
542
543 if (IdentCdrom(CDROM,ident) == false)
544 {
545 ident = "";
546 return false;
547 }
548
549 msg.str("");
550 ioprintf(msg, "[%s]\n",ident.c_str());
551 log->Update(msg.str());
552
553
554 // Read the database
555 Configuration Database;
556 string DFile = _config->FindFile("Dir::State::cdroms");
557 if (FileExists(DFile) == true)
558 {
559 if (ReadConfigFile(Database,DFile) == false)
560 return _error->Error("Unable to read the cdrom database %s",
561 DFile.c_str());
562 }
563 if(log) {
564 msg.str("");
565 ioprintf(msg, _("Stored label: %s \n"),
566 Database.Find("CD::"+ident).c_str());
567 log->Update(msg.str());
568 }
569 return true;
570 }
571
572
573 bool pkgCdrom::Add(pkgCdromStatus *log)
574 {
575 stringstream msg;
576
577 // Startup
578 string CDROM = _config->FindDir("Acquire::cdrom::mount","/cdrom/");
579 if (CDROM[0] == '.')
580 CDROM= SafeGetCWD() + '/' + CDROM;
581
582 if(log) {
583 log->SetTotal(STEP_LAST);
584 msg.str("");
585 ioprintf(msg, _("Using CD-ROM mount point %s\n"), CDROM.c_str());
586 log->Update(msg.str(), STEP_PREPARE);
587 }
588
589 // Read the database
590 Configuration Database;
591 string DFile = _config->FindFile("Dir::State::cdroms");
592 if (FileExists(DFile) == true)
593 {
594 if (ReadConfigFile(Database,DFile) == false)
595 return _error->Error("Unable to read the cdrom database %s",
596 DFile.c_str());
597 }
598
599 // Unmount the CD and get the user to put in the one they want
600 if (_config->FindB("APT::CDROM::NoMount",false) == false)
601 {
602 if(log)
603 log->Update(_("Unmounting CD-ROM\n"), STEP_UNMOUNT);
604 UnmountCdrom(CDROM);
605
606 if(log) {
607 log->Update(_("Waiting for disc...\n"), STEP_WAIT);
608 if(!log->ChangeCdrom()) {
609 // user aborted
610 return false;
611 }
612 }
613
614 // Mount the new CDROM
615 log->Update(_("Mounting CD-ROM...\n"), STEP_MOUNT);
616 if (MountCdrom(CDROM) == false)
617 return _error->Error("Failed to mount the cdrom.");
618 }
619
620 // Hash the CD to get an ID
621 if(log)
622 log->Update(_("Identifying.. "), STEP_IDENT);
623 string ID;
624 if (IdentCdrom(CDROM,ID) == false)
625 {
626 log->Update("\n");
627 return false;
628 }
629 if(log)
630 log->Update("["+ID+"]\n");
631
632 if(log)
633 log->Update(_("Scanning disc for index files..\n"),STEP_SCAN);
634
635 // Get the CD structure
636 vector<string> List;
637 vector<string> SourceList;
638 vector<string> SigList;
639 vector<string> TransList;
640 string StartDir = SafeGetCWD();
641 string InfoDir;
642 if (FindPackages(CDROM,List,SourceList, SigList,TransList,InfoDir,log) == false)
643 {
644 log->Update("\n");
645 return false;
646 }
647
648 chdir(StartDir.c_str());
649
650 if (_config->FindB("Debug::aptcdrom",false) == true)
651 {
652 cout << "I found (binary):" << endl;
653 for (vector<string>::iterator I = List.begin(); I != List.end(); I++)
654 cout << *I << endl;
655 cout << "I found (source):" << endl;
656 for (vector<string>::iterator I = SourceList.begin(); I != SourceList.end(); I++)
657 cout << *I << endl;
658 cout << "I found (Signatures):" << endl;
659 for (vector<string>::iterator I = SigList.begin(); I != SigList.end(); I++)
660 cout << *I << endl;
661 }
662
663 //log->Update(_("Cleaning package lists..."), STEP_CLEAN);
664
665 // Fix up the list
666 DropBinaryArch(List);
667 DropRepeats(List,"Packages");
668 DropRepeats(SourceList,"Sources");
669 DropRepeats(SigList,"Release.gpg");
670 DropRepeats(TransList,"");
671 if(log) {
672 msg.str("");
673 ioprintf(msg, _("Found %i package indexes, %i source indexes, "
674 "%i translation indexes and %i signatures\n"),
675 List.size(), SourceList.size(), TransList.size(),
676 SigList.size());
677 log->Update(msg.str(), STEP_SCAN);
678 }
679
680 if (List.size() == 0 && SourceList.size() == 0)
681 {
682 if (_config->FindB("APT::CDROM::NoMount",false) == false)
683 UnmountCdrom(CDROM);
684 return _error->Error("Unable to locate any package files, perhaps this is not a Debian Disc");
685 }
686
687 // Check if the CD is in the database
688 string Name;
689 if (Database.Exists("CD::" + ID) == false ||
690 _config->FindB("APT::CDROM::Rename",false) == true)
691 {
692 // Try to use the CDs label if at all possible
693 if (InfoDir.empty() == false &&
694 FileExists(InfoDir + "/info") == true)
695 {
696 ifstream F(string(InfoDir + "/info").c_str());
697 if (!F == 0)
698 getline(F,Name);
699
700 if (Name.empty() == false)
701 {
702 // Escape special characters
703 string::iterator J = Name.begin();
704 for (; J != Name.end(); J++)
705 if (*J == '"' || *J == ']' || *J == '[')
706 *J = '_';
707
708 if(log) {
709 msg.str("");
710 ioprintf(msg, _("Found label '%s'\n"), Name.c_str());
711 log->Update(msg.str());
712 }
713 Database.Set("CD::" + ID + "::Label",Name);
714 }
715 }
716
717 if (_config->FindB("APT::CDROM::Rename",false) == true ||
718 Name.empty() == true)
719 {
720 if(!log)
721 {
722 if (_config->FindB("APT::CDROM::NoMount",false) == false)
723 UnmountCdrom(CDROM);
724 return _error->Error("No disc name found and no way to ask for it");
725 }
726
727 while(true) {
728 if(!log->AskCdromName(Name)) {
729 // user canceld
730 return false;
731 }
732 cout << "Name: '" << Name << "'" << endl;
733
734 if (Name.empty() == false &&
735 Name.find('"') == string::npos &&
736 Name.find('[') == string::npos &&
737 Name.find(']') == string::npos)
738 break;
739 log->Update(_("That is not a valid name, try again.\n"));
740 }
741 }
742 }
743 else
744 Name = Database.Find("CD::" + ID);
745
746 // Escape special characters
747 string::iterator J = Name.begin();
748 for (; J != Name.end(); J++)
749 if (*J == '"' || *J == ']' || *J == '[')
750 *J = '_';
751
752 Database.Set("CD::" + ID,Name);
753 if(log) {
754 msg.str("");
755 ioprintf(msg, _("This disc is called: \n'%s'\n"), Name.c_str());
756 log->Update(msg.str());
757 }
758
759 log->Update(_("Copying package lists..."), STEP_COPY);
760 // take care of the signatures and copy them if they are ok
761 // (we do this before PackageCopy as it modifies "List" and "SourceList")
762 SigVerify SignVerify;
763 SignVerify.CopyAndVerify(CDROM, Name, SigList, List, SourceList);
764
765 // Copy the package files to the state directory
766 PackageCopy Copy;
767 SourceCopy SrcCopy;
768 TranslationsCopy TransCopy;
769 if (Copy.CopyPackages(CDROM,Name,List, log) == false ||
770 SrcCopy.CopyPackages(CDROM,Name,SourceList, log) == false ||
771 TransCopy.CopyTranslations(CDROM,Name,TransList, log) == false)
772 return false;
773
774 // reduce the List so that it takes less space in sources.list
775 ReduceSourcelist(CDROM,List);
776 ReduceSourcelist(CDROM,SourceList);
777
778 // Write the database and sourcelist
779 if (_config->FindB("APT::cdrom::NoAct",false) == false)
780 {
781 if (WriteDatabase(Database) == false)
782 return false;
783
784 if(log) {
785 log->Update(_("Writing new source list\n"), STEP_WRITE);
786 }
787 if (WriteSourceList(Name,List,false) == false ||
788 WriteSourceList(Name,SourceList,true) == false)
789 return false;
790 }
791
792 // Print the sourcelist entries
793 if(log)
794 log->Update(_("Source list entries for this disc are:\n"));
795
796 for (vector<string>::iterator I = List.begin(); I != List.end(); I++)
797 {
798 string::size_type Space = (*I).find(' ');
799 if (Space == string::npos)
800 {
801 if (_config->FindB("APT::CDROM::NoMount",false) == false)
802 UnmountCdrom(CDROM);
803 return _error->Error("Internal error");
804 }
805
806 if(log) {
807 msg.str("");
808 msg << "deb cdrom:[" << Name << "]/" << string(*I,0,Space) <<
809 " " << string(*I,Space+1) << endl;
810 log->Update(msg.str());
811 }
812 }
813
814 for (vector<string>::iterator I = SourceList.begin(); I != SourceList.end(); I++)
815 {
816 string::size_type Space = (*I).find(' ');
817 if (Space == string::npos)
818 {
819 if (_config->FindB("APT::CDROM::NoMount",false) == false)
820 UnmountCdrom(CDROM);
821 return _error->Error("Internal error");
822 }
823
824 if(log) {
825 msg.str("");
826 msg << "deb-src cdrom:[" << Name << "]/" << string(*I,0,Space) <<
827 " " << string(*I,Space+1) << endl;
828 log->Update(msg.str());
829 }
830 }
831
832
833
834 // Unmount and finish
835 if (_config->FindB("APT::CDROM::NoMount",false) == false) {
836 log->Update(_("Unmounting CD-ROM...\n"), STEP_LAST);
837 UnmountCdrom(CDROM);
838 }
839
840 return true;
841 }