Adapted classes from liby2util, some of them to be later replaced by
[platform/upstream/libzypp.git] / zypp / PathInfo.h
1 /*---------------------------------------------------------------------\
2 |                          ____ _   __ __ ___                          |
3 |                         |__  / \ / / . \ . \                         |
4 |                           / / \ V /|  _/  _/                         |
5 |                          / /__ | | | | | |                           |
6 |                         /_____||_| |_| |_|                           |
7 |                                                                      |
8 \---------------------------------------------------------------------*/
9 /** \file zypp/PathInfo.h
10  *
11  * \todo replace by Blocxx
12  *
13 */
14 #ifndef ZYPP_PATHINFO_H
15 #define ZYPP_PATHINFO_H
16
17 extern "C"
18 {
19 #include <sys/types.h>
20 #include <sys/stat.h>
21 #include <fcntl.h>
22 #include <unistd.h>
23 #include <dirent.h>
24 }
25
26 #include <cerrno>
27 #include <iosfwd>
28 #include <list>
29 #include <set>
30 #include <map>
31
32 #include "zypp/Pathname.h"
33
34 namespace zypp {
35
36 ///////////////////////////////////////////////////////////////////
37 //
38 //      CLASS NAME : PathInfo
39 /**
40  * @short Wrapper class for ::stat/::lstat and other file/directory related operations.
41  **/
42 class PathInfo {
43
44   friend std::ostream & operator<<( std::ostream & str, const PathInfo & obj );
45
46   public:
47
48     enum Mode { STAT, LSTAT };
49
50     enum file_type {
51       NOT_AVAIL  = 0x00, // no typeinfo available
52       NOT_EXIST  = 0x01, // file does not exist
53       T_FILE     = 0x02,
54       T_DIR      = 0x04,
55       T_CHARDEV  = 0x08,
56       T_BLOCKDEV = 0x10,
57       T_FIFO     = 0x20,
58       T_LINK     = 0x40,
59       T_SOCKET   = 0x80
60     };
61     friend std::ostream & operator<<( std::ostream & str, file_type obj );
62
63     /**
64      * Wrapper class for mode_t values as derived from ::stat
65      **/
66     class stat_mode;
67
68     /**
69      * Simple cache remembering device/inode to detect hardlinks.
70      **/
71     class devino_cache;
72
73   private:
74
75     Pathname    path_t;
76
77     struct stat statbuf_C;
78     Mode        mode_e;
79     int         error_i;
80
81   public:
82
83     PathInfo( const Pathname & path = "", Mode initial = STAT );
84     PathInfo( const std::string & path, Mode initial = STAT );
85     PathInfo( const char * path, Mode initial = STAT );
86     virtual ~PathInfo();
87
88     const Pathname &    path()     const { return path_t; }
89     const std::string & asString() const { return path_t.asString(); }
90     Mode                mode()     const { return mode_e; }
91     int                 error()    const { return error_i; }
92
93     void setPath( const Pathname & path ) { if ( path != path_t ) error_i = -1; path_t = path; }
94     void setMode( Mode mode )             { if ( mode != mode_e ) error_i = -1; mode_e = mode; }
95
96     bool stat      ( const Pathname & path ) { setPath( path ); setMode( STAT );  return operator()(); }
97     bool lstat     ( const Pathname & path ) { setPath( path ); setMode( LSTAT ); return operator()(); }
98     bool operator()( const Pathname & path ) { setPath( path ); return operator()(); }
99
100     bool stat()   { setMode( STAT );  return operator()(); }
101     bool lstat()  { setMode( LSTAT ); return operator()(); }
102     bool operator()();
103
104   public:
105
106     bool   isExist() const { return !error_i; }
107
108     // file type
109     file_type fileType() const;
110
111     bool   isFile()  const { return isExist() && S_ISREG( statbuf_C.st_mode ); }
112     bool   isDir ()  const { return isExist() && S_ISDIR( statbuf_C.st_mode ); }
113     bool   isLink()  const { return isExist() && S_ISLNK( statbuf_C.st_mode ); }
114     bool   isChr()   const { return isExist() && S_ISCHR( statbuf_C.st_mode ); }
115     bool   isBlk()   const { return isExist() && S_ISBLK( statbuf_C.st_mode ); }
116     bool   isFifo()  const { return isExist() && S_ISFIFO( statbuf_C.st_mode ); }
117     bool   isSock()  const { return isExist() && S_ISSOCK( statbuf_C.st_mode ); }
118
119     nlink_t nlink()  const { return isExist() ? statbuf_C.st_nlink : 0; }
120
121     // owner
122     uid_t  owner()   const { return isExist() ? statbuf_C.st_uid : 0; }
123     gid_t  group()   const { return isExist() ? statbuf_C.st_gid : 0; }
124
125     // permission
126     bool   isRUsr()  const { return isExist() && (statbuf_C.st_mode & S_IRUSR); }
127     bool   isWUsr()  const { return isExist() && (statbuf_C.st_mode & S_IWUSR); }
128     bool   isXUsr()  const { return isExist() && (statbuf_C.st_mode & S_IXUSR); }
129
130     bool   isR()     const { return isRUsr(); }
131     bool   isW()     const { return isWUsr(); }
132     bool   isX()     const { return isXUsr(); }
133
134     bool   isRGrp()  const { return isExist() && (statbuf_C.st_mode & S_IRGRP); }
135     bool   isWGrp()  const { return isExist() && (statbuf_C.st_mode & S_IWGRP); }
136     bool   isXGrp()  const { return isExist() && (statbuf_C.st_mode & S_IXGRP); }
137
138     bool   isROth()  const { return isExist() && (statbuf_C.st_mode & S_IROTH); }
139     bool   isWOth()  const { return isExist() && (statbuf_C.st_mode & S_IWOTH); }
140     bool   isXOth()  const { return isExist() && (statbuf_C.st_mode & S_IXOTH); }
141
142     bool   isUid()   const { return isExist() && (statbuf_C.st_mode & S_ISUID); }
143     bool   isGid()   const { return isExist() && (statbuf_C.st_mode & S_ISGID); }
144     bool   isVtx()   const { return isExist() && (statbuf_C.st_mode & S_ISVTX); }
145
146     mode_t uperm()   const { return isExist() ? (statbuf_C.st_mode & S_IRWXU) : 0; }
147     mode_t gperm()   const { return isExist() ? (statbuf_C.st_mode & S_IRWXG) : 0; }
148     mode_t operm()   const { return isExist() ? (statbuf_C.st_mode & S_IRWXO) : 0; }
149     mode_t perm()    const { return isExist() ? (statbuf_C.st_mode & (S_IRWXU|S_IRWXG|S_IRWXO|S_ISUID|S_ISGID|S_ISVTX)) : 0; }
150
151     bool   isPerm ( mode_t m ) const { return (m == perm()); }
152     bool   hasPerm( mode_t m ) const { return (m == (m & perm())); }
153
154     mode_t st_mode() const { return isExist() ? statbuf_C.st_mode : 0; }
155
156     // permission according to current uid/gid (returns [0-7])
157     mode_t userMay() const;
158
159     bool   userMayR() const { return( userMay() & 01 ); }
160     bool   userMayW() const { return( userMay() & 02 ); }
161     bool   userMayX() const { return( userMay() & 04 ); }
162
163     bool   userMayRW()  const { return( (userMay() & 03) == 03 ); }
164     bool   userMayRX()  const { return( (userMay() & 05) == 05 ); }
165     bool   userMayWX()  const { return( (userMay() & 06) == 06 ); }
166
167     bool   userMayRWX() const { return( userMay() == 07 ); }
168
169     // device
170     dev_t  dev()     const { return isExist() ? statbuf_C.st_dev  : 0; }
171     dev_t  rdev()    const { return isExist() ? statbuf_C.st_rdev : 0; }
172     ino_t  ino()     const { return isExist() ? statbuf_C.st_ino  : 0; }
173
174     // size
175     off_t         size()    const { return isExist() ? statbuf_C.st_size : 0; }
176     unsigned long blksize() const { return isExist() ? statbuf_C.st_blksize : 0; }
177     unsigned long blocks()  const { return isExist() ? statbuf_C.st_blocks  : 0; }
178
179     // time
180     time_t atime()   const { return isExist() ? statbuf_C.st_atime : 0; } /* time of last access */
181     time_t mtime()   const { return isExist() ? statbuf_C.st_mtime : 0; } /* time of last modification */
182     time_t ctime()   const { return isExist() ? statbuf_C.st_ctime : 0; }
183
184   public:
185
186     ///////////////////////////////////////////////////////////////////
187     // convenience stuff
188     ///////////////////////////////////////////////////////////////////
189     // static functions as they may or may not invalidate any stat info
190     // stored by a PathiInfo.
191     ///////////////////////////////////////////////////////////////////
192
193     ///////////////////////////////////////////////////////////////////
194     // Directories
195     ///////////////////////////////////////////////////////////////////
196
197     /**
198      * Like '::mkdir'. Attempt to create a new directory named path. mode
199      * specifies the permissions to use. It is modified by the process's
200      * umask in the usual way.
201      *
202      * @return 0 on success, errno on failure
203      **/
204     static int mkdir( const Pathname & path, unsigned mode = 0755 );
205
206     /**
207      * Like 'mkdir -p'. No error if directory exists. Make parent directories
208      * as needed. mode specifies the permissions to use, if directories have to
209      * be created. It is modified by the process's umask in the usual way.
210      *
211      * @return 0 on success, errno on failure
212      **/
213     static int assert_dir( const Pathname & path, unsigned mode = 0755 );
214
215     /**
216      * Like '::rmdir'. Delete a directory, which must be empty.
217      *
218      * @return 0 on success, errno on failure
219      **/
220     static int rmdir( const Pathname & path );
221
222     /**
223      * Like 'rm -r DIR'. Delete a directory, recursively removing its contents.
224      *
225      * @return 0 on success, ENOTDIR if path is not a directory, otherwise the
226      * commands return value.
227      **/
228     static int recursive_rmdir( const Pathname & path );
229
230     /**
231      * Like 'rm -r DIR/ *'. Delete directory contents, but keep the directory itself.
232      *
233      * @return 0 on success, ENOTDIR if path is not a directory, otherwise the
234      * commands return value.
235      **/
236     static int clean_dir( const Pathname & path );
237
238     /**
239      * Like 'cp -a srcpath destpath'. Copy directory tree. srcpath/destpath must be
240      * directories. 'basename srcpath' must not exist in destpath.
241      *
242      * @return 0 on success, ENOTDIR if srcpath/destpath is not a directory, EEXIST if
243      * 'basename srcpath' exists in destpath, otherwise the commands return value.
244      **/
245     static int copy_dir( const Pathname & srcpath, const Pathname & destpath );
246
247     /**
248      * Return content of directory via retlist. If dots is false
249      * entries starting with '.' are not reported. "." and ".."
250      * are never reported.
251      *
252      * @return 0 on success, errno on failure.
253      **/
254     static int readdir( std::list<std::string> & retlist,
255                         const Pathname & path, bool dots = true );
256
257     struct direntry {
258       std::string name;
259       file_type   type;
260       direntry( const std::string & name_r = std::string(), file_type type_r = NOT_AVAIL )
261         : name( name_r )
262         , type( type_r )
263       {}
264     };
265
266     typedef std::list<direntry> dircontent;
267
268     /**
269      * Return content of directory via retlist. If dots is false
270      * entries starting with '.' are not reported. "." and ".."
271      * are never reported.
272      *
273      * The type of individual directory entries is determined accoding to
274      * statmode (i.e. via stat or lstat).
275      *
276      * @return 0 on success, errno on failure.
277      **/
278     static int readdir( dircontent & retlist, const Pathname & path,
279                         bool dots = true, Mode statmode = STAT );
280
281     ///////////////////////////////////////////////////////////////////
282     // Files
283     ///////////////////////////////////////////////////////////////////
284
285     /**
286      * Like '::unlink'. Delete a file (symbolic link, socket, fifo or device).
287      *
288      * @return 0 on success, errno on failure
289      **/
290     static int unlink( const Pathname & path );
291
292     /**
293      * Like '::rename'. Renames a file, moving it between directories if required.
294      *
295      * @return 0 on success, errno on failure
296      **/
297     static int rename( const Pathname & oldpath, const Pathname & newpath );
298
299     /**
300      * Like 'cp file dest'. Copy file to destination file.
301      *
302      * @return 0 on success, EINVAL if file is not a file, EISDIR if
303      * destiantion is a directory, otherwise the commands return value.
304      **/
305     static int copy( const Pathname & file, const Pathname & dest );
306
307     /**
308      * Like '::symlink'. Creates a symbolic link named newpath which contains
309      * the string oldpath. If newpath exists it will not be overwritten.
310      *
311      * @return 0 on success, errno on failure.
312      **/
313     static int symlink( const Pathname & oldpath, const Pathname & newpath );
314
315     /**
316      * Like '::link'. Creates a hard link named newpath to an existing file
317      * oldpath. If newpath exists it will not be overwritten.
318      *
319      * @return 0 on success, errno on failure.
320      **/
321     static int hardlink( const Pathname & oldpath, const Pathname & newpath );
322
323     /**
324      * Like 'cp file dest'. Copy file to dest dir.
325      *
326      * @return 0 on success, EINVAL if file is not a file, ENOTDIR if dest
327      * is no directory, otherwise the commands return value.
328      **/
329     static int copy_file2dir( const Pathname & file, const Pathname & dest );
330
331     /**
332      * Compute a files md5sum.
333      *
334      * @return the files md5sum on success, otherwise an empty string..
335      **/
336     static std::string md5sum( const Pathname & file );
337
338     /**
339      * Compute a files sha1sum.
340      *
341      * @return the files sha1sum on success, otherwise an empty string..
342      **/
343     static std::string sha1sum( const Pathname & file );
344
345     ///////////////////////////////////////////////////////////////////
346     //
347     ///////////////////////////////////////////////////////////////////
348
349     /**
350      * Erase whatever happens to be located at path (file or directory).
351      *
352      * @return 0 on success.
353      **/
354     static int erase( const Pathname & path );
355
356     ///////////////////////////////////////////////////////////////////
357     // permissions
358     ///////////////////////////////////////////////////////////////////
359
360     /**
361      * Like '::chmod'. The mode of the file given by path is changed.
362      *
363      * @return 0 on success, errno on failure
364      **/
365     static int chmod( const Pathname & path, mode_t mode );
366
367     ///////////////////////////////////////////////////////////////////
368     // magic
369     ///////////////////////////////////////////////////////////////////
370
371     /**
372      * Test whether a file is compressed (gzip/bzip2).
373      *
374      * @return ZT_GZ, ZT_BZ2 if file is compressed, otherwise ZT_NONE.
375      **/
376     enum ZIP_TYPE { ZT_NONE, ZT_GZ, ZT_BZ2 };
377
378     static ZIP_TYPE zipType( const Pathname & file );
379 };
380
381 ///////////////////////////////////////////////////////////////////
382
383 ///////////////////////////////////////////////////////////////////
384 //
385 //      CLASS NAME : PathInfo::stat_mode
386 /**
387  * @short Wrapper class for mode_t values as derived from ::stat
388  **/
389 class PathInfo::stat_mode {
390   friend std::ostream & operator<<( std::ostream & str, const stat_mode & obj );
391   private:
392     mode_t _mode;
393   public:
394     stat_mode( const mode_t & mode_r = 0 ) : _mode( mode_r ) {}
395   public:
396     // file type
397     file_type fileType() const;
398
399     bool   isFile()  const { return S_ISREG( _mode ); }
400     bool   isDir ()  const { return S_ISDIR( _mode ); }
401     bool   isLink()  const { return S_ISLNK( _mode ); }
402     bool   isChr()   const { return S_ISCHR( _mode ); }
403     bool   isBlk()   const { return S_ISBLK( _mode ); }
404     bool   isFifo()  const { return S_ISFIFO( _mode ); }
405     bool   isSock()  const { return S_ISSOCK( _mode ); }
406
407     // permission
408     bool   isRUsr()  const { return (_mode & S_IRUSR); }
409     bool   isWUsr()  const { return (_mode & S_IWUSR); }
410     bool   isXUsr()  const { return (_mode & S_IXUSR); }
411
412     bool   isR()     const { return isRUsr(); }
413     bool   isW()     const { return isWUsr(); }
414     bool   isX()     const { return isXUsr(); }
415
416     bool   isRGrp()  const { return (_mode & S_IRGRP); }
417     bool   isWGrp()  const { return (_mode & S_IWGRP); }
418     bool   isXGrp()  const { return (_mode & S_IXGRP); }
419
420     bool   isROth()  const { return (_mode & S_IROTH); }
421     bool   isWOth()  const { return (_mode & S_IWOTH); }
422     bool   isXOth()  const { return (_mode & S_IXOTH); }
423
424     bool   isUid()   const { return (_mode & S_ISUID); }
425     bool   isGid()   const { return (_mode & S_ISGID); }
426     bool   isVtx()   const { return (_mode & S_ISVTX); }
427
428     mode_t uperm()   const { return (_mode & S_IRWXU); }
429     mode_t gperm()   const { return (_mode & S_IRWXG); }
430     mode_t operm()   const { return (_mode & S_IRWXO); }
431     mode_t perm()    const { return (_mode & (S_IRWXU|S_IRWXG|S_IRWXO|S_ISUID|S_ISGID|S_ISVTX)); }
432
433     bool   isPerm ( mode_t m ) const { return (m == perm()); }
434     bool   hasPerm( mode_t m ) const { return (m == (m & perm())); }
435
436     mode_t st_mode() const { return _mode; }
437 };
438
439 ///////////////////////////////////////////////////////////////////
440
441 ///////////////////////////////////////////////////////////////////
442 //
443 //      CLASS NAME : PathInfo::devino_cache
444 /**
445  * @short Simple cache remembering device/inode to detect hardlinks.
446  * <pre>
447  *     PathInfo::devino_cache trace;
448  *     for ( all files ) {
449  *       if ( trace.insert( file.device, file.inode ) ) {
450  *         // 1st occurance of file
451  *       }
452  *         // else: hardlink; already counted this device/inode
453  *       }
454  *     }
455  * </pre>
456  **/
457 class PathInfo::devino_cache {
458
459   private:
460
461     std::map<dev_t,std::set<ino_t> > _devino;
462
463   public:
464     /**
465      * Constructor
466      **/
467     devino_cache() {}
468
469     /**
470      * Clear cache
471      **/
472     void clear() { _devino.clear(); }
473
474     /**
475      * Remember dev/ino. Return <code>true</code> if it's inserted the first
476      * time, <code>false</code> if alredy present in cache (a hardlink to a
477      * previously remembered file.
478      **/
479     bool insert( const dev_t & dev_r, const ino_t & ino_r ) {
480       return _devino[dev_r].insert( ino_r ).second;
481     }
482 };
483
484 ///////////////////////////////////////////////////////////////////
485
486 ///////////////////////////////////////////////////////////////////
487 } // namespace zypp
488
489 #endif // ZYPP_PATHINFO_H