------------------------------------------------------------------------
[platform/upstream/libzypp.git] / zypp / PathInfo.cc
1 /*---------------------------------------------------------------------\
2 |                          ____ _   __ __ ___                          |
3 |                         |__  / \ / / . \ . \                         |
4 |                           / / \ V /|  _/  _/                         |
5 |                          / /__ | | | | | |                           |
6 |                         /_____||_| |_| |_|                           |
7 |                                                                      |
8 \---------------------------------------------------------------------*/
9 /** \file zypp/PathInfo.cc
10  *
11 */
12
13 #include <sys/types.h> // for ::minor, ::major macros
14 #include <utime.h>     // for ::utime
15 #include <sys/statvfs.h>
16
17 #include <iostream>
18 #include <fstream>
19 #include <iomanip>
20
21 #include <boost/filesystem/operations.hpp>
22 #include <boost/filesystem/exception.hpp>
23
24 #include "zypp/base/Logger.h"
25 #include "zypp/base/String.h"
26 #include "zypp/base/IOStream.h"
27
28 #include "zypp/ExternalProgram.h"
29 #include "zypp/PathInfo.h"
30 #include "zypp/Digest.h"
31
32 using std::endl;
33 using std::string;
34
35 ///////////////////////////////////////////////////////////////////
36 namespace zypp
37 { /////////////////////////////////////////////////////////////////
38   ///////////////////////////////////////////////////////////////////
39   namespace filesystem
40   { /////////////////////////////////////////////////////////////////
41
42     /******************************************************************
43      **
44      ** FUNCTION NAME : operator<<
45      ** FUNCTION TYPE : std::ostream &
46     */
47     std::ostream & operator<<( std::ostream & str, FileType obj )
48     {
49       switch ( obj ) {
50 #define EMUMOUT(T) case T: return str << #T; break
51         EMUMOUT( FT_NOT_AVAIL );
52         EMUMOUT( FT_NOT_EXIST );
53         EMUMOUT( FT_FILE );
54         EMUMOUT( FT_DIR );
55         EMUMOUT( FT_CHARDEV );
56         EMUMOUT( FT_BLOCKDEV );
57         EMUMOUT( FT_FIFO );
58         EMUMOUT( FT_LINK );
59         EMUMOUT( FT_SOCKET );
60 #undef EMUMOUT
61       }
62       return str;
63     }
64
65     ///////////////////////////////////////////////////////////////////
66     //
67     //  METHOD NAME : StatMode::fileType
68     //  METHOD TYPE : FileType
69     //
70     FileType StatMode::fileType() const
71     {
72       if ( isFile() )
73         return FT_FILE;
74       if ( isDir() )
75         return FT_DIR;
76       if ( isLink() )
77         return FT_LINK;
78       if ( isChr() )
79         return FT_CHARDEV;
80       if ( isBlk() )
81         return FT_BLOCKDEV;
82       if ( isFifo() )
83         return FT_FIFO;
84       if ( isSock() )
85         return FT_SOCKET ;
86
87       return FT_NOT_AVAIL;
88     }
89
90     /******************************************************************
91      **
92      ** FUNCTION NAME : operator<<
93      ** FUNCTION TYPE : std::ostream &
94     */
95     std::ostream & operator<<( std::ostream & str, const StatMode & obj )
96     {
97       iostr::IosFmtFlagsSaver autoResoreState( str );
98
99       char t = '?';
100       if ( obj.isFile() )
101         t = '-';
102       else if ( obj.isDir() )
103         t = 'd';
104       else if ( obj.isLink() )
105         t = 'l';
106       else if ( obj.isChr() )
107         t = 'c';
108       else if ( obj.isBlk() )
109         t = 'b';
110       else if ( obj.isFifo() )
111         t = 'p';
112       else if ( obj.isSock() )
113         t = 's';
114
115       str << t << " " << std::setfill( '0' ) << std::setw( 4 ) << std::oct << obj.perm();
116       return str;
117     }
118
119     ///////////////////////////////////////////////////////////////////
120     //
121     //  Class : PathInfo
122     //
123     ///////////////////////////////////////////////////////////////////
124
125     ///////////////////////////////////////////////////////////////////
126     //
127     //  METHOD NAME : PathInfo::PathInfo
128     //  METHOD TYPE : Constructor
129     //
130     PathInfo::PathInfo()
131     : mode_e( STAT )
132     , error_i( -1 )
133     {}
134
135     ///////////////////////////////////////////////////////////////////
136     //
137     //  METHOD NAME : PathInfo::PathInfo
138     //  METHOD TYPE : Constructor
139     //
140     PathInfo::PathInfo( const Pathname & path, Mode initial )
141     : path_t( path )
142     , mode_e( initial )
143     , error_i( -1 )
144     {
145       operator()();
146     }
147
148     ///////////////////////////////////////////////////////////////////
149     //
150     //  METHOD NAME : PathInfo::PathInfo
151     //  METHOD TYPE : Constructor
152     //
153     PathInfo::PathInfo( const std::string & path, Mode initial )
154     : path_t( path )
155     , mode_e( initial )
156     , error_i( -1 )
157     {
158       operator()();
159     }
160
161     ///////////////////////////////////////////////////////////////////
162     //
163     //  METHOD NAME : PathInfo::PathInfo
164     //  METHOD TYPE : Constructor
165     //
166     PathInfo::PathInfo( const char * path, Mode initial )
167     : path_t( path )
168     , mode_e( initial )
169     , error_i( -1 )
170     {
171       operator()();
172     }
173
174     ///////////////////////////////////////////////////////////////////
175     //
176     //  METHOD NAME : PathInfo::~PathInfo
177     //  METHOD TYPE : Destructor
178     //
179     PathInfo::~PathInfo()
180     {
181     }
182
183     ///////////////////////////////////////////////////////////////////
184     //
185     //  METHOD NAME : PathInfo::operator()
186     //  METHOD TYPE : bool
187     //
188     bool PathInfo::operator()()
189     {
190       if ( path_t.empty() ) {
191         error_i = -1;
192       } else {
193         switch ( mode_e ) {
194         case STAT:
195           error_i = ::stat( path_t.asString().c_str(), &statbuf_C );
196           break;
197         case LSTAT:
198           error_i = ::lstat( path_t.asString().c_str(), &statbuf_C );
199           break;
200         }
201         if ( error_i == -1 )
202           error_i = errno;
203       }
204       return !error_i;
205     }
206
207     ///////////////////////////////////////////////////////////////////
208     //
209     //  METHOD NAME : PathInfo::fileType
210     //  METHOD TYPE : File_type
211     //
212     FileType PathInfo::fileType() const
213     {
214       if ( isExist() )
215         return asStatMode().fileType();
216       return FT_NOT_EXIST;
217     }
218
219     ///////////////////////////////////////////////////////////////////
220     //
221     //  METHOD NAME : PathInfo::userMay
222     //  METHOD TYPE : mode_t
223     //
224     mode_t PathInfo::userMay() const
225     {
226       if ( !isExist() )
227         return 0;
228       if ( owner() == getuid() ) {
229         return( uperm()/0100 );
230       } else if ( group() == getgid() ) {
231         return( gperm()/010 );
232       }
233       return operm();
234     }
235
236     /******************************************************************
237      **
238      ** FUNCTION NAME : PathInfo::major
239      ** FUNCTION TYPE : unsigned int
240      */
241     unsigned int PathInfo::major() const
242     {
243       return isBlk() || isChr() ? ::major(statbuf_C.st_rdev) : 0;
244     }
245
246     /******************************************************************
247      **
248      ** FUNCTION NAME : PathInfo::minor
249      ** FUNCTION TYPE : unsigned int
250      */
251     unsigned int PathInfo::minor() const
252     {
253       return isBlk() || isChr() ? ::minor(statbuf_C.st_rdev) : 0;
254     }
255
256     /******************************************************************
257      **
258      ** FUNCTION NAME : operator<<
259      ** FUNCTION TYPE :  std::ostream &
260     */
261     std::ostream & operator<<( std::ostream & str, const PathInfo & obj )
262     {
263       iostr::IosFmtFlagsSaver autoResoreState( str );
264
265       str << obj.asString() << "{";
266       if ( !obj.isExist() ) {
267         str << "does not exist}";
268       } else {
269         str << obj.asStatMode() << " " << std::dec << obj.owner() << "/" << obj.group();
270
271         if ( obj.isFile() )
272           str << " size " << obj.size();
273
274         str << "}";
275       }
276
277       return str;
278     }
279
280     ///////////////////////////////////////////////////////////////////
281     //
282     //  filesystem utilities
283     //
284     ///////////////////////////////////////////////////////////////////
285
286     /******************************************************************
287      **
288      ** FUNCTION NAME : _Log_Result
289      ** FUNCTION TYPE : int
290      **
291      ** DESCRIPTION : Helper function to log return values.
292     */
293     inline int _Log_Result( const int res, const char * rclass = "errno" )
294     {
295       MIL << endl;
296       if ( res )
297         WAR << " FAILED: " << rclass << " " << res << endl;
298       return res;
299     }
300
301     ///////////////////////////////////////////////////////////////////
302     //
303     //  METHOD NAME : PathInfo::mkdir
304     //  METHOD TYPE : int
305     //
306     int mkdir( const Pathname & path, unsigned mode )
307     {
308       MIL << "mkdir " << path << ' ' << str::octstring( mode );
309       if ( ::mkdir( path.asString().c_str(), mode ) == -1 ) {
310         return _Log_Result( errno );
311       }
312       return _Log_Result( 0 );
313     }
314
315     ///////////////////////////////////////////////////////////////////
316     //
317     //  METHOD NAME : assert_dir()
318     //  METHOD TYPE : int
319     //
320     int assert_dir( const Pathname & path, unsigned mode )
321     {
322       string::size_type pos, lastpos = 0;
323       string spath = path.asString()+"/";
324       int ret = 0;
325
326       if(path.empty())
327         return ENOENT;
328
329       // skip ./
330       if(path.relative())
331         lastpos=2;
332       // skip /
333       else
334         lastpos=1;
335
336       //    MIL << "about to create " << spath << endl;
337       while((pos = spath.find('/',lastpos)) != string::npos )
338         {
339           string dir = spath.substr(0,pos);
340           ret = ::mkdir(dir.c_str(), mode);
341           if(ret == -1)
342           {
343             // ignore errors about already existing directorys
344             if(errno == EEXIST)
345               ret=0;
346             else
347             {
348               ret=errno;
349               WAR << " FAILED: mkdir " << path << ' ' << str::octstring( mode ) << " errno " << ret << endl;
350             }
351           }
352           else
353           {
354             MIL << "mkdir " << path << ' ' << str::octstring( mode );
355           }
356           lastpos = pos+1;
357         }
358       return ret;
359     }
360
361     ///////////////////////////////////////////////////////////////////
362     //
363     //  METHOD NAME : rmdir
364     //  METHOD TYPE : int
365     //
366     int rmdir( const Pathname & path )
367     {
368       MIL << "rmdir " << path;
369       if ( ::rmdir( path.asString().c_str() ) == -1 ) {
370         return _Log_Result( errno );
371       }
372       return _Log_Result( 0 );
373     }
374
375     ///////////////////////////////////////////////////////////////////
376     //
377     //  METHOD NAME : recursive_rmdir
378     //  METHOD TYPE : int
379     //
380     static int recursive_rmdir_1( const Pathname & dir )
381     {
382       DIR * dp;
383       struct dirent * d;
384
385       if ( ! (dp = opendir( dir.c_str() )) )
386         return _Log_Result( errno );
387
388       while ( (d = readdir(dp)) )
389       {
390         std::string direntry = d->d_name;
391         if ( direntry == "." || direntry == ".." )
392           continue;
393         Pathname new_path( dir / d->d_name );
394
395         struct stat st;
396         if ( ! lstat( new_path.c_str(), &st ) )
397         {
398           if ( S_ISDIR( st.st_mode ) )
399             recursive_rmdir_1( new_path );
400           else
401             ::unlink( new_path.c_str() );
402         }
403       }
404       closedir( dp );
405
406       if ( ::rmdir( dir.c_str() ) < 0 )
407         return _Log_Result( errno );
408
409       return _Log_Result( 0 );
410     }
411     ///////////////////////////////////////////////////////////////////
412     int recursive_rmdir( const Pathname & path )
413     {
414       MIL << "recursive_rmdir " << path << ' ';
415       PathInfo p( path );
416
417       if ( !p.isExist() ) {
418         return _Log_Result( 0 );
419       }
420
421       if ( !p.isDir() ) {
422         return _Log_Result( ENOTDIR );
423       }
424
425       return recursive_rmdir_1( path );
426     }
427
428     ///////////////////////////////////////////////////////////////////
429     //
430     //  METHOD NAME : clean_dir
431     //  METHOD TYPE : int
432     //
433     int clean_dir( const Pathname & path )
434     {
435       MIL << "clean_dir " << path << ' ';
436       PathInfo p( path );
437
438       if ( !p.isExist() ) {
439         return _Log_Result( 0 );
440       }
441
442       if ( !p.isDir() ) {
443         return _Log_Result( ENOTDIR );
444       }
445
446       string cmd( str::form( "cd '%s' && rm -rf --preserve-root -- *", path.asString().c_str() ) );
447       ExternalProgram prog( cmd, ExternalProgram::Stderr_To_Stdout );
448       for ( string output( prog.receiveLine() ); output.length(); output = prog.receiveLine() ) {
449         MIL << "  " << output;
450       }
451       int ret = prog.close();
452       return _Log_Result( ret, "returned" );
453     }
454
455     ///////////////////////////////////////////////////////////////////
456     //
457     //  METHOD NAME : copy_dir
458     //  METHOD TYPE : int
459     //
460     int copy_dir( const Pathname & srcpath, const Pathname & destpath )
461     {
462       MIL << "copy_dir " << srcpath << " -> " << destpath << ' ';
463
464       PathInfo sp( srcpath );
465       if ( !sp.isDir() ) {
466         return _Log_Result( ENOTDIR );
467       }
468
469       PathInfo dp( destpath );
470       if ( !dp.isDir() ) {
471         return _Log_Result( ENOTDIR );
472       }
473
474       PathInfo tp( destpath + srcpath.basename() );
475       if ( tp.isExist() ) {
476         return _Log_Result( EEXIST );
477       }
478
479
480       const char *const argv[] = {
481         "/bin/cp",
482         "-dR",
483         "--",
484         srcpath.asString().c_str(),
485         destpath.asString().c_str(),
486         NULL
487       };
488       ExternalProgram prog( argv, ExternalProgram::Stderr_To_Stdout );
489       for ( string output( prog.receiveLine() ); output.length(); output = prog.receiveLine() ) {
490         MIL << "  " << output;
491       }
492       int ret = prog.close();
493       return _Log_Result( ret, "returned" );
494     }
495
496     ///////////////////////////////////////////////////////////////////
497     //
498     //  METHOD NAME : copy_dir_content
499     //  METHOD TYPE : int
500     //
501     int copy_dir_content(const Pathname & srcpath, const Pathname & destpath)
502     {
503       MIL << "copy_dir " << srcpath << " -> " << destpath << ' ';
504
505       PathInfo sp( srcpath );
506       if ( !sp.isDir() ) {
507         return _Log_Result( ENOTDIR );
508       }
509
510       PathInfo dp( destpath );
511       if ( !dp.isDir() ) {
512         return _Log_Result( ENOTDIR );
513       }
514
515       if ( srcpath == destpath ) {
516         return _Log_Result( EEXIST );
517       }
518
519       std::string src( srcpath.asString());
520       src += "/.";
521       const char *const argv[] = {
522         "/bin/cp",
523         "-dR",
524         "--",
525         src.c_str(),
526         destpath.asString().c_str(),
527         NULL
528       };
529       ExternalProgram prog( argv, ExternalProgram::Stderr_To_Stdout );
530       for ( string output( prog.receiveLine() ); output.length(); output = prog.receiveLine() ) {
531         MIL << "  " << output;
532       }
533       int ret = prog.close();
534       return _Log_Result( ret, "returned" );
535     }
536
537     ///////////////////////////////////////////////////////////////////
538     //
539     //  METHOD NAME : readdir
540     //  METHOD TYPE : int
541     //
542     int readdir( std::list<std::string> & retlist,
543                  const Pathname & path, bool dots )
544     {
545       retlist.clear();
546
547       MIL << "readdir " << path << ' ';
548
549       DIR * dir = ::opendir( path.asString().c_str() );
550       if ( ! dir ) {
551         return _Log_Result( errno );
552       }
553
554       struct dirent *entry;
555       while ( (entry = ::readdir( dir )) != 0 ) {
556
557         if ( entry->d_name[0] == '.' ) {
558           if ( !dots )
559             continue;
560           if ( entry->d_name[1] == '\0'
561                || (    entry->d_name[1] == '.'
562                     && entry->d_name[2] == '\0' ) )
563             continue;
564         }
565         retlist.push_back( entry->d_name );
566       }
567
568       ::closedir( dir );
569
570       return _Log_Result( 0 );
571     }
572
573
574     ///////////////////////////////////////////////////////////////////
575     //
576     //  METHOD NAME : readdir
577     //  METHOD TYPE : int
578     //
579     int readdir( std::list<Pathname> & retlist,
580                  const Pathname & path, bool dots )
581     {
582       retlist.clear();
583
584       std::list<string> content;
585       int res = readdir( content, path, dots );
586
587       if ( !res ) {
588         for ( std::list<string>::const_iterator it = content.begin(); it != content.end(); ++it ) {
589           retlist.push_back( path + *it );
590         }
591       }
592
593       return res;
594     }
595
596     ///////////////////////////////////////////////////////////////////
597     //
598     //  METHOD NAME : readdir
599     //  METHOD TYPE : int
600     //
601     int readdir( DirContent & retlist, const Pathname & path,
602                  bool dots, PathInfo::Mode statmode )
603     {
604       retlist.clear();
605
606       std::list<string> content;
607       int res = readdir( content, path, dots );
608
609       if ( !res ) {
610         for ( std::list<string>::const_iterator it = content.begin(); it != content.end(); ++it ) {
611           PathInfo p( path + *it, statmode );
612           retlist.push_back( DirEntry( *it, p.fileType() ) );
613         }
614       }
615
616       return res;
617     }
618
619     ///////////////////////////////////////////////////////////////////
620     //
621     //  METHOD NAME : is_empty_dir
622     //  METHOD TYPE : int
623     //
624     int is_empty_dir(const Pathname & path)
625     {
626       DIR * dir = ::opendir( path.asString().c_str() );
627       if ( ! dir ) {
628         return _Log_Result( errno );
629       }
630
631       struct dirent *entry;
632       while ( (entry = ::readdir( dir )) != NULL )
633       {
634         std::string name(entry->d_name);
635
636         if ( name == "." || name == "..")
637           continue;
638
639         break;
640       }
641       ::closedir( dir );
642
643       return entry != NULL ? -1 : 0;
644     }
645
646     ///////////////////////////////////////////////////////////////////
647     //
648     //  METHOD NAME : unlink
649     //  METHOD TYPE : int
650     //
651     int unlink( const Pathname & path )
652     {
653       MIL << "unlink " << path;
654       if ( ::unlink( path.asString().c_str() ) == -1 ) {
655         return _Log_Result( errno );
656       }
657       return _Log_Result( 0 );
658     }
659
660     ///////////////////////////////////////////////////////////////////
661     //
662     //  METHOD NAME : rename
663     //  METHOD TYPE : int
664     //
665     int rename( const Pathname & oldpath, const Pathname & newpath )
666     {
667       MIL << "rename " << oldpath << " -> " << newpath;
668       if ( ::rename( oldpath.asString().c_str(), newpath.asString().c_str() ) == -1 ) {
669         return _Log_Result( errno );
670       }
671       return _Log_Result( 0 );
672     }
673
674     ///////////////////////////////////////////////////////////////////
675     //
676     //  METHOD NAME : copy
677     //  METHOD TYPE : int
678     //
679     int copy( const Pathname & file, const Pathname & dest )
680     {
681       MIL << "copy " << file << " -> " << dest << ' ';
682
683       PathInfo sp( file );
684       if ( !sp.isFile() ) {
685         return _Log_Result( EINVAL );
686       }
687
688       PathInfo dp( dest );
689       if ( dp.isDir() ) {
690         return _Log_Result( EISDIR );
691       }
692
693       const char *const argv[] = {
694         "/bin/cp",
695         "--",
696         file.asString().c_str(),
697         dest.asString().c_str(),
698         NULL
699       };
700       ExternalProgram prog( argv, ExternalProgram::Stderr_To_Stdout );
701       for ( string output( prog.receiveLine() ); output.length(); output = prog.receiveLine() ) {
702         MIL << "  " << output;
703       }
704       int ret = prog.close();
705       return _Log_Result( ret, "returned" );
706     }
707
708     ///////////////////////////////////////////////////////////////////
709     //
710     //  METHOD NAME : symlink
711     //  METHOD TYPE : int
712     //
713     int symlink( const Pathname & oldpath, const Pathname & newpath )
714     {
715       MIL << "symlink " << newpath << " -> " << oldpath;
716       if ( ::symlink( oldpath.asString().c_str(), newpath.asString().c_str() ) == -1 ) {
717         return _Log_Result( errno );
718       }
719       return _Log_Result( 0 );
720     }
721
722     ///////////////////////////////////////////////////////////////////
723     //
724     //  METHOD NAME : hardlink
725     //  METHOD TYPE : int
726     //
727     int hardlink( const Pathname & oldpath, const Pathname & newpath )
728     {
729       MIL << "hardlink " << newpath << " -> " << oldpath;
730       if ( ::link( oldpath.asString().c_str(), newpath.asString().c_str() ) == -1 ) {
731         return _Log_Result( errno );
732       }
733       return _Log_Result( 0 );
734     }
735
736     ///////////////////////////////////////////////////////////////////
737     //
738     //  METHOD NAME : readlink
739     //  METHOD TYPE : int
740     //
741     int readlink( const Pathname & symlink_r, Pathname & target_r )
742     {
743       static const ssize_t bufsiz = 2047;
744       static char buf[bufsiz+1];
745       ssize_t ret = ::readlink( symlink_r.c_str(), buf, bufsiz );
746       if ( ret == -1 )
747       {
748         target_r = Pathname();
749         MIL << "readlink " << symlink_r;
750         return _Log_Result( errno );
751       }
752       buf[ret] = '\0';
753       target_r = buf;
754       return 0;
755     }
756
757     ///////////////////////////////////////////////////////////////////
758     //
759     //  METHOD NAME : expandlink
760     //  METHOD TYPE : Pathname
761     //
762     Pathname expandlink( const Pathname & path_r )
763     {
764       static const unsigned int level_limit = 256;
765       static unsigned int count;
766       Pathname path(path_r);
767       PathInfo info(path_r, PathInfo::LSTAT);
768
769       for (count = level_limit; info.isLink() && count; count--)
770       {
771         DBG << "following symlink " << path << std::endl;
772         path = readlink(path);
773         info = PathInfo(path, PathInfo::LSTAT);
774       }
775
776       // expand limit reached
777       if (count == 0)
778       {
779         ERR << "Expand level limit reached. Probably a cyclic symbolic link." << endl;
780         return Pathname();
781       }
782       // symlink
783       else if (count < level_limit)
784       {
785         // check for a broken link
786         if (PathInfo(path).isExist())
787           return path;
788         // broken link, return and empty path
789         else
790         {
791           ERR << path << " is broken (expanded from " << path_r << ")" << endl;
792           return Pathname();
793         }
794       }
795
796       // not a symlink, return the original pathname
797       DBG << "not a symlink" << endl;
798       return path;
799     }
800
801     ///////////////////////////////////////////////////////////////////
802     //
803     //  METHOD NAME : copy_file2dir
804     //  METHOD TYPE : int
805     //
806     int copy_file2dir( const Pathname & file, const Pathname & dest )
807     {
808       MIL << "copy_file2dir " << file << " -> " << dest << ' ';
809
810       PathInfo sp( file );
811       if ( !sp.isFile() ) {
812         return _Log_Result( EINVAL );
813       }
814
815       PathInfo dp( dest );
816       if ( !dp.isDir() ) {
817         return _Log_Result( ENOTDIR );
818       }
819
820       const char *const argv[] = {
821         "/bin/cp",
822         "--",
823         file.asString().c_str(),
824         dest.asString().c_str(),
825         NULL
826       };
827       ExternalProgram prog( argv, ExternalProgram::Stderr_To_Stdout );
828       for ( string output( prog.receiveLine() ); output.length(); output = prog.receiveLine() ) {
829         MIL << "  " << output;
830       }
831       int ret = prog.close();
832       return _Log_Result( ret, "returned" );
833     }
834
835     ///////////////////////////////////////////////////////////////////
836     //
837     //  METHOD NAME : md5sum
838     //  METHOD TYPE : std::string
839     //
840     std::string md5sum( const Pathname & file )
841     {
842       if ( ! PathInfo( file ).isFile() ) {
843         return string();
844       }
845       std::ifstream istr( file.asString().c_str() );
846       if ( ! istr ) {
847         return string();
848       }
849       return Digest::digest( "MD5", istr );
850     }
851
852     ///////////////////////////////////////////////////////////////////
853     //
854     //  METHOD NAME : sha1sum
855     //  METHOD TYPE : std::string
856     //
857     std::string sha1sum( const Pathname & file )
858     {
859       return checksum(file, "SHA1");
860     }
861
862     ///////////////////////////////////////////////////////////////////
863     //
864     //  METHOD NAME : checksum
865     //  METHOD TYPE : std::string
866     //
867     std::string checksum( const Pathname & file, const std::string &algorithm )
868     {
869       if ( ! PathInfo( file ).isFile() ) {
870         return string();
871       }
872       std::ifstream istr( file.asString().c_str() );
873       if ( ! istr ) {
874         return string();
875       }
876       return Digest::digest( algorithm, istr );
877     }
878
879     bool is_checksum( const Pathname & file, const CheckSum &checksum )
880     {
881       return ( filesystem::checksum(file,  checksum.type()) == checksum.checksum() );
882     }
883
884     ///////////////////////////////////////////////////////////////////
885     //
886     //  METHOD NAME : erase
887     //  METHOD TYPE : int
888     //
889     int erase( const Pathname & path )
890     {
891       int res = 0;
892       PathInfo p( path, PathInfo::LSTAT );
893       if ( p.isExist() )
894         {
895           if ( p.isDir() )
896             res = recursive_rmdir( path );
897           else
898             res = unlink( path );
899         }
900       return res;
901     }
902
903     ///////////////////////////////////////////////////////////////////
904     //
905     //  METHOD NAME : chmod
906     //  METHOD TYPE : int
907     //
908     int chmod( const Pathname & path, mode_t mode )
909     {
910       MIL << "chmod " << path << ' ' << str::octstring( mode );
911       if ( ::chmod( path.asString().c_str(), mode ) == -1 ) {
912         return _Log_Result( errno );
913       }
914       return _Log_Result( 0 );
915     }
916
917     ///////////////////////////////////////////////////////////////////
918     //
919     //  METHOD NAME : zipType
920     //  METHOD TYPE : ZIP_TYPE
921     //
922     ZIP_TYPE zipType( const Pathname & file )
923     {
924       ZIP_TYPE ret = ZT_NONE;
925
926       int fd = open( file.asString().c_str(), O_RDONLY );
927
928       if ( fd != -1 ) {
929         const int magicSize = 3;
930         unsigned char magic[magicSize];
931         memset( magic, 0, magicSize );
932         if ( read( fd, magic, magicSize ) == magicSize ) {
933           if ( magic[0] == 0037 && magic[1] == 0213 ) {
934             ret = ZT_GZ;
935           } else if ( magic[0] == 'B' && magic[1] == 'Z' && magic[2] == 'h' ) {
936             ret = ZT_BZ2;
937           }
938         }
939         close( fd );
940       }
941
942       return ret;
943     }
944
945     ///////////////////////////////////////////////////////////////////
946     //
947     //  METHOD NAME : df
948     //  METHOD TYPE : ByteCount
949     //
950     ByteCount df( const Pathname & path_r )
951     {
952       ByteCount ret( -1 );
953       struct statvfs sb;
954       if ( statvfs( path_r.c_str(), &sb ) == 0 )
955         {
956           ret = sb.f_bfree * sb.f_bsize;
957         }
958       return ret;
959     }
960
961     ///////////////////////////////////////////////////////////////////
962     //
963     //  METHOD NAME : getUmask
964     //  METHOD TYPE : mode_t
965     //
966     mode_t getUmask()
967     {
968       mode_t mask = ::umask( 0022 );
969       ::umask( mask );
970       return mask;
971     }
972
973     ///////////////////////////////////////////////////////////////////
974     //
975     //  METHOD NAME : touch
976     //  METHOD TYPE : int
977     //
978     int touch (const Pathname & path)
979     {
980       MIL << "touch " << path;
981       struct ::utimbuf times;
982       times.actime = ::time( 0 );
983       times.modtime = ::time( 0 );
984       if ( ::utime( path.asString().c_str(), &times ) == -1 ) {
985         return _Log_Result( errno );
986       }
987       return _Log_Result( 0 );
988     }
989
990     /////////////////////////////////////////////////////////////////
991   } // namespace filesystem
992   ///////////////////////////////////////////////////////////////////
993   /////////////////////////////////////////////////////////////////
994 } // namespace zypp
995 ///////////////////////////////////////////////////////////////////