Cleanup and remove deprecated interface methods
[platform/upstream/libzypp.git] / zypp / MediaSetAccess.cc
1 /*---------------------------------------------------------------------\
2 |                          ____ _   __ __ ___                          |
3 |                         |__  / \ / / . \ . \                         |
4 |                           / / \ V /|  _/  _/                         |
5 |                          / /__ | | | | | |                           |
6 |                         /_____||_| |_| |_|                           |
7 |                                                                      |
8 \---------------------------------------------------------------------*/
9
10 #include <iostream>
11 #include <fstream>
12
13 #include "zypp/base/LogTools.h"
14 #include "zypp/base/Regex.h"
15 #include "zypp/base/UserRequestException.h"
16 #include "zypp/ZYppCallbacks.h"
17 #include "zypp/MediaSetAccess.h"
18 #include "zypp/PathInfo.h"
19 //#include "zypp/source/MediaSetAccessReportReceivers.h"
20
21 using namespace std;
22
23 ///////////////////////////////////////////////////////////////////
24 namespace zypp
25 { /////////////////////////////////////////////////////////////////
26
27 IMPL_PTR_TYPE(MediaSetAccess);
28
29 ///////////////////////////////////////////////////////////////////
30
31   MediaSetAccess::MediaSetAccess(const Url &url,
32                                  const Pathname & prefered_attach_point)
33       : _url(url)
34       , _prefAttachPoint(prefered_attach_point)
35   {}
36
37   MediaSetAccess::MediaSetAccess(const std::string & label_r,
38                                  const Url &url,
39                                  const Pathname & prefered_attach_point)
40       : _url(url)
41       , _prefAttachPoint(prefered_attach_point)
42       , _label( label_r )
43   {}
44
45   MediaSetAccess::~MediaSetAccess()
46   {
47     try
48     {
49       release();
50     }
51     catch(...) {} // don't let exception escape a dtor.
52   }
53
54
55   void MediaSetAccess::setVerifier( unsigned media_nr, media::MediaVerifierRef verifier )
56   {
57     if (_medias.find(media_nr) != _medias.end())
58     {
59       // the media already exists, set theverifier
60       media::MediaAccessId id = _medias[media_nr];
61       media::MediaManager media_mgr;
62       media_mgr.addVerifier( id, verifier );
63       // remove any saved verifier for this media
64       _verifiers.erase(media_nr);
65     }
66     else
67     {
68       // save the verifier in the map, and set it when
69       // the media number is first attached
70       _verifiers[media_nr] = verifier;
71     }
72   }
73
74   void MediaSetAccess::releaseFile( const OnMediaLocation & on_media_file )
75   {
76     releaseFile( on_media_file.filename(), on_media_file.medianr() );
77   }
78
79   void MediaSetAccess::releaseFile( const Pathname & file, unsigned media_nr)
80   {
81     media::MediaManager media_mgr;
82     media::MediaAccessId media;
83
84     media = getMediaAccessId( media_nr);
85     DBG << "Going to release file " << file
86         << " from media number " << media_nr << endl;
87
88     if ( ! media_mgr.isAttached(media) )
89       return; //disattached media is free
90
91     media_mgr.releaseFile (media, file);
92   }
93
94   void MediaSetAccess::dirInfo( filesystem::DirContent &retlist, const Pathname &dirname,
95                                 bool dots, unsigned media_nr )
96   {
97     media::MediaManager media_mgr;
98     media::MediaAccessId media;
99     media = getMediaAccessId(media_nr);
100
101     // try to attach the media
102     if ( ! media_mgr.isAttached(media) )
103         media_mgr.attach(media);
104
105     media_mgr.dirInfo(media, retlist, dirname, dots);
106   }
107
108   struct ProvideFileOperation
109   {
110     Pathname result;
111     void operator()( media::MediaAccessId media, const Pathname &file )
112     {
113       media::MediaManager media_mgr;
114       media_mgr.provideFile(media, file);
115       result = media_mgr.localPath(media, file);
116     }
117   };
118
119   struct ProvideDirTreeOperation
120   {
121     Pathname result;
122     void operator()( media::MediaAccessId media, const Pathname &file )
123     {
124       media::MediaManager media_mgr;
125       media_mgr.provideDirTree(media, file);
126       result = media_mgr.localPath(media, file);
127     }
128   };
129
130   struct ProvideDirOperation
131   {
132     Pathname result;
133     void operator()( media::MediaAccessId media, const Pathname &file )
134     {
135       media::MediaManager media_mgr;
136       media_mgr.provideDir(media, file);
137       result = media_mgr.localPath(media, file);
138     }
139   };
140
141   struct ProvideFileExistenceOperation
142   {
143     bool result;
144     ProvideFileExistenceOperation()
145         : result(false)
146     {}
147
148     void operator()( media::MediaAccessId media, const Pathname &file )
149     {
150       media::MediaManager media_mgr;
151       result = media_mgr.doesFileExist(media, file);
152     }
153   };
154
155
156
157   Pathname MediaSetAccess::provideFile( const OnMediaLocation & resource, ProvideFileOptions options )
158   {
159     ProvideFileOperation op;
160     provide( boost::ref(op), resource, options );
161     return op.result;
162   }
163
164   Pathname MediaSetAccess::provideFile(const Pathname & file, unsigned media_nr, ProvideFileOptions options )
165   {
166     OnMediaLocation resource;
167     ProvideFileOperation op;
168     resource.setLocation(file, media_nr);
169     provide( boost::ref(op), resource, options );
170     return op.result;
171   }
172
173   bool MediaSetAccess::doesFileExist(const Pathname & file, unsigned media_nr )
174   {
175     ProvideFileExistenceOperation op;
176     OnMediaLocation resource;
177     resource.setLocation(file, media_nr);
178     provide( boost::ref(op), resource, PROVIDE_DEFAULT);
179     return op.result;
180   }
181
182   void MediaSetAccess::provide( ProvideOperation op,
183                                 const OnMediaLocation &resource,
184                                 ProvideFileOptions options )
185   {
186     Pathname file(resource.filename());
187     unsigned media_nr(resource.medianr());
188
189     callback::SendReport<media::MediaChangeReport> report;
190     media::MediaManager media_mgr;
191
192     media::MediaAccessId media;
193
194     do
195     {
196       // get the mediaId, but don't try to attach it here
197       media = getMediaAccessId( media_nr);
198
199       try
200       {
201         DBG << "Going to try to provide " << (resource.optional() ? "optional" : "") << " file " << file
202             << " from media number " << media_nr << endl;
203         // try to attach the media
204         if ( ! media_mgr.isAttached(media) )
205           media_mgr.attach(media);
206         op(media, file);
207         break;
208       }
209       catch ( media::MediaException & excp )
210       {
211         ZYPP_CAUGHT(excp);
212         media::MediaChangeReport::Action user = media::MediaChangeReport::ABORT;
213         unsigned int devindex = 0;
214         vector<string> devices;
215         media_mgr.getDetectedDevices(media, devices, devindex);
216
217         do
218         {
219           if (user != media::MediaChangeReport::EJECT) // no use in calling this again
220           {
221             DBG << "Media couldn't provide file " << file << " , releasing." << endl;
222             try
223             {
224               media_mgr.release(media);
225             }
226             catch (const Exception & excpt_r)
227             {
228                 ZYPP_CAUGHT(excpt_r);
229                 MIL << "Failed to release media " << media << endl;
230             }
231           }
232
233           // set up the reason
234           media::MediaChangeReport::Error reason = media::MediaChangeReport::INVALID;
235
236           if( typeid(excp) == typeid( media::MediaFileNotFoundException )  ||
237               typeid(excp) == typeid( media::MediaNotAFileException ) )
238           {
239             reason = media::MediaChangeReport::NOT_FOUND;
240           }
241           else if( typeid(excp) == typeid( media::MediaNotDesiredException)  ||
242               typeid(excp) == typeid( media::MediaNotAttachedException) )
243           {
244             reason = media::MediaChangeReport::WRONG;
245           }
246           else if( typeid(excp) == typeid( media::MediaTimeoutException) ||
247                    typeid(excp) == typeid( media::MediaTemporaryProblemException))
248           {
249             reason = media::MediaChangeReport::IO_SOFT;
250           }
251
252           // non interactive only bother the user if wrong medium is in the drive
253           // otherwise propagate the error
254           if ( ( options & PROVIDE_NON_INTERACTIVE ) && reason != media::MediaChangeReport::WRONG)
255           {
256               MIL << "Can't provide file. Non-Interactive mode." << endl;
257               ZYPP_RETHROW(excp);
258           }
259           else
260           {
261             // release all media before requesting another (#336881)
262             media_mgr.releaseAll();
263
264             user = report->requestMedia (
265               _url,
266               media_nr,
267               _label,
268               reason,
269               excp.asUserString(),
270               devices,
271               devindex
272             );
273           }
274
275           MIL << "ProvideFile exception caught, callback answer: " << user << endl;
276
277           if( user == media::MediaChangeReport::ABORT )
278           {
279             DBG << "Aborting" << endl;
280             ZYPP_RETHROW ( excp );
281           }
282           else if ( user == media::MediaChangeReport::IGNORE )
283           {
284             DBG << "Skipping" << endl;
285             SkipRequestException nexcp("User-requested skipping of a file");
286             nexcp.remember(excp);
287             ZYPP_THROW(nexcp);
288           }
289           else if ( user == media::MediaChangeReport::EJECT )
290           {
291             DBG << "Eject: try to release" << endl;
292             media_mgr.releaseAll();
293             // eject
294             media_mgr.release (media,
295               devindex < devices.size() ? devices[devindex] : "");
296           }
297           else if ( user == media::MediaChangeReport::RETRY  ||
298             user == media::MediaChangeReport::CHANGE_URL )
299           {
300             // retry
301             DBG << "Going to try again" << endl;
302             // invalidate current media access id
303             media_mgr.close(media);
304             _medias.erase(media_nr);
305
306             // not attaching, media set will do that for us
307             // this could generate uncaught exception (#158620)
308             break;
309           }
310           else
311           {
312             DBG << "Don't know, let's ABORT" << endl;
313             ZYPP_RETHROW ( excp );
314           }
315         } while( user == media::MediaChangeReport::EJECT );
316       }
317
318       // retry or change URL
319     } while( true );
320   }
321
322   Pathname MediaSetAccess::provideDir(const Pathname & dir,
323                                       bool recursive,
324                                       unsigned media_nr,
325                                       ProvideFileOptions options )
326   {
327     OnMediaLocation resource;
328     resource.setLocation(dir, media_nr);
329     if ( recursive )
330     {
331         ProvideDirTreeOperation op;
332         provide( boost::ref(op), resource, options);
333         return op.result;
334     }
335     ProvideDirOperation op;
336     provide( boost::ref(op), resource, options);
337     return op.result;
338   }
339
340   media::MediaAccessId MediaSetAccess::getMediaAccessId (media::MediaNr medianr)
341   {
342     media::MediaManager media_mgr;
343
344     if (_medias.find(medianr) != _medias.end())
345     {
346       media::MediaAccessId id = _medias[medianr];
347       return id;
348     }
349     Url url;
350     url = rewriteUrl (_url, medianr);
351     media::MediaAccessId id = media_mgr.open(url, _prefAttachPoint);
352     _medias[medianr] = id;
353
354     try
355     {
356       if (_verifiers.find(medianr) != _verifiers.end())
357       {
358         // a verifier is set for this media
359         // FIXME check the case where the verifier exists
360         // but we have no access id for the media
361         media::MediaAccessId id = _medias[medianr];
362         media::MediaManager media_mgr;
363         media_mgr.delVerifier(id);
364         media_mgr.addVerifier( id, _verifiers[medianr] );
365         // remove any saved verifier for this media
366         _verifiers.erase(medianr);
367       }
368     }
369     catch ( const Exception &e )
370     {
371       ZYPP_CAUGHT(e);
372       WAR << "Verifier not found" << endl;
373     }
374
375     return id;
376   }
377
378
379   Url MediaSetAccess::rewriteUrl (const Url & url_r, const media::MediaNr medianr)
380   {
381     std::string scheme = url_r.getScheme();
382     if (scheme == "cd" || scheme == "dvd")
383       return url_r;
384
385     DBG << "Rewriting url " << url_r << endl;
386
387     if( scheme == "iso")
388     {
389       // TODO the iso parameter will not be required in the future, this
390       // code has to be adapted together with the MediaISO change.
391       // maybe some MediaISOURL interface should be used.
392       std::string isofile = url_r.getQueryParam("iso");
393       str::regex e("^(.*)(cd|dvd)[0-9]+\\.iso$", str::regex::icase);
394
395       str::smatch what;
396       if(str::regex_match(isofile, what, e))
397       {
398         Url url( url_r);
399         isofile = what[1] + what[2] + str::numstring(medianr) + ".iso";
400         url.setQueryParam("iso", isofile);
401         DBG << "Url rewrite result: " << url << endl;
402         return url;
403       }
404     }
405     else
406     {
407       std::string pathname = url_r.getPathName();
408       str::regex e("^(.*)(cd|dvd)[0-9]+(/)?$", str::regex::icase);
409       str::smatch what;
410       if(str::regex_match(pathname, what, e))
411       {
412         Url url( url_r);
413         pathname = what[1] + what[2] + str::numstring(medianr) + what[3];
414         url.setPathName(pathname);
415         DBG << "Url rewrite result: " << url << endl;
416         return url;
417       }
418     }
419     return url_r;
420   }
421
422   void MediaSetAccess::release()
423   {
424     DBG << "Releasing all media IDs held by this MediaSetAccess" << endl;
425     media::MediaManager manager;
426     for (MediaMap::const_iterator m = _medias.begin(); m != _medias.end(); ++m)
427       manager.release(m->second, "");
428   }
429
430   std::ostream & MediaSetAccess::dumpOn( std::ostream & str ) const
431   {
432     str << "MediaSetAccess (URL='" << _url << "', attach_point_hint='" << _prefAttachPoint << "')";
433     return str;
434   }
435
436 /////////////////////////////////////////////////////////////////
437 } // namespace zypp
438 ///////////////////////////////////////////////////////////////////