File indexing completed on 2024-06-02 04:44:36
0001 /* 0002 * ==================================================================== 0003 * Copyright (c) 2002-2009 The RapidSvn Group. All rights reserved. 0004 * 0005 * This program is free software: you can redistribute it and/or modify 0006 * it under the terms of the GNU General Public License as published by 0007 * the Free Software Foundation, either version 3 of the License, or 0008 * (at your option) any later version. 0009 * 0010 * This program is distributed in the hope that it will be useful, 0011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 0012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 0013 * GNU General Public License for more details. 0014 * 0015 * You should have received a copy of the GNU General Public License 0016 * along with this program (in the file GPL.txt. 0017 * If not, see <http://www.gnu.org/licenses/>. 0018 * 0019 * This software consists of voluntary contributions made by many 0020 * individuals. For exact contribution history, see the revision 0021 * history and logs, available at http://rapidsvn.tigris.org/. 0022 * ==================================================================== 0023 */ 0024 0025 // subversion api 0026 #include "svn_path.h" 0027 #include "svn_dirent_uri.h" 0028 0029 // apr api 0030 #include "apr_file_io.h" 0031 0032 // svncpp 0033 #include "kdevsvncpp/path.hpp" 0034 #include "kdevsvncpp/pool.hpp" 0035 #include "kdevsvncpp/url.hpp" 0036 0037 namespace svn 0038 { 0039 const PathVector EmptyPathVector; 0040 0041 Path::Path(const char * path) 0042 { 0043 init(path); 0044 } 0045 0046 Path::Path(const std::string & path) 0047 { 0048 init(path.c_str()); 0049 } 0050 0051 Path::Path(const Path & path) 0052 { 0053 init(path.c_str()); 0054 } 0055 0056 void 0057 Path::init(const char * path) 0058 { 0059 Pool pool; 0060 0061 m_pathIsUrl = false; 0062 0063 if (path == nullptr) 0064 m_path = ""; 0065 else 0066 { 0067 const char * int_path = svn_dirent_canonicalize(path, pool); 0068 0069 m_path = int_path; 0070 0071 if (svn::Url::isValid(int_path)) 0072 m_pathIsUrl = true; 0073 } 0074 } 0075 0076 const std::string & 0077 Path::path() const 0078 { 0079 return m_path; 0080 } 0081 0082 const char * 0083 Path::c_str() const 0084 { 0085 return m_path.c_str(); 0086 } 0087 0088 Path& 0089 Path::operator= (const Path & path) 0090 { 0091 if (this == &path) 0092 return *this; 0093 0094 init(path.c_str()); 0095 0096 return *this; 0097 } 0098 0099 bool 0100 Path::operator== (const Path& path) const 0101 { 0102 if (path.path() == this->path()) 0103 return true; 0104 0105 return false; 0106 } 0107 0108 bool 0109 Path::isSet() const 0110 { 0111 return m_path.length() > 0; 0112 } 0113 0114 bool 0115 Path::isUrl() const 0116 { 0117 return m_pathIsUrl; 0118 } 0119 0120 static bool 0121 isAbsolute(const char * path) 0122 { 0123 if (nullptr == path) 0124 return false; 0125 0126 std::string p(path); 0127 0128 if (0 == p.length()) 0129 return false; 0130 0131 // a path that begins with "/" is absolute 0132 if ('/' == p [0]) 0133 return true; 0134 0135 // a path with a ":" like "http://xxx" or 0136 // "c:/foo" is absolute too 0137 if (p.find(":", 0) != std::string::npos) 0138 return true; 0139 0140 // Well it's relative 0141 return false; 0142 } 0143 0144 void 0145 Path::addComponent(const char * component) 0146 { 0147 Pool pool; 0148 0149 if (nullptr == component) 0150 return; 0151 0152 // in case of an empty string, return 0153 if (*component == 0) 0154 return; 0155 0156 // if the @a component is absolute, simply 0157 // use it 0158 if (isAbsolute(component)) 0159 { 0160 m_path = component; 0161 return; 0162 } 0163 0164 if (Url::isValid(m_path.c_str())) 0165 { 0166 const char * newPath = 0167 svn_path_url_add_component(m_path.c_str(), 0168 component, 0169 pool); 0170 m_path = newPath; 0171 } 0172 else 0173 { 0174 svn_stringbuf_t * pathStringbuf = 0175 svn_stringbuf_create(m_path.c_str(), pool); 0176 0177 svn_path_add_component(pathStringbuf, 0178 component); 0179 0180 m_path = pathStringbuf->data; 0181 } 0182 } 0183 0184 void 0185 Path::addComponent(const std::string & component) 0186 { 0187 addComponent(component.c_str()); 0188 } 0189 0190 void 0191 Path::split(std::string & dirpath, std::string & basename) const 0192 { 0193 Pool pool; 0194 0195 const char * cdirpath; 0196 const char * cbasename; 0197 0198 svn_path_split(m_path.c_str(), &cdirpath, &cbasename, pool); 0199 0200 dirpath = cdirpath; 0201 basename = cbasename; 0202 } 0203 0204 void 0205 Path::split(std::string & dir, std::string & filename, std::string & ext) const 0206 { 0207 std::string basename; 0208 0209 // first split path into dir and filename+ext 0210 split(dir, basename); 0211 0212 // next search for last . 0213 size_t pos = basename.find_last_of("."); 0214 if (pos == std::string::npos) 0215 { 0216 filename = basename; 0217 ext = ""; 0218 } 0219 else 0220 { 0221 filename = basename.substr(0, pos); 0222 ext = basename.substr(pos); 0223 } 0224 } 0225 0226 std::string 0227 Path::basename() const 0228 { 0229 std::string dir; 0230 std::string filename; 0231 0232 split(dir, filename); 0233 0234 return filename; 0235 } 0236 0237 std::string 0238 Path::dirpath() const 0239 { 0240 std::string dir; 0241 std::string filename; 0242 0243 split(dir, filename); 0244 0245 return dir; 0246 } 0247 0248 std::string 0249 Path::substr(const size_t count) const 0250 { 0251 if (m_path.length() > count) 0252 return m_path.substr(count); 0253 else 0254 return ""; 0255 } 0256 0257 std::string 0258 Path::unescape() const 0259 { 0260 return svn::Url::unescape(m_path.c_str()); 0261 } 0262 0263 0264 /* =================================================================== 0265 * The next two Fixed_* functions are copies of the APR 0266 * apr_temp_dir_get functionality with a fix applied. 0267 * This should turn up in APR release 0.9.5 or 1.0, but 0268 * for now is reproduced here. 0269 * 0270 * TODO: Remove this section! 0271 */ 0272 #include "apr_env.h" 0273 0274 #define test_tempdir Fixed_test_tempdir 0275 #define apr_temp_dir_get Fixed_apr_temp_dir_get 0276 0277 static char global_temp_dir[APR_PATH_MAX+1] = { 0 }; 0278 0279 /* Try to open a temporary file in the temporary dir, write to it, 0280 and then close it. */ 0281 static int Fixed_test_tempdir(const char *temp_dir, apr_pool_t *p) 0282 { 0283 apr_file_t *dummy_file; 0284 // This is the only actual fix - adding the ".XXXXXX"! 0285 const char *path = apr_pstrcat(p, temp_dir, "/apr-tmp.XXXXXX", NULL); 0286 0287 if (apr_file_mktemp(&dummy_file, (char *)path, 0, p) == APR_SUCCESS) { 0288 if (apr_file_putc('!', dummy_file) == APR_SUCCESS) { 0289 if (apr_file_close(dummy_file) == APR_SUCCESS) { 0290 apr_file_remove(path, p); 0291 return 1; 0292 } 0293 } 0294 } 0295 return 0; 0296 } 0297 0298 static apr_status_t Fixed_apr_temp_dir_get(const char **temp_dir, apr_pool_t *p) 0299 { 0300 apr_status_t apr_err; 0301 const char *try_dirs[] = { "/tmp", "/usr/tmp", "/var/tmp" }; 0302 const char *try_envs[] = { "TMP", "TEMP", "TMPDIR" }; 0303 char *cwd; 0304 size_t i; 0305 0306 /* Our goal is to find a temporary directory suitable for writing 0307 into. We'll only pay the price once if we're successful -- we 0308 cache our successful find. Here's the order in which we'll try 0309 various paths: 0310 0311 $TMP 0312 $TEMP 0313 $TMPDIR 0314 "/tmp" 0315 "/var/tmp" 0316 "/usr/tmp" 0317 `pwd` 0318 0319 NOTE: This algorithm is basically the same one used by Python 0320 2.2's tempfile.py module. */ 0321 0322 /* Try the environment first. */ 0323 for (i = 0; i < (sizeof(try_envs) / sizeof(const char *)); i++) { 0324 char *value; 0325 apr_err = apr_env_get(&value, try_envs[i], p); 0326 if ((apr_err == APR_SUCCESS) && value) { 0327 apr_size_t len = strlen(value); 0328 if (len && (len < APR_PATH_MAX) && test_tempdir(value, p)) { 0329 memcpy(global_temp_dir, value, len + 1); 0330 goto end; 0331 } 0332 } 0333 } 0334 0335 /* Next, try a set of hard-coded paths. */ 0336 for (i = 0; i < (sizeof(try_dirs) / sizeof(const char *)); i++) { 0337 if (test_tempdir(try_dirs[i], p)) { 0338 memcpy(global_temp_dir, try_dirs[i], strlen(try_dirs[i]) + 1); 0339 goto end; 0340 } 0341 } 0342 0343 /* Finally, try the current working directory. */ 0344 if (APR_SUCCESS == apr_filepath_get(&cwd, APR_FILEPATH_NATIVE, p)) { 0345 if (test_tempdir(cwd, p)) { 0346 memcpy(global_temp_dir, cwd, strlen(cwd) + 1); 0347 goto end; 0348 } 0349 } 0350 0351 end: 0352 if (global_temp_dir[0]) { 0353 *temp_dir = apr_pstrdup(p, global_temp_dir); 0354 return APR_SUCCESS; 0355 } 0356 return APR_EGENERAL; 0357 } 0358 /* =================================================================== 0359 * End of inserted fixed APR code 0360 */ 0361 0362 Path 0363 Path::getTempDir() 0364 { 0365 const char * tempdir = nullptr; 0366 Pool pool; 0367 0368 if (apr_temp_dir_get(&tempdir, pool) != APR_SUCCESS) 0369 { 0370 tempdir = nullptr; 0371 } 0372 0373 return tempdir; 0374 } 0375 0376 size_t 0377 Path::length() const 0378 { 0379 return m_path.length(); 0380 } 0381 0382 std::string 0383 Path::native() const 0384 { 0385 if (m_pathIsUrl) 0386 { 0387 // this converts something like 0388 // http://foo/my%20location 0389 // to 0390 // http://foo/my location 0391 return Url::unescape(m_path.c_str()); 0392 } 0393 else 0394 { 0395 // On Windows, p://foo/bar will be converted to p:\foo\bar 0396 Pool pool; 0397 return svn_path_local_style(m_path.c_str(), pool); 0398 } 0399 } 0400 } 0401 0402 /* ----------------------------------------------------------------- 0403 * local variables: 0404 * eval: (load-file "../../rapidsvn-dev.el") 0405 * end: 0406 */