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: 2019-04-24 14:10:30 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-2019  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.1 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  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      724347 : std::string pruneTrailingSeparator(std::string path)
      60             : {
      61      724347 :     if(path.size() > 0)
      62             :     {
      63      409962 :         if(path[path.size() - 1] == g_separator)
      64             :         {
      65       21009 :             path.erase(path.size() - 1);
      66             :         }
      67             :     }
      68             : 
      69      724347 :     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      724010 : FilePath::FilePath(std::string const& path)
     104      724010 :     : m_path(pruneTrailingSeparator(path))
     105             :     //, m_stat() -- see below
     106             :     //, m_checked(false) -- auto-init
     107             :     //, m_exists(false) -- auto-init
     108             : {
     109      724010 :     memset(&m_stat, 0, sizeof(m_stat));
     110      724010 : }
     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     1088610 : void FilePath::check() const
     125             : {
     126     1088610 :     if(!m_checked)
     127             :     {
     128       75732 :         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             :          * See zipios/zipios-config.hpp.in
     138             :          */
     139       75732 :         memset(&m_stat, 0, sizeof(m_stat));
     140       75732 :         m_exists = stat(m_path.c_str(), &m_stat) == 0;
     141             :     }
     142     1088610 : }
     143             : 
     144             : 
     145             : /** \brief Replace the path with a new path.
     146             :  *
     147             :  * This function replaces the internal path of this FilePath with
     148             :  * the new specified path.
     149             :  *
     150             :  * \param[in] path  The new path to save in this object.
     151             :  *
     152             :  * \return A reference to this object.
     153             :  */
     154         337 : FilePath& FilePath::operator = (std::string const& path)
     155             : {
     156         337 :     m_path = pruneTrailingSeparator(path);
     157         337 :     return *this;
     158             : }
     159             : 
     160             : 
     161             : /** \brief Retrieve the path.
     162             :  *
     163             :  * This operator can be used to retrieve a copy of the path.
     164             :  *
     165             :  * \return The m_path string returned as is (i.e. the whole path).
     166             :  */
     167   105480626 : FilePath::operator std::string () const
     168             : {
     169   105480626 :     return m_path;
     170             : }
     171             : 
     172             : 
     173             : /** \brief Append the a child name to this path.
     174             :  *
     175             :  * This function concatenates two FilePath objects and returns
     176             :  * another FilePath.
     177             :  *
     178             :  * A file separator is inserted between both names if appropriate.
     179             :  *
     180             :  * \warning
     181             :  * Note that the function allows you to append two full paths,
     182             :  * or even a relative path (left) to a full path (right), which
     183             :  * may result in a new path that is not quite sensible.
     184             :  *
     185             :  * \param[in] rhs  The right hand side.
     186             :  */
     187       21270 : FilePath FilePath::operator + (FilePath const& rhs) const
     188             : {
     189       21270 :     if(m_path.empty())
     190             :     {
     191         126 :         return rhs;
     192             :     }
     193             : 
     194       21144 :     if(rhs.m_path.empty())
     195             :     {
     196        1770 :         return *this;
     197             :     }
     198             : 
     199       19374 :     if(rhs.m_path[0] == g_separator)
     200             :     {
     201           2 :         return m_path + rhs.m_path;
     202             :     }
     203             : 
     204       19372 :     return m_path + g_separator + rhs.m_path;
     205             : }
     206             : 
     207             : 
     208             : /** \brief Check whether two FilePath represent the same file.
     209             :  *
     210             :  * This function compares a FilePath object (this) and a C-string
     211             :  * to know whether the two are the same.
     212             :  *
     213             :  * A null pointer as the C-string is viewed as an empty string.
     214             :  *
     215             :  * \param[in] rhs  The right hand side to compare with.
     216             :  *
     217             :  * \sa operator == (FilePath const& rhs);
     218             :  */
     219           6 : bool FilePath::operator == (char const *rhs) const
     220             : {
     221           6 :     return m_path == rhs;
     222             : }
     223             : 
     224             : 
     225             : /** \brief Check whether two FilePath represent the same file.
     226             :  *
     227             :  * This function compares a FilePath object (this) and a C-string
     228             :  * to know whether the two are the same.
     229             :  *
     230             :  * A null pointer as the C-string is viewed as an empty string.
     231             :  *
     232             :  * \param[in] lhs  The left hand side to compare with.
     233             :  * \param[in] rhs  The right hand side to compare with.
     234             :  *
     235             :  * \sa operator == (FilePath const& rhs);
     236             :  */
     237           6 : bool operator == (char const *lhs, FilePath const& rhs)
     238             : {
     239           6 :     return lhs == rhs.m_path;
     240             : }
     241             : 
     242             : 
     243             : /** \brief Check whether two FilePath represent the same file.
     244             :  *
     245             :  * This function compares a FilePath object (this) against
     246             :  * a string representing a path to know whether the two are
     247             :  * the equal.
     248             :  *
     249             :  * \param[in] rhs  The right hand side to compare with.
     250             :  *
     251             :  * \sa operator == (FilePath const& rhs);
     252             :  */
     253           6 : bool FilePath::operator == (std::string const& rhs) const
     254             : {
     255           6 :     return m_path == rhs;
     256             : }
     257             : 
     258             : 
     259             : /** \brief Check whether two FilePath represent the same file.
     260             :  *
     261             :  * This function compares a FilePath object (this) against
     262             :  * a string representing a path to know whether the two are
     263             :  * the equal.
     264             :  *
     265             :  * \param[in] lhs  The left hand side to compare with.
     266             :  * \param[in] rhs  The right hand side to compare with.
     267             :  *
     268             :  * \sa operator == (FilePath const& rhs);
     269             :  */
     270           6 : bool operator == (std::string const& lhs, FilePath const& rhs)
     271             : {
     272           6 :     return lhs == rhs.m_path;
     273             : }
     274             : 
     275             : 
     276             : /** \brief Check whether two FilePath represent the same file.
     277             :  *
     278             :  * This function compares two FilePath objects (this and rhs)
     279             :  * to know whether the two are the same.
     280             :  *
     281             :  * \note
     282             :  * It is important to know that the compare is rather primitive.
     283             :  * The two paths must be equal character by character instead
     284             :  * of actually representing exactly the same file. Also relative
     285             :  * paths will likely be equal and these may not represent the
     286             :  * same file at all.
     287             :  *
     288             :  * \param[in] rhs  The right hand side to compare with.
     289             :  *
     290             :  * \sa operator == (char const *rhs);
     291             :  * \sa operator == (std::string const& rhs);
     292             :  */
     293      109048 : bool FilePath::operator == (FilePath const& rhs) const
     294             : {
     295      109048 :     return m_path == rhs.m_path;
     296             : }
     297             : 
     298             : 
     299             : /** \brief Retrieve the basename.
     300             :  *
     301             :  * This function returns the filename part of the FilePath
     302             :  * object by pruning the path off.
     303             :  *
     304             :  * \return Return the basename of this FilePath filename.
     305             :  */
     306     3466042 : std::string FilePath::filename() const
     307             : {
     308     3466042 :     std::string::size_type const pos(m_path.find_last_of(g_separator));
     309     3466042 :     if(pos != std::string::npos)
     310             :     {
     311     3457581 :         return m_path.substr(pos + 1);
     312             :     }
     313             : 
     314        8461 :     return m_path;
     315             : }
     316             : 
     317             : 
     318             : /** \brief Get the length of the string.
     319             :  *
     320             :  * This function returns the length of the string used to
     321             :  * represent this FilePath path and filename.
     322             :  *
     323             :  * \return The length of the string representing this file path.
     324             :  *
     325             :  * \sa size()
     326             :  */
     327      857385 : size_t FilePath::length() const
     328             : {
     329      857385 :     return m_path.length();
     330             : }
     331             : 
     332             : 
     333             : /** \brief Get the length of the string.
     334             :  *
     335             :  * This function returns the length of the string used to
     336             :  * represent this FilePath path and filename.
     337             :  *
     338             :  * \note
     339             :  * This is an overloaded function that calls the length() function.
     340             :  * It is defined because the string represents an array of bytes
     341             :  * and as such the size() function may be used.
     342             :  *
     343             :  * \return The length of the string representing this file path.
     344             :  *
     345             :  * \sa length()
     346             :  */
     347          27 : size_t FilePath::size() const
     348             : {
     349          27 :     return length();
     350             : }
     351             : 
     352             : 
     353             : /** \brief Check whether the file exists.
     354             :  *
     355             :  * This function calls check() and then returns true if the file
     356             :  * exists on disk.
     357             :  *
     358             :  * \return true If the path is a valid file system entity.
     359             :  */
     360          27 : bool FilePath::exists() const
     361             : {
     362          27 :     check();
     363          27 :     return m_exists;
     364             : }
     365             : 
     366             : 
     367             : /** \brief Check whether the file is a regular file.
     368             :  *
     369             :  * This function returns true if the file exists and is a
     370             :  * regular file.
     371             :  *
     372             :  * \return true if the path is a regular file.
     373             :  */
     374       75923 : bool FilePath::isRegular() const
     375             : {
     376       75923 :     check();
     377       75923 :     return m_exists && S_ISREG(m_stat.st_mode);
     378             : }
     379             : 
     380             : 
     381             : /** \brief Check whether the file is a directory.
     382             :  *
     383             :  * This function returns true if the file exists and is a
     384             :  * directory.
     385             :  *
     386             :  * \return true if the path is a directory.
     387             :  */
     388      862383 : bool FilePath::isDirectory() const
     389             : {
     390      862383 :     check();
     391      862383 :     return m_exists && S_ISDIR(m_stat.st_mode);
     392             : }
     393             : 
     394             : 
     395             : /** \brief Check whether the file is a character special file.
     396             :  *
     397             :  * This function returns true if the file exists and is a
     398             :  * character special file.
     399             :  *
     400             :  * \return true if the path is character special (a character device file).
     401             :  */
     402          27 : bool FilePath::isCharSpecial() const
     403             : {
     404          27 :     check();
     405          27 :     return m_exists && S_ISCHR(m_stat.st_mode);
     406             : }
     407             : 
     408             : 
     409             : /** \brief Check whether the file is a block special file.
     410             :  *
     411             :  * This function returns true if the file exists and is a
     412             :  * block special file.
     413             :  *
     414             :  * \return true if the path is block special (a block device file).
     415             :  */
     416          27 : bool FilePath::isBlockSpecial() const
     417             : {
     418          27 :     check();
     419          27 :     return m_exists && S_ISBLK(m_stat.st_mode);
     420             : }
     421             : 
     422             : 
     423             : /** \brief Check whether the file is a socket.
     424             :  *
     425             :  * This function returns true if the file exists and is a
     426             :  * socket file.
     427             :  *
     428             :  * \return true if the path is a socket.
     429             :  */
     430          27 : bool FilePath::isSocket() const
     431             : {
     432          27 :     check();
     433          27 :     return m_exists && S_ISSOCK(m_stat.st_mode);
     434             : }
     435             : 
     436             : 
     437             : /** \brief Check whether the file is a pipe.
     438             :  *
     439             :  * This function returns true if the file exists and is a
     440             :  * pipe file.
     441             :  *
     442             :  * \return true if the path is a FIFO.
     443             :  */
     444          27 : bool FilePath::isFifo() const
     445             : {
     446          27 :     check();
     447          27 :     return m_exists && S_ISFIFO(m_stat.st_mode);
     448             : }
     449             : 
     450             : 
     451             : /** \brief Get the size of the file.
     452             :  *
     453             :  * This function returns the size of the file. The size may be a 64 bit
     454             :  * size on 64 bit systems.
     455             :  *
     456             :  * \note
     457             :  * If the file represents a directory, the size will be zero.
     458             :  *
     459             :  * \note
     460             :  * If the file is not considered valid, the size returned is zero.
     461             :  *
     462             :  * \warning
     463             :  * There is also a function called size() which actually checks the
     464             :  * length of the path and not the size of the file.
     465             :  *
     466             :  * \return The last modification as a Unix time.
     467             :  *
     468             :  * \sa size()
     469             :  */
     470       74566 : size_t FilePath::fileSize() const
     471             : {
     472       74566 :     check();
     473       74566 :     return m_stat.st_size;
     474             : }
     475             : 
     476             : 
     477             : /** \brief Get the last modification time of the file.
     478             :  *
     479             :  * This function returns the last modification time of the specified
     480             :  * file.
     481             :  *
     482             :  * \note
     483             :  * If the file is not considered valid, the time returned is zero.
     484             :  *
     485             :  * \return The last modification as a Unix time.
     486             :  */
     487       75603 : std::time_t FilePath::lastModificationTime() const
     488             : {
     489       75603 :     check();
     490       75603 :     return m_stat.st_mtime;
     491             : }
     492             : 
     493             : 
     494             : /** \brief Print out a FilePath.
     495             :  *
     496             :  * This function prints out the name of the file that this FilePath
     497             :  * represents.
     498             :  *
     499             :  * \param[in,out] os  The output stream.
     500             :  * \param[in] path  The path to print out.
     501             :  *
     502             :  * \return A copy of the \p os stream reference.
     503             :  */
     504         579 : std::ostream& operator << (std::ostream& os, FilePath const& path)
     505             : {
     506         579 :     os << static_cast<std::string>(path);
     507         579 :     return os;
     508             : }
     509             : 
     510           3 : } // namespace
     511             : 
     512             : // Local Variables:
     513             : // mode: cpp
     514             : // indent-tabs-mode: nil
     515             : // c-basic-offset: 4
     516             : // tab-width: 4
     517             : // End:
     518             : 
     519             : // vim: ts=4 sw=4 et

Generated by: LCOV version 1.12