XMLFilesBackend.cc

Go to the documentation of this file.
00001 /*---------------------------------------------------------------------\
00002 |                          ____ _   __ __ ___                          |
00003 |                         |__  / \ / / . \ . \                         |
00004 |                           / / \ V /|  _/  _/                         |
00005 |                          / /__ | | | | | |                           |
00006 |                         /_____||_| |_| |_|                           |
00007 |                                                                      |
00008 \---------------------------------------------------------------------*/
00012 #include <iostream>
00013 #include <ctime>
00014 #include <cstdlib>
00015 #include <cstdio>
00016 #include <fcntl.h>
00017 
00018 #include "zypp/base/Logger.h"
00019 #include "zypp/base/Exception.h"
00020 
00021 #include "zypp/CapFactory.h"
00022 #include "zypp/Digest.h"
00023 #include "zypp/Source.h"
00024 #include "zypp/SourceManager.h"
00025 #include "zypp/ExternalProgram.h"
00026 
00027 #include "zypp/target/store/xml/XMLPatchImpl.h"
00028 #include "zypp/target/store/xml/XMLMessageImpl.h"
00029 #include "zypp/target/store/xml/XMLScriptImpl.h"
00030 #include "zypp/target/store/xml/XMLSelectionImpl.h"
00031 #include "zypp/target/store/xml/XMLProductImpl.h"
00032 #include "zypp/target/store/xml/XMLPatternImpl.h"
00033 #include "zypp/target/store/xml/XMLAtomImpl.h"
00034 
00035 #include "zypp/parser/xmlstore/XMLProductParser.h"
00036 #include "zypp/parser/xmlstore/XMLPatternParser.h"
00037 #include "zypp/parser/xmlstore/XMLPatchParser.h"
00038 #include "zypp/parser/xmlstore/XMLLanguageParser.h"
00039 
00040 #include <iostream>
00041 #include <fstream>
00042 #include <sstream>
00043 #include <streambuf>
00044 
00045 #include <list>
00046 
00047 #include <zypp/TmpPath.h>
00048 #include <zypp/ZYppFactory.h>
00049 #include <zypp/ZYpp.h>
00050 #include <zypp/PathInfo.h>
00051 
00052 #include "zypp/parser/xmlstore/XMLSourceCacheParser.h"
00053 
00054 #include "boost/filesystem/operations.hpp" // includes boost/filesystem/path.hpp
00055 #include "boost/filesystem/fstream.hpp"    // ditto
00056 
00057 #include "XMLFilesBackend.h"
00058 #include "serialize.h"
00059 
00060 //#define ZYPP_DB_DIR "/var/lib/zypp_db/"
00061 #define ZYPP_DB_DIR ( getZYpp()->homePath().asString()+"/db/" )
00062 
00063 using std::endl;
00064 using namespace boost::filesystem;
00065 using namespace zypp;
00066 using namespace zypp::filesystem;
00067 
00069 namespace zypp
00070 { 
00071 namespace storage
00072 { 
00073 
00074 
00076 //
00077 //      CLASS NAME : XMLFilesBackend::Private
00078 //
00080 class XMLFilesBackend::Private
00081 {
00082   public:
00083   Private()
00084   { }
00085   bool randomFileName;
00086   std::set<Resolvable::Kind> kinds;
00087   std::set<Resolvable::Kind> kinds_flags;
00088   Pathname root;
00089 };
00090 
00092 //
00093 //      CLASS NAME : XMLFilesBackend
00094 //
00096 
00098 //
00099 //      METHOD NAME : XMLFilesBackend::XMLFilesBackend
00100 //      METHOD TYPE : Ctor
00101 //
00102 XMLFilesBackend::XMLFilesBackend(const Pathname &root) : Backend(root)
00103 {
00104   d = new Private;
00105   d->randomFileName = false;
00106   d->root = root;
00107 
00108   // types of resolvables stored (supported)
00109   d->kinds.insert(ResTraits<zypp::Patch>::kind);
00110   //d->kinds.insert(ResTraits<zypp::Message>::kind);
00111   //d->kinds.insert(ResTraits<zypp::Script>::kind);
00112   d->kinds.insert(ResTraits<zypp::Selection>::kind);
00113   d->kinds.insert(ResTraits<zypp::Product>::kind);
00114   d->kinds.insert(ResTraits<zypp::Pattern>::kind);
00115   d->kinds.insert(ResTraits<zypp::Language>::kind);
00116 
00117   // types of resolvables stored (supported)
00118   d->kinds_flags.insert(ResTraits<zypp::Package>::kind);
00119   d->kinds_flags.insert(ResTraits<zypp::Patch>::kind);
00120   //d->kinds.insert(ResTraits<zypp::Message>::kind);
00121   //d->kinds.insert(ResTraits<zypp::Script>::kind);
00122   d->kinds_flags.insert(ResTraits<zypp::Selection>::kind);
00123   d->kinds_flags.insert(ResTraits<zypp::Product>::kind);
00124   d->kinds_flags.insert(ResTraits<zypp::Pattern>::kind);
00125   d->kinds_flags.insert(ResTraits<zypp::Language>::kind);
00126 
00127 
00128   // check if the db exists
00129   if (!isBackendInitialized())
00130   {
00131     DBG << "Database not initialized" << std::endl;
00132     initBackend();
00133     // should be initialized now...
00134     if (!isBackendInitialized())
00135       DBG << "Error, cant init database" << std::endl;
00136     else
00137       DBG << "Database initialized" << std::endl;
00138    }
00139    else
00140    {
00141      DBG << "Database already initialized" << std::endl;
00142    }
00143 }
00144 
00145 // Taken from KApplication
00146 int XMLFilesBackend::random() const
00147 {
00148    static bool init = false;
00149    if (!init)
00150    {
00151       unsigned int seed;
00152       init = true;
00153       int fd = open("/dev/urandom", O_RDONLY);
00154       if (fd < 0 || ::read(fd, &seed, sizeof(seed)) != sizeof(seed))
00155       {
00156             // No /dev/urandom... try something else.
00157             srand(getpid());
00158             seed = rand()+time(0);
00159       }
00160       if (fd >= 0) close(fd);
00161       srand(seed);
00162    }
00163    return rand();
00164 }
00165 
00166 // Taken from KApplication
00167 std::string XMLFilesBackend::randomString(int length) const
00168 {
00169    if (length <=0 ) return std::string();
00170 
00171    std::string str; str.resize( length );
00172    int i = 0;
00173    while (length--)
00174    {
00175       int r=random() % 62;
00176       r+=48;
00177       if (r>57) r+=7;
00178       if (r>90) r+=6;
00179       str[i++] =  char(r);
00180       // so what if I work backwards?
00181    }
00182    return str;
00183 }
00184 
00185 bool
00186 XMLFilesBackend::isBackendInitialized() const
00187 {
00188   bool ok = true;
00189   Pathname dbdir = d->root +  ZYPP_DB_DIR;
00190   ok = ok && PathInfo(dbdir).isExist();
00191 
00192   bool fixperms = false;
00193   
00194   // The db dir was created with 700 permissions
00195   // see bug #169094
00196   if ( ok && PathInfo(dbdir).perm() == 0700 )
00197   {
00198     if ( geteuid() == 0 )
00199     {
00200       fixperms = true;
00201       WAR << "Wrong permissions for /var/lib/zypp, will fix" << std::endl;
00202       
00203       const char* argv[] =
00204       {
00205         "chmod",
00206         "-R",
00207         "0755",
00208         "/var/lib/zypp",
00209         NULL
00210       };
00211       
00212       ExternalProgram prog(argv,ExternalProgram::Discard_Stderr, false, -1, true);
00213       prog.close();    
00214     }
00215     else
00216     {
00217       WAR << "Wrong permissions for /var/lib/zypp, but can't fix unless you run as root." << std::endl;
00218     }
00219     
00220   }
00221     
00222   // folders for resolvables
00223   std::set<Resolvable::Kind>::const_iterator it_kinds;
00224   for ( it_kinds = d->kinds.begin() ; it_kinds != d->kinds.end(); ++it_kinds )
00225   {
00226     Resolvable::Kind kind = (*it_kinds);
00227     bool isthere = exists(dirForResolvableKind(kind));
00228     ok = ok && isthere;
00229   }
00230 
00231   // resolvable flags folder flags
00232   for ( it_kinds = d->kinds_flags.begin() ; it_kinds != d->kinds_flags.end(); ++it_kinds )
00233   {
00234     Resolvable::Kind kind = (*it_kinds);
00235     bool isthere = exists(dirForResolvableKindFlags(kind));
00236     ok = ok && isthere;
00237   }
00238 
00239   // named flags
00240   bool nmthere = exists(dirForNamedFlags());
00241   ok = ok && nmthere;
00242     
00243   Pathname sourcesdir = d->root + ZYPP_DB_DIR + "/sources";
00244   bool srcthere = PathInfo(sourcesdir).isExist();
00245   ok = ok && srcthere;
00246   
00247   if (srcthere && fixperms)
00248   {
00249     MIL << "Making " << sourcesdir << " not readable by others (0700)" << std::endl;
00250     filesystem::chmod( sourcesdir, 0700);
00251   }
00252   
00253   return ok;
00254 }
00255 
00256 void
00257 XMLFilesBackend::initBackend()
00258 {
00259   // all directories are 755 except the sources directory which can contain passwords
00260   // in urls.
00261   
00262   Pathname topdir = d->root + Pathname(ZYPP_DB_DIR);
00263   DBG << "Creating directory structure " << topdir << std::endl;
00264 
00265   if (0 != assert_dir(topdir, 0755))
00266       ZYPP_THROW(Exception("Cannot create XMLBackend db directory " + topdir.asString()));
00267 
00268   // create dir for resolvables
00269   std::set<Resolvable::Kind>::const_iterator it_kinds;
00270   for ( it_kinds = d->kinds.begin() ; it_kinds != d->kinds.end(); ++it_kinds )
00271   {
00272     Resolvable::Kind kind = (*it_kinds);
00273     Pathname p(dirForResolvableKind(kind));
00274     if (0 != assert_dir(p, 0755))
00275       ZYPP_THROW(Exception("Cannot create directory " + p.asString()));
00276     else
00277       MIL << "Created " << p.asString() << std::endl;
00278   }
00279 
00280   // create dir for resolvables flags
00281   for ( it_kinds = d->kinds_flags.begin() ; it_kinds != d->kinds_flags.end(); ++it_kinds )
00282   {
00283     Resolvable::Kind kind = (*it_kinds);
00284     Pathname p(dirForResolvableKindFlags(kind));
00285     if (0 != assert_dir(p, 0755))
00286       ZYPP_THROW(Exception("Cannot create directory " + p.asString()));
00287     else
00288       MIL << "Created " << p.asString() << std::endl;
00289   }
00290 
00291   // dir for named flags
00292   Pathname namedflags(dirForNamedFlags());
00293   if (0 != assert_dir(namedflags, 0755))
00294     ZYPP_THROW(Exception("Cannot create directory " + namedflags.asString()));
00295   else
00296     MIL << "Created " << namedflags.asString() << std::endl;
00297 
00298   // create dir for source list
00299   Pathname source_p = d->root + Pathname(ZYPP_DB_DIR) + Pathname("/sources/");
00300   if (0 != assert_dir(source_p, 0700))
00301     ZYPP_THROW(Exception("Cannot create directory " + source_p.asString()));
00302   else
00303     MIL << "Created " << source_p.asString() << std::endl;
00304 }
00305 
00306 void XMLFilesBackend::setRandomFileNameEnabled( bool enabled )
00307 {
00308   d->randomFileName = enabled;
00309 }
00310 
00311 std::string
00312 XMLFilesBackend::dirForResolvableKind( Resolvable::Kind kind ) const
00313 {
00314   std::string dir;
00315   dir += Pathname( d->root + Pathname(ZYPP_DB_DIR) + Pathname(resolvableKindToString(kind, true)) ).asString();
00316   return dir;
00317 }
00318 
00319 std::string
00320 XMLFilesBackend::dirForResolvableKindFlags( Resolvable::Kind kind ) const
00321 {
00322   std::string dir;
00323   dir += Pathname( d->root + Pathname(ZYPP_DB_DIR) + Pathname("flags") + Pathname(resolvableKindToString(kind, true)) ).asString();
00324   return dir;
00325 }
00326 
00327 std::string
00328 XMLFilesBackend::dirForNamedFlags() const
00329 {
00330   std::string dir;
00331   dir += Pathname( d->root + Pathname(ZYPP_DB_DIR) + Pathname("named-flags")).asString();
00332   return dir;
00333 }
00334 
00335 std::string
00336 XMLFilesBackend::dirForResolvable( ResObject::constPtr resolvable ) const
00337 {
00338   return dirForResolvableKind(resolvable->kind());
00339 }
00340 
00341 std::string
00342 XMLFilesBackend::dirForResolvableFlags( ResObject::constPtr resolvable ) const
00343 {
00344   return dirForResolvableKindFlags(resolvable->kind());
00345 }
00346 
00347 std::string
00348 XMLFilesBackend::fileNameForResolvable( ResObject::constPtr resolvable ) const
00349 {
00350   std::string filename;
00351   //filename = d->randomFileName ? randomString(40) : (resolvable->name() + suffix);
00352   filename = resolvable->name();
00353   if (resolvable->edition() != Edition::noedition )
00354   {
00355      filename += "-" + resolvable->edition().asString();
00356   }
00357   // get rid of spaces and other characters
00358   std::stringstream filename_stream(filename);
00359   std::string filename_encoded = Digest::digest("MD5", filename_stream);
00360   return filename_encoded;
00361 }
00362 
00363 std::string
00364 XMLFilesBackend::fullPathForResolvable( ResObject::constPtr resolvable ) const
00365 {
00366   return path( path(dirForResolvable(resolvable)) / path(fileNameForResolvable(resolvable))).string();
00367 }
00368 
00369 std::string
00370 XMLFilesBackend::fullPathForNamedFlags( const std::string &key ) const
00371 {
00372   std::stringstream key_stream(key);
00373   std::string key_encoded = Digest::digest("MD5", key_stream);
00374   return path( path(dirForNamedFlags()) / path(key_encoded)).string();
00375 }
00376 
00377 std::string
00378 XMLFilesBackend::fullPathForResolvableFlags( ResObject::constPtr resolvable ) const
00379 {
00380   // flags are in a hidden file with the same name
00381   return path( path(dirForResolvableFlags(resolvable)) / path(fileNameForResolvable(resolvable))).string();
00382 }
00383 
00384 void
00385 XMLFilesBackend::setObjectFlag( ResObject::constPtr resolvable, const std::string &flag )
00386 {
00387   std::set<std::string> flags = objectFlags(resolvable);
00388   flags.insert(flag);
00389   writeObjectFlags(resolvable, flags);
00390 }
00391 
00392 void
00393 XMLFilesBackend::removeObjectFlag( ResObject::constPtr resolvable, const std::string &flag )
00394 {
00395   std::set<std::string> flags = objectFlags(resolvable);
00396   flags.erase(flag);
00397   writeObjectFlags(resolvable, flags);
00398 }
00399 
00400 void
00401 XMLFilesBackend::writeObjectFlags( ResObject::constPtr resolvable, const std::set<std::string> &flags )
00402 {
00403   std::string filename = fullPathForResolvableFlags(resolvable);
00404   writeFlagsInFile( filename, flags );
00405   MIL << "Wrote " << flags.size() << " flags for " << resolvable->name() << " " << resolvable->edition() << std::endl;
00406 }
00407 
00408 std::set<std::string>
00409 XMLFilesBackend::objectFlags( ResObject::constPtr resolvable ) const
00410 {
00411   std::string filename = fullPathForResolvableFlags(resolvable);
00412   return flagsFromFile(filename);
00413 }
00414 
00415 bool
00416 XMLFilesBackend::doesObjectHasFlag( ResObject::constPtr resolvable, const std::string &flag ) const
00417 {
00418   std::set<std::string> flags = objectFlags(resolvable);
00419   return (find(flags.begin(), flags.end(), flag) != flags.end());
00420 }
00421 
00423 // Named Flags API
00425 
00426 void
00427 XMLFilesBackend::setFlag( const std::string &key, const std::string &flag )
00428 {
00429   std::set<std::string> _flags = flags(key);
00430   _flags.insert(flag);
00431   writeFlags(key, _flags);
00432 }
00433 
00434 void
00435 XMLFilesBackend::removeFlag( const std::string &key, const std::string &flag )
00436 {
00437   std::set<std::string> _flags = flags(key);
00438   _flags.erase(flag);
00439   writeFlags(key, _flags);
00440 }
00441 
00442 std::set<std::string>
00443 XMLFilesBackend::flags( const std::string &key ) const
00444 {
00445   std::string filename = fullPathForNamedFlags(key);
00446   return flagsFromFile(filename);
00447 }
00448 
00449 bool
00450 XMLFilesBackend::hasFlag( const std::string &key, const std::string &flag ) const
00451 {
00452   std::set<std::string> _flags = flags(key);
00453   return (find(_flags.begin(), _flags.end(), flag) != _flags.end());
00454 }
00455 
00456 void
00457 XMLFilesBackend::writeFlags( const std::string &key, const std::set<std::string> &pflags )
00458 {
00459   std::string filename = fullPathForNamedFlags(key);
00460   writeFlagsInFile( filename, pflags );
00461   MIL << "Wrote " << pflags.size() << " flags for " << key << std::endl;
00462 }
00463 
00465 // Common functions for both named and resolvable flags
00467 
00468 void
00469 XMLFilesBackend::writeFlagsInFile( const std::string &filename, const std::set<std::string> &pflags )
00470 {
00471   std::ofstream file(filename.c_str());
00472   if (!file) {
00473     ZYPP_THROW (Exception( "Can't open " + filename ) );
00474   }
00475 
00476   try
00477   {
00478     for ( std::set<std::string>::const_iterator it = pflags.begin(); it != pflags.end(); it++)
00479     {
00480       // dont save empty strings
00481       if ( *it == std::string() )
00482         continue;
00483       else
00484         file << *it << std::endl;
00485     }
00486     file << std::endl;
00487     MIL << "Wrote " << pflags.size() << " flags in " << filename << std::endl;
00488   }
00489   catch( std::exception &e )
00490   {
00491     //ZYPP_RETHROW(e);
00492   }
00493 }
00494 
00495 std::set<std::string>
00496 XMLFilesBackend::flagsFromFile( const std::string &filename ) const
00497 {
00498   std::set<std::string> _flags;
00499   // do we have previous saved flags?
00500   if (!exists(path(filename)))
00501     return _flags;
00502 
00503   std::ifstream file(filename.c_str());
00504   if (!file) {
00505     ZYPP_THROW (Exception( "Can't open " + filename ) );
00506   }
00507 
00508   std::string buffer;
00509   while(file && !file.eof())
00510   {
00511     getline(file, buffer);
00512     if (buffer == std::string())
00513       continue;
00514 
00515     _flags.insert(buffer);
00516   }
00517   //MIL << "Read " << flags.size() << " flags for " << resolvable->name() << " " << resolvable->edition() << std::endl;
00518   return _flags;
00519 }
00520 
00522 // Resolvables storage
00524 
00525 void
00526 XMLFilesBackend::storeObject( ResObject::constPtr resolvable )
00527 {
00528   // only ignore if it is not a supported resolvable kind
00529   std::set<Resolvable::Kind>::const_iterator it;
00530   it = find(d->kinds.begin(), d->kinds.end(), resolvable->kind() );
00531   if (it == d->kinds.end())
00532   {
00533     ERR << "This backend was not designed to store resolvable of kind " << resolvableKindToString(resolvable->kind()) << ", ignoring..." << std::endl;
00534     return;
00535   }
00536 
00537   std::string xml = castedToXML(resolvable);
00538   std::string filename = fullPathForResolvable(resolvable);
00539   //DBG << std::endl << xml << std::endl;
00540   std::ofstream file;
00541   //DBG << filename << std::endl;
00542   try
00543   {
00544     file.open(filename.c_str());
00545     file << xml;
00546     file.close();
00547   }
00548   catch(std::exception &e)
00549   {
00550     ERR << "Error saving resolvable " << resolvable << std::endl;
00551     ZYPP_THROW(Exception(e.what()));
00552   }
00553 }
00554 
00555 void
00556 XMLFilesBackend::deleteObject( ResObject::constPtr resolvable )
00557 {
00558   // only remove the file
00559   std::string filename = fullPathForResolvable(resolvable);
00560   try
00561   {
00562     int ret = filesystem::unlink(Pathname(filename));
00563     if ( ret != 0 )
00564     {
00565       ERR << "Error removing resolvable " << resolvable << std::endl;
00566       ZYPP_THROW(Exception("Error deleting " + filename));
00567     }
00568   }
00569   catch(std::exception &e)
00570   {
00571     ERR << "Error removing resolvable " << resolvable << std::endl;
00572     ZYPP_THROW(Exception(e.what()));
00573   }
00574 }
00575 
00576 std::list<ResObject::Ptr> XMLFilesBackend::resolvablesFromFile( std::string file_path, Resolvable::Kind kind ) const
00577 {
00578   MIL << "[" << resolvableKindToString( kind, false ) << "] - " << file_path << std::endl;
00579   std::list<ResObject::Ptr> resolvables;
00580   std::ifstream res_file(file_path.c_str());
00581   if ( kind == ResTraits<zypp::Patch>::kind )
00582   {
00583     // a patch file can contain more than one patch, but we store only
00584     // one patch, so we break at the first
00585     // FIXME how can we avoid creating this for every object?
00586     try {
00587     XMLPatchParser iter(res_file,"");
00588     for (; !iter.atEnd(); ++iter)
00589     {
00590       Patch::Ptr patch = createPatch(**iter);
00591       resolvables.push_back(patch);
00592       Patch::AtomList atoms = patch->atoms();
00593       for (Patch::AtomList::iterator at = atoms.begin(); at != atoms.end(); at++)
00594         resolvables.push_back(*at);
00595 
00596       break;
00597     }
00598     }
00599     catch (const Exception & excpt_r) {
00600         ZYPP_CAUGHT( excpt_r );
00601         WAR << "Skipping invalid patch file " << file_path << endl;
00602     }
00603   }
00604   else if ( kind == ResTraits<zypp::Product>::kind )
00605   {
00606     XMLProductParser iter(res_file,"");
00607     for (; !iter.atEnd(); ++iter)
00608     {
00609       resolvables.push_back(createProduct(**iter));
00610       break;
00611     }
00612   }
00613   else if ( kind == ResTraits<zypp::Selection>::kind )
00614   {
00615     XMLPatternParser iter(res_file,"");
00616     for (; !iter.atEnd(); ++iter)
00617     {
00618       resolvables.push_back(createSelection(**iter));
00619       break;
00620     }
00621   }
00622   else if ( kind == ResTraits<zypp::Pattern>::kind )
00623   {
00624     XMLPatternParser iter(res_file,"");
00625     for (; !iter.atEnd(); ++iter)
00626     {
00627       resolvables.push_back(createPattern(**iter));
00628       break;
00629     }
00630   }
00631   else if ( kind == ResTraits<zypp::Language>::kind )
00632   {
00633     XMLLanguageParser iter(res_file,"");
00634     for (; !iter.atEnd(); ++iter)
00635     {
00636       resolvables.push_back(createLanguage(**iter));
00637       break;
00638     }
00639   }
00640   else
00641   {
00642     /* nothing for now */
00643   }
00644   return resolvables;
00645 }
00646 
00647 std::list<ResObject::Ptr>
00648 XMLFilesBackend::storedObjects() const
00649 {
00650   DBG << std::endl;
00651   std::list<ResObject::Ptr> objects;
00652 
00653   std::set<Resolvable::Kind>::const_iterator it_kinds;
00654   for ( it_kinds = d->kinds.begin() ; it_kinds != d->kinds.end(); ++it_kinds )
00655   {
00656     Resolvable::Kind kind = (*it_kinds);
00657     std::list<ResObject::Ptr> objects_for_kind = storedObjects(kind);
00658     std::list<ResObject::Ptr>::iterator it;
00659     for( it = objects_for_kind.begin(); it != objects_for_kind.end(); ++it)
00660     {
00661       //DBG << "adding objects back" << std::endl;
00662       objects.push_back(*it);
00663     }
00664   }
00665   return objects;
00666 }
00667 
00668 std::list<ResObject::Ptr>
00669 XMLFilesBackend::storedObjects(const Resolvable::Kind kind) const
00670 {
00671   std::list<ResObject::Ptr> objects;
00672   std::string dir_path = dirForResolvableKind(kind);
00673   DBG << "Reading objects of kind " << resolvableKindToString(kind) << " in " << dir_path << std::endl;
00674   directory_iterator end_iter;
00675   // return empty list if the dir does not exist
00676   if ( !exists( dir_path ) )
00677   {
00678     ERR << "path " << dir_path << " does not exists. Required to read objects of kind " << resolvableKindToString(kind) << std::endl;
00679     return std::list<ResObject::Ptr>();
00680   }
00681 
00682   for ( directory_iterator dir_itr( dir_path ); dir_itr != end_iter; ++dir_itr )
00683   {
00684     DBG << "[" << resolvableKindToString( kind, false ) << "] - " << dir_itr->leaf() << std::endl;
00685     std::list<ResObject::Ptr> objects_for_file;
00686     objects_for_file = resolvablesFromFile( dir_path + "/" + dir_itr->leaf(), kind);
00687     for ( std::list<ResObject::Ptr>::iterator it = objects_for_file.begin(); it != objects_for_file.end(); ++it)
00688       objects.push_back(*it);
00689   }
00690   MIL << "done reading " <<  objects.size() << " stored objects for file of kind " << resolvableKindToString(kind) << std::endl;
00691   return objects;
00692 }
00693 
00694 std::list<ResObject::Ptr>
00695 XMLFilesBackend::storedObjects(const Resolvable::Kind kind, const std::string & name, bool partial_match) const
00696 {
00697   std::list<ResObject::Ptr> result;
00698   std::list<ResObject::Ptr> all;
00699   all = storedObjects(kind);
00700   std::list<ResObject::Ptr>::const_iterator it;
00701   for( it = all.begin(); it != all.end(); ++it)
00702   {
00703     ResObject::Ptr item = *it;
00704     if (item->name() == name )
00705       result.push_back(item);
00706   }
00707   MIL << "done reading stored objects of kind " << resolvableKindToString(kind) << " and keyword [" << name <<"]" << std::endl;
00708   return result;
00709 }
00710 
00711 Patch::Ptr
00712 XMLFilesBackend::createPatch( const zypp::parser::xmlstore::XMLPatchData & parsed ) const
00713 {
00714   try
00715   {
00716     detail::ResImplTraits<XMLPatchImpl>::Ptr impl(new XMLPatchImpl());
00717     impl->_patch_id = parsed.patchId;
00718     impl->_timestamp = str::strtonum<time_t>(parsed.timestamp);
00719     impl->_category = parsed.category;
00720     impl->_reboot_needed = parsed.rebootNeeded;
00721     impl->_affects_pkg_manager = parsed.packageManager;
00722     // impl._atoms -> std::list<shared_ptr<YUMPatchAtom> > parsed.atoms */
00723 
00724     impl->_summary = parsed.summary;
00725     impl->_description = parsed.summary;
00726 
00727     impl->_install_notify = parsed.install_notify;
00728     impl->_delete_notify = parsed.delete_notify;
00729     impl->_license_to_confirm = parsed.license_to_confirm;
00730     impl->_size = parsed.size;
00731     impl->_archive_size = parsed.archive_size;
00732     impl->_install_only = parsed.install_only;
00733     impl->_build_time = parsed.build_time;
00734     impl->_install_time = parsed.install_time;
00735     
00736     Arch arch;
00737     if (!parsed.arch.empty())
00738       arch = Arch(parsed.arch);
00739     
00740     // Collect basic Resolvable data
00741     NVRAD dataCollect( parsed.name,
00742                        Edition( parsed.ver, parsed.rel, parsed.epoch ), arch,
00743                        createDependencies(parsed, ResTraits<Patch>::kind) );
00744     Patch::Ptr patch = detail::makeResolvableFromImpl( dataCollect, impl );
00745     CapFactory _f;
00746 
00747     //MIL << parsed.atoms.size() << " to process" << std::endl;
00748 
00749     // now process the atoms
00750     ResObject::Ptr atom;
00751     for (std::list<XMLPatchAtomData_Ptr >::const_iterator it = parsed.atoms.begin(); it != parsed.atoms.end(); it++)
00752     {
00753       switch ((*it)->atomType())
00754       {
00755         case XMLPatchAtomData::Atom:
00756         {
00757           // atoms are mostly used for packages
00758           // we dont create a package resolvable and then add it to the atoms list, because we
00759           // dont know if the package is in the pool or not. It is different to Scripts and Messages
00760           // that are actually contributed to the Patch itself, instead we create and atom, make
00761           // the patch require the atom, the atom require and freshens the package.
00762 
00763           // get the parsed patch atom data
00764           XMLPatchAtomData_Ptr atom_data = dynamic_pointer_cast<XMLPatchAtomData>(*it);
00765           atom = createAtom(*atom_data);
00766           impl->_atoms.push_back(atom);
00767           break;
00768         }
00769         case XMLPatchAtomData::Message:
00770         {
00771           XMLPatchMessageData_Ptr message_data = dynamic_pointer_cast<XMLPatchMessageData>(*it);
00772           atom = createMessage(*message_data);
00773           impl->_atoms.push_back(atom);
00774           break;
00775         }
00776         case XMLPatchAtomData::Script:
00777         {
00778           XMLPatchScriptData_Ptr script_data = dynamic_pointer_cast<XMLPatchScriptData>(*it);
00779           atom = createScript(*script_data);
00780           impl->_atoms.push_back(atom);
00781           break;
00782         }
00783         default:
00784           ERR << "Unknown type of atom" << endl;
00785       }
00786       // the patch should depends on its atoms, so we inject a requires on the just created atom resolvable
00787       Capability cap( _f.parse(atom->kind(), atom->name(), Rel::EQ, atom->edition() ));
00788       patch->injectRequires(cap);
00789     }
00790     return patch;
00791   }
00792   catch (const Exception & excpt_r)
00793   {
00794     ZYPP_CAUGHT(excpt_r);
00795     ZYPP_THROW(Exception("Cannot create patch object"));
00796   }
00797   return 0L;
00798 }
00799 
00800 Atom::Ptr
00801 XMLFilesBackend::createAtom( const zypp::parser::xmlstore::XMLPatchAtomData & parsed ) const
00802 {
00803   try
00804   {
00805     detail::ResImplTraits<XMLAtomImpl>::Ptr impl(new XMLAtomImpl());
00806 
00807     Arch arch;
00808     if (!parsed.arch.empty())
00809       arch = Arch(parsed.arch);
00810     
00811     // Collect basic Resolvable data
00812     NVRAD dataCollect( parsed.name, Edition( parsed.ver, parsed.rel, parsed.epoch ), arch, createDependencies(parsed, ResTraits<Atom>::kind) );
00813     
00814     impl->_summary = parsed.summary;
00815     impl->_description = parsed.summary;
00816 
00817     impl->_install_notify = parsed.install_notify;
00818     impl->_delete_notify = parsed.delete_notify;
00819     impl->_license_to_confirm = parsed.license_to_confirm;
00820     impl->_size = parsed.size;
00821     impl->_archive_size = parsed.archive_size;
00822     impl->_install_only = parsed.install_only;
00823     impl->_build_time = parsed.build_time;
00824     impl->_install_time = parsed.install_time;
00825     
00826     Atom::Ptr atom = detail::makeResolvableFromImpl( dataCollect, impl);
00827     return atom;
00828   }
00829   catch (const Exception & excpt_r)
00830   {
00831     ZYPP_CAUGHT(excpt_r);
00832     ZYPP_THROW(Exception("Cannot create atom object"));
00833   }
00834   return 0L;
00835 }
00836 
00837 Message::Ptr
00838 XMLFilesBackend::createMessage( const zypp::parser::xmlstore::XMLPatchMessageData & parsed ) const
00839 {
00840   try
00841   {
00842     detail::ResImplTraits<XMLMessageImpl>::Ptr impl(new XMLMessageImpl());
00843     impl->_text = parsed.text;
00844 
00845     Arch arch;
00846     if (!parsed.arch.empty())
00847       arch = Arch(parsed.arch);
00848     
00849     impl->_summary = parsed.summary;
00850     impl->_description = parsed.summary;
00851 
00852     impl->_install_notify = parsed.install_notify;
00853     impl->_delete_notify = parsed.delete_notify;
00854     impl->_license_to_confirm = parsed.license_to_confirm;
00855     impl->_size = parsed.size;
00856     impl->_archive_size = parsed.archive_size;
00857     impl->_install_only = parsed.install_only;
00858     impl->_build_time = parsed.build_time;
00859     impl->_install_time = parsed.install_time;
00860     
00861     // Collect basic Resolvable data
00862     NVRAD dataCollect( parsed.name, Edition( parsed.ver, parsed.rel, parsed.epoch ), arch, createDependencies(parsed, ResTraits<Message>::kind) );
00863     Message::Ptr message = detail::makeResolvableFromImpl( dataCollect, impl);
00864     return message;
00865   }
00866   catch (const Exception & excpt_r)
00867   {
00868     ZYPP_CAUGHT(excpt_r);
00869     ZYPP_THROW(Exception("Cannot create message object"));
00870   }
00871   return 0L;
00872 }
00873 
00874 Script::Ptr
00875 XMLFilesBackend::createScript(const zypp::parser::xmlstore::XMLPatchScriptData & parsed ) const
00876 {
00877   try
00878   {
00879     detail::ResImplTraits<XMLScriptImpl>::Ptr impl(new XMLScriptImpl());
00880 
00881     ofstream file;
00882     file.open(impl->_do_script->path().asString().c_str());
00883 
00884     if ( ! file )
00885       ZYPP_THROW(Exception(N_("Can't write the patch script to a temporary file.")));
00886 
00887     file << parsed.do_script;;
00888     file.close();
00889 
00890     file.open(impl->_undo_script->path().asString().c_str());
00891     if ( ! file )
00892       ZYPP_THROW(Exception(N_("Can't write the patch script to a temporary file.")));
00893 
00894     file << parsed.undo_script;;
00895     file.close();
00896 
00897     Arch arch;
00898     if (!parsed.arch.empty())
00899       arch = Arch(parsed.arch);
00900     
00901     impl->_summary = parsed.summary;
00902     impl->_description = parsed.summary;
00903 
00904     impl->_install_notify = parsed.install_notify;
00905     impl->_delete_notify = parsed.delete_notify;
00906     impl->_license_to_confirm = parsed.license_to_confirm;
00907     impl->_size = parsed.size;
00908     impl->_archive_size = parsed.archive_size;
00909     impl->_install_only = parsed.install_only;
00910     impl->_build_time = parsed.build_time;
00911     impl->_install_time = parsed.install_time;
00912     
00913     // Collect basic Resolvable data
00914     NVRAD dataCollect( parsed.name, Edition( parsed.ver, parsed.rel, parsed.epoch ), arch, createDependencies(parsed, ResTraits<Script>::kind));
00915     Script::Ptr script = detail::makeResolvableFromImpl( dataCollect, impl );
00916     return script;
00917   }
00918   catch (const Exception & excpt_r)
00919   {
00920     ZYPP_CAUGHT(excpt_r);
00921     ZYPP_THROW(Exception("Cannot create script object"));
00922   }
00923   catch (const std::exception & excpt_r)
00924   {
00925     ERR << excpt_r.what() << endl;
00926     ZYPP_THROW(Exception("Cannot create script object"));
00927   }
00928   return 0L;
00929 }
00930 
00931 Language::Ptr
00932 XMLFilesBackend::createLanguage( const zypp::parser::xmlstore::XMLLanguageData & parsed ) const
00933 {
00934   try
00935   {
00936     return Language::installedInstance( Locale(parsed.name) );
00937   }
00938   catch (const Exception & excpt_r)
00939   {
00940     ZYPP_CAUGHT(excpt_r);
00941     ZYPP_THROW(Exception("Cannot create language object"));
00942   }
00943   return 0L;
00944 }
00945 
00946 
00947 Product::Ptr
00948 XMLFilesBackend::createProduct( const zypp::parser::xmlstore::XMLProductData & parsed ) const
00949 {
00950   try
00951   {
00952     detail::ResImplTraits<XMLProductImpl>::Ptr impl(new XMLProductImpl());
00953 
00954     impl->_summary = parsed.summary;
00955     impl->_description = parsed.summary;
00956 
00957     impl->_install_notify = parsed.install_notify;
00958     impl->_delete_notify = parsed.delete_notify;
00959     impl->_license_to_confirm = parsed.license_to_confirm;
00960     impl->_size = parsed.size;
00961     impl->_archive_size = parsed.archive_size;
00962     impl->_install_only = parsed.install_only;
00963     impl->_build_time = parsed.build_time;
00964     impl->_install_time = parsed.install_time;
00965     
00966     impl->_category = parsed.type;
00967     impl->_short_name = parsed.short_name;
00968 
00969     if ( parsed.releasenotesurl.size() > 0 )
00970       impl->_release_notes_url = parsed.releasenotesurl;
00971     else
00972       impl->_release_notes_url = Url();
00973 
00974     // update_urls
00975     std::list<std::string>::const_iterator
00976         b = parsed.update_urls.begin(),
00977         e = parsed.update_urls.end(),
00978         i;
00979     for (i = b; i != e; ++i) {
00980         Url u;
00981         try {
00982             u = *i;
00983         }
00984         catch (...) {
00985         }
00986         impl->_update_urls.push_back (u);
00987     }
00988 
00989     impl->_flags = parsed.flags;
00990 
00991     Arch arch;
00992     if (!parsed.arch.empty())
00993       arch = Arch(parsed.arch);
00994 
00995     // Collect basic Resolvable data
00996     NVRAD dataCollect( parsed.name, Edition( parsed.ver, parsed.rel, parsed.epoch ), arch, createDependencies(parsed, ResTraits<Product>::kind) );
00997     Product::Ptr product = detail::makeResolvableFromImpl( dataCollect, impl );
00998     return product;
00999   }
01000   catch (const Exception & excpt_r)
01001   {
01002     ZYPP_CAUGHT(excpt_r);
01003     ZYPP_THROW(Exception("Cannot create product object"));
01004   }
01005   return 0L;
01006 }
01007 
01008 Pattern::Ptr
01009 XMLFilesBackend::createPattern( const zypp::parser::xmlstore::XMLPatternData & parsed ) const
01010 {
01011   try
01012   {
01013     detail::ResImplTraits<XMLPatternImpl>::Ptr impl(new XMLPatternImpl());
01014 
01015     impl->_summary = parsed.summary;
01016     impl->_description = parsed.summary;
01017 
01018     impl->_install_notify = parsed.install_notify;
01019     impl->_delete_notify = parsed.delete_notify;
01020     impl->_license_to_confirm = parsed.license_to_confirm;
01021     impl->_size = parsed.size;
01022     impl->_archive_size = parsed.archive_size;
01023     impl->_install_only = parsed.install_only;
01024     impl->_build_time = parsed.build_time;
01025     impl->_install_time = parsed.install_time;
01026     
01027     impl->_user_visible = parsed.userVisible;
01028     impl->_default = ((parsed.default_ == "false" ) ? false : true );
01029     impl->_category = parsed.category;
01030     impl->_icon = parsed.icon;
01031     impl->_script = parsed.script;
01032 
01033     Arch arch;
01034     if (!parsed.arch.empty())
01035       arch = Arch(parsed.arch);
01036 
01037     // Collect basic Resolvable data
01038     NVRAD dataCollect( parsed.name, Edition( parsed.ver, parsed.rel, parsed.epoch ), arch, createDependencies( parsed, ResTraits<Pattern>::kind));
01039     Pattern::Ptr pattern = detail::makeResolvableFromImpl( dataCollect, impl );
01040     return pattern;
01041   }
01042   catch (const Exception & excpt_r)
01043   {
01044     ZYPP_CAUGHT(excpt_r);
01045     ZYPP_THROW(Exception("Cannot create installation pattern object"));
01046   }
01047   return 0L;
01048 }
01049 
01050 Selection::Ptr
01051 XMLFilesBackend::createSelection( const zypp::parser::xmlstore::XMLPatternData & parsed ) const
01052 {
01053   try
01054   {
01055     detail::ResImplTraits<XMLSelectionImpl>::Ptr impl(new XMLSelectionImpl());
01056 
01057     impl->_summary = parsed.summary;
01058     impl->_description = parsed.summary;
01059 
01060     impl->_install_notify = parsed.install_notify;
01061     impl->_delete_notify = parsed.delete_notify;
01062     impl->_license_to_confirm = parsed.license_to_confirm;
01063     impl->_size = parsed.size;
01064     impl->_archive_size = parsed.archive_size;
01065     impl->_install_only = parsed.install_only;
01066     impl->_build_time = parsed.build_time;
01067     impl->_install_time = parsed.install_time;
01068     
01069     impl->_visible = parsed.userVisible;
01070     impl->_name = parsed.name;
01071     //impl->_default = ((parsed.default_ == "false" ) ? false : true );
01072     impl->_category = parsed.category;
01073 
01074     Arch arch;
01075     if (!parsed.arch.empty())
01076       arch = Arch(parsed.arch);
01077     
01078     // Collect basic Resolvable data
01079     NVRAD dataCollect( parsed.name, Edition( parsed.ver, parsed.rel, parsed.epoch ), arch, createDependencies( parsed, ResTraits<Pattern>::kind));
01080     Selection::Ptr selection = detail::makeResolvableFromImpl( dataCollect, impl );
01081     return selection;
01082   }
01083   catch (const Exception & excpt_r)
01084   {
01085     ZYPP_CAUGHT(excpt_r);
01086     ZYPP_THROW(Exception("Cannot create installation selection object"));
01087   }
01088   return 0L;
01089 }
01090 
01091 Dependencies
01092 XMLFilesBackend::createDependencies( const zypp::parser::xmlstore::XMLResObjectData & parsed, const Resolvable::Kind my_kind ) const
01093 {
01094   Dependencies _deps;
01095   for (std::list<XMLDependency>::const_iterator it = parsed.provides.begin(); it != parsed.provides.end(); it++)
01096   {
01097     _deps[Dep::PROVIDES].insert(createCapability(*it, my_kind));
01098   }
01099   for (std::list<XMLDependency>::const_iterator it = parsed.conflicts.begin(); it != parsed.conflicts.end(); it++)
01100   {
01101     _deps[Dep::CONFLICTS].insert(createCapability(*it, my_kind));
01102   }
01103 
01104   for (std::list<XMLDependency>::const_iterator it = parsed.obsoletes.begin(); it != parsed.obsoletes.end(); it++)
01105   {
01106     _deps[Dep::OBSOLETES].insert(createCapability(*it, my_kind));
01107   }
01108 
01109   for (std::list<XMLDependency>::const_iterator it = parsed.freshens.begin(); it != parsed.freshens.end(); it++)
01110   {
01111     _deps[Dep::FRESHENS].insert(createCapability(*it, my_kind));
01112   }
01113 
01114   for (std::list<XMLDependency>::const_iterator it = parsed.recommends.begin(); it != parsed.recommends.end(); it++)
01115   {
01116     _deps[Dep::RECOMMENDS].insert(createCapability(*it, my_kind));
01117   }
01118 
01119   for (std::list<XMLDependency>::const_iterator it = parsed.suggests.begin(); it != parsed.suggests.end(); it++)
01120   {
01121     _deps[Dep::SUGGESTS].insert(createCapability(*it, my_kind));
01122   }
01123 
01124   for (std::list<XMLDependency>::const_iterator it = parsed.enhances.begin(); it != parsed.enhances.end(); it++)
01125   {
01126     _deps[Dep::ENHANCES].insert(createCapability(*it, my_kind));
01127   }
01128 
01129   for (std::list<XMLDependency>::const_iterator it = parsed.requires.begin(); it != parsed.requires.end(); it++)
01130   {
01131     _deps[Dep::REQUIRES].insert(createCapability(*it, my_kind));
01132   }
01133 
01134   for (std::list<XMLDependency>::const_iterator it = parsed.prerequires.begin(); it != parsed.prerequires.end(); it++)
01135   {
01136     _deps[Dep::PREREQUIRES].insert(createCapability(*it, my_kind));
01137   }
01138   return _deps;
01139 }
01140 
01141 Capability
01142 XMLFilesBackend::createCapability(const XMLDependency & dep, const Resolvable::Kind & my_kind) const
01143 {
01144   CapFactory _f;
01145   Resolvable::Kind _kind = dep.kind == "" ? my_kind : Resolvable::Kind(dep.kind);
01146   Capability cap;
01147   cap = _f.parse( _kind, dep.encoded );
01148   return cap;
01149 }
01150 
01152 //
01153 //      METHOD NAME : XMLFilesBackend::~XMLFilesBackend
01154 //      METHOD TYPE : Dtor
01155 //
01156 XMLFilesBackend::~XMLFilesBackend()
01157 {
01158   delete d;
01159 }
01160 
01162 //
01163 //      METHOD NAME : XMLFilesBackend::doTest()
01164 //      METHOD TYPE : Dtor
01165 //
01166 void XMLFilesBackend::doTest()
01167 {}
01168 
01169 /******************************************************************
01170 **
01171 **      FUNCTION NAME : operator<<
01172 **      FUNCTION TYPE : std::ostream &
01173 */
01174 std::ostream & operator<<( std::ostream & str, const XMLFilesBackend & obj )
01175 {
01176         return str;
01177 }
01178 
01180 // SOURCES API
01182 
01183 std::list<PersistentStorage::SourceData>
01184 XMLFilesBackend::storedSources() const
01185 {
01186   path source_p = path(d->root.asString()) / path(ZYPP_DB_DIR) / path ("sources");
01187   std::list<PersistentStorage::SourceData> sources;
01188   DBG << "Reading source cache in " << source_p.string() << std::endl;
01189   directory_iterator end_iter;
01190   // return empty list if the dir does not exist
01191   if ( !exists( source_p ) )
01192   {
01193     ERR << "path " << source_p.string() << " does not exists. Required to read source cache " << std::endl;
01194     return std::list<PersistentStorage::SourceData>();
01195   }
01196 
01197   for ( directory_iterator dir_itr( source_p ); dir_itr != end_iter; ++dir_itr )
01198   {
01199     DBG << "[source-list] - " << dir_itr->leaf() << std::endl;
01200     //sources.insert( sourceDataFromCacheFile( source_p + "/" + dir_itr->leaf() ) );
01201     std::string full_path = (source_p / dir_itr->leaf()).string();
01202     std::ifstream anIstream(full_path.c_str());
01203     zypp::parser::xmlstore::XMLSourceCacheParser iter(anIstream, "");
01204     for (; ! iter.atEnd(); ++iter) {
01205       PersistentStorage::SourceData data = **iter;
01206       sources.push_back(data);
01207     }
01208   }
01209   MIL << "done reading source cache" << std::endl;
01210   return sources;
01211 
01212 }
01213 
01214 void
01215 XMLFilesBackend::storeSource(const PersistentStorage::SourceData &data)
01216 {
01217   // serialize and save a file
01218   std::string xml = toXML(data);
01219   path source_p = path(d->root.asString()) / path(ZYPP_DB_DIR) / path ("sources");
01220 
01221   // generate a filename
01222   if (data.alias.size() == 0)
01223   {
01224     ZYPP_THROW(Exception("Cant save source with empty alias"));
01225   }
01226 
01227   //DBG << std::endl << xml << std::endl;
01228   std::ofstream file;
01229   //DBG << filename << std::endl;
01230   try
01231   {
01232     std::stringstream message_stream(data.alias);
01233     std::string full_path = (source_p / Digest::digest("MD5", message_stream)).string();
01234 
01235     file.open(full_path.c_str());
01236     file << xml;
01237     file.close();
01238   }
01239   catch ( std::exception &e )
01240   {
01241     ERR << "Error saving source " << data.alias << " in the cache" << std::endl;
01242     ZYPP_THROW(Exception(e.what()));
01243   }
01244 }
01245 
01246 void
01247 XMLFilesBackend::deleteSource(const std::string &alias)
01248 {
01249   // just delete the files
01250   path source_p = path(d->root.asString()) / path(ZYPP_DB_DIR) / path ("sources");
01251   try
01252   {
01253     std::stringstream message_stream(alias);
01254     std::string full_path = (source_p / Digest::digest("MD5", message_stream)).string();
01255     remove(full_path);
01256   }
01257   catch ( std::exception &e )
01258   {
01259     ERR << "Error deleting source " << alias << " in the cache" << std::endl;
01260     ZYPP_THROW(Exception(e.what()));
01261   }
01262 }
01263 
01265 } // namespace storage
01268 } // namespace zypp

Generated on Wed Sep 27 01:16:55 2006 for zypp by  doxygen 1.4.6