+ case filesystem::FT_DIR: // newer directory.yast contain at least directory info
+ if ( flags & FetcherJob::Recursive )
+ addDirJobs(media, filename, dest_dir, flags);
+ break;
+ default:
+ // don't provide devices, sockets, etc.
+ break;
+ }
+ }
+ }
+
+ void Fetcher::Impl::provideToDest( MediaSetAccess &media, const OnMediaLocation &resource, const Pathname &dest_dir, const Pathname &deltafile )
+ {
+ bool got_from_cache = false;
+
+ // start look in cache
+ got_from_cache = provideFromCache(resource, dest_dir);
+
+ if ( ! got_from_cache )
+ {
+ MIL << "Not found in cache, downloading" << endl;
+
+ // try to get the file from the net
+ try
+ {
+ Pathname tmp_file = media.provideFile(resource, resource.optional() ? MediaSetAccess::PROVIDE_NON_INTERACTIVE : MediaSetAccess::PROVIDE_DEFAULT, deltafile );
+
+ Pathname dest_full_path = dest_dir + resource.filename();
+
+ if ( assert_dir( dest_full_path.dirname() ) != 0 )
+ ZYPP_THROW( Exception("Can't create " + dest_full_path.dirname().asString()));
+ if ( filesystem::hardlinkCopy( tmp_file, dest_full_path ) != 0 )
+ {
+ if ( ! PathInfo(tmp_file).isExist() )
+ ERR << tmp_file << " does not exist" << endl;
+ if ( ! PathInfo(dest_full_path.dirname()).isExist() )
+ ERR << dest_full_path.dirname() << " does not exist" << endl;
+
+ media.releaseFile(resource); //not needed anymore, only eat space
+ ZYPP_THROW( Exception("Can't hardlink/copy " + tmp_file.asString() + " to " + dest_dir.asString()));
+ }
+
+ media.releaseFile(resource); //not needed anymore, only eat space
+ }
+ catch (Exception & excpt_r)
+ {
+ if ( resource.optional() )
+ {
+ ZYPP_CAUGHT(excpt_r);
+ WAR << "optional resource " << resource << " could not be transfered" << endl;
+ return;
+ }
+ else
+ {
+ excpt_r.remember("Can't provide " + resource.filename().asString() );
+ ZYPP_RETHROW(excpt_r);
+ }
+ }
+ }
+ else
+ {
+ // We got the file from cache
+ // continue with next file
+ return;
+ }
+ }
+
+ // helper class to consume a content file
+ struct ContentReaderHelper : public parser::susetags::ContentFileReader
+ {
+ ContentReaderHelper()
+ {
+ setRepoIndexConsumer( bind( &ContentReaderHelper::consumeIndex, this, _1 ) );
+ }
+
+ void consumeIndex( const parser::susetags::RepoIndex_Ptr & data_r )
+ { _repoindex = data_r; }
+
+ parser::susetags::RepoIndex_Ptr _repoindex;
+ };
+
+ // generic function for reading indexes
+ void Fetcher::Impl::readIndex( const Pathname &index, const Pathname &basedir )
+ {
+ if ( index.basename() == "CHECKSUMS" || index.basename() == "SHA1SUMS" )
+ readChecksumsIndex(index, basedir);
+ else if ( index.basename() == "content" )
+ readContentFileIndex(index, basedir);
+ else
+ WAR << index << ": index file format not known" << endl;
+ }
+
+ // reads a content file index
+ void Fetcher::Impl::readContentFileIndex( const Pathname &index, const Pathname &basedir )
+ {
+ ContentReaderHelper reader;
+ reader.parse(index);
+ MIL << index << " contains " << reader._repoindex->mediaFileChecksums.size() << " checksums." << endl;
+ for_( it, reader._repoindex->mediaFileChecksums.begin(), reader._repoindex->mediaFileChecksums.end() )
+ {
+ // content file entries don't start with /
+ _checksums[(basedir + it->first).asString()] = it->second;
+ }
+ }
+
+ // reads a CHECKSUMS (old SHA1SUMS) file index
+ void Fetcher::Impl::readChecksumsIndex( const Pathname &index, const Pathname &basedir )
+ {
+ std::ifstream in( index.c_str() );
+ if ( ! in.fail() )
+ {
+ std::string buffer;
+ while ( getline( in, buffer ) )