032b1c8dfca42aa758a2c925d117404d8e057f37
[platform/upstream/libzypp.git] / zypp / target / store / XMLFilesBackend.cc
1 /*---------------------------------------------------------------------\
2 |                          ____ _   __ __ ___                          |
3 |                         |__  / \ / / . \ . \                         |
4 |                           / / \ V /|  _/  _/                         |
5 |                          / /__ | | | | | |                           |
6 |                         /_____||_| |_| |_|                           |
7 |                                                                      |
8 \---------------------------------------------------------------------*/
9 /** \file       devel/devel.dmacvicar/XMLFilesBackend.cc
10 *
11 */
12 #include <iostream>
13 #include <ctime>
14 #include <cstdlib>
15 #include <cstdio>
16 #include <fcntl.h>
17
18 #include "zypp/base/Logger.h"
19 #include "zypp/base/Exception.h"
20
21 #include "zypp/CapFactory.h"
22
23 #include "zypp/target/store/xml/XMLPatchImpl.h"
24 #include "zypp/target/store/xml/XMLMessageImpl.h"
25 #include "zypp/target/store/xml/XMLScriptImpl.h"
26 #include "zypp/target/store/xml/XMLSelectionImpl.h"
27 #include "zypp/target/store/xml/XMLProductImpl.h"
28
29 #include <iostream>
30 #include <fstream>
31 #include <sstream>
32 #include <streambuf>
33
34 #include <list>
35
36 #include <zypp/target/store/xml/XMLSourceCacheParser.h>
37
38 #include "boost/filesystem/operations.hpp" // includes boost/filesystem/path.hpp
39 #include "boost/filesystem/fstream.hpp"    // ditto
40
41 #include "XMLFilesBackend.h"
42 #include "serialize.h"
43
44 #include "md5.h"
45
46 #define ZYPP_DB_DIR "/var/lib/zypp_db"
47
48 using std::endl;
49 using namespace boost::filesystem;
50 using namespace zypp;
51 using namespace zypp::parser::yum;
52
53 ///////////////////////////////////////////////////////////////////
54 namespace zypp
55 { /////////////////////////////////////////////////////////////////
56 namespace storage
57 { /////////////////////////////////////////////////////////////////
58
59
60 ///////////////////////////////////////////////////////////////////
61 //
62 //      CLASS NAME : XMLFilesBackend::Private
63 //
64 ///////////////////////////////////////////////////////////////////
65 class XMLFilesBackend::Private
66 {
67   public:
68   Private()
69   { }
70   bool randomFileName;
71   std::set<Resolvable::Kind> kinds;
72   Pathname root;
73 };
74
75 ///////////////////////////////////////////////////////////////////
76 //
77 //      CLASS NAME : XMLFilesBackend
78 //
79 ///////////////////////////////////////////////////////////////////
80
81 ///////////////////////////////////////////////////////////////////
82 //
83 //      METHOD NAME : XMLFilesBackend::XMLFilesBackend
84 //      METHOD TYPE : Ctor
85 //
86 XMLFilesBackend::XMLFilesBackend(const Pathname &root) : Backend(root)
87 {
88   d = new Private;
89   d->randomFileName = false;
90   d->root = root;
91   // types of resolvables stored (supported)
92   d->kinds.insert(ResTraits<zypp::Patch>::kind);
93   //d->kinds.insert(ResTraits<zypp::Message>::kind);
94   //d->kinds.insert(ResTraits<zypp::Script>::kind);
95   d->kinds.insert(ResTraits<zypp::Selection>::kind);
96   d->kinds.insert(ResTraits<zypp::Product>::kind);
97
98         // check if the db exists
99         if (!isBackendInitialized())
100         {
101                 DBG << "Database not initialized" << std::endl;
102                 initBackend();
103     // should be initialized now...
104                 if (!isBackendInitialized())
105                         DBG << "Error, cant init database" << std::endl;
106                 else
107                         DBG << "Database initialized" << std::endl;
108         }
109         else
110         {
111                 DBG << "Database already initialized" << std::endl;
112         }
113 }
114
115 // Taken from KApplication
116 int XMLFilesBackend::random() const
117 {
118    static bool init = false;
119    if (!init)
120    {
121       unsigned int seed;
122       init = true;
123       int fd = open("/dev/urandom", O_RDONLY);
124       if (fd < 0 || ::read(fd, &seed, sizeof(seed)) != sizeof(seed))
125       {
126             // No /dev/urandom... try something else.
127             srand(getpid());
128             seed = rand()+time(0);
129       }
130       if (fd >= 0) close(fd);
131       srand(seed);
132    }
133    return rand();
134 }
135
136 // Taken from KApplication
137 std::string XMLFilesBackend::randomString(int length) const
138 {
139    if (length <=0 ) return std::string();
140
141    std::string str; str.resize( length );
142    int i = 0;
143    while (length--)
144    {
145       int r=random() % 62;
146       r+=48;
147       if (r>57) r+=7;
148       if (r>90) r+=6;
149       str[i++] =  char(r);
150       // so what if I work backwards?
151    }
152    return str;
153 }
154
155
156 bool
157 XMLFilesBackend::isBackendInitialized() const
158 {
159   bool ok = true;
160   ok = ok && exists( ZYPP_DB_DIR );
161   std::set<Resolvable::Kind>::const_iterator it_kinds;
162   for ( it_kinds = d->kinds.begin() ; it_kinds != d->kinds.end(); ++it_kinds )
163   {
164     Resolvable::Kind kind = (*it_kinds);
165     ok = ok && exists(dirForResolvableKind(kind));
166   }
167   ok = ok && exists( path(d->root.asString()) / path(ZYPP_DB_DIR) / path ("source-cache") );
168   return ok;
169 }
170
171 void
172 XMLFilesBackend::initBackend()
173 {
174   // FIXME duncan * handle exceptions
175   DBG << "Creating directory structure..." << std::endl;
176   try
177   {
178     path topdir = path(d->root.asString()) / path(ZYPP_DB_DIR);
179     if (!exists(topdir))
180       create_directory(topdir);
181     MIL << "Created..." << topdir.string() << std::endl;
182     std::set<Resolvable::Kind>::const_iterator it_kinds;
183     for ( it_kinds = d->kinds.begin() ; it_kinds != d->kinds.end(); ++it_kinds )
184     {
185       Resolvable::Kind kind = (*it_kinds);
186       # warning "add exception handling here"
187       path p(topdir / path(resolvableKindToString(kind, true /* plural */)));
188       if (!exists(p))
189       {
190         create_directory(p);
191         MIL << "Created..." << p.string() << std::endl;
192       }
193     }
194     // create source-cache
195     path source_p = path(d->root.asString()) / path(ZYPP_DB_DIR) / path ("source-cache");
196     if (!exists(source_p))
197     {
198       create_directory(source_p);
199       MIL << "Created..." << source_p.string() << std::endl;
200     }
201   }
202   catch(std::exception &e)
203   {
204     ZYPP_RETHROW(Exception(e.what()));
205   }
206 }
207
208 void XMLFilesBackend::setRandomFileNameEnabled( bool enabled )
209 {
210   d->randomFileName = enabled;
211 }
212
213 std::string
214 XMLFilesBackend::dirForResolvableKind( Resolvable::Kind kind ) const
215 {
216   std::string dir;
217   dir += path( path(d->root.asString()) / path(ZYPP_DB_DIR) / path(resolvableKindToString(kind, true)) ).string();
218   return dir;
219 }
220
221 std::string
222 XMLFilesBackend::dirForResolvable( Resolvable::constPtr resolvable ) const
223 {
224   return dirForResolvableKind(resolvable->kind());
225 }
226
227 std::string
228 XMLFilesBackend::fullPathForResolvable( Resolvable::constPtr resolvable ) const
229 {
230   std::string filename;
231   // only append edition if there is one
232   std::string suffix = ( (resolvable->edition() == Edition::noedition) ? std::string() : ("-" + resolvable->edition().version() + "-" + resolvable->edition().release()) );
233   filename = d->randomFileName ? randomString(40) : (resolvable->name() + suffix);
234   return path( path(dirForResolvable(resolvable)) / path(filename)).string();
235 }
236
237 void
238 XMLFilesBackend::storeObject( Resolvable::constPtr resolvable )
239 {
240   std::string xml = castedToXML(resolvable);
241   std::string filename = fullPathForResolvable(resolvable);
242   //DBG << std::endl << xml << std::endl;
243   std::ofstream file;
244   //DBG << filename << std::endl;
245   try
246   {
247     file.open(filename.c_str());
248     file << xml;
249     file.close();
250   }
251   catch(std::exception &e)
252   {
253     ERR << "Error saving resolvable " << resolvable << std::endl;
254     ZYPP_THROW(Exception(e.what()));
255   }
256 }
257
258 void
259 XMLFilesBackend::deleteObject( Resolvable::Ptr resolvable )
260 {
261   // only remove the file
262   std::string filename = fullPathForResolvable(resolvable);
263   try
264   {
265     remove(path(filename));
266   }
267   catch(std::exception &e)
268   {
269     ERR << "Error removing resolvable " << resolvable << std::endl;
270     ZYPP_THROW(Exception(e.what()));
271   }
272 }
273
274 Resolvable::Ptr XMLFilesBackend::resolvableFromFile( std::string file_path, Resolvable::Kind kind ) const
275 {
276   //DBG << "[" << resolvableKindToString( kind, false ) << "] - " << file_path << std::endl;
277   Resolvable::Ptr resolvable;
278   std::ifstream res_file(file_path.c_str());
279   if ( kind == ResTraits<zypp::Patch>::kind )
280   {
281     // a patch file can contain more than one patch, but we store only
282     // one patch, so we break at the first
283     // FIXME how can we avoid creating this for every object?
284     YUMPatchParser iter(res_file,"");
285     for (; !iter.atEnd(); ++iter)
286     {
287       DBG << "here..." << std::endl;
288       resolvable = createPatch(**iter);
289       break;
290     }
291   }
292   else if ( kind == ResTraits<zypp::Product>::kind )
293   {
294     YUMProductParser iter(res_file,"");
295     for (; !iter.atEnd(); ++iter)
296     {
297       DBG << "here..." << std::endl;
298       resolvable = createProduct(**iter);
299       break;
300     }
301   }
302   else if ( kind == ResTraits<zypp::Selection>::kind )
303   {
304     YUMGroupParser iter(res_file,"");
305     for (; !iter.atEnd(); ++iter)
306     {
307       DBG << "here..." << std::endl;
308       resolvable = createSelection(**iter);
309       break;
310     }
311   }
312   /*
313   else if ( kind == ResTraits<zypp::Message>::kind )
314   {
315     YUMMessageParser iter(res_file,"");
316     for (; !iter.atEnd(); ++iter)
317     {
318       DBG << "here..." << std::endl;
319       resolvable = createMessage(**iter);
320       break;
321     }
322   }
323   else if ( kind == ResTraits<zypp::Script>::kind )
324   {
325     YUMScriptParser iter(res_file,"");
326     for (; !iter.atEnd(); ++iter)
327     {
328       DBG << "here..." << std::endl;
329       resolvable = createScript(**iter);
330       break;
331     }
332   }
333   */
334   else
335   {
336     resolvable = 0;
337   }
338   return resolvable;
339 }
340
341 std::list<Resolvable::Ptr>
342 XMLFilesBackend::storedObjects() const
343 {
344   DBG << std::endl;
345   std::list<Resolvable::Ptr> objects;
346
347   std::set<Resolvable::Kind>::const_iterator it_kinds;
348   for ( it_kinds = d->kinds.begin() ; it_kinds != d->kinds.end(); ++it_kinds )
349   {
350     Resolvable::Kind kind = (*it_kinds);
351     std::list<Resolvable::Ptr> objects_for_kind = storedObjects(kind);
352     std::list<Resolvable::Ptr>::iterator it;
353     for( it = objects_for_kind.begin(); it != objects_for_kind.end(); ++it)
354     {
355       //DBG << "adding objects back" << std::endl;
356       objects.push_back(*it);
357     }
358   }
359   return objects;
360 }
361
362 std::list<Resolvable::Ptr>
363 XMLFilesBackend::storedObjects(const Resolvable::Kind kind) const
364 {
365   std::list<Resolvable::Ptr> objects;
366   std::string dir_path = dirForResolvableKind(kind);
367   DBG << "Reading objects of kind " << resolvableKindToString(kind) << " in " << dir_path << std::endl;
368   directory_iterator end_iter;
369   // return empty list if the dir does not exist
370   if ( !exists( dir_path ) )
371   {
372     ERR << "path " << dir_path << " does not exists. Required to read objects of kind " << resolvableKindToString(kind) << std::endl;
373     return std::list<Resolvable::Ptr>();
374   }
375
376   for ( directory_iterator dir_itr( dir_path ); dir_itr != end_iter; ++dir_itr )
377   {
378     DBG << "[" << resolvableKindToString( kind, false ) << "] - " << dir_itr->leaf() << std::endl;
379     objects.push_back( resolvableFromFile( dir_path + "/" + dir_itr->leaf(), kind) );
380   }
381   MIL << "done reading stored objecs of kind " << resolvableKindToString(kind) << std::endl;
382   return objects;
383 }
384
385 std::list<Resolvable::Ptr>
386 XMLFilesBackend::storedObjects(const Resolvable::Kind kind, const std::string & name, bool partial_match) const
387 {
388   std::list<Resolvable::Ptr> result;
389   std::list<Resolvable::Ptr> all;
390   all = storedObjects(kind);
391   std::list<Resolvable::Ptr>::const_iterator it;
392   for( it = all.begin(); it != all.end(); ++it)
393   {
394     Resolvable::Ptr item = *it;
395     if (item->name() == name )
396       result.push_back(item);
397   }
398   MIL << "done reading stored objecs of kind " << resolvableKindToString(kind) << " and keyword [" << name <<"]" << std::endl;
399   return result;
400 }
401
402 Patch::Ptr
403 XMLFilesBackend::createPatch( const zypp::parser::yum::YUMPatchData & parsed ) const
404 {
405   try
406   {
407     shared_ptr<XMLPatchImpl> impl(new XMLPatchImpl());
408     impl->_patch_id = parsed.patchId;
409     impl->_timestamp = str::strtonum<time_t>(parsed.timestamp);
410     impl->_category = parsed.category;
411     impl->_reboot_needed = parsed.rebootNeeded;
412     impl->_affects_pkg_manager = parsed.packageManager;
413     // impl._atoms -> std::list<shared_ptr<YUMPatchAtom> > parsed.atoms */
414     
415     impl->_summary = parsed.summary;
416     impl->_description = parsed.summary;
417     
418     // Collect basic Resolvable data
419     NVRAD dataCollect( parsed.name,
420                        Edition( parsed.ver, parsed.rel, parsed.epoch ), Arch_noarch,
421                        createDependencies(parsed, ResTraits<Patch>::kind) );
422     Patch::Ptr patch = detail::makeResolvableFromImpl( dataCollect, impl );
423     return patch;
424   }
425   catch (const Exception & excpt_r)
426   {
427     ERR << excpt_r << endl;
428     throw "Cannot create patch object";
429   }
430 }
431
432 Message::Ptr
433 XMLFilesBackend::createMessage( const zypp::parser::yum::YUMPatchMessage & parsed ) const
434 {
435   try
436   {
437     shared_ptr<XMLMessageImpl> impl(new XMLMessageImpl());
438     impl->_text = parsed.text;
439
440     // Collect basic Resolvable data
441     NVRAD dataCollect( parsed.name, Edition( parsed.ver, parsed.rel, parsed.epoch ), Arch_noarch, createDependencies(parsed, ResTraits<Message>::kind) );
442     Message::Ptr message = detail::makeResolvableFromImpl( dataCollect, impl);
443     return message;
444   }
445   catch (const Exception & excpt_r)
446   {
447     ERR << excpt_r << endl;
448     throw "Cannot create message object";
449   }
450 }
451
452 Script::Ptr
453 XMLFilesBackend::createScript(const zypp::parser::yum::YUMPatchScript & parsed ) const
454 {
455   try
456   {
457     shared_ptr<XMLScriptImpl> impl(new XMLScriptImpl());
458     impl->_do_script = parsed.do_script;
459     impl->_undo_script = parsed.undo_script;
460     // Collect basic Resolvable data
461     NVRAD dataCollect( parsed.name, Edition( parsed.ver, parsed.rel, parsed.epoch ), Arch_noarch, createDependencies(parsed, ResTraits<Script>::kind));
462     Script::Ptr script = detail::makeResolvableFromImpl( dataCollect, impl );
463     return script;
464   }
465   catch (const Exception & excpt_r)
466   {
467     ERR << excpt_r << endl;
468     throw "Cannot create script object";
469   }
470 }
471
472 /*
473       std::string groupId;
474       std::list<MultiLang> name;
475       std::string default_;
476       std::string userVisible;
477       std::list<MultiLang> description;
478       std::list<MetaPkg> grouplist;
479       std::list<PackageReq> package_list;
480 */
481
482 Product::Ptr
483 XMLFilesBackend::createProduct( const zypp::parser::yum::YUMProductData & parsed ) const
484 {
485   try
486   {
487     shared_ptr<XMLProductImpl> impl(new XMLProductImpl());
488
489     impl->_category = parsed.type;
490     impl->_vendor = parsed.vendor;
491     #warning "FIX when YUM parser uses TranslatedString"
492     //impl->_displayname = parsed.displayname;
493     //impl->_description = parsed.description;
494
495     // Collect basic Resolvable data
496     NVRAD dataCollect( parsed.name, Edition( parsed.ver, parsed.rel, parsed.epoch ), Arch_noarch, createDependencies(parsed, ResTraits<Product>::kind) );
497     Product::Ptr product = detail::makeResolvableFromImpl( dataCollect, impl );
498     return product;
499   }
500   catch (const Exception & excpt_r)
501   {
502     ERR << excpt_r << endl;
503     throw "Cannot create product object";
504   }
505 }
506
507 Selection::Ptr
508 XMLFilesBackend::createSelection( const zypp::parser::yum::YUMGroupData & parsed ) const
509 {
510   try
511   {
512     DBG << parsed << std::endl;
513     shared_ptr<XMLSelectionImpl> impl(new XMLSelectionImpl());
514       /*
515       YUMGroupData();
516         std::string groupId;
517         std::list<MultiLang> name;
518         std::string default_;
519         std::string userVisible;
520         std::list<MultiLang> description;
521         std::list<MetaPkg> grouplist;
522         std::list<PackageReq> packageList;
523       */
524     impl->_summary = parsed.description;
525     //impl->_description = parsed.description;
526     impl->_name = parsed.groupId;
527     //impl->_order = parsed.summary;
528     //impl->_category = parsed.summary;
529     impl->_visible = ((parsed.userVisible == "true") ? true : false);
530     
531     for( std::list<MetaPkg>::const_iterator it = parsed.grouplist.begin(); it != parsed.grouplist.end(); ++it)
532     {
533       DBG << "Selection dependencies" << std::endl;
534       if ((*it).type == "optional" )
535         impl->_suggests.insert((*it).name);
536       if ((*it).type == "mandatory" )
537         impl->_recommends.insert((*it).name);
538     }
539     for( std::list<PackageReq>::const_iterator it = parsed.packageList.begin(); it != parsed.packageList.end(); ++it)
540     {
541         DBG << "Selection package dependencies" << std::endl;
542         impl->_install_packages.insert((*it).name);
543     }
544     // Collect basic Resolvable data
545     NVRAD dataCollect( parsed.groupId, Edition::noedition, Arch_noarch, createGroupDependencies(parsed) );
546     Selection::Ptr selection = detail::makeResolvableFromImpl( dataCollect, impl );
547     return selection;
548   }
549   catch (const Exception & excpt_r)
550   {
551     ERR << excpt_r << endl;
552     throw "Cannot create selection object";
553   }
554 }
555
556 Dependencies 
557 XMLFilesBackend::createDependencies( const zypp::parser::yum::YUMObjectData & parsed, const Resolvable::Kind my_kind ) const
558 {
559   Dependencies _deps;
560   for (std::list<YUMDependency>::const_iterator it = parsed.provides.begin(); it != parsed.provides.end(); it++)
561   {
562     _deps[Dep::PROVIDES].insert(createCapability(*it, my_kind));
563   }
564
565   for (std::list<YUMDependency>::const_iterator it = parsed.conflicts.begin(); it != parsed.conflicts.end(); it++)
566   {
567     _deps[Dep::CONFLICTS].insert(createCapability(*it, my_kind));
568   }
569   
570   for (std::list<YUMDependency>::const_iterator it = parsed.obsoletes.begin(); it != parsed.obsoletes.end(); it++)
571   {
572     _deps[Dep::OBSOLETES].insert(createCapability(*it, my_kind));
573   }
574
575   for (std::list<YUMDependency>::const_iterator it = parsed.freshen.begin(); it != parsed.freshen.end(); it++)
576   {
577     _deps[Dep::FRESHENS].insert(createCapability(*it, my_kind));
578   }
579
580   for (std::list<YUMDependency>::const_iterator it = parsed.requires.begin(); it != parsed.requires.end(); it++)
581   {
582     if (it->pre == "1")
583       _deps[Dep::PREREQUIRES].insert(createCapability(*it, my_kind));
584     else
585       _deps[Dep::REQUIRES].insert(createCapability(*it, my_kind));
586   }
587
588     return _deps;
589   }
590
591 Dependencies 
592 XMLFilesBackend::createGroupDependencies( const zypp::parser::yum::YUMGroupData & parsed ) const
593 {
594   Dependencies _deps;
595
596   for (std::list<PackageReq>::const_iterator it = parsed.packageList.begin(); it != parsed.packageList.end(); it++)
597   {
598     if (it->type == "mandatory" || it->type == "")
599     {
600       _deps[Dep::REQUIRES].insert(createCapability(YUMDependency( "", it->name, "EQ", it->epoch, it->ver, it->rel, "" ), ResTraits<Package>::kind));
601     }
602   }
603   for (std::list<MetaPkg>::const_iterator it = parsed.grouplist.begin(); it != parsed.grouplist.end(); it++)
604   {
605     if (it->type == "mandatory" || it->type == "")
606     {
607       _deps[Dep::REQUIRES].insert(createCapability(YUMDependency("", it->name, "", "", "", "", "" ), ResTraits<Selection>::kind));
608     }
609   }
610   return _deps;
611 }
612
613 Dependencies
614 XMLFilesBackend::createPatternDependencies( const zypp::parser::yum::YUMPatternData & parsed ) const
615 {
616   Dependencies _deps;
617
618   for (std::list<PackageReq>::const_iterator it = parsed.packageList.begin(); it != parsed.packageList.end(); it++)
619   {
620     if (it->type == "mandatory" || it->type == "")
621     {
622       _deps[Dep::REQUIRES].insert(createCapability(YUMDependency( "", it->name, "EQ", it->epoch, it->ver, it->rel, "" ), ResTraits<Package>::kind));
623     }
624   }
625   for (std::list<MetaPkg>::const_iterator it = parsed.patternlist.begin(); it != parsed.patternlist.end(); it++)
626   {
627     if (it->type == "mandatory" || it->type == "")
628     {
629       _deps[Dep::REQUIRES].insert(createCapability(YUMDependency( "", it->name, "", "", "", "", "" ), ResTraits<Selection>::kind));
630     }
631   }
632   return _deps;
633 }
634
635 Capability
636 XMLFilesBackend::createCapability(const YUMDependency & dep, const Resolvable::Kind & my_kind) const
637 {
638   CapFactory _f;
639   Resolvable::Kind _kind = dep.kind == "" ? my_kind : Resolvable::Kind(dep.kind);
640   Capability cap;
641   if ( ! dep.isEncoded() )
642   {
643     cap = _f.parse( _kind, dep.name, Rel(dep.flags), Edition(dep.ver, dep.rel, dep.epoch) );
644   }
645   else
646   {
647     cap = _f.parse( _kind, dep.encoded );
648   }
649   return cap;
650 }
651
652 ///////////////////////////////////////////////////////////////////
653 //
654 //      METHOD NAME : XMLFilesBackend::~XMLFilesBackend
655 //      METHOD TYPE : Dtor
656 //
657 XMLFilesBackend::~XMLFilesBackend()
658 {
659   delete d;
660 }
661
662 ///////////////////////////////////////////////////////////////////
663 //
664 //      METHOD NAME : XMLFilesBackend::doTest()
665 //      METHOD TYPE : Dtor
666 //
667 void XMLFilesBackend::doTest()
668 {}
669
670 /******************************************************************
671 **
672 **      FUNCTION NAME : operator<<
673 **      FUNCTION TYPE : std::ostream &
674 */
675 std::ostream & operator<<( std::ostream & str, const XMLFilesBackend & obj )
676 {
677         return str;
678 }
679
680 /////////////////////////////////////////////////////////
681 // SOURCES API
682 ////////////////////////////////////////////////////////
683
684 std::list<PersistentStorage::SourceData>
685 XMLFilesBackend::storedSources() const
686 {
687   path source_p = path(d->root.asString()) / path(ZYPP_DB_DIR) / path ("source-cache");
688   std::list<PersistentStorage::SourceData> sources;
689   DBG << "Reading source cache in " << source_p.string() << std::endl;
690   directory_iterator end_iter;
691   // return empty list if the dir does not exist
692   if ( !exists( source_p ) )
693   {
694     ERR << "path " << source_p.string() << " does not exists. Required to read source cache " << std::endl;
695     return std::list<PersistentStorage::SourceData>();
696   }
697
698   for ( directory_iterator dir_itr( source_p ); dir_itr != end_iter; ++dir_itr )
699   {
700     DBG << "[source-cache] - " << dir_itr->leaf() << std::endl;
701     //sources.insert( sourceDataFromCacheFile( source_p + "/" + dir_itr->leaf() ) );
702     std::string full_path = (source_p / dir_itr->leaf()).string();
703     std::ifstream anIstream(full_path.c_str());
704     XMLSourceCacheParser iter(anIstream, "");
705     for (; ! iter.atEnd(); ++iter) {
706       PersistentStorage::SourceData data = **iter;
707       sources.push_back(data);
708     }
709   }
710   MIL << "done reading source cache" << std::endl;
711   return sources;
712
713 }
714
715 static std::string hexDigest(const std::string &message)
716 {
717   md5_state_t state;
718   md5_byte_t digest[16];
719
720   md5_init(&state);
721   /* Append a string to the message. */
722   md5_append(&state, (md5_byte_t*) message.c_str(), message.size());  /* Finish the message and return the digest. */
723   md5_finish(&state, digest);
724
725   char s[33];
726   int i;
727   for (i=0; i<16; i++)
728     sprintf(s+i*2, "%02x", digest[i]);
729
730   s[32]='\0';
731   return std::string(s);
732 }
733
734 void
735 XMLFilesBackend::storeSource(const PersistentStorage::SourceData &data)
736 {
737   // serialize and save a file
738   std::string xml = toXML(data);
739   path source_p = path(d->root.asString()) / path(ZYPP_DB_DIR) / path ("source-cache");
740
741   // generate a filename
742   if (data.alias.size() == 0)
743   {
744     ZYPP_THROW(Exception("Cant save source with empty alias"));
745   }
746
747   //DBG << std::endl << xml << std::endl;
748   std::ofstream file;
749   //DBG << filename << std::endl;
750   try
751   {
752     std::string full_path = (source_p / hexDigest(data.alias)).string();
753     
754     file.open(full_path.c_str());
755     file << xml;
756     file.close();
757   }
758   catch ( std::exception &e )
759   {
760     ERR << "Error saving source " << data.alias << " in the cache" << std::endl;
761     ZYPP_THROW(Exception(e.what()));
762   }
763 }
764
765 void
766 XMLFilesBackend::deleteSource(const std::string &alias)
767 {
768   // just delete the files
769   path source_p = path(d->root.asString()) / path(ZYPP_DB_DIR) / path ("source-cache");
770   try
771   {
772     std::string full_path = (source_p / hexDigest(alias)).string();
773     remove(full_path);
774   }
775   catch ( std::exception &e )
776   {
777     ERR << "Error deleting source " << alias << " in the cache" << std::endl;
778     ZYPP_THROW(Exception(e.what()));
779   }
780 }
781
782 /////////////////////////////////////////////////////////////////
783 } // namespace storage
784 ///////////////////////////////////////////////////////////////////
785 /////////////////////////////////////////////////////////////////
786 } // namespace zypp
787 ///////////////////////////////////////////////////////////////////