[280] | 1 | /* rcdscanner.cc |
---|
| 2 | * |
---|
| 3 | * Copyright (c) 2000-2003 Conectiva S/A |
---|
| 4 | * |
---|
| 5 | * Author: Alfredo K. Kojima <kojima@conectiva.com.br> |
---|
| 6 | * |
---|
| 7 | * This program is free software; you can redistribute it and/or |
---|
| 8 | * modify it under the terms of the GNU General Public License as |
---|
| 9 | * published by the Free Software Foundation; either version 2 of the |
---|
| 10 | * License, or (at your option) any later version. |
---|
| 11 | * |
---|
| 12 | * This program 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. |
---|
| 16 | * |
---|
| 17 | * You should have received a copy of the GNU General Public License |
---|
| 18 | * along with this program; if not, write to the Free Software |
---|
| 19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 |
---|
| 20 | * USA |
---|
| 21 | */ |
---|
| 22 | |
---|
| 23 | #include<config.h> |
---|
| 24 | #ifndef HAVE_APTPKG_CDROM |
---|
| 25 | |
---|
| 26 | #include <sys/stat.h> |
---|
| 27 | #include <sys/fcntl.h> |
---|
| 28 | #include <dirent.h> |
---|
| 29 | #include <unistd.h> |
---|
| 30 | #include <iostream> |
---|
| 31 | #include <fstream> |
---|
| 32 | #include <algorithm> |
---|
| 33 | #include <cstdio> |
---|
| 34 | |
---|
| 35 | #include <apt-pkg/error.h> |
---|
| 36 | #include <apt-pkg/fileutl.h> |
---|
| 37 | #include <apt-pkg/configuration.h> |
---|
| 38 | #include <apt-pkg/cdromutl.h> |
---|
| 39 | #include <apt-pkg/strutl.h> |
---|
| 40 | |
---|
| 41 | #include "i18n.h" |
---|
| 42 | #include "rcdscanner.h" |
---|
| 43 | |
---|
| 44 | #ifdef HAVE_RPM |
---|
| 45 | #include "rpmindexcopy.h" |
---|
| 46 | #else |
---|
| 47 | #include "indexcopy.h" |
---|
| 48 | #endif |
---|
| 49 | |
---|
| 50 | using namespace std; |
---|
| 51 | |
---|
| 52 | // ReduceSourceList - Takes the path list and reduces it /*{{{*/ |
---|
| 53 | // --------------------------------------------------------------------- |
---|
| 54 | /* This takes the list of source list expressed entires and collects |
---|
| 55 | similar ones to form a single entry for each dist */ |
---|
| 56 | void ReduceSourcelist(string CD, vector<string> &List) |
---|
| 57 | { |
---|
| 58 | sort(List.begin(), List.end()); |
---|
| 59 | |
---|
| 60 | // Collect similar entries |
---|
| 61 | for (vector<string>::iterator I = List.begin(); I != List.end(); I++) { |
---|
| 62 | // Find a space.. |
---|
| 63 | string::size_type Space = (*I).find(' '); |
---|
| 64 | if (Space == string::npos) |
---|
| 65 | continue; |
---|
| 66 | string::size_type SSpace = (*I).find(' ', Space + 1); |
---|
| 67 | if (SSpace == string::npos) |
---|
| 68 | continue; |
---|
| 69 | |
---|
| 70 | string Word1 = string(*I, Space, SSpace - Space); |
---|
| 71 | string Prefix = string(*I, 0, Space); |
---|
| 72 | for (vector<string>::iterator J = List.begin(); J != I; J++) { |
---|
| 73 | // Find a space.. |
---|
| 74 | string::size_type Space2 = (*J).find(' '); |
---|
| 75 | if (Space2 == string::npos) |
---|
| 76 | continue; |
---|
| 77 | string::size_type SSpace2 = (*J).find(' ', Space2 + 1); |
---|
| 78 | if (SSpace2 == string::npos) |
---|
| 79 | continue; |
---|
| 80 | |
---|
| 81 | if (string(*J, 0, Space2) != Prefix) |
---|
| 82 | continue; |
---|
| 83 | if (string(*J, Space2, SSpace2 - Space2) != Word1) |
---|
| 84 | continue; |
---|
| 85 | |
---|
| 86 | *J += string(*I, SSpace); |
---|
| 87 | *I = string(); |
---|
| 88 | } |
---|
| 89 | } |
---|
| 90 | |
---|
| 91 | // Wipe erased entries |
---|
| 92 | for (unsigned int I = 0; I < List.size();) { |
---|
| 93 | if (List[I].empty() == false) |
---|
| 94 | I++; |
---|
| 95 | else |
---|
| 96 | List.erase(List.begin() + I); |
---|
| 97 | } |
---|
| 98 | } |
---|
| 99 | |
---|
| 100 | /*}}} */ |
---|
| 101 | bool RCDScanner::writeDatabase() |
---|
| 102 | { |
---|
| 103 | _database->Set("CD::" + _cdId, _cdName); |
---|
| 104 | |
---|
| 105 | string DFile = _config->FindFile("Dir::State::cdroms"); |
---|
| 106 | string NewFile = DFile + ".new"; |
---|
| 107 | |
---|
| 108 | unlink(NewFile.c_str()); |
---|
| 109 | ofstream Out(NewFile.c_str()); |
---|
| 110 | if (!Out) |
---|
| 111 | return _error->Errno("ofstream::ofstream", |
---|
| 112 | _("Failed to open %s.new"), DFile.c_str()); |
---|
| 113 | |
---|
| 114 | /* Write out all of the configuration directives by walking the |
---|
| 115 | configuration tree */ |
---|
| 116 | const Configuration::Item *Top = _database->Tree(0); |
---|
| 117 | for (; Top != 0;) { |
---|
| 118 | // Print the config entry |
---|
| 119 | if (Top->Value.empty() == false) |
---|
| 120 | Out << Top->FullTag() + " \"" << Top->Value << "\";" << endl; |
---|
| 121 | |
---|
| 122 | if (Top->Child != 0) { |
---|
| 123 | Top = Top->Child; |
---|
| 124 | continue; |
---|
| 125 | } |
---|
| 126 | |
---|
| 127 | while (Top != 0 && Top->Next == 0) |
---|
| 128 | Top = Top->Parent; |
---|
| 129 | if (Top != 0) |
---|
| 130 | Top = Top->Next; |
---|
| 131 | } |
---|
| 132 | |
---|
| 133 | Out.close(); |
---|
| 134 | |
---|
| 135 | rename(DFile.c_str(), string(DFile + '~').c_str()); |
---|
| 136 | if (rename(NewFile.c_str(), DFile.c_str()) != 0) |
---|
| 137 | return _error->Errno("rename", _("Failed to rename %s.new to %s"), |
---|
| 138 | DFile.c_str(), DFile.c_str()); |
---|
| 139 | |
---|
| 140 | return true; |
---|
| 141 | } |
---|
| 142 | |
---|
| 143 | bool RCDScanner::writeSourceList(vector<string> &list, bool pkg) |
---|
| 144 | { |
---|
| 145 | // copy&paste from apt-cdrom |
---|
| 146 | |
---|
| 147 | if (list.size() == 0) |
---|
| 148 | return true; |
---|
| 149 | |
---|
| 150 | string File = _config->FindFile("Dir::Etc::sourcelist"); |
---|
| 151 | |
---|
| 152 | // Open the stream for reading |
---|
| 153 | ifstream F((FileExists(File) ? File.c_str() : "/dev/null"), ios::in); |
---|
| 154 | if (!F != 0) |
---|
| 155 | return _error->Errno("ifstream::ifstream", "Opening %s", File.c_str()); |
---|
| 156 | |
---|
| 157 | string NewFile = File + ".new"; |
---|
| 158 | unlink(NewFile.c_str()); |
---|
| 159 | ofstream Out(NewFile.c_str()); |
---|
| 160 | if (!Out) |
---|
| 161 | return _error->Errno("ofstream::ofstream", |
---|
| 162 | _("Failed to open %s.new"), File.c_str()); |
---|
| 163 | |
---|
| 164 | // Create a short uri without the path |
---|
| 165 | string ShortURI = "cdrom:[" + _cdName + "]/"; |
---|
| 166 | string ShortURI2 = "cdrom:" + _cdName + "/"; // For Compatibility |
---|
| 167 | |
---|
| 168 | string ShortOldURI; |
---|
| 169 | string ShortOldURI2; |
---|
| 170 | if (_cdOldName.empty() == false) { |
---|
| 171 | ShortOldURI = "cdrom:[" + _cdOldName + "]/"; |
---|
| 172 | ShortOldURI2 = "cdrom:" + _cdOldName + "/"; |
---|
| 173 | } |
---|
| 174 | |
---|
| 175 | string Type; |
---|
| 176 | |
---|
| 177 | if (pkg) |
---|
| 178 | Type = pkgSourceType().c_str(); |
---|
| 179 | else |
---|
| 180 | Type = srcSourceType().c_str(); |
---|
| 181 | |
---|
| 182 | char Buffer[300]; |
---|
| 183 | int CurLine = 0; |
---|
| 184 | bool First = true; |
---|
| 185 | while (F.eof() == false) { |
---|
| 186 | F.getline(Buffer, sizeof(Buffer)); |
---|
| 187 | CurLine++; |
---|
| 188 | _strtabexpand(Buffer, sizeof(Buffer)); |
---|
| 189 | _strstrip(Buffer); |
---|
| 190 | |
---|
| 191 | // Comment or blank |
---|
| 192 | if (Buffer[0] == '#' || Buffer[0] == 0) { |
---|
| 193 | Out << Buffer << endl; |
---|
| 194 | continue; |
---|
| 195 | } |
---|
| 196 | |
---|
| 197 | if (First == true) { |
---|
| 198 | for (vector<string>::iterator I = list.begin(); I != list.end(); |
---|
| 199 | I++) { |
---|
| 200 | string::size_type Space = (*I).find(' '); |
---|
| 201 | if (Space == string::npos) |
---|
| 202 | return _error->Error(_("Internal error")); |
---|
| 203 | Out << Type << " cdrom:[" << _cdName << "]/" << string(*I, 0, |
---|
| 204 | Space) << |
---|
| 205 | " " << string(*I, Space + 1) << endl; |
---|
| 206 | } |
---|
| 207 | } |
---|
| 208 | First = false; |
---|
| 209 | |
---|
| 210 | // Grok it |
---|
| 211 | string cType; |
---|
| 212 | string URI; |
---|
| 213 | const char *C = Buffer; |
---|
| 214 | if (ParseQuoteWord(C, cType) == false || ParseQuoteWord(C, URI) == false) { |
---|
| 215 | Out << Buffer << endl; |
---|
| 216 | continue; |
---|
| 217 | } |
---|
| 218 | // Omit lines like this one |
---|
| 219 | if (cType != Type |
---|
| 220 | || (string(URI, 0, ShortURI.length()) != ShortURI && |
---|
| 221 | string(URI, 0, ShortURI.length()) != ShortURI2 && |
---|
| 222 | (_cdOldName.empty() |
---|
| 223 | || (string(URI, 0, ShortOldURI.length()) != ShortOldURI && |
---|
| 224 | string(URI, 0, ShortOldURI.length()) != ShortOldURI2)))) { |
---|
| 225 | Out << Buffer << endl; |
---|
| 226 | continue; |
---|
| 227 | } |
---|
| 228 | } |
---|
| 229 | |
---|
| 230 | // Just in case the file was empty |
---|
| 231 | if (First == true) { |
---|
| 232 | for (vector<string>::iterator I = list.begin(); I != list.end(); I++) { |
---|
| 233 | string::size_type Space = (*I).find(' '); |
---|
| 234 | if (Space == string::npos) |
---|
| 235 | return _error->Error(_("Internal error")); |
---|
| 236 | |
---|
| 237 | Out << Type << " cdrom:[" << _cdName << "]/" << string(*I, 0, |
---|
| 238 | Space) << " " |
---|
| 239 | << string(*I, Space + 1) << endl; |
---|
| 240 | } |
---|
| 241 | } |
---|
| 242 | |
---|
| 243 | Out.close(); |
---|
| 244 | |
---|
| 245 | rename(File.c_str(), string(File + '~').c_str()); |
---|
| 246 | if (rename(NewFile.c_str(), File.c_str()) != 0) |
---|
| 247 | return _error->Errno("rename", _("Failed to rename %s.new to %s"), |
---|
| 248 | File.c_str(), File.c_str()); |
---|
| 249 | |
---|
| 250 | return true; |
---|
| 251 | } |
---|
| 252 | |
---|
| 253 | |
---|
| 254 | bool RCDScanner::start(RCDScanProgress *progress) |
---|
| 255 | { |
---|
| 256 | _cdName = ""; |
---|
| 257 | _scannedOk = false; |
---|
| 258 | |
---|
| 259 | progress->setTotal(STEP_LAST); |
---|
| 260 | progress->update(_("Preparing..."), STEP_PREPARE); |
---|
| 261 | |
---|
| 262 | // Startup |
---|
| 263 | string CDROM = _config->FindDir("Acquire::cdrom::mount", "/mnt/cdrom/"); |
---|
| 264 | if (CDROM[0] == '.') |
---|
| 265 | CDROM = SafeGetCWD() + '/' + CDROM; |
---|
| 266 | string DEVICE = _config->FindDir("Acquire::cdrom::device", "/dev/cdrom/"); |
---|
| 267 | |
---|
| 268 | if (!_database) |
---|
| 269 | _database = new Configuration(); |
---|
| 270 | |
---|
| 271 | string DFile = _config->FindFile("Dir::State::cdroms"); |
---|
| 272 | if (FileExists(DFile) == true) { |
---|
| 273 | if (ReadConfigFile(*_database, DFile) == false) { |
---|
| 274 | return _error->Error(_("Unable to read the cdrom database %s"), |
---|
| 275 | DFile.c_str()); |
---|
| 276 | } |
---|
| 277 | } |
---|
| 278 | // Unmount the CD and get the user to put in the one they want |
---|
| 279 | _cdromMounted = false; |
---|
| 280 | if (_config->FindB("APT::CDROM::NoMount", false) == false) { |
---|
| 281 | progress->update(_("Unmounting CD-ROM..."), STEP_UNMOUNT); |
---|
| 282 | UnmountCdrom(CDROM); |
---|
| 283 | |
---|
| 284 | progress->update(_("Waiting for disc..."), STEP_WAIT); |
---|
| 285 | if (_userDialog->proceed(_("Insert a disc in the drive.")) == false) |
---|
| 286 | return false; |
---|
| 287 | |
---|
| 288 | // Mount the new CDROM |
---|
| 289 | progress->update(_("Mounting CD-ROM..."), STEP_MOUNT); |
---|
| 290 | |
---|
| 291 | if (MountCdrom(CDROM, DEVICE) == false) |
---|
| 292 | return _error->Error(_("Failed to mount the cdrom.")); |
---|
| 293 | _cdromMounted = true; |
---|
| 294 | } |
---|
| 295 | |
---|
| 296 | progress->update(_("Identifying disc..."), STEP_IDENT); |
---|
| 297 | |
---|
| 298 | if (!IdentCdrom(CDROM, _cdId)) { |
---|
| 299 | return _error->Error(_("Couldn't identify disc.")); |
---|
| 300 | } |
---|
| 301 | |
---|
| 302 | progress->update(_("Scanning disc..."), STEP_SCAN); |
---|
| 303 | |
---|
| 304 | string cwd = SafeGetCWD(); |
---|
| 305 | |
---|
| 306 | _pkgList.clear(); |
---|
| 307 | _srcList.clear(); |
---|
| 308 | _infoDir = ""; |
---|
| 309 | |
---|
| 310 | if (!scanDirectory(CDROM, progress)) { |
---|
| 311 | chdir(cwd.c_str()); |
---|
| 312 | return false; |
---|
| 313 | } |
---|
| 314 | |
---|
| 315 | chdir(cwd.c_str()); |
---|
| 316 | |
---|
| 317 | progress->update(_("Cleaning package lists..."), STEP_CLEAN); |
---|
| 318 | |
---|
| 319 | cleanPkgList(_pkgList); |
---|
| 320 | cleanSrcList(_srcList); |
---|
| 321 | |
---|
| 322 | if (_pkgList.size() == 0 && _srcList.size() == 0) { |
---|
| 323 | progress->update(_("Unmounting CD-ROM..."), STEP_UNMOUNT2); |
---|
| 324 | |
---|
| 325 | if (_cdromMounted |
---|
| 326 | && _config->FindB("APT::CDROM::NoMount", false) == false) { |
---|
| 327 | UnmountCdrom(CDROM); |
---|
| 328 | _cdromMounted = false; |
---|
| 329 | } |
---|
| 330 | return _error->Error(_("Unable to locate any package files. " |
---|
| 331 | "Perhaps this is not an APT enabled disc.")); |
---|
| 332 | } |
---|
| 333 | |
---|
| 334 | _scannedOk = true; |
---|
| 335 | return true; |
---|
| 336 | } |
---|
| 337 | |
---|
| 338 | void RCDScanner::countLists(int &pkgLists, int &srcLists) |
---|
| 339 | { |
---|
| 340 | pkgLists = _pkgList.size(); |
---|
| 341 | srcLists = _srcList.size(); |
---|
| 342 | } |
---|
| 343 | |
---|
| 344 | string RCDScanner::getDiscName() |
---|
| 345 | { |
---|
| 346 | string name = ""; |
---|
| 347 | |
---|
| 348 | if (_database->Exists("CD::" + _cdId)) { |
---|
| 349 | name = _database->Find("CD::" + _cdId, ""); |
---|
| 350 | _cdOldName = name; |
---|
| 351 | } else if (!_infoDir.empty() && FileExists(_infoDir + "/info")) { |
---|
| 352 | ifstream F(string(_infoDir + "/info").c_str()); |
---|
| 353 | if (!F == 0) |
---|
| 354 | getline(F, name); |
---|
| 355 | |
---|
| 356 | if (name.empty() == false) { |
---|
| 357 | // Escape special characters |
---|
| 358 | string::iterator J = name.begin(); |
---|
| 359 | for (; J != name.end(); J++) |
---|
| 360 | if (*J == '"' || *J == ']' || *J == '[') |
---|
| 361 | *J = '_'; |
---|
| 362 | } |
---|
| 363 | } |
---|
| 364 | |
---|
| 365 | return name; |
---|
| 366 | } |
---|
| 367 | |
---|
| 368 | bool RCDScanner::setDiscName(string name) |
---|
| 369 | { |
---|
| 370 | if (name.empty() == true || |
---|
| 371 | name.find('"') != string::npos || |
---|
| 372 | name.find('[') != string::npos || name.find(']') != string::npos) |
---|
| 373 | return false; |
---|
| 374 | _cdName = name; |
---|
| 375 | return true; |
---|
| 376 | } |
---|
| 377 | |
---|
| 378 | bool RCDScanner::finish(RCDScanProgress *progress) |
---|
| 379 | { |
---|
| 380 | if (_scannedOk == false) { |
---|
| 381 | return _error->Error(_("Disc not successfully scanned.")); |
---|
| 382 | } |
---|
| 383 | |
---|
| 384 | if (_cdName.empty() == true) { |
---|
| 385 | return _error->Error(_("Empty disc name.")); |
---|
| 386 | } |
---|
| 387 | |
---|
| 388 | progress->update(_("Registering disc..."), STEP_REGISTER); |
---|
| 389 | |
---|
| 390 | if (writeDatabase() == false) { |
---|
| 391 | return false; |
---|
| 392 | } |
---|
| 393 | // Copy the package files to the state directory |
---|
| 394 | #ifdef HAVE_RPM |
---|
| 395 | RPMPackageCopy Copy; |
---|
| 396 | RPMSourceCopy SrcCopy; |
---|
| 397 | #else |
---|
| 398 | PackageCopy Copy; |
---|
| 399 | SourceCopy SrcCopy; |
---|
| 400 | #endif |
---|
| 401 | |
---|
| 402 | progress->update(_("Copying package lists..."), STEP_COPY); |
---|
| 403 | |
---|
| 404 | string CDROM = _config->FindDir("Acquire::cdrom::mount", "/cdrom/"); |
---|
| 405 | |
---|
| 406 | if (Copy.CopyPackages(CDROM, _cdName, _pkgList) == false || |
---|
| 407 | SrcCopy.CopyPackages(CDROM, _cdName, _srcList) == false) { |
---|
| 408 | return false; |
---|
| 409 | } |
---|
| 410 | |
---|
| 411 | progress->update(_("Writing sources list..."), STEP_WRITE); |
---|
| 412 | |
---|
| 413 | ReduceSourcelist(CDROM, _pkgList); |
---|
| 414 | ReduceSourcelist(CDROM, _srcList); |
---|
| 415 | |
---|
| 416 | if (!writeSourceList(_pkgList, true) |
---|
| 417 | || !writeSourceList(_srcList, false)) { |
---|
| 418 | return false; |
---|
| 419 | } |
---|
| 420 | |
---|
| 421 | if (_cdromMounted) { |
---|
| 422 | progress->update(_("Unmounting CD-ROM..."), STEP_UNMOUNT3); |
---|
| 423 | UnmountCdrom(CDROM); |
---|
| 424 | } |
---|
| 425 | |
---|
| 426 | progress->update(_("Done!"), STEP_LAST); |
---|
| 427 | |
---|
| 428 | return true; |
---|
| 429 | } |
---|
| 430 | |
---|
| 431 | void RCDScanner::unmount() |
---|
| 432 | { |
---|
| 433 | string CDROM = _config->FindDir("Acquire::cdrom::mount", "/cdrom/"); |
---|
| 434 | if (_cdromMounted) |
---|
| 435 | UnmountCdrom(CDROM); |
---|
| 436 | } |
---|
| 437 | |
---|
| 438 | // DropBinaryArch - Dump dirs with a string like /binary-<foo>/ /*{{{*/ |
---|
| 439 | // --------------------------------------------------------------------- |
---|
| 440 | /* Here we drop everything that is not this machines arch */ |
---|
| 441 | bool DropBinaryArch(vector<string> &List) |
---|
| 442 | { |
---|
| 443 | char S[300]; |
---|
| 444 | snprintf(S, sizeof(S), "/binary-%s/", |
---|
| 445 | _config->Find("Apt::Architecture").c_str()); |
---|
| 446 | |
---|
| 447 | for (unsigned int I = 0; I < List.size(); I++) { |
---|
| 448 | const char *Str = List[I].c_str(); |
---|
| 449 | |
---|
| 450 | const char *Res; |
---|
| 451 | if ((Res = strstr(Str, "/binary-")) == 0) |
---|
| 452 | continue; |
---|
| 453 | |
---|
| 454 | // Weird, remove it. |
---|
| 455 | if (strlen(Res) < strlen(S)) { |
---|
| 456 | List.erase(List.begin() + I); |
---|
| 457 | I--; |
---|
| 458 | continue; |
---|
| 459 | } |
---|
| 460 | // See if it is our arch |
---|
| 461 | if (stringcmp(Res, Res + strlen(S), S) == 0) |
---|
| 462 | continue; |
---|
| 463 | |
---|
| 464 | // Erase it |
---|
| 465 | List.erase(List.begin() + I); |
---|
| 466 | I--; |
---|
| 467 | } |
---|
| 468 | |
---|
| 469 | return true; |
---|
| 470 | } |
---|
| 471 | |
---|
| 472 | /*}}} */ |
---|
| 473 | // Score - We compute a 'score' for a path /*{{{*/ |
---|
| 474 | // --------------------------------------------------------------------- |
---|
| 475 | /* Paths are scored based on how close they come to what I consider |
---|
| 476 | normal. That is ones that have 'dist' 'stable' 'frozen' will score |
---|
| 477 | higher than ones without. */ |
---|
| 478 | int Score(string Path) |
---|
| 479 | { |
---|
| 480 | int Res = 0; |
---|
| 481 | #ifdef HAVE_RPM |
---|
| 482 | if (Path.find("base/") != string::npos) |
---|
| 483 | Res = 1; |
---|
| 484 | #else |
---|
| 485 | if (Path.find("stable/") != string::npos) |
---|
| 486 | Res += 29; |
---|
| 487 | if (Path.find("/binary-") != string::npos) |
---|
| 488 | Res += 20; |
---|
| 489 | if (Path.find("frozen/") != string::npos) |
---|
| 490 | Res += 28; |
---|
| 491 | if (Path.find("unstable/") != string::npos) |
---|
| 492 | Res += 27; |
---|
| 493 | if (Path.find("/dists/") != string::npos) |
---|
| 494 | Res += 40; |
---|
| 495 | if (Path.find("/main/") != string::npos) |
---|
| 496 | Res += 20; |
---|
| 497 | if (Path.find("/contrib/") != string::npos) |
---|
| 498 | Res += 20; |
---|
| 499 | if (Path.find("/non-free/") != string::npos) |
---|
| 500 | Res += 20; |
---|
| 501 | if (Path.find("/non-US/") != string::npos) |
---|
| 502 | Res += 20; |
---|
| 503 | if (Path.find("/source/") != string::npos) |
---|
| 504 | Res += 10; |
---|
| 505 | if (Path.find("/debian/") != string::npos) |
---|
| 506 | Res -= 10; |
---|
| 507 | #endif |
---|
| 508 | return Res; |
---|
| 509 | } |
---|
| 510 | |
---|
| 511 | /*}}} */ |
---|
| 512 | // DropRepeats - Drop repeated files resulting from symlinks /*{{{*/ |
---|
| 513 | // --------------------------------------------------------------------- |
---|
| 514 | /* Here we go and stat every file that we found and strip dup inodes. */ |
---|
| 515 | bool DropRepeats(vector<string> &List, const char *Name) |
---|
| 516 | { |
---|
| 517 | // Get a list of all the inodes |
---|
| 518 | ino_t *Inodes = new ino_t[List.size()]; |
---|
| 519 | for (unsigned int I = 0; I != List.size(); I++) { |
---|
| 520 | struct stat Buf; |
---|
| 521 | if (stat((List[I]).c_str(), &Buf) != 0 && |
---|
| 522 | stat((List[I] + Name).c_str(), &Buf) != 0 && |
---|
| 523 | stat((List[I] + Name + ".gz").c_str(), &Buf) != 0) |
---|
| 524 | _error->Errno("stat", _("Failed to stat %s%s"), List[I].c_str(), |
---|
| 525 | Name); |
---|
| 526 | Inodes[I] = Buf.st_ino; |
---|
| 527 | } |
---|
| 528 | |
---|
| 529 | if (_error->PendingError() == true) |
---|
| 530 | return false; |
---|
| 531 | |
---|
| 532 | // Look for dups |
---|
| 533 | for (unsigned int I = 0; I != List.size(); I++) { |
---|
| 534 | for (unsigned int J = I + 1; J < List.size(); J++) { |
---|
| 535 | // No match |
---|
| 536 | if (Inodes[J] != Inodes[I]) |
---|
| 537 | continue; |
---|
| 538 | |
---|
| 539 | // We score the two paths.. and erase one |
---|
| 540 | int ScoreA = Score(List[I]); |
---|
| 541 | int ScoreB = Score(List[J]); |
---|
| 542 | if (ScoreA < ScoreB) { |
---|
| 543 | List[I] = string(); |
---|
| 544 | break; |
---|
| 545 | } |
---|
| 546 | |
---|
| 547 | List[J] = string(); |
---|
| 548 | } |
---|
| 549 | } |
---|
| 550 | |
---|
| 551 | // Wipe erased entries |
---|
| 552 | for (unsigned int I = 0; I < List.size();) { |
---|
| 553 | if (List[I].empty() == false) |
---|
| 554 | I++; |
---|
| 555 | else |
---|
| 556 | List.erase(List.begin() + I); |
---|
| 557 | } |
---|
| 558 | |
---|
| 559 | return true; |
---|
| 560 | } |
---|
| 561 | |
---|
| 562 | void RCDScanner::cleanPkgList(vector<string> &list) |
---|
| 563 | { |
---|
| 564 | #ifdef HAVE_RPM |
---|
| 565 | DropRepeats(list, "pkglist"); |
---|
| 566 | #else |
---|
| 567 | DropBinaryArch(list); |
---|
| 568 | DropRepeats(list, "Packages"); |
---|
| 569 | #endif |
---|
| 570 | } |
---|
| 571 | |
---|
| 572 | void RCDScanner::cleanSrcList(vector<string> &list) |
---|
| 573 | { |
---|
| 574 | #ifdef HAVE_RPM |
---|
| 575 | DropRepeats(list, "srclist"); |
---|
| 576 | #else |
---|
| 577 | DropRepeats(list, "Sources"); |
---|
| 578 | #endif |
---|
| 579 | } |
---|
| 580 | |
---|
| 581 | string RCDScanner::pkgSourceType() const |
---|
| 582 | { |
---|
| 583 | #ifdef HAVE_RPM |
---|
| 584 | return "rpm"; |
---|
| 585 | #else |
---|
| 586 | return "deb"; |
---|
| 587 | #endif |
---|
| 588 | } |
---|
| 589 | |
---|
| 590 | string RCDScanner::srcSourceType() const |
---|
| 591 | { |
---|
| 592 | #ifdef HAVE_RPM |
---|
| 593 | return "rpm-src"; |
---|
| 594 | #else |
---|
| 595 | return "deb-src"; |
---|
| 596 | #endif |
---|
| 597 | } |
---|
| 598 | |
---|
| 599 | #if 0 |
---|
| 600 | static int strrcmp_(const char *a, const char *b) |
---|
| 601 | { |
---|
| 602 | int la = strlen(a); |
---|
| 603 | int lb = strlen(b); |
---|
| 604 | |
---|
| 605 | if (la == 0 || lb == 0) |
---|
| 606 | return 0; |
---|
| 607 | |
---|
| 608 | if (la > lb) |
---|
| 609 | return strcmp(&a[la - lb], b); |
---|
| 610 | else |
---|
| 611 | return strcmp(&b[lb - la], a); |
---|
| 612 | } |
---|
| 613 | #endif |
---|
| 614 | |
---|
| 615 | bool RCDScanner::scanDirectory(string CD, RCDScanProgress *progress, |
---|
| 616 | int Depth) |
---|
| 617 | { |
---|
| 618 | static ino_t Inodes[9]; |
---|
| 619 | if (Depth >= 7) |
---|
| 620 | return true; |
---|
| 621 | |
---|
| 622 | if (CD[CD.length() - 1] != '/') |
---|
| 623 | CD += '/'; |
---|
| 624 | |
---|
| 625 | if (chdir(CD.c_str()) != 0) |
---|
| 626 | return _error->Errno("chdir", _("Unable to change to %s"), CD.c_str()); |
---|
| 627 | |
---|
| 628 | // Look for a .disk subdirectory |
---|
| 629 | struct stat Buf; |
---|
| 630 | if (stat(".disk", &Buf) == 0) { |
---|
| 631 | if (_infoDir.empty() == true) |
---|
| 632 | _infoDir = CD + ".disk/"; |
---|
| 633 | } |
---|
| 634 | // Don't look into directories that have been marked to ingore. |
---|
| 635 | if (stat(".aptignr", &Buf) == 0) |
---|
| 636 | return true; |
---|
| 637 | |
---|
| 638 | #ifdef HAVE_RPM |
---|
| 639 | bool Found = false; |
---|
| 640 | if (stat("release", &Buf) == 0) |
---|
| 641 | Found = true; |
---|
| 642 | #else |
---|
| 643 | /* Aha! We found some package files. We assume that everything under |
---|
| 644 | this dir is controlled by those package files so we don't look down |
---|
| 645 | anymore */ |
---|
| 646 | if (stat("Packages", &Buf) == 0 || stat("Packages.gz", &Buf) == 0) { |
---|
| 647 | _pkgList.push_back(CD); |
---|
| 648 | |
---|
| 649 | // Continue down if thorough is given |
---|
| 650 | if (_config->FindB("APT::CDROM::Thorough", false) == false) |
---|
| 651 | return true; |
---|
| 652 | } |
---|
| 653 | if (stat("Sources.gz", &Buf) == 0 || stat("Sources", &Buf) == 0) { |
---|
| 654 | _srcList.push_back(CD); |
---|
| 655 | |
---|
| 656 | // Continue down if thorough is given |
---|
| 657 | if (_config->FindB("APT::CDROM::Thorough", false) == false) |
---|
| 658 | return true; |
---|
| 659 | } |
---|
| 660 | #endif |
---|
| 661 | |
---|
| 662 | DIR *D = opendir("."); |
---|
| 663 | if (D == 0) |
---|
| 664 | return _error->Errno("opendir", _("Unable to read %s"), CD.c_str()); |
---|
| 665 | |
---|
| 666 | // Run over the directory |
---|
| 667 | for (struct dirent * Dir = readdir(D); Dir != 0; Dir = readdir(D)) { |
---|
| 668 | // Skip some files.. |
---|
| 669 | if (strcmp(Dir->d_name, ".") == 0 || strcmp(Dir->d_name, "..") == 0 || |
---|
| 670 | //strcmp(Dir->d_name,"source") == 0 || |
---|
| 671 | strcmp(Dir->d_name, ".disk") == 0 || |
---|
| 672 | #ifdef HAVE_RPM |
---|
| 673 | strncmp(Dir->d_name, "RPMS", 4) == 0 || |
---|
| 674 | strncmp(Dir->d_name, "doc", 3) == 0) |
---|
| 675 | #else |
---|
| 676 | strcmp(Dir->d_name, "experimental") == 0 || |
---|
| 677 | strcmp(Dir->d_name, "binary-all") == 0) |
---|
| 678 | #endif |
---|
| 679 | continue; |
---|
| 680 | |
---|
| 681 | #ifdef HAVE_RPM |
---|
| 682 | if (strncmp(Dir->d_name, "pkglist.", 8) == 0 && |
---|
| 683 | strcmp(Dir->d_name + strlen(Dir->d_name) - 4, ".bz2") == 0) { |
---|
| 684 | _pkgList.push_back(CD + string(Dir->d_name)); |
---|
| 685 | Found = true; |
---|
| 686 | continue; |
---|
| 687 | } |
---|
| 688 | if (strncmp(Dir->d_name, "srclist.", 8) == 0 && |
---|
| 689 | strcmp(Dir->d_name + strlen(Dir->d_name) - 4, ".bz2") == 0) { |
---|
| 690 | _srcList.push_back(CD + string(Dir->d_name)); |
---|
| 691 | Found = true; |
---|
| 692 | continue; |
---|
| 693 | } |
---|
| 694 | if (_config->FindB("APT::CDROM::Thorough", false) == false && |
---|
| 695 | Found == true) |
---|
| 696 | continue; |
---|
| 697 | #endif |
---|
| 698 | |
---|
| 699 | // See if the name is a sub directory |
---|
| 700 | struct stat Buf; |
---|
| 701 | if (stat(Dir->d_name, &Buf) != 0) |
---|
| 702 | continue; |
---|
| 703 | |
---|
| 704 | if (S_ISDIR(Buf.st_mode) == 0) |
---|
| 705 | continue; |
---|
| 706 | |
---|
| 707 | int I; |
---|
| 708 | for (I = 0; I != Depth; I++) |
---|
| 709 | if (Inodes[I] == Buf.st_ino) |
---|
| 710 | break; |
---|
| 711 | if (I != Depth) |
---|
| 712 | continue; |
---|
| 713 | |
---|
| 714 | // Store the inodes weve seen |
---|
| 715 | Inodes[Depth] = Buf.st_ino; |
---|
| 716 | |
---|
| 717 | // Descend |
---|
| 718 | if (scanDirectory(CD + Dir->d_name, progress, Depth + 1) == false) |
---|
| 719 | break; |
---|
| 720 | |
---|
| 721 | if (chdir(CD.c_str()) != 0) |
---|
| 722 | return _error->Errno("chdir", _("Unable to change to %s"), |
---|
| 723 | CD.c_str()); |
---|
| 724 | } |
---|
| 725 | |
---|
| 726 | closedir(D); |
---|
| 727 | |
---|
| 728 | return !_error->PendingError(); |
---|
| 729 | } |
---|
| 730 | |
---|
| 731 | #endif |
---|
| 732 | // vim:sts=4:sw=4 |
---|