fixup Fix to build with libxml 2.12.x (fixes #505)
[platform/upstream/libzypp.git] / zypp / RepoStatus.cc
1 /*---------------------------------------------------------------------\
2 |                          ____ _   __ __ ___                          |
3 |                         |__  / \ / / . \ . \                         |
4 |                           / / \ V /|  _/  _/                         |
5 |                          / /__ | | | | | |                           |
6 |                         /_____||_| |_| |_|                           |
7 |                                                                      |
8 \---------------------------------------------------------------------*/
9 /** \file       zypp/RepoStatus.cc
10  *
11 */
12 #include <iostream>
13 #include <sstream>
14 #include <fstream>
15 #include "zypp/base/Logger.h"
16 #include "zypp/base/String.h"
17 #include "zypp/RepoStatus.h"
18 #include "zypp/PathInfo.h"
19
20 using namespace std;
21
22 ///////////////////////////////////////////////////////////////////
23 namespace zypp
24 { /////////////////////////////////////////////////////////////////
25
26   ///////////////////////////////////////////////////////////////////
27   //
28   //    CLASS NAME : RepoStatus::Impl
29   //
30   /** RepoStatus implementation. */
31   struct RepoStatus::Impl
32   {
33   public:
34     string _checksum;
35     Date _timestamp;
36
37     /** Recursive computation of max dir timestamp. */
38     static void recursive_timestamp( const Pathname & dir_r, time_t & max_r )
39     {
40       std::list<std::string> dircontent;
41       if ( filesystem::readdir( dircontent, dir_r, false/*no dots*/ ) != 0 )
42         return; // readdir logged the error
43
44       for_( it, dircontent.begin(), dircontent.end() )
45       {
46         PathInfo pi( dir_r + *it, PathInfo::LSTAT );
47         if ( pi.isDir() )
48         {
49           if ( pi.mtime() > max_r )
50             max_r = pi.mtime();
51           recursive_timestamp( pi.path(), max_r );
52         }
53       }
54     }
55
56   private:
57     friend Impl * rwcowClone<Impl>( const Impl * rhs );
58     /** clone for RWCOW_pointer */
59     Impl * clone() const
60     { return new Impl( *this ); }
61   };
62   ///////////////////////////////////////////////////////////////////
63
64   /** \relates RepoStatus::Impl Stream output */
65   inline std::ostream & operator<<( std::ostream & str, const RepoStatus::Impl & obj )
66   { return str << obj._checksum << " " << (time_t)obj._timestamp; }
67
68   ///////////////////////////////////////////////////////////////////
69   //
70   //    CLASS NAME : RepoStatus
71   //
72   ///////////////////////////////////////////////////////////////////
73
74   RepoStatus::RepoStatus()
75     : _pimpl( new Impl() )
76   {}
77
78   RepoStatus::RepoStatus( const Pathname & path_r )
79     : _pimpl( new Impl() )
80   {
81     PathInfo info( path_r );
82     if ( info.isExist() )
83     {
84       if ( info.isFile() )
85       {
86         _pimpl->_timestamp = Date( info.mtime() );
87         _pimpl->_checksum = filesystem::sha1sum( path_r );
88       }
89       else if ( info.isDir() )
90       {
91         time_t t = info.mtime();
92         Impl::recursive_timestamp( path_r, t );
93         _pimpl->_timestamp = Date(t);
94         _pimpl->_checksum = CheckSum::sha1FromString( str::numstring( t ) ).checksum();
95       }
96
97       // NOTE: changing magic will once invalidate all solv file caches
98       // Helpfull if solv file content must be refreshed (e.g. due to different
99       // repo2* arguments) even if raw metadata are unchanged.
100       static const std::string magic( "43" );
101       _pimpl->_checksum += magic;
102     }
103   }
104
105   RepoStatus::~RepoStatus()
106   {}
107
108   RepoStatus RepoStatus::fromCookieFile( const Pathname & path_r )
109   {
110     RepoStatus ret;
111     std::ifstream file( path_r.c_str() );
112     if ( !file )
113     {
114       WAR << "No cookie file " << path_r << endl;
115     }
116     else
117     {
118       // line := "[checksum] time_t"
119       std::string line( str::getline( file ) );
120       ret._pimpl->_timestamp = Date( str::strtonum<time_t>( str::stripLastWord( line ) ) );
121       ret._pimpl->_checksum = line;
122     }
123     return ret;
124   }
125
126   void RepoStatus::saveToCookieFile( const Pathname & path_r ) const
127   {
128     std::ofstream file(path_r.c_str());
129     if (!file) {
130       ZYPP_THROW (Exception( "Can't open " + path_r.asString() ) );
131     }
132     file << _pimpl->_checksum << " " << (time_t)_pimpl->_timestamp << endl;
133     file.close();
134   }
135
136   bool RepoStatus::empty() const
137   { return _pimpl->_checksum.empty(); }
138
139   Date RepoStatus::timestamp() const
140   { return _pimpl->_timestamp; }
141
142   std::ostream & operator<<( std::ostream & str, const RepoStatus & obj )
143   { return str << *obj._pimpl; }
144
145   RepoStatus operator&&( const RepoStatus & lhs, const RepoStatus & rhs )
146   {
147     RepoStatus result;
148
149     if ( lhs.empty() )
150       result = rhs;
151     else if ( rhs.empty() )
152       result = lhs;
153     else
154     {
155       // order strings to assert && is kommutativ
156       std::string lchk( lhs._pimpl->_checksum );
157       std::string rchk( rhs._pimpl->_checksum );
158       stringstream ss( lchk < rchk ? lchk+rchk : rchk+lchk );
159
160       result._pimpl->_checksum = CheckSum::sha1(ss).checksum();
161       result._pimpl->_timestamp = std::max( lhs._pimpl->_timestamp, rhs._pimpl->_timestamp );
162     }
163     return result;
164   }
165
166   bool operator==( const RepoStatus & lhs, const RepoStatus & rhs )
167   { return lhs._pimpl->_checksum == rhs._pimpl->_checksum; }
168
169   /////////////////////////////////////////////////////////////////
170 } // namespace zypp
171 ///////////////////////////////////////////////////////////////////