1 /*---------------------------------------------------------------------\
3 | |__ / \ / / . \ . \ |
8 \---------------------------------------------------------------------*/
9 /** \file zypp/PathInfo.h
12 #ifndef ZYPP_PATHINFO_H
13 #define ZYPP_PATHINFO_H
17 #include <sys/types.h>
30 #include "zypp/APIConfig.h"
31 #include "zypp/Pathname.h"
32 #include "zypp/CheckSum.h"
33 #include "zypp/ByteCount.h"
35 ///////////////////////////////////////////////////////////////////
37 { /////////////////////////////////////////////////////////////////
41 ///////////////////////////////////////////////////////////////////
42 /** Types and functions for filesystem operations.
43 * \todo move zypp::filesystem stuff into separate header
44 * \todo Add tmpfile and tmpdir handling.
45 * \todo think about using Exceptions in zypp::filesystem
46 * \todo provide a readdir iterator; at least provide an interface
47 * using an insert_iterator to be independent from std::container.
50 { /////////////////////////////////////////////////////////////////
52 ///////////////////////////////////////////////////////////////////
53 /** File type information.
54 * \todo Think about an \ref g_EnumerationClass
58 FT_NOT_AVAIL = 0x00, // no typeinfo available
59 FT_NOT_EXIST = 0x01, // file does not exist
68 ///////////////////////////////////////////////////////////////////
70 /** \relates FileType Stram output. */
71 extern std::ostream & operator<<( std::ostream & str, FileType obj );
73 ///////////////////////////////////////////////////////////////////
75 ///////////////////////////////////////////////////////////////////
77 // CLASS NAME : StatMode
79 * @short Wrapper class for mode_t values as derived from ::stat
83 friend std::ostream & operator<<( std::ostream & str, const StatMode & obj );
86 /** Ctor taking mode_t value from ::stat. */
87 StatMode( const mode_t & mode_r = 0 )
93 /** \name Query FileType. */
95 FileType fileType() const;
97 bool isFile() const { return S_ISREG( _mode ); }
98 bool isDir () const { return S_ISDIR( _mode ); }
99 bool isLink() const { return S_ISLNK( _mode ); }
100 bool isChr() const { return S_ISCHR( _mode ); }
101 bool isBlk() const { return S_ISBLK( _mode ); }
102 bool isFifo() const { return S_ISFIFO( _mode ); }
103 bool isSock() const { return S_ISSOCK( _mode ); }
106 /** \name Query user permissions. */
108 bool isRUsr() const { return (_mode & S_IRUSR); }
109 bool isWUsr() const { return (_mode & S_IWUSR); }
110 bool isXUsr() const { return (_mode & S_IXUSR); }
112 /** Short for isRUsr().*/
113 bool isR() const { return isRUsr(); }
114 /** Short for isWUsr().*/
115 bool isW() const { return isWUsr(); }
116 /** Short for isXUsr().*/
117 bool isX() const { return isXUsr(); }
120 /** \name Query group permissions. */
122 bool isRGrp() const { return (_mode & S_IRGRP); }
123 bool isWGrp() const { return (_mode & S_IWGRP); }
124 bool isXGrp() const { return (_mode & S_IXGRP); }
127 /** \name Query others permissions. */
129 bool isROth() const { return (_mode & S_IROTH); }
130 bool isWOth() const { return (_mode & S_IWOTH); }
131 bool isXOth() const { return (_mode & S_IXOTH); }
134 /** \name Query special permissions. */
137 bool isUid() const { return (_mode & S_ISUID); }
139 bool isGid() const { return (_mode & S_ISGID); }
141 bool isVtx() const { return (_mode & S_ISVTX); }
144 /** \name Query permission */
146 /** Test for equal permission bits. */
147 bool isPerm ( mode_t m ) const { return (m == perm()); }
148 /** Test for set permission bits. */
149 bool hasPerm( mode_t m ) const { return (m == (m & perm())); }
152 /** \name Extract permission bits only. */
154 mode_t uperm() const { return (_mode & S_IRWXU); }
155 mode_t gperm() const { return (_mode & S_IRWXG); }
156 mode_t operm() const { return (_mode & S_IRWXO); }
157 mode_t perm() const { return (_mode & (S_IRWXU|S_IRWXG|S_IRWXO|S_ISUID|S_ISGID|S_ISVTX)); }
160 /** Return the mode_t value. */
161 mode_t st_mode() const { return _mode; }
166 ///////////////////////////////////////////////////////////////////
168 /** \relates StatMode Stream output. */
169 extern std::ostream & operator<<( std::ostream & str, const StatMode & obj );
171 ///////////////////////////////////////////////////////////////////
173 ///////////////////////////////////////////////////////////////////
175 // CLASS NAME : DevInoCache
176 /** Simple cache remembering device/inode to detect hardlinks.
179 * for ( all files ) {
180 * if ( trace.insert( file.device, file.inode ) ) {
181 * // 1st occurance of file
183 * // else: hardlink; already counted this device/inode
195 void clear() { _devino.clear(); }
197 /** Remember dev/ino.
198 * \Return <code>true</code> if it's inserted the first
199 * time, <code>false</code> if alredy present in cache
200 * (a hardlink to a previously remembered file).
202 bool insert( const dev_t & dev_r, const ino_t & ino_r ) {
203 return _devino[dev_r].insert( ino_r ).second;
207 std::map<dev_t,std::set<ino_t> > _devino;
209 ///////////////////////////////////////////////////////////////////
211 ///////////////////////////////////////////////////////////////////
213 // CLASS NAME : PathInfo
214 /** Wrapper class for ::stat/::lstat.
216 * \note All attribute quieries test for isExist(), and return \c false or
217 * \c 0, if stat was not successful.
219 * \note For convenience PathInfo is available as zypp::PathInfo too.
223 friend std::ostream & operator<<( std::ostream & str, const PathInfo & obj );
226 /** stat() or lstat() */
227 enum Mode { STAT, LSTAT };
230 /** \name Construct from Pathname.
231 * Default mode is \c STAT.
236 PathInfo( const Pathname & path, Mode initial = STAT );
238 PathInfo( const std::string & path, Mode initial = STAT );
240 PathInfo( const char * path, Mode initial = STAT );
246 /** Return current Pathname. */
247 const Pathname & path() const { return path_t; }
248 /** Return current Pathname as String. */
249 const std::string & asString() const { return path_t.asString(); }
250 /** Return current Pathname as C-string. */
251 const char * c_str() const { return path_t.asString().c_str(); }
252 /** Return current stat Mode. */
253 Mode mode() const { return mode_e; }
254 /** Return error returned from last stat/lstat call. */
255 int error() const { return error_i; }
257 /** Set a new Pathname. */
258 void setPath( const Pathname & path ) { if ( path != path_t ) error_i = -1; path_t = path; }
259 /** Set a new Mode . */
260 void setMode( Mode mode ) { if ( mode != mode_e ) error_i = -1; mode_e = mode; }
263 bool stat ( const Pathname & path ) { setPath( path ); setMode( STAT ); return operator()(); }
264 /** LSTAT \a path. */
265 bool lstat ( const Pathname & path ) { setPath( path ); setMode( LSTAT ); return operator()(); }
266 /** Restat \a path using current mode. */
267 bool operator()( const Pathname & path ) { setPath( path ); return operator()(); }
269 /** STAT current path. */
270 bool stat() { setMode( STAT ); return operator()(); }
271 /** LSTAT current path. */
272 bool lstat() { setMode( LSTAT ); return operator()(); }
273 /** Restat current path using current mode. */
278 /** Return whether valid stat info exists.
279 * That's usg. whether the file exist and you had permission to
282 bool isExist() const { return !error_i; }
284 /** \name Query StatMode attibutes.
285 * Combines \ref zypp::PathInfo::isExist and \ref zypp::filesystem::StatMode query.
288 FileType fileType() const;
290 bool isFile() const { return isExist() && S_ISREG( statbuf_C.st_mode ); }
291 bool isDir () const { return isExist() && S_ISDIR( statbuf_C.st_mode ); }
292 bool isLink() const { return isExist() && S_ISLNK( statbuf_C.st_mode ); }
293 bool isChr() const { return isExist() && S_ISCHR( statbuf_C.st_mode ); }
294 bool isBlk() const { return isExist() && S_ISBLK( statbuf_C.st_mode ); }
295 bool isFifo() const { return isExist() && S_ISFIFO( statbuf_C.st_mode ); }
296 bool isSock() const { return isExist() && S_ISSOCK( statbuf_C.st_mode ); }
299 bool isRUsr() const { return isExist() && (statbuf_C.st_mode & S_IRUSR); }
300 bool isWUsr() const { return isExist() && (statbuf_C.st_mode & S_IWUSR); }
301 bool isXUsr() const { return isExist() && (statbuf_C.st_mode & S_IXUSR); }
303 bool isR() const { return isRUsr(); }
304 bool isW() const { return isWUsr(); }
305 bool isX() const { return isXUsr(); }
307 bool isRGrp() const { return isExist() && (statbuf_C.st_mode & S_IRGRP); }
308 bool isWGrp() const { return isExist() && (statbuf_C.st_mode & S_IWGRP); }
309 bool isXGrp() const { return isExist() && (statbuf_C.st_mode & S_IXGRP); }
311 bool isROth() const { return isExist() && (statbuf_C.st_mode & S_IROTH); }
312 bool isWOth() const { return isExist() && (statbuf_C.st_mode & S_IWOTH); }
313 bool isXOth() const { return isExist() && (statbuf_C.st_mode & S_IXOTH); }
315 bool isUid() const { return isExist() && (statbuf_C.st_mode & S_ISUID); }
316 bool isGid() const { return isExist() && (statbuf_C.st_mode & S_ISGID); }
317 bool isVtx() const { return isExist() && (statbuf_C.st_mode & S_ISVTX); }
319 bool isPerm ( mode_t m ) const { return isExist() && (m == perm()); }
320 bool hasPerm( mode_t m ) const { return isExist() && (m == (m & perm())); }
322 mode_t uperm() const { return isExist() ? (statbuf_C.st_mode & S_IRWXU) : 0; }
323 mode_t gperm() const { return isExist() ? (statbuf_C.st_mode & S_IRWXG) : 0; }
324 mode_t operm() const { return isExist() ? (statbuf_C.st_mode & S_IRWXO) : 0; }
325 mode_t perm() const { return isExist() ? (statbuf_C.st_mode & (S_IRWXU|S_IRWXG|S_IRWXO|S_ISUID|S_ISGID|S_ISVTX)) : 0; }
327 mode_t st_mode() const { return isExist() ? statbuf_C.st_mode : 0; }
330 /** Return st_mode() as filesystem::StatMode. */
331 StatMode asStatMode() const { return st_mode(); }
333 nlink_t nlink() const { return isExist() ? statbuf_C.st_nlink : 0; }
335 /** \name Owner and group */
337 uid_t owner() const { return isExist() ? statbuf_C.st_uid : 0; }
338 gid_t group() const { return isExist() ? statbuf_C.st_gid : 0; }
341 /** \name Permission according to current uid/gid. */
343 /** Returns current users permission (<tt>[0-7]</tt>)*/
344 mode_t userMay() const;
346 bool userMayR() const { return( userMay() & 04 ); }
347 bool userMayW() const { return( userMay() & 02 ); }
348 bool userMayX() const { return( userMay() & 01 ); }
350 bool userMayRW() const { return( (userMay() & 06) == 06 ); }
351 bool userMayRX() const { return( (userMay() & 05) == 05 ); }
352 bool userMayWX() const { return( (userMay() & 03) == 03 ); }
354 bool userMayRWX() const { return( userMay() == 07 ); }
357 /** \name Device and inode info. */
359 ino_t ino() const { return isExist() ? statbuf_C.st_ino : 0; }
360 dev_t dev() const { return isExist() ? statbuf_C.st_dev : 0; }
361 dev_t rdev() const { return isExist() ? statbuf_C.st_rdev : 0; }
363 unsigned int devMajor() const;
364 unsigned int devMinor() const;
366 /** \deprecated Name clashes with GNU libc macro, use \ref devMajor instead. */
367 unsigned int major() const ZYPP_DEPRECATED;
368 /** \deprecated Name clashes with GNU libc macro, use \ref devMinor instead. */
369 unsigned int minor() const ZYPP_DEPRECATED;
372 /** \name Size info. */
374 off_t size() const { return isExist() ? statbuf_C.st_size : 0; }
375 unsigned long blksize() const { return isExist() ? statbuf_C.st_blksize : 0; }
376 unsigned long blocks() const { return isExist() ? statbuf_C.st_blocks : 0; }
379 /** \name Time stamps. */
381 time_t atime() const { return isExist() ? statbuf_C.st_atime : 0; } /* time of last access */
382 time_t mtime() const { return isExist() ? statbuf_C.st_mtime : 0; } /* time of last modification */
383 time_t ctime() const { return isExist() ? statbuf_C.st_ctime : 0; }
388 struct stat statbuf_C;
392 ///////////////////////////////////////////////////////////////////
394 /** \relates PathInfo Stream output. */
395 extern std::ostream & operator<<( std::ostream & str, const PathInfo & obj );
397 ///////////////////////////////////////////////////////////////////
399 ///////////////////////////////////////////////////////////////////
400 /** \name Directory related functions. */
403 * Like '::mkdir'. Attempt to create a new directory named path. mode
404 * specifies the permissions to use. It is modified by the process's
405 * umask in the usual way.
407 * @return 0 on success, errno on failure
409 int mkdir( const Pathname & path, unsigned mode = 0755 );
412 * Like 'mkdir -p'. No error if directory exists. Make parent directories
413 * as needed. mode specifies the permissions to use, if directories have to
414 * be created. It is modified by the process's umask in the usual way.
416 * @return 0 on success, errno on failure
418 int assert_dir( const Pathname & path, unsigned mode = 0755 );
421 * Like '::rmdir'. Delete a directory, which must be empty.
423 * @return 0 on success, errno on failure
425 int rmdir( const Pathname & path );
428 * Like 'rm -r DIR'. Delete a directory, recursively removing its contents.
430 * @return 0 on success, ENOTDIR if path is not a directory, otherwise the
431 * commands return value.
433 int recursive_rmdir( const Pathname & path );
436 * Like 'rm -r DIR/ *'. Delete directory contents, but keep the directory itself.
438 * @return 0 on success, ENOTDIR if path is not a directory, otherwise the
439 * commands return value.
441 int clean_dir( const Pathname & path );
444 * Like 'cp -a srcpath destpath'. Copy directory tree. srcpath/destpath must be
445 * directories. 'basename srcpath' must not exist in destpath.
447 * @return 0 on success, ENOTDIR if srcpath/destpath is not a directory, EEXIST if
448 * 'basename srcpath' exists in destpath, otherwise the commands return value.
450 int copy_dir( const Pathname & srcpath, const Pathname & destpath );
453 * Like 'cp -a srcpath/. destpath'. Copy the content of srcpath recursively
454 * into destpath. Both \p srcpath and \p destpath has to exists.
456 * @return 0 on success, ENOTDIR if srcpath/destpath is not a directory,
457 * EEXIST if srcpath and destpath are equal, otherwise the commands
460 int copy_dir_content( const Pathname & srcpath, const Pathname & destpath);
463 * Convenience returning <tt>StrMatcher( "[^.]*", Match::GLOB )</tt>
464 * \see \ref dirForEach
466 const StrMatcher & matchNoDots();
469 * Invoke callback function \a fnc_r for each entry in directory \a dir_r.
471 * If \a fnc_r is a \c NULL function \c 0 is returned immediately without even
472 * testing or accessing \a dir_r.
474 * Otherwise \c ::readdir is used to read the name of every entry in \a dir_r,
475 * omitting \c '.' and \c '..'. \a dir_r and the current entries name are passed
476 * as arguments to \a fnc_r. If \a fnc_r returns \c false processing is aborted.
478 * @return 0 on success, -1 if aborted by callback, errno > 0 on ::readdir failure.
480 int dirForEach( const Pathname & dir_r, function<bool(const Pathname &, const char *const)> fnc_r );
483 * \overload taking a \ref StrMatcher to filter the entries for which \a fnc_r is invoked.
485 * For convenience a \ref StrMatcher \ref matchNoDots is provided in this namespace.</tt>
488 * bool cbfnc( const Pathname & dir_r, const char *const str_r )
490 * D BG <*< " - " << dir_r/str_r << endl;
493 * // Print no-dot files in "/tmp" via callback
494 * filesystem::dirForEach( "/tmp", filesystem::matchNoDots(), cbfnc );
497 * filesystem::dirForEach( "/tmp", filesystem::matchNoDots(),
498 * [](const Pathname & dir_r, const std::string & str_r)->bool
500 * DBG << " - " << dir_r/str_r << endl;
505 int dirForEach( const Pathname & dir_r, const StrMatcher & matcher_r, function<bool(const Pathname &, const char *const)> fnc_r );
508 * Return content of directory via retlist. If dots is false
509 * entries starting with '.' are not reported. "." and ".."
510 * are never reported.
512 * Returns just the directory entries as string.
514 * @return 0 on success, errno on failure.
516 * \todo provide some readdirIterator.
519 int readdir( std::list<std::string> & retlist,
520 const Pathname & path, bool dots = true );
523 * Return content of directory via retlist. If dots is false
524 * entries starting with '.' are not reported. "." and ".."
525 * are never reported.
527 * Returns the directory entries prefixed with \a path.
529 * @return 0 on success, errno on failure.
531 * \todo provide some readdirIterator.
534 int readdir( std::list<Pathname> & retlist,
535 const Pathname & path, bool dots = true );
537 /** Listentry returned by readdir. */
541 DirEntry( const std::string & name_r = std::string(), FileType type_r = FT_NOT_AVAIL )
546 bool operator==( const DirEntry &rhs ) const;
549 inline std::ostream & operator<<( std::ostream & str, const DirEntry & obj )
550 { return str << '[' << obj.type << "] " << obj.name; }
552 /** Returned by readdir. */
553 typedef std::list<DirEntry> DirContent;
555 std::ostream & operator<<( std::ostream & str, const DirContent & obj );
558 * Return content of directory via retlist. If dots is false
559 * entries starting with '.' are not reported. "." and ".."
560 * are never reported.
562 * The type of individual directory entries is determined accoding to
563 * statmode (i.e. via stat or lstat).
565 * @return 0 on success, errno on failure.
567 int readdir( DirContent & retlist, const Pathname & path,
568 bool dots = true, PathInfo::Mode statmode = PathInfo::STAT );
571 * Check if the specified directory is empty.
572 * \param path The path of the directory to check.
573 * \return 0 if directory is empty, -1 if not, errno > 0 on failure.
575 int is_empty_dir(const Pathname & path);
579 ///////////////////////////////////////////////////////////////////
580 /** \name File related functions. */
583 * Create an empty file if it does not yet exist. Make parent directories
584 * as needed. mode specifies the permissions to use. It is modified by the
585 * process's umask in the usual way.
587 * @return 0 on success, errno on failure
589 int assert_file( const Pathname & path, unsigned mode = 0644 );
592 * Change file's modification and access times.
594 * \return 0 on success, errno on failure
597 int touch (const Pathname & path);
600 * Like '::unlink'. Delete a file (symbolic link, socket, fifo or device).
602 * @return 0 on success, errno on failure
604 int unlink( const Pathname & path );
607 * Like '::rename'. Renames a file, moving it between directories if required.
609 * @return 0 on success, errno on failure
611 int rename( const Pathname & oldpath, const Pathname & newpath );
613 /** Exchanges two files or directories.
615 * Most common use is when building a new config file (or dir)
616 * in a tempfile. After the job is done, configfile and tempfile
617 * are exchanged. This includes moving away the configfile in case
618 * the tempfile does not exist. Parent directories are created as
621 * \note Paths are exchanged using \c ::rename, so take care both paths
622 * are located on the same filesystem.
625 * Pathname configfile( "/etc/myconfig" );
626 * TmpFile newconfig( TmpFile::makeSibling( configfile ) );
627 * // now write the new config:
628 * std::ofstream o( newconfig.path().c_str() );
629 * o << "mew values << endl;
631 * // If everything is fine, exchange the files:
632 * exchange( newconfig.path(), configfile );
633 * // Now the old configfile is still available at newconfig.path()
634 * // until newconfig goes out of scope.
637 * @return 0 on success, errno on failure
639 int exchange( const Pathname & lpath, const Pathname & rpath );
642 * Like 'cp file dest'. Copy file to destination file.
644 * @return 0 on success, EINVAL if file is not a file, EISDIR if
645 * destiantion is a directory, otherwise the commands return value.
647 int copy( const Pathname & file, const Pathname & dest );
650 * Like '::symlink'. Creates a symbolic link named newpath which contains
651 * the string oldpath. If newpath exists it will not be overwritten.
653 * @return 0 on success, errno on failure.
655 int symlink( const Pathname & oldpath, const Pathname & newpath );
658 * Like '::link'. Creates a hard link named newpath to an existing file
659 * oldpath. If newpath exists it will not be overwritten.
661 * @return 0 on success, errno on failure.
663 int hardlink( const Pathname & oldpath, const Pathname & newpath );
666 * Create \a newpath as hardlink or copy of \a oldpath.
668 * @return 0 on success, errno on failure.
670 int hardlinkCopy( const Pathname & oldpath, const Pathname & newpath );
673 * Like '::readlink'. Return the contents of the symbolic link
674 * \a symlink_r via \a target_r.
676 * @return 0 on success, errno on failure.
678 int readlink( const Pathname & symlink_r, Pathname & target_r );
679 /** \overload Return an empty Pathname on error. */
680 inline Pathname readlink( const Pathname & symlink_r )
683 readlink( symlink_r, target );
688 * Recursively follows the symlink pointed to by \a path_r and returns
689 * the Pathname to the real file or directory pointed to by the link.
691 * There is a recursion limit of 256 iterations to protect against a cyclic
694 * @return Pathname of the file or directory pointed to by the given link
695 * if it is a valid link. If \a path_r is not a link, an exact copy of
696 * it is returned. If \a path_r is a broken or a cyclic link, an empty
697 * Pathname is returned and the event logged.
699 Pathname expandlink( const Pathname & path_r );
702 * Like 'cp file dest'. Copy file to dest dir.
704 * @return 0 on success, EINVAL if file is not a file, ENOTDIR if dest
705 * is no directory, otherwise the commands return value.
707 int copy_file2dir( const Pathname & file, const Pathname & dest );
710 ///////////////////////////////////////////////////////////////////
711 /** \name Digest computaion.
712 * \todo check cooperation with zypp::Digest
716 * Compute a files md5sum.
718 * @return the files md5sum on success, otherwise an empty string..
720 std::string md5sum( const Pathname & file );
723 * Compute a files sha1sum.
725 * @return the files sha1sum on success, otherwise an empty string..
727 std::string sha1sum( const Pathname & file );
731 * Compute a files checksum
733 * @return the files checksum on success, otherwise an empty string..
735 std::string checksum( const Pathname & file, const std::string &algorithm );
738 * check files checksum
740 * @return true if the checksum matches (an empty Checksum always matches!)
742 bool is_checksum( const Pathname & file, const CheckSum &checksum );
744 ///////////////////////////////////////////////////////////////////
745 /** \name Changing permissions. */
748 * Like '::chmod'. The mode of the file given by path is changed.
750 * @return 0 on success, errno on failure
752 int chmod( const Pathname & path, mode_t mode );
755 * Add the \c mode bits to the file given by path.
757 * @return 0 on success, errno on failure
759 int addmod( const Pathname & path, mode_t mode );
762 * Remove the \c mode bits from the file given by path.
764 * @return 0 on success, errno on failure
766 int delmod( const Pathname & path, mode_t mode );
769 ///////////////////////////////////////////////////////////////////
773 * Test whether a file is compressed (gzip/bzip2).
775 * @return ZT_GZ, ZT_BZ2 if file is compressed, otherwise ZT_NONE.
777 enum ZIP_TYPE { ZT_NONE, ZT_GZ, ZT_BZ2 };
779 ZIP_TYPE zipType( const Pathname & file );
782 * Erase whatever happens to be located at path (file or directory).
784 * @return 0 on success.
786 * \todo check cooperation with zypp::TmpFile and zypp::TmpDir
788 int erase( const Pathname & path );
791 * Report free disk space on a mounted file system.
793 * path is the path name of any file within the mounted filesystem.
795 * @return Free disk space or -1 on error.
797 ByteCount df( const Pathname & path );
800 * Get the current umask (file mode creation mask)
802 * @return The current umask
807 * Modify \c mode_r according to the current umask
808 * <tt>( mode_r & ~getUmask() )</tt>.
809 * \see \ref getUmask.
810 * @return The resulting permissions.
812 inline mode_t applyUmaskTo( mode_t mode_r )
813 { return mode_r & ~getUmask(); }
816 /////////////////////////////////////////////////////////////////
817 } // namespace filesystem
818 ///////////////////////////////////////////////////////////////////
820 /** Dragged into namespace zypp. */
821 using filesystem::PathInfo;
823 /////////////////////////////////////////////////////////////////
825 ///////////////////////////////////////////////////////////////////
826 #endif // ZYPP_PATHINFO_H