LCOV - code coverage report
Current view: top level - src - filepath.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 78 78 100.0 %
Date: 2015-05-05 Functions: 26 26 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :   Zipios++ - a small C++ library that provides easy access to .zip files.
       3             : 
       4             :   Copyright (C) 2000-2007  Thomas Sondergaard
       5             :   Copyright (C) 2015  Made to Order Software Corporation
       6             : 
       7             :   This library is free software; you can redistribute it and/or
       8             :   modify it under the terms of the GNU Lesser General Public
       9             :   License as published by the Free Software Foundation; either
      10             :   version 2 of the License, or (at your option) any later version.
      11             : 
      12             :   This library is distributed in the hope that it will be useful,
      13             :   but WITHOUT ANY WARRANTY; without even the implied warranty of
      14             :   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      15             :   Lesser General Public License for more details.
      16             : 
      17             :   You should have received a copy of the GNU Lesser General Public
      18             :   License along with this library; if not, write to the Free Software
      19             :   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
      20             : */
      21             : 
      22             : /** \file
      23             :  * \brief Implementation of zipios::FilePath.
      24             :  *
      25             :  * This file includes the zipios::FilePath implementation which makes it
      26             :  * a little easier to handle the stat() system call on any file for any
      27             :  * system.
      28             :  */
      29             : 
      30             : #include "zipios/filepath.hpp"
      31             : 
      32             : #include "zipios_common.hpp"
      33             : 
      34             : #include <memory.h>
      35             : 
      36             : 
      37             : namespace zipios
      38             : {
      39             : 
      40             : 
      41             : namespace
      42             : {
      43             : 
      44             : 
      45             : /** \brief Prune the trailing separator if present.
      46             :  *
      47             :  * This function is used to ensure that the FilePath does NOT end
      48             :  * with a separator.
      49             :  *
      50             :  * \warning
      51             :  * At this time the path is not canonicalized properly. We expect \p path
      52             :  * to not include double separators one after another. However, passing
      53             :  * such a path to the FilePath will keep it as is.
      54             :  *
      55             :  * \param[in] path  The path to prune of one trailing separator.
      56             :  *
      57             :  * \return The path as is or without the last '/'.
      58             :  */
      59      634031 : std::string pruneTrailingSeparator(std::string path)
      60             : {
      61      634031 :     if(path.size() > 0)
      62             :     {
      63      396594 :         if(path[path.size() - 1] == g_separator)
      64             :         {
      65       16934 :             path.erase(path.size() - 1);
      66             :         }
      67             :     }
      68             : 
      69      634031 :     return path;
      70             : }
      71             : 
      72             : 
      73             : } // no name namespace
      74             : 
      75             : 
      76             : 
      77             : /** \class FilePath
      78             :  * \brief Handle a file path and name and its statistics.
      79             :  *
      80             :  * The FilePath class represents a path to a file or directory name.
      81             :  * FilePath has member functions to check if the file path is a valid
      82             :  * file system entity, and to check what kind of file system entity
      83             :  * it is, e.g. is it a file, a directory, a pipe, etc.
      84             :  *
      85             :  * It also knows of the last modification time and size of the file.
      86             :  *
      87             :  * \warning
      88             :  * The information about a file is cached so at the time it gets used
      89             :  * the file on disk may have changed, it may even have been deleted.
      90             :  */
      91             : 
      92             : 
      93             : /** \brief Initialize a FilePath object.
      94             :  *
      95             :  * The constructor saves the path and if \p check_exists is true, read
      96             :  * the file statistics, especially the st_mode.
      97             :  *
      98             :  * \param[in] path  A string representation of the path.
      99             :  *
     100             :  * \sa exists()
     101             :  * \sa pruneTrailingSeparator()
     102             :  */
     103      633588 : FilePath::FilePath(std::string const& path)
     104      633588 :     : m_path(pruneTrailingSeparator(path))
     105             :     //, m_stat() -- see below
     106             :     //, m_checked(false) -- auto-init
     107             :     //, m_exists(false) -- auto-init
     108             : {
     109      633588 :     memset(&m_stat, 0, sizeof(m_stat));
     110      633588 : }
     111             : 
     112             : 
     113             : /** \brief Read the file mode.
     114             :  *
     115             :  * This function sets m_checked to true, stat()'s the path, to see if
     116             :  * it exists and to determine what type of file it is. All the query
     117             :  * functions call check() before they test a flag to make sure it
     118             :  * is set appropriately.
     119             :  *
     120             :  * This means stat()'ing is deferred until it becomes necessary. But also
     121             :  * it is cached meaning that if the file changes in between we get the
     122             :  * old flags.
     123             :  */
     124     1220957 : void FilePath::check() const
     125             : {
     126     1220957 :     if(!m_checked)
     127             :     {
     128      140837 :         m_checked     = true;
     129             : 
     130             :         /** \TODO
     131             :          * Under MS-Windows, we need to use _wstat() to make it work in
     132             :          * Unicode (i.e. UTF-8 to wchar_t then call _wstat()...) Also we
     133             :          * want to use the 64 bit variant to make sure that we get a
     134             :          * valid size. Any other reference to the stat() command should
     135             :          * be replace by using a FilePath().
     136             :          */
     137      140837 :         memset(&m_stat, 0, sizeof(m_stat));
     138      140837 :         m_exists = stat(m_path.c_str(), &m_stat) == 0;
     139             :     }
     140     1220957 : }
     141             : 
     142             : 
     143             : /** \brief Replace the path with a new path.
     144             :  *
     145             :  * This function replaces the internal path of this FilePath with
     146             :  * the new specified path.
     147             :  *
     148             :  * \param[in] path  The new path to save in this object.
     149             :  *
     150             :  * \return A reference to this object.
     151             :  */
     152         443 : FilePath& FilePath::operator = (std::string const& path)
     153             : {
     154         443 :     m_path = pruneTrailingSeparator(path);
     155         443 :     return *this;
     156             : }
     157             : 
     158             : 
     159             : /** \brief Retrieve the path.
     160             :  *
     161             :  * This operator can be used to retrieve a copy of the path.
     162             :  *
     163             :  * \return The m_path string returned as is (i.e. the whole path).
     164             :  */
     165    63761612 : FilePath::operator std::string () const
     166             : {
     167    63761612 :     return m_path;
     168             : }
     169             : 
     170             : 
     171             : /** \brief Append the a child name to this path.
     172             :  *
     173             :  * This function concatenates two FilePath objects and returns
     174             :  * another FilePath.
     175             :  *
     176             :  * A file separator is inserted between both names if appropriate.
     177             :  *
     178             :  * \warning
     179             :  * Note that the function allows you to append two full paths,
     180             :  * or even a relative path (left) to a full path (right), which
     181             :  * may result in a new path that is not quite sensible.
     182             :  *
     183             :  * \param[in] rhs  The right hand side.
     184             :  */
     185       20226 : FilePath FilePath::operator + (FilePath const& rhs) const
     186             : {
     187       20226 :     if(m_path.empty())
     188             :     {
     189         132 :         return rhs;
     190             :     }
     191             : 
     192       20094 :     if(rhs.m_path.empty())
     193             :     {
     194        2109 :         return *this;
     195             :     }
     196             : 
     197       17985 :     if(rhs.m_path[0] == g_separator)
     198             :     {
     199           4 :         return m_path + rhs.m_path;
     200             :     }
     201             : 
     202       17981 :     return m_path + g_separator + rhs.m_path;
     203             : }
     204             : 
     205             : 
     206             : /** \brief Check whether two FilePath represent the same file.
     207             :  *
     208             :  * This function compares a FilePath object (this) and a C-string
     209             :  * to know whether the two are the same.
     210             :  *
     211             :  * A null pointer as the C-string is viewed as an empty string.
     212             :  *
     213             :  * \param[in] rhs  The right hand side to compare with.
     214             :  *
     215             :  * \sa operator == (FilePath const& rhs);
     216             :  */
     217           6 : bool FilePath::operator == (char const *rhs) const
     218             : {
     219           6 :     return m_path == rhs;
     220             : }
     221             : 
     222             : 
     223             : /** \brief Check whether two FilePath represent the same file.
     224             :  *
     225             :  * This function compares a FilePath object (this) and a C-string
     226             :  * to know whether the two are the same.
     227             :  *
     228             :  * A null pointer as the C-string is viewed as an empty string.
     229             :  *
     230             :  * \param[in] lhs  The left hand side to compare with.
     231             :  * \param[in] rhs  The right hand side to compare with.
     232             :  *
     233             :  * \sa operator == (FilePath const& rhs);
     234             :  */
     235           6 : bool operator == (char const *lhs, FilePath const& rhs)
     236             : {
     237           6 :     return lhs == rhs.m_path;
     238             : }
     239             : 
     240             : 
     241             : /** \brief Check whether two FilePath represent the same file.
     242             :  *
     243             :  * This function compares a FilePath object (this) against
     244             :  * a string representing a path to know whether the two are
     245             :  * the equal.
     246             :  *
     247             :  * \param[in] rhs  The right hand side to compare with.
     248             :  *
     249             :  * \sa operator == (FilePath const& rhs);
     250             :  */
     251           6 : bool FilePath::operator == (std::string const& rhs) const
     252             : {
     253           6 :     return m_path == rhs;
     254             : }
     255             : 
     256             : 
     257             : /** \brief Check whether two FilePath represent the same file.
     258             :  *
     259             :  * This function compares a FilePath object (this) against
     260             :  * a string representing a path to know whether the two are
     261             :  * the equal.
     262             :  *
     263             :  * \param[in] lhs  The left hand side to compare with.
     264             :  * \param[in] rhs  The right hand side to compare with.
     265             :  *
     266             :  * \sa operator == (FilePath const& rhs);
     267             :  */
     268           6 : bool operator == (std::string const& lhs, FilePath const& rhs)
     269             : {
     270           6 :     return lhs == rhs.m_path;
     271             : }
     272             : 
     273             : 
     274             : /** \brief Check whether two FilePath represent the same file.
     275             :  *
     276             :  * This function compares two FilePath objects (this and rhs)
     277             :  * to know whether the two are the same.
     278             :  *
     279             :  * \note
     280             :  * It is important to know that the compare is rather primitive.
     281             :  * The two paths must be equal character by character instead
     282             :  * of actually representing exactly the same file. Also relative
     283             :  * paths will likely be equal and these may not represent the
     284             :  * same file at all.
     285             :  *
     286             :  * \param[in] rhs  The right hand side to compare with.
     287             :  *
     288             :  * \sa operator == (char const *rhs);
     289             :  * \sa operator == (std::string const& rhs);
     290             :  */
     291       82667 : bool FilePath::operator == (FilePath const& rhs) const
     292             : {
     293       82667 :     return m_path == rhs.m_path;
     294             : }
     295             : 
     296             : 
     297             : /** \brief Retrieve the basename.
     298             :  *
     299             :  * This function returns the filename part of the FilePath
     300             :  * object by pruning the path off.
     301             :  *
     302             :  * \return Return the basename of this FilePath filename.
     303             :  */
     304     3747615 : std::string FilePath::filename() const
     305             : {
     306     3747615 :     std::string::size_type const pos(m_path.find_last_of(g_separator));
     307     3747615 :     if(pos != std::string::npos)
     308             :     {
     309     3738843 :         return m_path.substr(pos + 1);
     310             :     }
     311             : 
     312        8772 :     return m_path;
     313             : }
     314             : 
     315             : 
     316             : /** \brief Get the length of the string.
     317             :  *
     318             :  * This function returns the length of the string used to
     319             :  * represent this FilePath path and filename.
     320             :  *
     321             :  * \return The length of the string representing this file path.
     322             :  *
     323             :  * \sa size()
     324             :  */
     325      726950 : size_t FilePath::length() const
     326             : {
     327      726950 :     return m_path.length();
     328             : }
     329             : 
     330             : 
     331             : /** \brief Get the length of the string.
     332             :  *
     333             :  * This function returns the length of the string used to
     334             :  * represent this FilePath path and filename.
     335             :  *
     336             :  * \note
     337             :  * This is an overloaded function that calls the length() function.
     338             :  * It is defined because the string represents an array of bytes
     339             :  * and as such the size() function may be used.
     340             :  *
     341             :  * \return The length of the string representing this file path.
     342             :  *
     343             :  * \sa length()
     344             :  */
     345          27 : size_t FilePath::size() const
     346             : {
     347          27 :     return length();
     348             : }
     349             : 
     350             : 
     351             : /** \brief Check whether the file exists.
     352             :  *
     353             :  * This function calls check() and then returns true if the file
     354             :  * exists on disk.
     355             :  *
     356             :  * \return true If the path is a valid file system entity.
     357             :  */
     358          27 : bool FilePath::exists() const
     359             : {
     360          27 :     check();
     361          27 :     return m_exists;
     362             : }
     363             : 
     364             : 
     365             : /** \brief Check whether the file is a regular file.
     366             :  *
     367             :  * This function returns true if the file exists and is a
     368             :  * regular file.
     369             :  *
     370             :  * \return true if the path is a regular file.
     371             :  */
     372      141084 : bool FilePath::isRegular() const
     373             : {
     374      141084 :     check();
     375      141084 :     return m_exists && S_ISREG(m_stat.st_mode);
     376             : }
     377             : 
     378             : 
     379             : /** \brief Check whether the file is a directory.
     380             :  *
     381             :  * This function returns true if the file exists and is a
     382             :  * directory.
     383             :  *
     384             :  * \return true if the path is a directory.
     385             :  */
     386      799359 : bool FilePath::isDirectory() const
     387             : {
     388      799359 :     check();
     389      799359 :     return m_exists && S_ISDIR(m_stat.st_mode);
     390             : }
     391             : 
     392             : 
     393             : /** \brief Check whether the file is a character special file.
     394             :  *
     395             :  * This function returns true if the file exists and is a
     396             :  * character special file.
     397             :  *
     398             :  * \return true if the path is character special (a character device file).
     399             :  */
     400          27 : bool FilePath::isCharSpecial() const
     401             : {
     402          27 :     check();
     403          27 :     return m_exists && S_ISCHR(m_stat.st_mode);
     404             : }
     405             : 
     406             : 
     407             : /** \brief Check whether the file is a block special file.
     408             :  *
     409             :  * This function returns true if the file exists and is a
     410             :  * block special file.
     411             :  *
     412             :  * \return true if the path is block special (a block device file).
     413             :  */
     414          27 : bool FilePath::isBlockSpecial() const
     415             : {
     416          27 :     check();
     417          27 :     return m_exists && S_ISBLK(m_stat.st_mode);
     418             : }
     419             : 
     420             : 
     421             : /** \brief Check whether the file is a socket.
     422             :  *
     423             :  * This function returns true if the file exists and is a
     424             :  * socket file.
     425             :  *
     426             :  * \return true if the path is a socket.
     427             :  */
     428          27 : bool FilePath::isSocket() const
     429             : {
     430          27 :     check();
     431          27 :     return m_exists && S_ISSOCK(m_stat.st_mode);
     432             : }
     433             : 
     434             : 
     435             : /** \brief Check whether the file is a pipe.
     436             :  *
     437             :  * This function returns true if the file exists and is a
     438             :  * pipe file.
     439             :  *
     440             :  * \return true if the path is a FIFO.
     441             :  */
     442          27 : bool FilePath::isFifo() const
     443             : {
     444          27 :     check();
     445          27 :     return m_exists && S_ISFIFO(m_stat.st_mode);
     446             : }
     447             : 
     448             : 
     449             : /** \brief Get the size of the file.
     450             :  *
     451             :  * This function returns the size of the file. The size may be a 64 bit
     452             :  * size on 64 bit systems.
     453             :  *
     454             :  * \note
     455             :  * If the file represents a directory, the size will be zero.
     456             :  *
     457             :  * \note
     458             :  * If the file is not considered valid, the size returned is zero.
     459             :  *
     460             :  * \warning
     461             :  * There is also a function called size() which actually checks the
     462             :  * length of the path and not the size of the file.
     463             :  *
     464             :  * \return The last modification as a Unix time.
     465             :  *
     466             :  * \sa size()
     467             :  */
     468      139675 : size_t FilePath::fileSize() const
     469             : {
     470      139675 :     check();
     471      139675 :     return m_stat.st_size;
     472             : }
     473             : 
     474             : 
     475             : /** \brief Get the last modification time of the file.
     476             :  *
     477             :  * This function returns the last modification time of the specified
     478             :  * file.
     479             :  *
     480             :  * \note
     481             :  * If the file is not considered valid, the time returned is zero.
     482             :  *
     483             :  * \return The last modification as a Unix time.
     484             :  */
     485      140704 : std::time_t FilePath::lastModificationTime() const
     486             : {
     487      140704 :     check();
     488      140704 :     return m_stat.st_mtime;
     489             : }
     490             : 
     491             : 
     492             : /** \brief Print out a FilePath.
     493             :  *
     494             :  * This function prints out the name of the file that this FilePath
     495             :  * represents.
     496             :  *
     497             :  * \param[in,out] os  The output stream.
     498             :  * \param[in] path  The path to print out.
     499             :  *
     500             :  * \return A copy of the \p os stream reference.
     501             :  */
     502         760 : std::ostream& operator << (std::ostream& os, FilePath const& path)
     503             : {
     504         760 :     os << static_cast<std::string>(path);
     505         760 :     return os;
     506             : }
     507             : 
     508           3 : } // namespace
     509             : 
     510             : // Local Variables:
     511             : // mode: cpp
     512             : // indent-tabs-mode: nil
     513             : // c-basic-offset: 4
     514             : // tab-width: 4
     515             : // End:
     516             : 
     517             : // vim: ts=4 sw=4 et

Generated by: LCOV version 1.10