00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 #include <iostream>
00011 #include <fstream>
00012
00013 #include "zypp/base/LogTools.h"
00014 #include "zypp/base/Regex.h"
00015 #include "zypp/base/UserRequestException.h"
00016 #include "zypp/ZYppCallbacks.h"
00017 #include "zypp/MediaSetAccess.h"
00018 #include "zypp/PathInfo.h"
00019
00020
00021 using namespace std;
00022
00024 namespace zypp
00025 {
00026
00027 IMPL_PTR_TYPE(MediaSetAccess);
00028
00030
00031 MediaSetAccess::MediaSetAccess(const Url &url,
00032 const Pathname & prefered_attach_point)
00033 : _url(url)
00034 , _prefAttachPoint(prefered_attach_point)
00035 {}
00036
00037 MediaSetAccess::MediaSetAccess(const std::string & label_r,
00038 const Url &url,
00039 const Pathname & prefered_attach_point)
00040 : _url(url)
00041 , _prefAttachPoint(prefered_attach_point)
00042 , _label( label_r )
00043 {}
00044
00045 MediaSetAccess::~MediaSetAccess()
00046 {
00047 try
00048 {
00049 release();
00050 }
00051 catch(...) {}
00052 }
00053
00054
00055 void MediaSetAccess::setVerifier( unsigned media_nr, media::MediaVerifierRef verifier )
00056 {
00057 if (_medias.find(media_nr) != _medias.end())
00058 {
00059
00060 media::MediaAccessId id = _medias[media_nr];
00061 media::MediaManager media_mgr;
00062 media_mgr.addVerifier( id, verifier );
00063
00064 _verifiers.erase(media_nr);
00065 }
00066 else
00067 {
00068
00069
00070 _verifiers[media_nr] = verifier;
00071 }
00072 }
00073
00074 void MediaSetAccess::releaseFile( const OnMediaLocation & on_media_file )
00075 {
00076 releaseFile( on_media_file.filename(), on_media_file.medianr() );
00077 }
00078
00079 void MediaSetAccess::releaseFile( const Pathname & file, unsigned media_nr)
00080 {
00081 media::MediaManager media_mgr;
00082 media::MediaAccessId media;
00083
00084 media = getMediaAccessId( media_nr);
00085 DBG << "Going to release file " << file
00086 << " from media number " << media_nr << endl;
00087
00088 if ( ! media_mgr.isAttached(media) )
00089 return;
00090
00091 media_mgr.releaseFile (media, file);
00092 }
00093
00094 void MediaSetAccess::dirInfo( filesystem::DirContent &retlist, const Pathname &dirname,
00095 bool dots, unsigned media_nr )
00096 {
00097 media::MediaManager media_mgr;
00098 media::MediaAccessId media;
00099 media = getMediaAccessId(media_nr);
00100
00101
00102 if ( ! media_mgr.isAttached(media) )
00103 media_mgr.attach(media);
00104
00105 media_mgr.dirInfo(media, retlist, dirname, dots);
00106 }
00107
00108 struct ProvideFileOperation
00109 {
00110 Pathname result;
00111 void operator()( media::MediaAccessId media, const Pathname &file )
00112 {
00113 media::MediaManager media_mgr;
00114 media_mgr.provideFile(media, file);
00115 result = media_mgr.localPath(media, file);
00116 }
00117 };
00118
00119 struct ProvideDirTreeOperation
00120 {
00121 Pathname result;
00122 void operator()( media::MediaAccessId media, const Pathname &file )
00123 {
00124 media::MediaManager media_mgr;
00125 media_mgr.provideDirTree(media, file);
00126 result = media_mgr.localPath(media, file);
00127 }
00128 };
00129
00130 struct ProvideDirOperation
00131 {
00132 Pathname result;
00133 void operator()( media::MediaAccessId media, const Pathname &file )
00134 {
00135 media::MediaManager media_mgr;
00136 media_mgr.provideDir(media, file);
00137 result = media_mgr.localPath(media, file);
00138 }
00139 };
00140
00141 struct ProvideFileExistenceOperation
00142 {
00143 bool result;
00144 ProvideFileExistenceOperation()
00145 : result(false)
00146 {}
00147
00148 void operator()( media::MediaAccessId media, const Pathname &file )
00149 {
00150 media::MediaManager media_mgr;
00151 result = media_mgr.doesFileExist(media, file);
00152 }
00153 };
00154
00155
00156
00157 Pathname MediaSetAccess::provideFile( const OnMediaLocation & resource, ProvideFileOptions options )
00158 {
00159 ProvideFileOperation op;
00160 provide( boost::ref(op), resource, options );
00161 return op.result;
00162 }
00163
00164 Pathname MediaSetAccess::provideFile(const Pathname & file, unsigned media_nr, ProvideFileOptions options )
00165 {
00166 OnMediaLocation resource;
00167 ProvideFileOperation op;
00168 resource.setLocation(file, media_nr);
00169 provide( boost::ref(op), resource, options );
00170 return op.result;
00171 }
00172
00173 bool MediaSetAccess::doesFileExist(const Pathname & file, unsigned media_nr )
00174 {
00175 ProvideFileExistenceOperation op;
00176 OnMediaLocation resource;
00177 resource.setLocation(file, media_nr);
00178 provide( boost::ref(op), resource, PROVIDE_DEFAULT);
00179 return op.result;
00180 }
00181
00182 void MediaSetAccess::provide( ProvideOperation op,
00183 const OnMediaLocation &resource,
00184 ProvideFileOptions options )
00185 {
00186 Pathname file(resource.filename());
00187 unsigned media_nr(resource.medianr());
00188
00189 callback::SendReport<media::MediaChangeReport> report;
00190 media::MediaManager media_mgr;
00191
00192 media::MediaAccessId media;
00193
00194 do
00195 {
00196
00197 media = getMediaAccessId( media_nr);
00198
00199 try
00200 {
00201 DBG << "Going to try to provide " << (resource.optional() ? "optional" : "") << " file " << file
00202 << " from media number " << media_nr << endl;
00203
00204 if ( ! media_mgr.isAttached(media) )
00205 media_mgr.attach(media);
00206 op(media, file);
00207 break;
00208 }
00209 catch ( media::MediaException & excp )
00210 {
00211 ZYPP_CAUGHT(excp);
00212 media::MediaChangeReport::Action user = media::MediaChangeReport::ABORT;
00213 unsigned int devindex = 0;
00214 vector<string> devices;
00215 media_mgr.getDetectedDevices(media, devices, devindex);
00216
00217 do
00218 {
00219 if (user != media::MediaChangeReport::EJECT)
00220 {
00221 DBG << "Media couldn't provide file " << file << " , releasing." << endl;
00222 try
00223 {
00224 media_mgr.release(media);
00225 }
00226 catch (const Exception & excpt_r)
00227 {
00228 ZYPP_CAUGHT(excpt_r);
00229 MIL << "Failed to release media " << media << endl;
00230 }
00231 }
00232
00233
00234 media::MediaChangeReport::Error reason = media::MediaChangeReport::INVALID;
00235
00236 if( typeid(excp) == typeid( media::MediaFileNotFoundException ) ||
00237 typeid(excp) == typeid( media::MediaNotAFileException ) )
00238 {
00239 reason = media::MediaChangeReport::NOT_FOUND;
00240 }
00241 else if( typeid(excp) == typeid( media::MediaNotDesiredException) ||
00242 typeid(excp) == typeid( media::MediaNotAttachedException) )
00243 {
00244 reason = media::MediaChangeReport::WRONG;
00245 }
00246 else if( typeid(excp) == typeid( media::MediaTimeoutException) ||
00247 typeid(excp) == typeid( media::MediaTemporaryProblemException))
00248 {
00249 reason = media::MediaChangeReport::IO_SOFT;
00250 }
00251
00252
00253
00254 if ( ( options & PROVIDE_NON_INTERACTIVE ) && reason != media::MediaChangeReport::WRONG)
00255 {
00256 MIL << "Can't provide file. Non-Interactive mode." << endl;
00257 ZYPP_RETHROW(excp);
00258 }
00259 else
00260 {
00261
00262 media_mgr.releaseAll();
00263
00264 user = report->requestMedia (
00265 _url,
00266 media_nr,
00267 _label,
00268 reason,
00269 excp.asUserString(),
00270 devices,
00271 devindex
00272 );
00273 }
00274
00275 MIL << "ProvideFile exception caught, callback answer: " << user << endl;
00276
00277 if( user == media::MediaChangeReport::ABORT )
00278 {
00279 DBG << "Aborting" << endl;
00280 ZYPP_RETHROW ( excp );
00281 }
00282 else if ( user == media::MediaChangeReport::IGNORE )
00283 {
00284 DBG << "Skipping" << endl;
00285 SkipRequestException nexcp("User-requested skipping of a file");
00286 nexcp.remember(excp);
00287 ZYPP_THROW(nexcp);
00288 }
00289 else if ( user == media::MediaChangeReport::EJECT )
00290 {
00291 DBG << "Eject: try to release" << endl;
00292 media_mgr.releaseAll();
00293
00294 media_mgr.release (media,
00295 devindex < devices.size() ? devices[devindex] : "");
00296 }
00297 else if ( user == media::MediaChangeReport::RETRY ||
00298 user == media::MediaChangeReport::CHANGE_URL )
00299 {
00300
00301 DBG << "Going to try again" << endl;
00302
00303 media_mgr.close(media);
00304 _medias.erase(media_nr);
00305
00306
00307
00308 break;
00309 }
00310 else
00311 {
00312 DBG << "Don't know, let's ABORT" << endl;
00313 ZYPP_RETHROW ( excp );
00314 }
00315 } while( user == media::MediaChangeReport::EJECT );
00316 }
00317
00318
00319 } while( true );
00320 }
00321
00322 Pathname MediaSetAccess::provideDir(const Pathname & dir,
00323 bool recursive,
00324 unsigned media_nr,
00325 ProvideFileOptions options )
00326 {
00327 OnMediaLocation resource;
00328 resource.setLocation(dir, media_nr);
00329 if ( recursive )
00330 {
00331 ProvideDirTreeOperation op;
00332 provide( boost::ref(op), resource, options);
00333 return op.result;
00334 }
00335 ProvideDirOperation op;
00336 provide( boost::ref(op), resource, options);
00337 return op.result;
00338 }
00339
00340 media::MediaAccessId MediaSetAccess::getMediaAccessId (media::MediaNr medianr)
00341 {
00342 media::MediaManager media_mgr;
00343
00344 if (_medias.find(medianr) != _medias.end())
00345 {
00346 media::MediaAccessId id = _medias[medianr];
00347 return id;
00348 }
00349 Url url;
00350 url = rewriteUrl (_url, medianr);
00351 media::MediaAccessId id = media_mgr.open(url, _prefAttachPoint);
00352 _medias[medianr] = id;
00353
00354 try
00355 {
00356 if (_verifiers.find(medianr) != _verifiers.end())
00357 {
00358
00359
00360
00361 media::MediaAccessId id = _medias[medianr];
00362 media::MediaManager media_mgr;
00363 media_mgr.delVerifier(id);
00364 media_mgr.addVerifier( id, _verifiers[medianr] );
00365
00366 _verifiers.erase(medianr);
00367 }
00368 }
00369 catch ( const Exception &e )
00370 {
00371 ZYPP_CAUGHT(e);
00372 WAR << "Verifier not found" << endl;
00373 }
00374
00375 return id;
00376 }
00377
00378
00379 Url MediaSetAccess::rewriteUrl (const Url & url_r, const media::MediaNr medianr)
00380 {
00381 std::string scheme = url_r.getScheme();
00382 if (scheme == "cd" || scheme == "dvd")
00383 return url_r;
00384
00385 DBG << "Rewriting url " << url_r << endl;
00386
00387 if( scheme == "iso")
00388 {
00389
00390
00391
00392 std::string isofile = url_r.getQueryParam("iso");
00393 str::regex e("^(.*)(cd|dvd|media)[0-9]+\\.iso$", str::regex::icase);
00394
00395 str::smatch what;
00396 if(str::regex_match(isofile, what, e))
00397 {
00398 Url url( url_r);
00399 isofile = what[1] + what[2] + str::numstring(medianr) + ".iso";
00400 url.setQueryParam("iso", isofile);
00401 DBG << "Url rewrite result: " << url << endl;
00402 return url;
00403 }
00404 }
00405 else
00406 {
00407 std::string pathname = url_r.getPathName();
00408 str::regex e("^(.*)(cd|dvd|media)[0-9]+(/)?$", str::regex::icase);
00409 str::smatch what;
00410 if(str::regex_match(pathname, what, e))
00411 {
00412 Url url( url_r);
00413 pathname = what[1] + what[2] + str::numstring(medianr) + what[3];
00414 url.setPathName(pathname);
00415 DBG << "Url rewrite result: " << url << endl;
00416 return url;
00417 }
00418 }
00419 return url_r;
00420 }
00421
00422 void MediaSetAccess::release()
00423 {
00424 DBG << "Releasing all media IDs held by this MediaSetAccess" << endl;
00425 media::MediaManager manager;
00426 for (MediaMap::const_iterator m = _medias.begin(); m != _medias.end(); ++m)
00427 manager.release(m->second, "");
00428 }
00429
00430 std::ostream & MediaSetAccess::dumpOn( std::ostream & str ) const
00431 {
00432 str << "MediaSetAccess (URL='" << _url << "', attach_point_hint='" << _prefAttachPoint << "')";
00433 return str;
00434 }
00435
00437 }