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/CheckSum.h"
25 #include "zypp/base/UserRequestException.h"
26 #include "zypp/parser/susetags/ContentFileReader.h"
27 #include "zypp/parser/susetags/RepoIndex.h"
31 #undef ZYPP_BASE_LOGGER_LOGGROUP
32 #define ZYPP_BASE_LOGGER_LOGGROUP "zypp:fetcher"
34 ///////////////////////////////////////////////////////////////////
36 { /////////////////////////////////////////////////////////////////
39 * class that represents indexes which add metadata
40 * to fetcher jobs and therefore need to be retrieved
45 FetcherIndex( const OnMediaLocation &loc )
48 /** Index localtion. */
49 OnMediaLocation location;
50 /** Whether we read this index. */
51 DefaultIntegral<bool,false> read;
54 typedef shared_ptr<FetcherIndex> FetcherIndex_Ptr;
56 /** std::set ordering (less semantic) */
57 struct SameFetcherIndex
59 bool operator()( const FetcherIndex_Ptr & lhs, const FetcherIndex_Ptr & rhs )
62 return false; // incl. NULL == NULL
64 return true; // NULL < nonNULL
66 return false; // nonNULL > NULL
67 // both nonNULL ==> compare medianr and path
68 if ( lhs->location.medianr() == rhs->location.medianr() )
69 return lhs->location.filename() < rhs->location.filename();
71 return lhs->location.medianr() < rhs->location.medianr();
76 * Class to encapsulate the \ref OnMediaLocation object
77 * and the \ref FileChecker together
86 RecursiveDirectory = Directory | Recursive,
87 // check checksums even if there is no such
88 // checksum (warns of no checksum)
89 AlwaysVerifyChecksum = 0x0004,
91 ZYPP_DECLARE_FLAGS(Flags, Flag);
94 FetcherJob( const OnMediaLocation &loc )
98 //MIL << location << endl;
103 //MIL << location << " | * " << checkers.size() << endl;
106 OnMediaLocation location;
107 //CompositeFileChecker checkers;
108 list<FileChecker> checkers;
112 ZYPP_DECLARE_OPERATORS_FOR_FLAGS(FetcherJob::Flags);
113 typedef shared_ptr<FetcherJob> FetcherJob_Ptr;
115 std::ostream & operator<<( std::ostream & str, const FetcherJob_Ptr & obj )
117 return str << obj->location;
120 ///////////////////////////////////////////////////////////////////
122 // CLASS NAME : Fetcher::Impl
124 /** Fetcher implementation. */
127 friend std::ostream & operator<<( std::ostream & str, const Fetcher::Impl & obj );
136 void setOptions( Fetcher::Options options );
137 Fetcher::Options options() const;
139 void addIndex( const OnMediaLocation &resource );
141 void enqueueDir( const OnMediaLocation &resource, bool recursive, const FileChecker &checker = FileChecker() );
142 void enqueueDigestedDir( const OnMediaLocation &resource, bool recursive, const FileChecker &checker = FileChecker() );
144 void enqueue( const OnMediaLocation &resource, const FileChecker &checker = FileChecker() );
145 void enqueueDigested( const OnMediaLocation &resource, const FileChecker &checker = FileChecker() );
146 void addCachePath( const Pathname &cache_dir );
148 void start( const Pathname &dest_dir,
149 MediaSetAccess &media,
150 const ProgressData::ReceiverFnc & progress_receiver );
152 /** Offer default Impl. */
153 static shared_ptr<Impl> nullimpl()
155 static shared_ptr<Impl> _nullimpl( new Impl );
160 * download the indexes and reads them
162 void downloadAndReadIndexList( MediaSetAccess &media, const Pathname &dest_dir);
165 * download the indexes and reads them
167 void downloadIndex( MediaSetAccess &media, const OnMediaLocation &resource, const Pathname &dest_dir);
170 * reads a downloaded index file and updates internal
173 * The index lists files relative to a directory, which is
174 * normally the same as the index file is located.
176 void readIndex( const Pathname &index, const Pathname &basedir );
178 /** specific version of \ref readIndex for SHA1SUMS file */
179 void readSha1sumsIndex( const Pathname &index, const Pathname &basedir );
181 /** specific version of \ref readIndex for SHA1SUMS file */
182 void readContentFileIndex( const Pathname &index, const Pathname &basedir );
184 /** reads the content of a directory but keeps a cache **/
185 void getDirectoryContent( MediaSetAccess &media, const OnMediaLocation &resource, filesystem::DirContent &content );
188 * tries to provide the file represented by job into dest_dir by
189 * looking at the cache. If success, returns true, and the desired
190 * file should be available on dest_dir
192 bool provideFromCache( const OnMediaLocation &resource, const Pathname &dest_dir );
194 * Validates the job against is checkers, by using the file instance
198 void validate( const OnMediaLocation &resource, const Pathname &dest_dir, const list<FileChecker> &checkers );
201 * scan the directory and adds the individual jobs
203 void addDirJobs( MediaSetAccess &media, const OnMediaLocation &resource,
204 const Pathname &dest_dir, FetcherJob::Flags flags );
207 * auto discovery and reading of indexes
209 void autoaddIndexes( const filesystem::DirContent &content,
210 MediaSetAccess &media,
211 const OnMediaLocation &resource,
212 const Pathname &dest_dir );
214 * Provide the resource to \ref dest_dir
216 void provideToDest( MediaSetAccess &media, const OnMediaLocation &resource, const Pathname &dest_dir );
219 friend Impl * rwcowClone<Impl>( const Impl * rhs );
220 /** clone for RWCOW_pointer */
222 { return new Impl( *this ); }
224 list<FetcherJob_Ptr> _resources;
225 std::set<FetcherIndex_Ptr,SameFetcherIndex> _indexes;
226 std::set<Pathname> _caches;
227 // checksums read from the indexes
228 map<string, CheckSum> _checksums;
229 // cache of dir contents
230 map<string, filesystem::DirContent> _dircontent;
232 Fetcher::Options _options;
234 ///////////////////////////////////////////////////////////////////
236 void Fetcher::Impl::enqueueDigested( const OnMediaLocation &resource, const FileChecker &checker )
239 job.reset(new FetcherJob(resource));
240 job->flags |= FetcherJob:: AlwaysVerifyChecksum;
241 _resources.push_back(job);
244 Fetcher::Impl::Impl()
249 void Fetcher::Impl::setOptions( Fetcher::Options options )
250 { _options = options; }
252 Fetcher::Options Fetcher::Impl::options() const
255 void Fetcher::Impl::enqueueDir( const OnMediaLocation &resource,
257 const FileChecker &checker )
260 job.reset(new FetcherJob(resource));
262 job->checkers.push_back(checker);
264 job->flags |= FetcherJob::Recursive;
265 job->flags |= FetcherJob::Directory;
267 _resources.push_back(job);
270 void Fetcher::Impl::enqueueDigestedDir( const OnMediaLocation &resource,
272 const FileChecker &checker )
275 job.reset(new FetcherJob(resource));
277 job->checkers.push_back(checker);
279 job->flags |= FetcherJob::Recursive;
280 job->flags |= FetcherJob::Directory;
281 job->flags |= FetcherJob::AlwaysVerifyChecksum;
283 _resources.push_back(job);
287 void Fetcher::Impl::enqueue( const OnMediaLocation &resource, const FileChecker &checker )
290 job.reset(new FetcherJob(resource));
292 job->checkers.push_back(checker);
293 _resources.push_back(job);
296 void Fetcher::Impl::addIndex( const OnMediaLocation &resource )
298 MIL << "adding index " << resource << endl;
299 _indexes.insert(FetcherIndex_Ptr(new FetcherIndex(resource)));
303 void Fetcher::Impl::reset()
311 void Fetcher::Impl::addCachePath( const Pathname &cache_dir )
313 PathInfo info(cache_dir);
314 if ( info.isExist() )
318 DBG << "Adding fetcher cache: '" << cache_dir << "'." << endl;
319 _caches.insert(cache_dir);
323 // don't add bad cache directory, just log the error
324 ERR << "Not adding cache: '" << cache_dir << "'. Not a directory." << endl;
329 ERR << "Not adding cache '" << cache_dir << "'. Path does not exists." << endl;
334 // tries to provide resource to dest_dir from any of the configured additional
335 // cache paths where the file may already be present. returns true if the
336 // file was provided from the cache.
337 bool Fetcher::Impl::provideFromCache( const OnMediaLocation &resource, const Pathname &dest_dir )
339 Pathname dest_full_path = dest_dir + resource.filename();
341 // first check in the destination directory
342 if ( PathInfo(dest_full_path).isExist() )
344 if ( is_checksum( dest_full_path, resource.checksum() )
345 && (! resource.checksum().empty() ) )
349 MIL << "start fetcher with " << _caches.size() << " cache directories." << endl;
350 for_ ( it_cache, _caches.begin(), _caches.end() )
352 // does the current file exists in the current cache?
353 Pathname cached_file = *it_cache + resource.filename();
354 if ( PathInfo( cached_file ).isExist() )
356 DBG << "File '" << cached_file << "' exist, testing checksum " << resource.checksum() << endl;
357 // check the checksum
358 if ( is_checksum( cached_file, resource.checksum() ) && (! resource.checksum().empty() ) )
361 MIL << "file " << resource.filename() << " found in previous cache. Using cached copy." << endl;
362 // checksum is already checked.
363 // we could later implement double failover and try to download if file copy fails.
364 // replicate the complete path in the target directory
365 if( dest_full_path != cached_file )
367 if ( assert_dir( dest_full_path.dirname() ) != 0 )
368 ZYPP_THROW( Exception("Can't create " + dest_full_path.dirname().asString()));
370 if ( filesystem::hardlink(cached_file, dest_full_path ) != 0 )
372 WAR << "Can't hardlink '" << cached_file << "' to '" << dest_dir << "'. Trying copying." << endl;
373 if ( filesystem::copy(cached_file, dest_full_path ) != 0 )
375 ERR << "Can't copy " << cached_file + " to " + dest_dir << endl;
385 } // iterate over caches
389 void Fetcher::Impl::validate( const OnMediaLocation &resource, const Pathname &dest_dir, const list<FileChecker> &checkers )
391 // no matter where did we got the file, try to validate it:
392 Pathname localfile = dest_dir + resource.filename();
393 // call the checker function
396 MIL << "Checking job [" << localfile << "] (" << checkers.size() << " checkers )" << endl;
398 for ( list<FileChecker>::const_iterator it = checkers.begin();
399 it != checkers.end();
408 ERR << "Invalid checker for '" << localfile << "'" << endl;
413 catch ( const FileCheckException &e )
417 catch ( const Exception &e )
423 ZYPP_THROW(Exception("Unknown error while validating " + resource.filename().asString()));
427 void Fetcher::Impl::autoaddIndexes( const filesystem::DirContent &content,
428 MediaSetAccess &media,
429 const OnMediaLocation &resource,
430 const Pathname &dest_dir )
432 if ( _options & AutoAddSha1sumsIndexes )
434 // only try to add an index if it exists
435 filesystem::DirEntry shafile;
436 shafile.name = "SHA1SUMS"; shafile.type = filesystem::FT_FILE;
437 if ( find( content.begin(), content.end(), shafile ) != content.end() )
439 // add the index of this directory
440 OnMediaLocation indexloc(resource);
441 indexloc.changeFilename(resource.filename() + "SHA1SUMS");
443 // we need to read it now
444 downloadAndReadIndexList(media, dest_dir);
447 if ( _options & AutoAddContentFileIndexes )
449 // only try to add an index if it exists
450 filesystem::DirEntry contentfile;
451 contentfile.name = "content"; contentfile.type = filesystem::FT_FILE;
452 if ( find( content.begin(), content.end(), contentfile ) != content.end() )
454 // add the index of this directory
455 OnMediaLocation indexloc(resource);
456 indexloc.changeFilename(resource.filename() + "content");
458 // we need to read it now
459 downloadAndReadIndexList(media, dest_dir);
464 void Fetcher::Impl::getDirectoryContent( MediaSetAccess &media,
465 const OnMediaLocation &resource,
466 filesystem::DirContent &content )
468 if ( _dircontent.find(resource.filename().asString())
469 != _dircontent.end() )
471 filesystem::DirContent filled(_dircontent[resource.filename().asString()]);
473 std::copy(filled.begin(), filled.end(), std::back_inserter(content));
477 filesystem::DirContent tofill;
478 media.dirInfo( tofill,
482 std::copy(tofill.begin(), tofill.end(), std::back_inserter(content));
483 _dircontent[resource.filename().asString()] = tofill;
487 void Fetcher::Impl::addDirJobs( MediaSetAccess &media,
488 const OnMediaLocation &resource,
489 const Pathname &dest_dir, FetcherJob::Flags flags )
491 // first get the content of the directory so we can add
492 // individual transfer jobs
493 MIL << "Adding directory " << resource.filename() << endl;
494 filesystem::DirContent content;
495 getDirectoryContent(media, resource, content);
497 // this method test for the option flags so indexes are added
498 // only if the options are enabled
499 autoaddIndexes(content, media, resource, dest_dir);
501 for ( filesystem::DirContent::const_iterator it = content.begin();
505 // skip SHA1SUMS* as they were already retrieved
506 if ( str::hasPrefix(it->name, "SHA1SUMS") )
509 Pathname filename = resource.filename() + it->name;
513 case filesystem::FT_NOT_AVAIL: // old directory.yast contains no typeinfo at all
514 case filesystem::FT_FILE:
516 CheckSum chksm(resource.checksum());
517 if ( _checksums.find(filename.asString()) != _checksums.end() )
519 // the checksum can be replaced with the one in the index.
520 chksm = _checksums[filename.asString()];
521 //MIL << "resource " << filename << " has checksum in the index file." << endl;
524 WAR << "Resource " << filename << " has no checksum in the index either." << endl;
526 if ( flags & FetcherJob::AlwaysVerifyChecksum )
527 enqueueDigested(OnMediaLocation(filename, resource.medianr()).setChecksum(chksm));
529 enqueue(OnMediaLocation(filename, resource.medianr()).setChecksum(chksm));
532 case filesystem::FT_DIR: // newer directory.yast contain at least directory info
533 if ( flags & FetcherJob::Recursive )
534 addDirJobs(media, filename, dest_dir, flags);
537 // don't provide devices, sockets, etc.
543 void Fetcher::Impl::provideToDest( MediaSetAccess &media, const OnMediaLocation &resource, const Pathname &dest_dir )
545 bool got_from_cache = false;
547 // start look in cache
548 got_from_cache = provideFromCache(resource, dest_dir);
550 if ( ! got_from_cache )
552 MIL << "Not found in cache, downloading" << endl;
554 // try to get the file from the net
557 Pathname tmp_file = media.provideFile(resource);
558 Pathname dest_full_path = dest_dir + resource.filename();
559 if ( assert_dir( dest_full_path.dirname() ) != 0 )
560 ZYPP_THROW( Exception("Can't create " + dest_full_path.dirname().asString()));
561 if ( filesystem::copy(tmp_file, dest_full_path ) != 0 )
563 if ( ! PathInfo(tmp_file).isExist() )
564 ERR << tmp_file << " does not exist" << endl;
565 if ( ! PathInfo(dest_full_path.dirname()).isExist() )
566 ERR << dest_full_path.dirname() << " does not exist" << endl;
568 media.releaseFile(resource); //not needed anymore, only eat space
569 ZYPP_THROW( Exception("Can't copy " + tmp_file.asString() + " to " + dest_dir.asString()));
572 media.releaseFile(resource); //not needed anymore, only eat space
574 catch (Exception & excpt_r)
576 ZYPP_CAUGHT(excpt_r);
577 excpt_r.remember("Can't provide " + resource.filename().asString() + " : " + excpt_r.msg());
579 if ( resource.optional() )
581 WAR << "optional resource " << resource << " could not be transfered" << endl;
586 ZYPP_RETHROW(excpt_r);
592 // We got the file from cache
593 // continue with next file
598 // helper class to consume a content file
599 struct ContentReaderHelper : public parser::susetags::ContentFileReader
601 ContentReaderHelper()
603 setRepoIndexConsumer( bind( &ContentReaderHelper::consumeIndex, this, _1 ) );
606 void consumeIndex( const parser::susetags::RepoIndex_Ptr & data_r )
607 { _repoindex = data_r; }
609 parser::susetags::RepoIndex_Ptr _repoindex;
612 // generic function for reading indexes
613 void Fetcher::Impl::readIndex( const Pathname &index, const Pathname &basedir )
615 if ( index.basename() == "SHA1SUMS" )
616 readSha1sumsIndex(index, basedir);
617 else if ( index.basename() == "content" )
618 readContentFileIndex(index, basedir);
620 WAR << index << ": index file format not known" << endl;
623 // reads a content file index
624 void Fetcher::Impl::readContentFileIndex( const Pathname &index, const Pathname &basedir )
626 ContentReaderHelper reader;
628 MIL << index << " contains " << reader._repoindex->mediaFileChecksums.size() << " checksums." << endl;
629 for_( it, reader._repoindex->mediaFileChecksums.begin(), reader._repoindex->mediaFileChecksums.end() )
631 // content file entries don't start with /
632 _checksums[(basedir + it->first).asString()] = it->second;
636 // reads a SHA1SUMS file index
637 void Fetcher::Impl::readSha1sumsIndex( const Pathname &index, const Pathname &basedir )
639 std::ifstream in( index.c_str() );
643 while ( getline(in, buffer) )
645 vector<string> words;
646 str::split( buffer, back_inserter(words) );
647 if ( words.size() != 2 )
648 ZYPP_THROW(Exception("Wrong format for SHA1SUMS file"));
649 //MIL << "check: '" << words[0] << "' | '" << words[1] << "'" << endl;
650 if ( ! words[1].empty() )
651 _checksums[(basedir + words[1]).asString()] = CheckSum::sha1(words[0]);
655 ZYPP_THROW(Exception("Can't open SHA1SUMS file: " + index.asString()));
658 void Fetcher::Impl::downloadIndex( MediaSetAccess &media, const OnMediaLocation &resource, const Pathname &dest_dir)
660 MIL << "downloading index " << resource << endl;
661 // create a new fetcher with a different state to transfer the
662 // file containing checksums and its signature
664 // signature checker for index. We havent got the signature from
666 SignatureFileChecker sigchecker;
668 // build the name of the index and the signature
669 OnMediaLocation idxloc(resource);
670 OnMediaLocation sigloc(resource);
671 OnMediaLocation keyloc(resource);
673 // we should not fail the download if those don't exists
674 // the checking will warn later
675 sigloc.setOptional(true);
676 keyloc.setOptional(true);
678 // calculate signature and key name
679 sigloc.changeFilename( sigloc.filename().extend(".asc") );
680 keyloc.changeFilename( keyloc.filename().extend(".key") );
682 //assert_dir(dest_dir + idxloc.filename().dirname());
684 // transfer the signature
685 fetcher.enqueue(sigloc);
686 fetcher.start( dest_dir, media );
687 // if we get the signature, update the checker
688 if ( PathInfo(dest_dir + sigloc.filename()).isExist() )
689 sigchecker = SignatureFileChecker(dest_dir + sigloc.filename());
694 fetcher.enqueue(keyloc);
695 fetcher.start( dest_dir, media );
698 // now the index itself
699 fetcher.enqueue( idxloc, FileChecker(sigchecker) );
700 fetcher.start( dest_dir, media );
704 // this method takes all the user pointed indexes, gets them and also tries to
705 // download their signature, and verify them. After that, its parses each one
706 // to fill the checksum cache.
707 void Fetcher::Impl::downloadAndReadIndexList( MediaSetAccess &media, const Pathname &dest_dir)
709 // if there is no indexes, then just return to avoid
710 // the directory listing
711 if ( _indexes.empty() )
713 MIL << "No indexes to read." << endl;
717 for_( it_idx, _indexes.begin(), _indexes.end() )
719 if ( (*it_idx)->read )
721 DBG << "Already read index " << PathInfo(dest_dir + (*it_idx)->location.filename()) << endl;
725 // base::LogControl::TmpLineWriter shutUp;
726 downloadIndex( media, (*it_idx)->location, dest_dir );
727 // now we have the indexes in dest_dir
728 readIndex( dest_dir + (*it_idx)->location.filename(), (*it_idx)->location.filename().dirname() );
729 // Take care we don't process it again
730 MIL << "Remember read index " << PathInfo(dest_dir + (*it_idx)->location.filename()) << endl;
731 (*it_idx)->read = true;
734 MIL << "done reading indexes" << endl;
737 // start processing all fetcher jobs.
738 // it processes any user pointed index first
739 void Fetcher::Impl::start( const Pathname &dest_dir,
740 MediaSetAccess &media,
741 const ProgressData::ReceiverFnc & progress_receiver )
743 ProgressData progress(_resources.size());
744 progress.sendTo(progress_receiver);
746 downloadAndReadIndexList(media, dest_dir);
748 for ( list<FetcherJob_Ptr>::const_iterator it_res = _resources.begin(); it_res != _resources.end(); ++it_res )
751 if ( (*it_res)->flags & FetcherJob::Directory )
753 const OnMediaLocation location((*it_res)->location);
754 addDirJobs(media, location, dest_dir, (*it_res)->flags);
758 // may be this code can be factored out
759 // together with the autodiscovery of indexes
761 if ( ( _options & AutoAddSha1sumsIndexes ) ||
762 ( _options & AutoAddContentFileIndexes ) )
764 // if auto indexing is enabled, then we need to read the
765 // index for each file. We look only in the directory
766 // where the file is. this is expensive of course.
767 filesystem::DirContent content;
768 getDirectoryContent(media, (*it_res)->location.filename().dirname(), content);
769 // this method test for the option flags so indexes are added
770 // only if the options are enabled
771 MIL << "Autodiscovering signed indexes on '"
772 << (*it_res)->location.filename().dirname() << "' for '"
773 << (*it_res)->location.filename() << "'" << endl;
775 autoaddIndexes(content, media, (*it_res)->location.filename().dirname(), dest_dir);
777 // also look in the root of the media
779 getDirectoryContent(media, Pathname("/"), content);
780 // this method test for the option flags so indexes are added
781 // only if the options are enabled
782 MIL << "Autodiscovering signed indexes on '"
784 << (*it_res)->location.filename() << "'" << endl;
786 autoaddIndexes(content, media, Pathname("/"), dest_dir);
789 provideToDest(media, (*it_res)->location, dest_dir);
791 // if the file was not transfered, and no exception, just
792 // return, as it was an optional file
793 if ( ! PathInfo(dest_dir + (*it_res)->location.filename()).isExist() )
796 // if the checksum is empty, but the checksum is in one of the
797 // indexes checksum, then add a checker
798 if ( (*it_res)->location.checksum().empty() )
800 if ( _checksums.find((*it_res)->location.filename().asString())
801 != _checksums.end() )
803 CheckSum chksm = _checksums[(*it_res)->location.filename().asString()];
804 ChecksumFileChecker digest_check(chksm);
805 (*it_res)->checkers.push_back(digest_check);
809 // if the index checksum is empty too, we only add the checker
810 // if the AlwaysVerifyChecksum option is set on
811 if ( (*it_res)->flags & FetcherJob::AlwaysVerifyChecksum )
813 // add the checker with the empty checksum
814 ChecksumFileChecker digest_check((*it_res)->location.checksum());
815 (*it_res)->checkers.push_back(digest_check);
821 // checksum is not empty, so add a checksum checker
822 ChecksumFileChecker digest_check((*it_res)->location.checksum());
823 (*it_res)->checkers.push_back(digest_check);
826 // validate job, this throws if not valid
827 validate((*it_res)->location, dest_dir, (*it_res)->checkers);
829 if ( ! progress.incr() )
830 ZYPP_THROW(AbortRequestException());
834 /** \relates Fetcher::Impl Stream output */
835 inline std::ostream & operator<<( std::ostream & str, const Fetcher::Impl & obj )
837 for ( list<FetcherJob_Ptr>::const_iterator it_res = obj._resources.begin(); it_res != obj._resources.end(); ++it_res )
845 : _pimpl( new Impl() )
851 void Fetcher::setOptions( Fetcher::Options options )
853 _pimpl->setOptions(options);
856 Fetcher::Options Fetcher::options() const
858 return _pimpl->options();
861 void Fetcher::enqueueDigested( const OnMediaLocation &resource, const FileChecker &checker )
863 _pimpl->enqueueDigested(resource, checker);
866 void Fetcher::enqueueDir( const OnMediaLocation &resource,
868 const FileChecker &checker )
870 _pimpl->enqueueDir(resource, recursive, checker);
873 void Fetcher::enqueueDigestedDir( const OnMediaLocation &resource,
875 const FileChecker &checker )
877 _pimpl->enqueueDigestedDir(resource, recursive, checker);
881 void Fetcher::addIndex( const OnMediaLocation &resource )
883 _pimpl->addIndex(resource);
887 void Fetcher::enqueue( const OnMediaLocation &resource, const FileChecker &checker )
889 _pimpl->enqueue(resource, checker);
892 void Fetcher::addCachePath( const Pathname &cache_dir )
894 _pimpl->addCachePath(cache_dir);
897 void Fetcher::reset()
902 void Fetcher::start( const Pathname &dest_dir,
903 MediaSetAccess &media,
904 const ProgressData::ReceiverFnc & progress_receiver )
906 _pimpl->start(dest_dir, media, progress_receiver);
909 std::ostream & operator<<( std::ostream & str, const Fetcher & obj )
911 return str << *obj._pimpl;
914 /////////////////////////////////////////////////////////////////
916 ///////////////////////////////////////////////////////////////////