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  */