1 /*---------------------------------------------------------------------\
3 | |__ / \ / / . \ . \ |
8 \---------------------------------------------------------------------*/
9 /** \file zypp/Fetcher.cc
17 #include "zypp/base/Easy.h"
18 #include "zypp/base/LogControl.h"
19 #include "zypp/base/LogTools.h"
20 #include "zypp/base/PtrTypes.h"
21 #include "zypp/base/DefaultIntegral.h"
22 #include "zypp/base/String.h"
23 #include "zypp/Fetcher.h"
24 #include "zypp/ZYppFactory.h"
25 #include "zypp/CheckSum.h"
26 #include "zypp/base/UserRequestException.h"
27 #include "zypp/parser/susetags/ContentFileReader.h"
28 #include "zypp/parser/susetags/RepoIndex.h"
32 #undef ZYPP_BASE_LOGGER_LOGGROUP
33 #define ZYPP_BASE_LOGGER_LOGGROUP "zypp:fetcher"
35 ///////////////////////////////////////////////////////////////////
37 { /////////////////////////////////////////////////////////////////
40 * class that represents indexes which add metadata
41 * to fetcher jobs and therefore need to be retrieved
46 FetcherIndex( const OnMediaLocation &loc )
49 /** Index localtion. */
50 OnMediaLocation location;
51 /** Whether we read this index. */
52 DefaultIntegral<bool,false> read;
55 typedef shared_ptr<FetcherIndex> FetcherIndex_Ptr;
57 /** std::set ordering (less semantic) */
58 struct SameFetcherIndex
60 bool operator()( const FetcherIndex_Ptr & lhs, const FetcherIndex_Ptr & rhs )
63 return false; // incl. NULL == NULL
65 return true; // NULL < nonNULL
67 return false; // nonNULL > NULL
68 // both nonNULL ==> compare medianr and path
69 if ( lhs->location.medianr() == rhs->location.medianr() )
70 return lhs->location.filename() < rhs->location.filename();
72 return lhs->location.medianr() < rhs->location.medianr();
77 * Class to encapsulate the \ref OnMediaLocation object
78 * and the \ref FileChecker together
87 RecursiveDirectory = Directory | Recursive,
88 // check checksums even if there is no such
89 // checksum (warns of no checksum)
90 AlwaysVerifyChecksum = 0x0004,
92 ZYPP_DECLARE_FLAGS(Flags, Flag);
95 FetcherJob( const OnMediaLocation &loc, const Pathname dfile = Pathname())
100 //MIL << location << endl;
105 //MIL << location << " | * " << checkers.size() << endl;
108 OnMediaLocation location;
110 //CompositeFileChecker checkers;
111 list<FileChecker> checkers;
115 ZYPP_DECLARE_OPERATORS_FOR_FLAGS(FetcherJob::Flags);
116 typedef shared_ptr<FetcherJob> FetcherJob_Ptr;
118 std::ostream & operator<<( std::ostream & str, const FetcherJob_Ptr & obj )
120 return str << obj->location;
123 ///////////////////////////////////////////////////////////////////
125 // CLASS NAME : Fetcher::Impl
127 /** Fetcher implementation. */
130 friend std::ostream & operator<<( std::ostream & str, const Fetcher::Impl & obj );
137 void setOptions( Fetcher::Options options );
138 Fetcher::Options options() const;
140 void addIndex( const OnMediaLocation &resource );
142 void enqueueDir( const OnMediaLocation &resource, bool recursive, const FileChecker &checker = FileChecker() );
143 void enqueueDigestedDir( const OnMediaLocation &resource, bool recursive, const FileChecker &checker = FileChecker() );
145 void enqueue( const OnMediaLocation &resource, const FileChecker &checker = FileChecker() );
146 void enqueueDigested( const OnMediaLocation &resource, const FileChecker &checker = FileChecker(), const Pathname &deltafile = Pathname() );
147 void addCachePath( const Pathname &cache_dir );
149 void start( const Pathname &dest_dir,
150 MediaSetAccess &media,
151 const ProgressData::ReceiverFnc & progress_receiver );
153 /** Offer default Impl. */
154 static shared_ptr<Impl> nullimpl()
156 static shared_ptr<Impl> _nullimpl( new Impl );
161 * download the indexes and reads them
163 void downloadAndReadIndexList( MediaSetAccess &media, const Pathname &dest_dir);
166 * download the indexes and reads them
168 void downloadIndex( MediaSetAccess &media, const OnMediaLocation &resource, const Pathname &dest_dir);
171 * reads a downloaded index file and updates internal
174 * The index lists files relative to a directory, which is
175 * normally the same as the index file is located.
177 void readIndex( const Pathname &index, const Pathname &basedir );
179 /** specific version of \ref readIndex for CHECKSUMS file */
180 void readChecksumsIndex( const Pathname &index, const Pathname &basedir );
182 /** specific version of \ref readIndex for content file */
183 void readContentFileIndex( const Pathname &index, const Pathname &basedir );
185 /** reads the content of a directory but keeps a cache **/
186 void getDirectoryContent( MediaSetAccess &media, const OnMediaLocation &resource, filesystem::DirContent &content );
189 * tries to provide the file represented by job into dest_dir by
190 * looking at the cache. If success, returns true, and the desired
191 * file should be available on dest_dir
193 bool provideFromCache( const OnMediaLocation &resource, const Pathname &dest_dir );
195 * Validates the job against is checkers, by using the file instance
199 void validate( const OnMediaLocation &resource, const Pathname &dest_dir, const list<FileChecker> &checkers );
202 * scan the directory and adds the individual jobs
204 void addDirJobs( MediaSetAccess &media, const OnMediaLocation &resource,
205 const Pathname &dest_dir, FetcherJob::Flags flags );
208 * auto discovery and reading of indexes
210 void autoaddIndexes( const filesystem::DirContent &content,
211 MediaSetAccess &media,
212 const OnMediaLocation &resource,
213 const Pathname &dest_dir );
215 * Provide the resource to \ref dest_dir
217 void provideToDest( MediaSetAccess &media, const OnMediaLocation &resource, const Pathname &dest_dir , const Pathname &deltafile);
220 friend Impl * rwcowClone<Impl>( const Impl * rhs );
221 /** clone for RWCOW_pointer */
223 { return new Impl( *this ); }
225 list<FetcherJob_Ptr> _resources;
226 std::set<FetcherIndex_Ptr,SameFetcherIndex> _indexes;
227 std::set<Pathname> _caches;
228 // checksums read from the indexes
229 map<string, CheckSum> _checksums;
230 // cache of dir contents
231 map<string, filesystem::DirContent> _dircontent;
233 Fetcher::Options _options;
235 ///////////////////////////////////////////////////////////////////
237 void Fetcher::Impl::enqueueDigested( const OnMediaLocation &resource, const FileChecker &checker, const Pathname &deltafile )
240 job.reset(new FetcherJob(resource, deltafile));
241 job->flags |= FetcherJob:: AlwaysVerifyChecksum;
242 _resources.push_back(job);
245 Fetcher::Impl::Impl()
250 void Fetcher::Impl::setOptions( Fetcher::Options options )
251 { _options = options; }
253 Fetcher::Options Fetcher::Impl::options() const
256 void Fetcher::Impl::enqueueDir( const OnMediaLocation &resource,
258 const FileChecker &checker )
261 job.reset(new FetcherJob(resource));
263 job->checkers.push_back(checker);
265 job->flags |= FetcherJob::Recursive;
266 job->flags |= FetcherJob::Directory;
268 _resources.push_back(job);
271 void Fetcher::Impl::enqueueDigestedDir( const OnMediaLocation &resource,
273 const FileChecker &checker )
276 job.reset(new FetcherJob(resource));
278 job->checkers.push_back(checker);
280 job->flags |= FetcherJob::Recursive;
281 job->flags |= FetcherJob::Directory;
282 job->flags |= FetcherJob::AlwaysVerifyChecksum;
284 _resources.push_back(job);
288 void Fetcher::Impl::enqueue( const OnMediaLocation &resource, const FileChecker &checker )
291 job.reset(new FetcherJob(resource));
293 job->checkers.push_back(checker);
294 _resources.push_back(job);
297 void Fetcher::Impl::addIndex( const OnMediaLocation &resource )
299 MIL << "adding index " << resource << endl;
300 _indexes.insert(FetcherIndex_Ptr(new FetcherIndex(resource)));
304 void Fetcher::Impl::reset()
312 void Fetcher::Impl::addCachePath( const Pathname &cache_dir )
314 PathInfo info(cache_dir);
315 if ( info.isExist() )
319 DBG << "Adding fetcher cache: '" << cache_dir << "'." << endl;
320 _caches.insert(cache_dir);
324 // don't add bad cache directory, just log the error
325 ERR << "Not adding cache: '" << cache_dir << "'. Not a directory." << endl;
330 ERR << "Not adding cache '" << cache_dir << "'. Path does not exists." << endl;
335 // tries to provide resource to dest_dir from any of the configured additional
336 // cache paths where the file may already be present. returns true if the
337 // file was provided from the cache.
338 bool Fetcher::Impl::provideFromCache( const OnMediaLocation &resource, const Pathname &dest_dir )
340 Pathname dest_full_path = dest_dir + resource.filename();
342 // first check in the destination directory
343 if ( PathInfo(dest_full_path).isExist() )
345 if ( is_checksum( dest_full_path, resource.checksum() )
346 && (! resource.checksum().empty() ) )
350 MIL << "start fetcher with " << _caches.size() << " cache directories." << endl;
351 for_ ( it_cache, _caches.begin(), _caches.end() )
353 // does the current file exists in the current cache?
354 Pathname cached_file = *it_cache + resource.filename();
355 if ( PathInfo( cached_file ).isExist() )
357 DBG << "File '" << cached_file << "' exist, testing checksum " << resource.checksum() << endl;
358 // check the checksum
359 if ( is_checksum( cached_file, resource.checksum() ) && (! resource.checksum().empty() ) )
362 MIL << "file " << resource.filename() << " found in previous cache. Using cached copy." << endl;
363 // checksum is already checked.
364 // we could later implement double failover and try to download if file copy fails.
365 // replicate the complete path in the target directory
366 if( dest_full_path != cached_file )
368 if ( assert_dir( dest_full_path.dirname() ) != 0 )
369 ZYPP_THROW( Exception("Can't create " + dest_full_path.dirname().asString()));
371 if ( filesystem::hardlinkCopy(cached_file, dest_full_path ) != 0 )
373 ERR << "Can't hardlink/copy " << cached_file + " to " + dest_dir << endl;
381 } // iterate over caches
385 void Fetcher::Impl::validate( const OnMediaLocation &resource, const Pathname &dest_dir, const list<FileChecker> &checkers )
387 // no matter where did we got the file, try to validate it:
388 Pathname localfile = dest_dir + resource.filename();
389 // call the checker function
392 MIL << "Checking job [" << localfile << "] (" << checkers.size() << " checkers )" << endl;
394 for ( list<FileChecker>::const_iterator it = checkers.begin();
395 it != checkers.end();
404 ERR << "Invalid checker for '" << localfile << "'" << endl;
409 catch ( const FileCheckException &e )
413 catch ( const Exception &e )
419 ZYPP_THROW(Exception("Unknown error while validating " + resource.filename().asString()));
423 void Fetcher::Impl::autoaddIndexes( const filesystem::DirContent &content,
424 MediaSetAccess &media,
425 const OnMediaLocation &resource,
426 const Pathname &dest_dir )
428 auto fnc_addIfInContent( [&]( const std::string & index_r ) -> bool
430 if ( find( content.begin(), content.end(), filesystem::DirEntry(index_r,filesystem::FT_FILE) ) == content.end() )
432 // add the index of this directory
433 OnMediaLocation indexloc( resource );
434 indexloc.changeFilename( resource.filename() + index_r );
435 addIndex( indexloc );
436 // we need to read it now
437 downloadAndReadIndexList( media, dest_dir );
441 if ( _options & AutoAddChecksumsIndexes )
443 fnc_addIfInContent( "CHECKSUMS" ) || fnc_addIfInContent( "SHA1SUMS" );
445 if ( _options & AutoAddContentFileIndexes )
447 fnc_addIfInContent( "content" );
451 void Fetcher::Impl::getDirectoryContent( MediaSetAccess &media,
452 const OnMediaLocation &resource,
453 filesystem::DirContent &content )
455 if ( _dircontent.find(resource.filename().asString())
456 != _dircontent.end() )
458 filesystem::DirContent filled(_dircontent[resource.filename().asString()]);
460 std::copy(filled.begin(), filled.end(), std::back_inserter(content));
464 filesystem::DirContent tofill;
465 media.dirInfo( tofill,
469 std::copy(tofill.begin(), tofill.end(), std::back_inserter(content));
470 _dircontent[resource.filename().asString()] = tofill;
474 void Fetcher::Impl::addDirJobs( MediaSetAccess &media,
475 const OnMediaLocation &resource,
476 const Pathname &dest_dir, FetcherJob::Flags flags )
478 // first get the content of the directory so we can add
479 // individual transfer jobs
480 MIL << "Adding directory " << resource.filename() << endl;
481 filesystem::DirContent content;
483 getDirectoryContent(media, resource, content);
485 catch ( media::MediaFileNotFoundException & exception )
487 ZYPP_CAUGHT( exception );
488 WAR << "Skiping subtree hidden at " << resource.filename() << endl;
492 // this method test for the option flags so indexes are added
493 // only if the options are enabled
494 autoaddIndexes(content, media, resource, dest_dir);
496 for ( filesystem::DirContent::const_iterator it = content.begin();
500 // skip CHECKSUMS* as they were already retrieved
501 if ( str::hasPrefix(it->name, "CHECKSUMS") || str::hasPrefix(it->name, "SHA1SUMS") )
504 Pathname filename = resource.filename() + it->name;
508 case filesystem::FT_NOT_AVAIL: // old directory.yast contains no typeinfo at all
509 case filesystem::FT_FILE:
511 CheckSum chksm(resource.checksum());
512 if ( _checksums.find(filename.asString()) != _checksums.end() )
514 // the checksum can be replaced with the one in the index.
515 chksm = _checksums[filename.asString()];
516 //MIL << "resource " << filename << " has checksum in the index file." << endl;
519 WAR << "Resource " << filename << " has no checksum in the index either." << endl;
521 if ( flags & FetcherJob::AlwaysVerifyChecksum )
522 enqueueDigested(OnMediaLocation(filename, resource.medianr()).setChecksum(chksm));
524 enqueue(OnMediaLocation(filename, resource.medianr()).setChecksum(chksm));
527 case filesystem::FT_DIR: // newer directory.yast contain at least directory info
528 if ( flags & FetcherJob::Recursive )
529 addDirJobs(media, filename, dest_dir, flags);
532 // don't provide devices, sockets, etc.
538 void Fetcher::Impl::provideToDest( MediaSetAccess &media, const OnMediaLocation &resource, const Pathname &dest_dir, const Pathname &deltafile )
540 bool got_from_cache = false;
542 // start look in cache
543 got_from_cache = provideFromCache(resource, dest_dir);
545 if ( ! got_from_cache )
547 MIL << "Not found in cache, downloading" << endl;
549 // try to get the file from the net
552 Pathname tmp_file = media.provideFile(resource, resource.optional() ? MediaSetAccess::PROVIDE_NON_INTERACTIVE : MediaSetAccess::PROVIDE_DEFAULT, deltafile );
554 Pathname dest_full_path = dest_dir + resource.filename();
556 if ( assert_dir( dest_full_path.dirname() ) != 0 )
557 ZYPP_THROW( Exception("Can't create " + dest_full_path.dirname().asString()));
558 if ( filesystem::hardlinkCopy( tmp_file, dest_full_path ) != 0 )
560 if ( ! PathInfo(tmp_file).isExist() )
561 ERR << tmp_file << " does not exist" << endl;
562 if ( ! PathInfo(dest_full_path.dirname()).isExist() )
563 ERR << dest_full_path.dirname() << " does not exist" << endl;
565 media.releaseFile(resource); //not needed anymore, only eat space
566 ZYPP_THROW( Exception("Can't hardlink/copy " + tmp_file.asString() + " to " + dest_dir.asString()));
569 media.releaseFile(resource); //not needed anymore, only eat space
571 catch (Exception & excpt_r)
573 if ( resource.optional() )
575 ZYPP_CAUGHT(excpt_r);
576 WAR << "optional resource " << resource << " could not be transferred" << endl;
581 excpt_r.remember("Can't provide " + resource.filename().asString() );
582 ZYPP_RETHROW(excpt_r);
588 // We got the file from cache
589 // continue with next file
594 // helper class to consume a content file
595 struct ContentReaderHelper : public parser::susetags::ContentFileReader
597 ContentReaderHelper()
599 setRepoIndexConsumer( bind( &ContentReaderHelper::consumeIndex, this, _1 ) );
602 void consumeIndex( const parser::susetags::RepoIndex_Ptr & data_r )
603 { _repoindex = data_r; }
605 parser::susetags::RepoIndex_Ptr _repoindex;
608 // generic function for reading indexes
609 void Fetcher::Impl::readIndex( const Pathname &index, const Pathname &basedir )
611 if ( index.basename() == "CHECKSUMS" || index.basename() == "SHA1SUMS" )
612 readChecksumsIndex(index, basedir);
613 else if ( index.basename() == "content" )
614 readContentFileIndex(index, basedir);
616 WAR << index << ": index file format not known" << endl;
619 // reads a content file index
620 void Fetcher::Impl::readContentFileIndex( const Pathname &index, const Pathname &basedir )
622 ContentReaderHelper reader;
624 MIL << index << " contains " << reader._repoindex->mediaFileChecksums.size() << " checksums." << endl;
625 for_( it, reader._repoindex->mediaFileChecksums.begin(), reader._repoindex->mediaFileChecksums.end() )
627 // content file entries don't start with /
628 _checksums[(basedir + it->first).asString()] = it->second;
632 // reads a CHECKSUMS (old SHA1SUMS) file index
633 void Fetcher::Impl::readChecksumsIndex( const Pathname &index, const Pathname &basedir )
635 std::ifstream in( index.c_str() );
639 while ( getline( in, buffer ) )
642 if ( buffer[0] == '#' )
643 continue; // simple comment
645 CheckSum checksum( str::stripFirstWord( buffer, /*ltrim before strip*/true ) );
646 if ( checksum.empty() )
647 continue; // empty line | unknown cheksum format
649 if ( buffer.empty() )
651 WAR << "Missing filename in CHECKSUMS file: " << index.asString() << " (" << checksum << ")" << endl;
655 _checksums[(basedir/buffer).asString()] = checksum;
659 ZYPP_THROW(Exception("Can't open CHECKSUMS file: " + index.asString()));
662 void Fetcher::Impl::downloadIndex( MediaSetAccess &media, const OnMediaLocation &resource, const Pathname &dest_dir)
664 MIL << "downloading index " << resource << endl;
665 // create a new fetcher with a different state to transfer the
666 // file containing checksums and its signature
668 // signature checker for index. We havent got the signature from
670 SignatureFileChecker sigchecker;
672 // build the name of the index and the signature
673 OnMediaLocation idxloc(resource);
674 OnMediaLocation sigloc(resource);
675 OnMediaLocation keyloc(resource);
677 // we should not fail the download if those don't exists
678 // the checking will warn later
679 sigloc.setOptional(true);
680 keyloc.setOptional(true);
682 // calculate signature and key name
683 sigloc.changeFilename( sigloc.filename().extend(".asc") );
684 keyloc.changeFilename( keyloc.filename().extend(".key") );
686 //assert_dir(dest_dir + idxloc.filename().dirname());
688 // transfer the signature
689 fetcher.enqueue(sigloc);
690 fetcher.start( dest_dir, media );
691 // if we get the signature, update the checker
692 if ( PathInfo(dest_dir + sigloc.filename()).isExist() )
693 sigchecker = SignatureFileChecker(dest_dir + sigloc.filename());
698 fetcher.enqueue(keyloc);
699 fetcher.start( dest_dir, media );
702 // try to import the key
703 if ( PathInfo(dest_dir + keyloc.filename()).isExist() )
704 getZYpp()->keyRing()->importKey(PublicKey(dest_dir + keyloc.filename()), false);
706 WAR << "No public key specified by user for index '" << keyloc.filename() << "'"<< endl;
708 // now the index itself
709 fetcher.enqueue( idxloc, FileChecker(sigchecker) );
710 fetcher.start( dest_dir, media );
714 // this method takes all the user pointed indexes, gets them and also tries to
715 // download their signature, and verify them. After that, its parses each one
716 // to fill the checksum cache.
717 void Fetcher::Impl::downloadAndReadIndexList( MediaSetAccess &media, const Pathname &dest_dir)
719 // if there is no indexes, then just return to avoid
720 // the directory listing
721 if ( _indexes.empty() )
723 MIL << "No indexes to read." << endl;
727 for_( it_idx, _indexes.begin(), _indexes.end() )
729 if ( (*it_idx)->read )
731 DBG << "Already read index " << PathInfo(dest_dir + (*it_idx)->location.filename()) << endl;
735 // base::LogControl::TmpLineWriter shutUp;
736 downloadIndex( media, (*it_idx)->location, dest_dir );
737 // now we have the indexes in dest_dir
738 readIndex( dest_dir + (*it_idx)->location.filename(), (*it_idx)->location.filename().dirname() );
739 // Take care we don't process it again
740 MIL << "Remember read index " << PathInfo(dest_dir + (*it_idx)->location.filename()) << endl;
741 (*it_idx)->read = true;
744 MIL << "done reading indexes" << endl;
747 // start processing all fetcher jobs.
748 // it processes any user pointed index first
749 void Fetcher::Impl::start( const Pathname &dest_dir,
750 MediaSetAccess &media,
751 const ProgressData::ReceiverFnc & progress_receiver )
753 ProgressData progress(_resources.size());
754 progress.sendTo(progress_receiver);
756 downloadAndReadIndexList(media, dest_dir);
758 for ( list<FetcherJob_Ptr>::const_iterator it_res = _resources.begin(); it_res != _resources.end(); ++it_res )
761 if ( (*it_res)->flags & FetcherJob::Directory )
763 const OnMediaLocation location((*it_res)->location);
764 addDirJobs(media, location, dest_dir, (*it_res)->flags);
768 // may be this code can be factored out
769 // together with the autodiscovery of indexes
771 if ( ( _options & AutoAddChecksumsIndexes ) ||
772 ( _options & AutoAddContentFileIndexes ) )
774 // if auto indexing is enabled, then we need to read the
775 // index for each file. We look only in the directory
776 // where the file is. this is expensive of course.
777 filesystem::DirContent content;
778 getDirectoryContent(media, (*it_res)->location.filename().dirname(), content);
779 // this method test for the option flags so indexes are added
780 // only if the options are enabled
781 MIL << "Autodiscovering signed indexes on '"
782 << (*it_res)->location.filename().dirname() << "' for '"
783 << (*it_res)->location.filename() << "'" << endl;
785 autoaddIndexes(content, media, (*it_res)->location.filename().dirname(), dest_dir);
787 // also look in the root of the media
789 getDirectoryContent(media, Pathname("/"), content);
790 // this method test for the option flags so indexes are added
791 // only if the options are enabled
792 MIL << "Autodiscovering signed indexes on '"
794 << (*it_res)->location.filename() << "'" << endl;
796 autoaddIndexes(content, media, Pathname("/"), dest_dir);
799 provideToDest(media, (*it_res)->location, dest_dir, (*it_res)->deltafile);
801 // if the file was not transferred, and no exception, just
802 // return, as it was an optional file
803 if ( ! PathInfo(dest_dir + (*it_res)->location.filename()).isExist() )
806 // if the checksum is empty, but the checksum is in one of the
807 // indexes checksum, then add a checker
808 if ( (*it_res)->location.checksum().empty() )
810 if ( _checksums.find((*it_res)->location.filename().asString())
811 != _checksums.end() )
813 CheckSum chksm = _checksums[(*it_res)->location.filename().asString()];
814 ChecksumFileChecker digest_check(chksm);
815 (*it_res)->checkers.push_back(digest_check);
819 // if the index checksum is empty too, we only add the checker
820 // if the AlwaysVerifyChecksum option is set on
821 if ( (*it_res)->flags & FetcherJob::AlwaysVerifyChecksum )
823 // add the checker with the empty checksum
824 ChecksumFileChecker digest_check((*it_res)->location.checksum());
825 (*it_res)->checkers.push_back(digest_check);
831 // checksum is not empty, so add a checksum checker
832 ChecksumFileChecker digest_check((*it_res)->location.checksum());
833 (*it_res)->checkers.push_back(digest_check);
836 // validate job, this throws if not valid
837 validate((*it_res)->location, dest_dir, (*it_res)->checkers);
839 if ( ! progress.incr() )
840 ZYPP_THROW(AbortRequestException());
844 /** \relates Fetcher::Impl Stream output */
845 inline std::ostream & operator<<( std::ostream & str, const Fetcher::Impl & obj )
847 for ( list<FetcherJob_Ptr>::const_iterator it_res = obj._resources.begin(); it_res != obj._resources.end(); ++it_res )
855 : _pimpl( new Impl() )
861 void Fetcher::setOptions( Fetcher::Options options )
863 _pimpl->setOptions(options);
866 Fetcher::Options Fetcher::options() const
868 return _pimpl->options();
871 void Fetcher::enqueueDigested( const OnMediaLocation &resource, const FileChecker &checker, const Pathname &deltafile )
873 _pimpl->enqueueDigested(resource, checker, deltafile);
876 void Fetcher::enqueueDir( const OnMediaLocation &resource,
878 const FileChecker &checker )
880 _pimpl->enqueueDir(resource, recursive, checker);
883 void Fetcher::enqueueDigestedDir( const OnMediaLocation &resource,
885 const FileChecker &checker )
887 _pimpl->enqueueDigestedDir(resource, recursive, checker);
891 void Fetcher::addIndex( const OnMediaLocation &resource )
893 _pimpl->addIndex(resource);
897 void Fetcher::enqueue( const OnMediaLocation &resource, const FileChecker &checker )
899 _pimpl->enqueue(resource, checker);
902 void Fetcher::addCachePath( const Pathname &cache_dir )
904 _pimpl->addCachePath(cache_dir);
907 void Fetcher::reset()
912 void Fetcher::start( const Pathname &dest_dir,
913 MediaSetAccess &media,
914 const ProgressData::ReceiverFnc & progress_receiver )
916 _pimpl->start(dest_dir, media, progress_receiver);
919 std::ostream & operator<<( std::ostream & str, const Fetcher & obj )
921 return str << *obj._pimpl;
924 /////////////////////////////////////////////////////////////////
926 ///////////////////////////////////////////////////////////////////