LCOV - code coverage report
Current view: top level - src - filepath.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 81 83 97.6 %
Date: 2024-06-15 08:26:09 Functions: 25 26 96.2 %
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-2022  Made to Order Software Corp.  All Rights Reserved
       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             : 
      35             : 
      36             : namespace zipios
      37             : {
      38             : 
      39             : 
      40             : namespace
      41             : {
      42             : 
      43             : 
      44             : /** \brief Prune the trailing separator if present.
      45             :  *
      46             :  * This function is used to ensure that the FilePath does NOT end
      47             :  * with a separator.
      48             :  *
      49             :  * \warning
      50             :  * At this time the path is not canonicalized properly. We expect \p path
      51             :  * to not include double separators one after another. However, passing
      52             :  * such a path to the FilePath will keep it as is.
      53             :  *
      54             :  * \param[in] path  The path to prune of one trailing separator.
      55             :  *
      56             :  * \return The path as is or without the last '/'.
      57             :  */
      58      438973 : std::string pruneTrailingSeparator(std::string path)
      59             : {
      60      438973 :     if(path.size() > 0)
      61             :     {
      62      267452 :         if(path[path.size() - 1] == g_separator)
      63             :         {
      64       10261 :             path.erase(path.size() - 1);
      65             :         }
      66             :     }
      67             : 
      68      438973 :     return path;
      69             : }
      70             : 
      71             : 
      72             : } // no name namespace
      73             : 
      74             : 
      75             : 
      76             : /** \class FilePath
      77             :  * \brief Handle a file path and name and its statistics.
      78             :  *
      79             :  * The FilePath class represents a path to a file or directory name.
      80             :  * FilePath has member functions to check if the file path is a valid
      81             :  * file system entity, and to check what kind of file system entity
      82             :  * it is, e.g. is it a file, a directory, a pipe, etc.
      83             :  *
      84             :  * It also knows of the last modification time and size of the file.
      85             :  *
      86             :  * \warning
      87             :  * The information about a file is cached so at the time it gets used
      88             :  * the file on disk may have changed, it may even have been deleted.
      89             :  */
      90             : 
      91             : 
      92             : /** \brief Initialize a FilePath object.
      93             :  *
      94             :  * The constructor saves the path and if \p check_exists is true, read
      95             :  * the file statistics, especially the st_mode.
      96             :  *
      97             :  * \param[in] path  A string representation of the path.
      98             :  *
      99             :  * \sa exists()
     100             :  * \sa pruneTrailingSeparator()
     101             :  */
     102      438972 : FilePath::FilePath(std::string const & path)
     103      438972 :     : m_path(pruneTrailingSeparator(path))
     104             : {
     105      438972 : }
     106             : 
     107             : 
     108             : /** \brief Read the file mode.
     109             :  *
     110             :  * This function sets m_checked to true, stat()'s the path, to see if
     111             :  * it exists and to determine what type of file it is. All the query
     112             :  * functions call check() before they test a flag to make sure it
     113             :  * is set appropriately.
     114             :  *
     115             :  * This means stat()'ing is deferred until it becomes necessary. But also
     116             :  * it is cached meaning that if the file changes in between we get the
     117             :  * old flags.
     118             :  */
     119      857849 : void FilePath::check() const
     120             : {
     121      857849 :     if(!m_checked)
     122             :     {
     123       75818 :         m_checked = true;
     124             : 
     125             :         /** \TODO
     126             :          * Under MS-Windows, we need to use _wstat() to make it work in
     127             :          * Unicode (i.e. UTF-8 to wchar_t then call _wstat()...) Also we
     128             :          * want to use the 64 bit variant to make sure that we get a
     129             :          * valid size. Any other reference to the stat() command should
     130             :          * be replace by using a FilePath().
     131             :          *
     132             :          * See zipios/zipios-config.hpp.in
     133             :          */
     134       75818 :         m_stat = {};
     135       75818 :         m_exists = stat(m_path.c_str(), &m_stat) == 0;
     136             :     }
     137      857849 : }
     138             : 
     139             : 
     140             : /** \brief Replace the path with a new path.
     141             :  *
     142             :  * This function replaces the internal path of this FilePath with
     143             :  * the new specified path.
     144             :  *
     145             :  * \param[in] path  The new path to save in this object.
     146             :  *
     147             :  * \return A reference to this object.
     148             :  */
     149           1 : FilePath & FilePath::operator = (std::string const & path)
     150             : {
     151           1 :     m_path = pruneTrailingSeparator(path);
     152           1 :     m_checked = false;
     153           1 :     return *this;
     154             : }
     155             : 
     156             : 
     157             : /** \brief Retrieve the path.
     158             :  *
     159             :  * This operator can be used to retrieve a copy of the path.
     160             :  *
     161             :  * \return The m_path string returned as is (i.e. the whole path).
     162             :  */
     163    39887120 : FilePath::operator std::string () const
     164             : {
     165    39887120 :     return m_path;
     166             : }
     167             : 
     168             : 
     169             : /** \brief Append the a child name to this path.
     170             :  *
     171             :  * This function concatenates two FilePath objects and returns
     172             :  * another FilePath.
     173             :  *
     174             :  * A file separator is inserted between both names if appropriate.
     175             :  *
     176             :  * \warning
     177             :  * Note that the function allows you to append two full paths,
     178             :  * or even a relative path (left) to a full path (right), which
     179             :  * may result in a new path that is not quite sensible.
     180             :  *
     181             :  * \param[in] rhs  The right hand side.
     182             :  *
     183             :  * \return The lhs and rhs concatenated.
     184             :  */
     185       21312 : FilePath FilePath::operator + (FilePath const & rhs) const
     186             : {
     187       21312 :     if(m_path.empty())
     188             :     {
     189         130 :         return rhs;
     190             :     }
     191             : 
     192       21182 :     if(rhs.m_path.empty())
     193             :     {
     194        1879 :         return *this;
     195             :     }
     196             : 
     197       19303 :     if(rhs.m_path[0] == g_separator)
     198             :     {
     199           4 :         return m_path + rhs.m_path;
     200             :     }
     201             : 
     202       38602 :     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       59634 : bool FilePath::operator == (FilePath const & rhs) const
     292             : {
     293       59634 :     return m_path == rhs.m_path;
     294             : }
     295             : 
     296             : 
     297             : /** \brief Clear the filename.
     298             :  *
     299             :  * This function clears the path to an empty string.
     300             :  */
     301         350 : void FilePath::clear()
     302             : {
     303         350 :     m_path.clear();
     304         350 :     m_checked = false;
     305         350 : }
     306             : 
     307             : 
     308             : /** \brief Retrieve the basename.
     309             :  *
     310             :  * This function returns the filename part of the FilePath
     311             :  * object by pruning the path off.
     312             :  *
     313             :  * \return Return the basename of this FilePath filename.
     314             :  */
     315     4806051 : std::string FilePath::filename() const
     316             : {
     317     4806051 :     std::string::size_type const pos(m_path.find_last_of(g_separator));
     318     4806051 :     if(pos != std::string::npos)
     319             :     {
     320     4796087 :         return m_path.substr(pos + 1);
     321             :     }
     322             : 
     323        9964 :     return m_path;
     324             : }
     325             : 
     326             : 
     327             : /** \brief Get the length of the string.
     328             :  *
     329             :  * This function returns the length of the string used to
     330             :  * represent this FilePath path and filename.
     331             :  *
     332             :  * \return The length of the string representing this file path.
     333             :  *
     334             :  * \sa size()
     335             :  */
     336      608805 : size_t FilePath::length() const
     337             : {
     338      608805 :     return m_path.length();
     339             : }
     340             : 
     341             : 
     342             : /** \brief Get the length of the string.
     343             :  *
     344             :  * This function returns the length of the string used to
     345             :  * represent this FilePath path and filename.
     346             :  *
     347             :  * \note
     348             :  * This is an overloaded function that calls the length() function.
     349             :  * It is defined because the string represents an array of bytes
     350             :  * and as such the size() function may be used.
     351             :  *
     352             :  * \return The length of the string representing this file path.
     353             :  *
     354             :  * \sa length()
     355             :  */
     356          27 : size_t FilePath::size() const
     357             : {
     358          27 :     return length();
     359             : }
     360             : 
     361             : 
     362             : /** \brief Check whether the filename is empty.
     363             :  *
     364             :  * This function returns true if the filename is empty. In other words, this
     365             :  * function returns true if the filename is not currently defined.
     366             :  *
     367             :  * \note
     368             :  * This function returns true after a call to the clear() function.
     369             :  *
     370             :  * \warning
     371             :  * If you are trying to know whether the file itself is empty, please use
     372             :  * the fileSize() instead and check whether it is zero or not:
     373             :  *
     374             :  *     if(file_path.fileSize() == 0) ...empty file...
     375             :  *
     376             :  * \return true when the file path is empty.
     377             :  *
     378             :  * \sa clear()
     379             :  * \sa fileSize()
     380             :  */
     381           0 : bool FilePath::empty() const
     382             : {
     383           0 :     return m_path.empty();
     384             : }
     385             : 
     386             : 
     387             : /** \brief Check whether the file exists.
     388             :  *
     389             :  * This function calls check() and then returns true if the file
     390             :  * exists on disk.
     391             :  *
     392             :  * \return true If the path is a valid file system entity.
     393             :  */
     394          27 : bool FilePath::exists() const
     395             : {
     396          27 :     check();
     397          27 :     return m_exists;
     398             : }
     399             : 
     400             : 
     401             : /** \brief Check whether the file is a regular file.
     402             :  *
     403             :  * This function returns true if the file exists and is a
     404             :  * regular file.
     405             :  *
     406             :  * \return true if the path is a regular file.
     407             :  */
     408       75985 : bool FilePath::isRegular() const
     409             : {
     410       75985 :     check();
     411       75985 :     return m_exists && S_ISREG(m_stat.st_mode);
     412             : }
     413             : 
     414             : 
     415             : /** \brief Check whether the file is a directory.
     416             :  *
     417             :  * This function returns true if the file exists and is a
     418             :  * directory.
     419             :  *
     420             :  * \return true if the path is a directory.
     421             :  */
     422      631392 : bool FilePath::isDirectory() const
     423             : {
     424      631392 :     check();
     425      631392 :     return m_exists && S_ISDIR(m_stat.st_mode);
     426             : }
     427             : 
     428             : 
     429             : /** \brief Check whether the file is a character special file.
     430             :  *
     431             :  * This function returns true if the file exists and is a
     432             :  * character special file.
     433             :  *
     434             :  * \return true if the path is character special (a character device file).
     435             :  */
     436          27 : bool FilePath::isCharSpecial() const
     437             : {
     438          27 :     check();
     439          27 :     return m_exists && S_ISCHR(m_stat.st_mode);
     440             : }
     441             : 
     442             : 
     443             : /** \brief Check whether the file is a block special file.
     444             :  *
     445             :  * This function returns true if the file exists and is a
     446             :  * block special file.
     447             :  *
     448             :  * \return true if the path is block special (a block device file).
     449             :  */
     450          27 : bool FilePath::isBlockSpecial() const
     451             : {
     452          27 :     check();
     453          27 :     return m_exists && S_ISBLK(m_stat.st_mode);
     454             : }
     455             : 
     456             : 
     457             : /** \brief Check whether the file is a socket.
     458             :  *
     459             :  * This function returns true if the file exists and is a
     460             :  * socket file.
     461             :  *
     462             :  * \return true if the path is a socket.
     463             :  */
     464          27 : bool FilePath::isSocket() const
     465             : {
     466          27 :     check();
     467          27 :     return m_exists && S_ISSOCK(m_stat.st_mode);
     468             : }
     469             : 
     470             : 
     471             : /** \brief Check whether the file is a pipe.
     472             :  *
     473             :  * This function returns true if the file exists and is a
     474             :  * pipe file.
     475             :  *
     476             :  * \return true if the path is a FIFO.
     477             :  */
     478          27 : bool FilePath::isFifo() const
     479             : {
     480          27 :     check();
     481          27 :     return m_exists && S_ISFIFO(m_stat.st_mode);
     482             : }
     483             : 
     484             : 
     485             : /** \brief Get the size of the file.
     486             :  *
     487             :  * This function returns the size of the file. The size may be a 64 bit
     488             :  * size on 64 bit systems.
     489             :  *
     490             :  * \note
     491             :  * If the file represents a directory, the size will be zero.
     492             :  *
     493             :  * \note
     494             :  * If the file is not considered valid, the size returned is zero.
     495             :  *
     496             :  * \warning
     497             :  * There is also a function called size() which actually checks the
     498             :  * length of the path and not the size of the file.
     499             :  *
     500             :  * \return The last modification as a Unix time.
     501             :  *
     502             :  * \sa size()
     503             :  */
     504       74648 : size_t FilePath::fileSize() const
     505             : {
     506       74648 :     check();
     507       74648 :     return m_stat.st_size;
     508             : }
     509             : 
     510             : 
     511             : /** \brief Get the last modification time of the file.
     512             :  *
     513             :  * This function returns the last modification time of the specified
     514             :  * file.
     515             :  *
     516             :  * \note
     517             :  * If the file is not considered valid, the time returned is zero.
     518             :  *
     519             :  * \return The last modification as a Unix time.
     520             :  */
     521       75689 : std::time_t FilePath::lastModificationTime() const
     522             : {
     523       75689 :     check();
     524       75689 :     return m_stat.st_mtime;
     525             : }
     526             : 
     527             : 
     528             : /** \brief Print out a FilePath.
     529             :  *
     530             :  * This function prints out the name of the file that this FilePath
     531             :  * represents.
     532             :  *
     533             :  * \param[in,out] os  The output stream.
     534             :  * \param[in] path  The path to print out.
     535             :  *
     536             :  * \return A copy of the \p os stream reference.
     537             :  */
     538         563 : std::ostream & operator << (std::ostream & os, FilePath const & path)
     539             : {
     540         563 :     os << static_cast<std::string>(path);
     541         563 :     return os;
     542             : }
     543             : 
     544             : } // namespace
     545             : 
     546             : // Local Variables:
     547             : // mode: cpp
     548             : // indent-tabs-mode: nil
     549             : // c-basic-offset: 4
     550             : // tab-width: 4
     551             : // End:
     552             : 
     553             : // vim: ts=4 sw=4 et

Generated by: LCOV version 1.14

Snap C++ | List of projects | List of versions