Imported Upstream version 15.21.0
[platform/upstream/libzypp.git] / zypp / TmpPath.cc
1 /*---------------------------------------------------------------------\
2 |                          ____ _   __ __ ___                          |
3 |                         |__  / \ / / . \ . \                         |
4 |                           / / \ V /|  _/  _/                         |
5 |                          / /__ | | | | | |                           |
6 |                         /_____||_| |_| |_|                           |
7 |                                                                      |
8 \---------------------------------------------------------------------*/
9 /** \file zypp/TmpPath.cc
10  *
11 */
12
13 #include <cstdlib>
14 #include <cstring>
15 #include <cerrno>
16
17 #include <iostream>
18
19 #include "zypp/base/ReferenceCounted.h"
20 #include "zypp/base/NonCopyable.h"
21 #include "zypp/base/Logger.h"
22 #include "zypp/PathInfo.h"
23 #include "zypp/TmpPath.h"
24
25 using namespace std;
26
27 namespace zypp {
28   namespace filesystem {
29
30     ///////////////////////////////////////////////////////////////////
31     //
32     //  CLASS NAME : TmpPath::Impl
33     /**
34      * Clean or delete a directory on destruction.
35      **/
36     class TmpPath::Impl : public base::ReferenceCounted, private base::NonCopyable
37     {
38       public:
39
40         enum Flags
41           {
42             NoOp         = 0,
43             Autodelete   = 1L << 0,
44             KeepTopdir   = 1L << 1,
45             //
46             CtorDefault  = Autodelete
47           };
48
49       public:
50
51         Impl( const Pathname & path_r, Flags flags_r = CtorDefault )
52         : _path( path_r ), _flags( flags_r )
53         {}
54
55         ~Impl()
56         {
57           if ( ! (_flags & Autodelete) || _path.empty() )
58             return;
59
60           PathInfo p( _path, PathInfo::LSTAT );
61           if ( ! p.isExist() )
62             return;
63
64           int res = 0;
65           if ( p.isDir() )
66             {
67               if ( _flags & KeepTopdir )
68                 res = clean_dir( _path );
69               else
70                 res = recursive_rmdir( _path );
71             }
72           else
73             res = unlink( _path );
74
75           if ( res )
76             INT << "TmpPath cleanup error (" << res << ") " << p << endl;
77           else
78             DBG << "TmpPath cleaned up " << p << endl;
79         }
80
81         const Pathname &
82         path() const
83         { return _path; }
84
85         bool autoCleanup() const
86         { return( _flags & Autodelete ); }
87
88         void autoCleanup( bool yesno_r )
89         { _flags = yesno_r ? CtorDefault : NoOp; }
90
91       private:
92         Pathname _path;
93         Flags    _flags;
94     };
95     ///////////////////////////////////////////////////////////////////
96
97     ///////////////////////////////////////////////////////////////////
98     //
99     //  CLASS NAME : TmpPath
100     //
101     ///////////////////////////////////////////////////////////////////
102
103     ///////////////////////////////////////////////////////////////////
104     //
105     //  METHOD NAME : TmpPath::TmpPath
106     //  METHOD TYPE : Constructor
107     //
108     TmpPath::TmpPath()
109     {}
110
111     ///////////////////////////////////////////////////////////////////
112     //
113     //  METHOD NAME : TmpPath::TmpPath
114     //  METHOD TYPE : Constructor
115     //
116     TmpPath::TmpPath( const Pathname & tmpPath_r )
117     :_impl( tmpPath_r.empty() ? nullptr : new Impl( tmpPath_r ) )
118     {}
119
120     ///////////////////////////////////////////////////////////////////
121     //
122     //  METHOD NAME : TmpPath::~TmpPath
123     //  METHOD TYPE : Destructor
124     //
125     TmpPath::~TmpPath()
126     {
127       // virtual not inlined dtor.
128     }
129
130     ///////////////////////////////////////////////////////////////////
131     //
132     //      METHOD NAME : TmpPath::operator const void *
133     //      METHOD TYPE :
134     //
135     TmpPath::operator bool() const
136     {
137       return _impl.get();
138     }
139
140     ///////////////////////////////////////////////////////////////////
141     //
142     //  METHOD NAME : TmpPath::path
143     //  METHOD TYPE : Pathname
144     //
145     Pathname
146     TmpPath::path() const
147     {
148       return _impl.get() ? _impl->path() : Pathname();
149     }
150
151     ///////////////////////////////////////////////////////////////////
152     //
153     //  METHOD NAME : TmpPath::defaultLocation
154     //  METHOD TYPE : const Pathname &
155     //
156     const Pathname &
157     TmpPath::defaultLocation()
158     {
159       static Pathname p( getenv("ZYPPTMPDIR") ? getenv("ZYPPTMPDIR") : "/var/tmp" );
160       return p;
161     }
162
163     bool TmpPath::autoCleanup() const
164     { return _impl.get() ? _impl->autoCleanup() : false; }
165
166     void TmpPath::autoCleanup( bool yesno_r )
167     { if ( _impl.get() ) _impl->autoCleanup( yesno_r ); }
168
169     ///////////////////////////////////////////////////////////////////
170     //
171     //  CLASS NAME : TmpFile
172     //
173     ///////////////////////////////////////////////////////////////////
174
175
176     ///////////////////////////////////////////////////////////////////
177     //
178     //  METHOD NAME : TmpFile::TmpFile
179     //  METHOD TYPE : Constructor
180     //
181     TmpFile::TmpFile( const Pathname & inParentDir_r,
182                       const std::string & prefix_r )
183     {
184       // parent dir must exist
185       if ( filesystem::assert_dir( inParentDir_r ) != 0 )
186       {
187         ERR << "Parent directory '" << inParentDir_r << "' can't be created." << endl;
188         return;
189       }
190
191       // create the temp file
192       Pathname tmpPath = (inParentDir_r + prefix_r).extend( "XXXXXX");
193       char * buf = ::strdup( tmpPath.asString().c_str() );
194       if ( ! buf )
195         {
196           ERR << "Out of memory" << endl;
197           return;
198         }
199
200       int tmpFd = ::mkostemp( buf, O_CLOEXEC );
201       if ( tmpFd != -1 )
202         {
203           // success; create _impl
204           ::close( tmpFd );
205           _impl = RW_pointer<Impl>( new Impl( buf ) );
206         }
207       else
208         ERR << "Cant create '" << buf << "' " << ::strerror( errno ) << endl;
209
210       ::free( buf );
211     }
212
213     ///////////////////////////////////////////////////////////////////
214     //
215     //  METHOD NAME : TmpFile::makeSibling
216     //  METHOD TYPE : TmpFile
217     //
218     TmpFile TmpFile::makeSibling( const Pathname & sibling_r )
219     {
220       TmpFile ret( sibling_r.dirname(), sibling_r.basename() );
221       // clone mode if sibling_r exists
222       PathInfo p( sibling_r );
223       if ( p.isFile() )
224       {
225         ::chmod( ret.path().c_str(), p.st_mode() );
226       }
227       return ret;
228     }
229
230     ///////////////////////////////////////////////////////////////////
231     //
232     //  METHOD NAME : TmpFile::defaultPrefix
233     //  METHOD TYPE : const std::string &
234     //
235     const std::string &
236     TmpFile::defaultPrefix()
237     {
238       static string p( "TmpFile." );
239       return p;
240     }
241
242     ///////////////////////////////////////////////////////////////////
243     //
244     //  CLASS NAME : TmpDir
245     //
246     ///////////////////////////////////////////////////////////////////
247
248     ///////////////////////////////////////////////////////////////////
249     //
250     //  METHOD NAME : TmpDir::TmpDir
251     //  METHOD TYPE : Constructor
252     //
253     TmpDir::TmpDir( const Pathname & inParentDir_r,
254                     const std::string & prefix_r )
255     {
256       // parent dir must exist
257       if ( filesystem::assert_dir( inParentDir_r ) != 0  )
258       {
259         ERR << "Parent directory '" << inParentDir_r << "' can't be created." << endl;
260         return;
261       }
262
263       // create the temp dir
264       Pathname tmpPath = (inParentDir_r + prefix_r).extend( "XXXXXX");
265       char * buf = ::strdup( tmpPath.asString().c_str() );
266       if ( ! buf )
267         {
268           ERR << "Out of memory" << endl;
269           return;
270         }
271
272       char * tmp = ::mkdtemp( buf );
273       if ( tmp )
274         // success; create _impl
275         _impl = RW_pointer<Impl>( new Impl( tmp ) );
276       else
277         ERR << "Cant create '" << tmpPath << "' " << ::strerror( errno ) << endl;
278
279       ::free( buf );
280     }
281
282     ///////////////////////////////////////////////////////////////////
283     //
284     //  METHOD NAME : TmpDir::makeSibling
285     //  METHOD TYPE : TmpDir
286     //
287     TmpDir TmpDir::makeSibling( const Pathname & sibling_r )
288     {
289       TmpDir ret( sibling_r.dirname(), sibling_r.basename() );
290       // clone mode if sibling_r exists
291       PathInfo p( sibling_r );
292       if ( p.isDir() )
293       {
294         ::chmod( ret.path().c_str(), p.st_mode() );
295       }
296       return ret;
297     }
298
299     ///////////////////////////////////////////////////////////////////
300     //
301     //  METHOD NAME : TmpDir::defaultPrefix
302     //  METHOD TYPE : const std::string &
303     //
304     const std::string &
305     TmpDir::defaultPrefix()
306     {
307       static string p( "TmpDir." );
308       return p;
309     }
310
311   } // namespace filesystem
312 } // namespace zypp