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 std::endl;
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     std::string _checksum;
35     Date _timestamp;
36
37     // NOTE: Changing magic will at once invalidate all solv file caches.
38     // Helpfull if solv file content must be refreshed (e.g. due to different
39     // repo2* arguments) even if raw metadata are unchanged.
40     // Only values set from a RepoStatus ctor need magic to be added.
41     void assignFromCtor( std::string && checksum_r, Date && timestamp_r )
42     {
43       _checksum = std::move(checksum_r);
44       _timestamp = std::move(timestamp_r);
45       if ( !_checksum.empty() )
46       {
47         static const std::string magic( "43" );
48         _checksum += magic;
49       }
50     }
51
52     /** Recursive computation of max dir timestamp. */
53     static void recursive_timestamp( const Pathname & dir_r, time_t & max_r )
54     {
55       std::list<std::string> dircontent;
56       if ( filesystem::readdir( dircontent, dir_r, false/*no dots*/ ) != 0 )
57         return; // readdir logged the error
58
59       for_( it, dircontent.begin(), dircontent.end() )
60       {
61         PathInfo pi( dir_r + *it, PathInfo::LSTAT );
62         if ( pi.isDir() )
63         {
64           if ( pi.mtime() > max_r )
65             max_r = pi.mtime();
66           recursive_timestamp( pi.path(), max_r );
67         }
68       }
69     }
70
71   private:
72     friend Impl * rwcowClone<Impl>( const Impl * rhs );
73     /** clone for RWCOW_pointer */
74     Impl * clone() const
75     { return new Impl( *this ); }
76   };
77   ///////////////////////////////////////////////////////////////////
78
79   /** \relates RepoStatus::Impl Stream output */
80   inline std::ostream & operator<<( std::ostream & str, const RepoStatus::Impl & obj )
81   { return str << obj._checksum << " " << (time_t)obj._timestamp; }
82
83   ///////////////////////////////////////////////////////////////////
84   //
85   //    CLASS NAME : RepoStatus
86   //
87   ///////////////////////////////////////////////////////////////////
88
89   RepoStatus::RepoStatus()
90     : _pimpl( new Impl() )
91   {}
92
93   RepoStatus::RepoStatus( const Pathname & path_r )
94     : _pimpl( new Impl() )
95   {
96     PathInfo info( path_r );
97     if ( info.isExist() )
98     {
99       if ( info.isFile() )
100       {
101         _pimpl->assignFromCtor( filesystem::sha1sum( path_r ), Date( info.mtime() ) );
102       }
103       else if ( info.isDir() )
104       {
105         time_t t = info.mtime();
106         Impl::recursive_timestamp( path_r, t );
107         _pimpl->assignFromCtor( CheckSum::sha1FromString( str::numstring( t ) ).checksum(), Date( t ) );
108       }
109     }
110   }
111
112   RepoStatus::RepoStatus( std::string checksum_r, Date timestamp_r )
113   : _pimpl( new Impl() )
114   {
115     _pimpl->assignFromCtor( std::move(checksum_r), std::move(timestamp_r) );
116   }
117
118   RepoStatus::~RepoStatus()
119   {}
120
121   RepoStatus RepoStatus::fromCookieFile( const Pathname & path_r )
122   {
123     RepoStatus ret;
124     std::ifstream file( path_r.c_str() );
125     if ( !file )
126     {
127       WAR << "No cookie file " << path_r << endl;
128     }
129     else
130     {
131       // line := "[checksum] time_t"
132       std::string line( str::getline( file ) );
133       ret._pimpl->_timestamp = Date( str::strtonum<time_t>( str::stripLastWord( line ) ) );
134       ret._pimpl->_checksum = line;
135     }
136     return ret;
137   }
138
139   void RepoStatus::saveToCookieFile( const Pathname & path_r ) const
140   {
141     std::ofstream file(path_r.c_str());
142     if (!file) {
143       ZYPP_THROW (Exception( "Can't open " + path_r.asString() ) );
144     }
145     file << _pimpl->_checksum << " " << (time_t)_pimpl->_timestamp << endl;
146     file.close();
147   }
148
149   bool RepoStatus::empty() const
150   { return _pimpl->_checksum.empty(); }
151
152   Date RepoStatus::timestamp() const
153   { return _pimpl->_timestamp; }
154
155   std::ostream & operator<<( std::ostream & str, const RepoStatus & obj )
156   { return str << *obj._pimpl; }
157
158   RepoStatus operator&&( const RepoStatus & lhs, const RepoStatus & rhs )
159   {
160     RepoStatus result;
161
162     if ( lhs.empty() )
163       result = rhs;
164     else if ( rhs.empty() )
165       result = lhs;
166     else
167     {
168       // order strings to assert && is kommutativ
169       std::string lchk( lhs._pimpl->_checksum );
170       std::string rchk( rhs._pimpl->_checksum );
171       std::stringstream ss( lchk < rchk ? lchk+rchk : rchk+lchk );
172
173       result._pimpl->_checksum = CheckSum::sha1(ss).checksum();
174       result._pimpl->_timestamp = std::max( lhs._pimpl->_timestamp, rhs._pimpl->_timestamp );
175     }
176     return result;
177   }
178
179   bool operator==( const RepoStatus & lhs, const RepoStatus & rhs )
180   { return lhs._pimpl->_checksum == rhs._pimpl->_checksum; }
181
182   /////////////////////////////////////////////////////////////////
183 } // namespace zypp
184 ///////////////////////////////////////////////////////////////////