libzypp: zypp-core/Pathname.cc Source File

libzypp 17.38.9

Pathname.cc
Go to the documentation of this file.
1/*---------------------------------------------------------------------\
2 | ____ _ __ __ ___ |
3 | |__ / \ / / . \ . \ |
4 | / / \ V /| _/ _/ |
5 | / /__ | | | | | | |
6 | /_____||_| |_| |_| |
7 | |
8 \---------------------------------------------------------------------*/
12#include <iostream>
13#include <climits>
14
15#include <zypp-core/base/String.h>
16#include <zypp-core/Pathname.h>
17#include <zypp-core/Url.h>
18
19using std::string;
20
22namespace zypp
23{
25 namespace filesystem
26 {
27
29 //
30 // METHOD NAME : Pathname::_assign
31 // METHOD TYPE : void
32 //
33 void Pathname::_assign( const string & name_r )
34 {
35 _name.clear();
36 if ( name_r.empty() )
37 return;
38 _name.reserve( name_r.size() );
39
40 // Collect up to "/.."
41 enum Pending {
42 P_none = 0, // ""
43 P_slash = 1, // "/"
44 P_dot1 = 2, // "/."
45 P_dot2 = 3 // "/.."
46 } pending = P_none;
47
48 // Assert relative path starting with "./"
49 // We rely on this below!
50 if ( name_r[0] != '/' )
51 {
52 _name += '.';
53 pending = P_slash;
54 }
55
56 // Lambda handling the "/.." case:
57 // [] + "/.." ==> []
58 // [.] + "/.." ==> [./..]
59 // [foo] is always [./foo] due to init above
60 // [*/..] + "/.." ==> [*/../..]
61 // [*/foo] + "/.." ==> [*]
62 auto goParent_f = [&](){
63 if ( _name.empty() )
64 /*NOOP*/;
65 else if ( _name.size() == 1 ) // content is '.'
66 _name += "/..";
67 else
68 {
69 std::string::size_type pos = _name.rfind( '/' );
70 if ( pos == _name.size() - 3 && _name[pos+1] == '.' && _name[pos+2] == '.' )
71 _name += "/..";
72 else
73 _name.erase( pos );
74 }
75 };
76
77 for ( char ch : name_r )
78 {
79 switch ( ch )
80 {
81 case '/':
82 switch ( pending )
83 {
84 case P_none: pending = P_slash; break;
85 case P_slash: break;
86 case P_dot1: pending = P_slash; break;
87 case P_dot2: goParent_f(); pending = P_slash; break;
88 }
89 break;
90
91 case '.':
92 switch ( pending )
93 {
94 case P_none: _name += '.'; break;
95 case P_slash: pending = P_dot1; break;
96 case P_dot1: pending = P_dot2; break;
97 case P_dot2: _name += "/..."; pending = P_none; break;
98 }
99 break;
100
101 default:
102 switch ( pending )
103 {
104 case P_none: break;
105 case P_slash: _name += '/'; pending = P_none; break;
106 case P_dot1: _name += "/."; pending = P_none; break;
107 case P_dot2: _name += "/.."; pending = P_none; break;
108 }
109 _name += ch;
110 break;
111 }
112 }
113
114 switch ( pending )
115 {
116 case P_none: break;
117 case P_slash: if ( _name.empty() ) _name = "/"; break;
118 case P_dot1: if ( _name.empty() ) _name = "/"; break;
119 case P_dot2: goParent_f(); if ( _name.empty() ) _name = "/"; break;
120 }
121 return;
122 }
123
125 //
126 // METHOD NAME : Pathname::dirname
127 // METHOD TYPE : Pathname
128 //
129 Pathname Pathname::dirname( const Pathname & name_r )
130 {
131 if ( name_r.empty() )
132 return Pathname();
133
134 Pathname ret_t( name_r );
135 std::string::size_type idx = ret_t._name.find_last_of( '/' );
136
137 if ( idx == std::string::npos ) {
138 ret_t._name = ".";
139 } else if ( idx == 0 ) {
140 ret_t._name = "/";
141 } else {
142 ret_t._name.erase( idx );
143 }
144
145 return ret_t;
146 }
147
149 //
150 // METHOD NAME : Pathname::basename
151 // METHOD TYPE : string
152 //
153 string Pathname::basename( const Pathname & name_r )
154 {
155 if ( name_r.empty() )
156 return string();
157
158 string ret_t( name_r.asString() );
159 std::string::size_type idx = ret_t.find_last_of( '/' );
160 if ( idx != std::string::npos && ( idx != 0 || ret_t.size() != 1 ) ) {
161 ret_t.erase( 0, idx+1 );
162 }
163
164 return ret_t;
165 }
166
168 //
169 // METHOD NAME : Pathname::asUrl
170 // METHOD TYPE : Url
171 //
172 Url Pathname::asUrl( const std::string & scheme_r ) const
173 {
174 Url ret;
175 ret.setPathName( asString() );
176 ret.setScheme( scheme_r );
177 return ret;
178 }
179
180 Url Pathname::asUrl() const
181 { return asUrl( "dir" ); }
182
183 Url Pathname::asDirUrl() const
184 { return asUrl( "dir" ); }
185
186 Url Pathname::asFileUrl() const
187 { return asUrl( "file" ); }
188
189
190 std::string Pathname::showRoot( const Pathname & root_r, const Pathname & path_r )
191 {
192 return str::Str() << "(" << root_r << ")" << path_r;
193 }
194
195 std::string Pathname::showRootIf( const Pathname & root_r, const Pathname & path_r )
196 {
197 if ( root_r.empty() || root_r == "/" )
198 return path_r.asString();
199 return showRoot( root_r, path_r );
200 }
201
203 //
204 // METHOD NAME : Pathname::extension
205 // METHOD TYPE : string
206 //
207 string Pathname::extension( const Pathname & name_r )
208 {
209 if ( name_r.empty() )
210 return string();
211
212 string base( basename( name_r ) );
213 std::string::size_type pos = base.rfind( '.' );
214 switch ( pos )
215 {
216 case 0:
217 if ( base.size() == 1 ) // .
218 return string();
219 break;
220 case 1:
221 if ( base.size() == 2 && base[0] == '.' ) // ..
222 return string();
223 break;
224 case std::string::npos:
225 return string();
226 break;
227 }
228 return base.substr( pos );
229 }
230
231 Pathname Pathname::realpath() const
232 {
233 std::string real;
234 if( !empty())
235 {
236 #if __GNUC__ > 2
238 char *ptr = ::realpath(_name.c_str(), NULL);
239 if( ptr != NULL)
240 {
241 real = ptr;
242 free( ptr);
243 }
244 else
246 if( EINVAL == errno)
247 {
248 char buff[PATH_MAX + 2];
249 memset(buff, '\0', sizeof(buff));
250 if( ::realpath(_name.c_str(), buff) != NULL)
251 {
252 real = buff;
253 }
254 }
255 #else
256 char buff[PATH_MAX + 2];
257 memset(buff, '\0', sizeof(buff));
258 if( ::realpath(_name.c_str(), buff) != NULL)
259 {
260 real = buff;
261 }
262 #endif
263 }
264 return zypp::Pathname(real);
265 }
266
268 //
269 // METHOD NAME : Pathname::assertprefix
270 // METHOD TYPE : Pathname
271 //
272 Pathname Pathname::assertprefix( const Pathname & root_r, const Pathname & path_r )
273 {
274 if ( root_r.empty() || root_r == path_r )
275 return path_r;
276
277 if ( str::hasPrefix( path_r.asString(), root_r.asString() ) && path_r.asString()[root_r.asString().size()] == '/' ) {
278 // NOTE: Pathological is root_r being "." (opt. followed by a sequence of "/.."):
279 // Pathname is normalized and does not contain any embedded "..". If root_r is ".(/..)*',
280 // then path_r could continue with a '..' and this way would escape root_r.
281 if ( root_r.absolute() || root_r.asString().find_first_not_of( "./" ) != std::string::npos )
282 return path_r;
283
284 const std::string & pathbegin = path_r.asString().substr( root_r.asString().size()+1, 3 );
285 if ( pathbegin[0] != '.' || pathbegin[1] != '.' || ( pathbegin[2] != '\0' && pathbegin[2] != '/' ) )
286 return path_r;
287 }
288
289 // Treat path_r as if it was in "/", then prefix root_r
290 return root_r / absolutename(path_r);
291 }
292
293 Pathname Pathname::stripprefix( const Pathname & root_r, const Pathname & path_r )
294 {
295 if ( root_r.emptyOrRoot() )
296 return path_r;
297 if ( root_r == path_r )
298 return "/";
299 std::string rest( str::stripPrefix( path_r.asString(), root_r.asString() ) );
300 if ( rest[0] == '/' ) // needs to be a dir prefix!
301 return rest;
302 return path_r;
303 }
304
306 //
307 // METHOD NAME : Pathname::cat
308 // METHOD TYPE : Pathname
309 //
310 Pathname Pathname::cat( const Pathname & name_r, const Pathname & add_tv )
311 {
312 if ( add_tv.empty() )
313 return name_r;
314 if ( name_r.empty() )
315 return add_tv;
316
317 string ret_ti( name_r._name );
318 if( add_tv._name[0] != '/' )
319 ret_ti += '/';
320 return ret_ti + add_tv._name;
321 }
322
324 //
325 // METHOD NAME : Pathname::Extend
326 // METHOD TYPE : Pathname
327 //
328 Pathname Pathname::extend( const Pathname & l, const string & r )
329 {
330 return l.asString() + r;
331 }
332
334 } // namespace filesystem
337} // namespace zypp
Pathname.h
String.h
Url.h
zypp::Url
Url manipulation class.
Definition Url.h:93
zypp::Url::setPathName
void setPathName(const std::string &path, EEncoding eflag=zypp::url::E_DECODED)
Set the path name.
Definition Url.cc:791
zypp::Url::setScheme
void setScheme(const std::string &scheme)
Set the scheme name in the URL.
Definition Url.cc:695
zypp::filesystem::Pathname
Pathname.
Definition Pathname.h:48
zypp::filesystem::Pathname::showRoot
static std::string showRoot(const Pathname &root_r, const Pathname &path_r)
String representation as "(root)/path".
Definition Pathname.cc:190
zypp::filesystem::Pathname::extend
Pathname extend(const std::string &r) const
Append string r to the last component of the path.
Definition Pathname.h:192
zypp::filesystem::Pathname::stripprefix
static Pathname stripprefix(const Pathname &root_r, const Pathname &path_r)
Return path_r with any root_r dir prefix striped.
Definition Pathname.cc:293
zypp::filesystem::Pathname::dirname
Pathname dirname() const
Return all but the last component od this path.
Definition Pathname.h:133
zypp::filesystem::Pathname::emptyOrRoot
bool emptyOrRoot() const
Test for "" or "/".
Definition Pathname.h:127
zypp::filesystem::Pathname::absolute
bool absolute() const
Test for an absolute path.
Definition Pathname.h:119
zypp::filesystem::Pathname::asDirUrl
Url asDirUrl() const
Definition Pathname.cc:183
zypp::filesystem::Pathname::cat
Pathname cat(const Pathname &r) const
Concatenation of pathnames.
Definition Pathname.h:184
zypp::filesystem::Pathname::asFileUrl
Url asFileUrl() const
Definition Pathname.cc:186
zypp::filesystem::Pathname::Pathname
Pathname()
Default ctor: an empty path.
Definition Pathname.h:51
zypp::filesystem::Pathname::asString
const std::string & asString() const
String representation.
Definition Pathname.h:94
zypp::filesystem::Pathname::basename
std::string basename() const
Return the last component of this path.
Definition Pathname.h:137
zypp::filesystem::Pathname::empty
bool empty() const
Test for an empty path.
Definition Pathname.h:117
zypp::filesystem::Pathname::assertprefix
static Pathname assertprefix(const Pathname &root_r, const Pathname &path_r)
Unless path_r does not already denote a path below root_r, combine them.
Definition Pathname.cc:272
zypp::filesystem::Pathname::_assign
void _assign(const std::string &name_r)
Definition Pathname.cc:33
zypp::filesystem::Pathname::realpath
Pathname realpath() const
Returns this path as the absolute canonical pathname.
Definition Pathname.cc:231
zypp::filesystem::Pathname::absolutename
Pathname absolutename() const
Return this path, adding a leading '/' if relative.
Definition Pathname.h:148
zypp::filesystem::Pathname::showRootIf
static std::string showRootIf(const Pathname &root_r, const Pathname &path_r)
String representation as "(root)/path", unless root is "/" or empty.
Definition Pathname.cc:195
zypp::filesystem::Pathname::asUrl
Url asUrl() const
Definition Pathname.cc:180
zypp::filesystem::Pathname::extension
std::string extension() const
Return all of the characters in name after and including the last dot in the last element of name.
Definition Pathname.h:144
zypp::filesystem::Pathname::_name
std::string _name
Definition Pathname.h:196
zypp::base
Definition Random.cc:7
zypp::filesystem
Types and functions for filesystem operations.
Definition Glob.cc:24
zypp::str::hasPrefix
bool hasPrefix(const C_Str &str_r, const C_Str &prefix_r)
Return whether str_r has prefix prefix_r.
Definition String.h:1097
zypp::str::stripPrefix
std::string stripPrefix(const C_Str &str_r, const C_Str &prefix_r)
Strip a prefix_r from str_r and return the resulting string.
Definition String.h:1104
zypp
Easy-to use interface to the ZYPP dependency resolver.
Definition CodePitfalls.doc:2
zypp::str::Str
Convenient building of std::string via std::ostringstream Basically a std::ostringstream autoconverti...
Definition String.h:213