LCOV - code coverage report
Current view: top level - okssystem/src - File.cpp (source / functions) Coverage Total Hit
Test: code.result Lines: 0.0 % 394 0
Test Date: 2026-10-11 15:05:20 Functions: 0.0 % 60 0

            Line data    Source code
       1              : // DUNE DAQ modification notice:
       2              : // This file has been modified from the original ATLAS system source for the DUNE DAQ project.
       3              : // Fork baseline commit: system-00-00-20 (2020-09-25).
       4              : // Renamed since fork: yes (from src/File.cxx to src/File.cpp).
       5              : 
       6              : /*
       7              :  *  File.cxx
       8              :  *  ers
       9              :  *
      10              :  *  Created by Matthias Wiesmann on 04.01.05.
      11              :  *  Copyright 2005 CERN. All rights reserved.
      12              :  *
      13              :  */
      14              : 
      15              : #include <assert.h>
      16              : #include <dirent.h>
      17              : #include <errno.h>
      18              : #include <fcntl.h>
      19              : #include <fstream>
      20              : #include <iostream>
      21              : #include <libgen.h>
      22              : #include <pwd.h>
      23              : #include <sstream>
      24              : #include <stdio.h>
      25              : #include <sys/param.h>
      26              : #include <sys/stat.h>
      27              : #include <sys/types.h>
      28              : #include <unistd.h>
      29              : 
      30              : #include "ers/ers.hpp"
      31              : 
      32              : #include "okssystem/Executable.hpp"
      33              : #include "okssystem/File.hpp"
      34              : #include "okssystem/User.hpp"
      35              : #include "okssystem/exceptions.hpp"
      36              : 
      37              : #define SPACE_CHAR ' '
      38              : 
      39              : const char* const OksSystem::File::HUMAN_SIZE_STR[] = { "B", "KB", "MB", "GB" };
      40              : const char* const OksSystem::File::HUMAN_OPEN_STR[] = { "READ",   "WRITE",    "NOBLOCK",  "APPEND",
      41              :                                                         "CREATE", "TRUNCATE", "EXCLUSIVE" };
      42              : const char* const OksSystem::File::FILE_COMMAND_PATH = "/usr/bin/file";
      43              : const char* const OksSystem::File::FILE_FLAG_STR = "-rwxS";
      44              : const char* const OksSystem::File::FILE_PROTOCOL = "file";
      45              : 
      46              : #define READ_CHAR_CODE (OksSystem::File::FILE_FLAG_STR[1])
      47              : #define WRITE_CHAR_CODE (OksSystem::File::FILE_FLAG_STR[2])
      48              : #define EXECUTE_CHAR_CODE (OksSystem::File::FILE_FLAG_STR[3])
      49              : #define NOTHING_CHAR_CODE (OksSystem::File::FILE_FLAG_STR[0])
      50              : #define SETUID_CHAR_CODE (OksSystem::File::FILE_FLAG_STR[4])
      51              : 
      52              : #define SLASH_CHAR '/'
      53              : #define COLON_CHAR ':'
      54              : #define DOT_CHAR '.'
      55              : 
      56              : const int OksSystem::File::KILOBYTE = 1024;
      57              : 
      58              : // --------------------------------------
      59              : // Static Methods
      60              : // --------------------------------------
      61              : 
      62              : /** Extracts the protocol part of an url.
      63              :  * The protocol part is everything until the colon (:)
      64              :  * \param url an url
      65              :  * \return the protocol part of an empty string
      66              :  */
      67              : 
      68              : std::string
      69            0 : OksSystem::File::protocol(const std::string& url) throw()
      70              : {
      71            0 :   std::string::size_type colon = url.find(COLON_CHAR);
      72            0 :   if (colon == std::string::npos)
      73            0 :     return std::string();
      74            0 :   return url.substr(0, colon);
      75              : } // protocol
      76              : 
      77              : /** Extracts the extension of an url or path
      78              :  * \param url an url or file path
      79              :  * \return the extension (without the dot) or an empty string
      80              :  */
      81              : 
      82              : std::string
      83            0 : OksSystem::File::extension(const std::string& url) throw()
      84              : {
      85            0 :   std::string::size_type dot = url.rfind(DOT_CHAR);
      86            0 :   if (dot == std::string::npos)
      87            0 :     return std::string();
      88            0 :   return url.substr(dot + 1);
      89              : } // extension
      90              : 
      91              : /** Extracts the short file name of an url or path
      92              :  * \param url an url or file path
      93              :  * \return the short name or the full url if it cannot be found
      94              :  */
      95              : 
      96              : std::string
      97            0 : OksSystem::File::short_name(const std::string& url) throw()
      98              : {
      99            0 :   std::string::size_type slash = url.rfind(SLASH_CHAR);
     100            0 :   if (slash == std::string::npos)
     101            0 :     return url;
     102            0 :   return url.substr(slash + 1);
     103              : } // extension
     104              : 
     105              : /** Extacts the uri part of an url.
     106              :  * The uri of an url is everything except the protocol part
     107              :  * In the case of \c file or \c http urls, the uri is the local path
     108              :  * \param url an url
     109              :  * \return the uri or the full url if no colon in the string
     110              :  */
     111              : 
     112              : std::string
     113            0 : OksSystem::File::uri(const std::string& url) throw()
     114              : {
     115            0 :   std::string::size_type colon = url.find(COLON_CHAR);
     116            0 :   if (colon == std::string::npos)
     117            0 :     return url;
     118            0 :   return url.substr(colon + 1);
     119              : } // uri
     120              : 
     121              : /** Calculates the depth of a file.
     122              :  * This depth is the number of parent directories.
     123              :  * Files in the root directory have depht of 0,
     124              :  * other files have a depth of their parent's depth + 1
     125              :  * \param path to analyze
     126              :  * \return depth or -1 if the format of the path is not understood.
     127              :  */
     128              : 
     129              : int
     130            0 : OksSystem::File::depth(const std::string& path) throw()
     131              : {
     132            0 :   if (path[0] == SLASH_CHAR) {
     133            0 :     int count = 0;
     134            0 :     std::string rest = path.substr(1);
     135            0 :     while (!rest.empty()) {
     136            0 :       std::string::size_type slash = rest.find(SLASH_CHAR);
     137            0 :       if (slash == std::string::npos)
     138              :         return count;
     139            0 :       count++;
     140            0 :       rest = rest.substr(slash + 1);
     141              :     } // while
     142              :     return count;
     143            0 :   } // path with slash
     144            0 :   if (protocol(path) == FILE_PROTOCOL) {
     145            0 :     return depth(uri(path));
     146              :   } //
     147              :   return -1;
     148              : } // depth
     149              : 
     150              : /** Extracts the first line of a text
     151              :  * \param text the text to process
     152              :  * \return the first line of the text
     153              :  */
     154              : 
     155              : std::string
     156            0 : OksSystem::File::first_line(const std::string& text)
     157              : {
     158            0 :   std::string::size_type nl = text.find('\n');
     159            0 :   if (nl > 0)
     160            0 :     return text.substr(0, nl);
     161            0 :   return text;
     162              : } // first_line
     163              : 
     164              : /** Builds a \c File object ou of an url
     165              :  * \param url the url, it must start with the file protocol
     166              :  * \return a File object
     167              :  */
     168              : 
     169              : OksSystem::File
     170            0 : OksSystem::File::from_url(const std::string& url)
     171              : {
     172            0 :   std::string prot = protocol(url);
     173            0 :   ERS_PRECONDITION(prot == FILE_PROTOCOL);
     174            0 :   const std::string path = uri(url);
     175            0 :   return File(path);
     176            0 : } // from_url
     177              : 
     178              : /** \return a string containing the working directory for the process */
     179              : 
     180              : std::string
     181            0 : OksSystem::File::working_directory()
     182              : {
     183            0 :   char* wd_buffer = getcwd(0, MAXPATHLEN);
     184            0 :   if (wd_buffer) {
     185            0 :     std::string directory = std::string(wd_buffer);
     186            0 :     free(wd_buffer);
     187            0 :     return directory;
     188              :   }
     189            0 :   std::string message("getting the current working directory");
     190            0 :   throw OksSystem::OksSystemCallIssue(ERS_HERE, errno, "getcwd", message.c_str());
     191            0 : } // working_directory
     192              : 
     193              : void
     194            0 : OksSystem::File::working_directory(const File& dir)
     195              : {
     196            0 :   const char* path = dir.c_full_name();
     197            0 :   const int status = ::chdir(path);
     198            0 :   if (status < 0) {
     199            0 :     std::string message = "on directory " + dir.full_name();
     200            0 :     throw OksSystem::OksSystemCallIssue(ERS_HERE, errno, "chdir", message.c_str());
     201            0 :   }
     202            0 : } // working_directory
     203              : 
     204              : /** Expands a file containing a home directory reference (~user).
     205              :  */
     206              : 
     207              : std::string
     208            0 : OksSystem::File::expand_home(const std::string path)
     209              : {
     210            0 :   ERS_PRECONDITION(!path.empty());
     211            0 :   ERS_PRECONDITION(path[0] == '~');
     212            0 :   std::string::size_type slash = path.find('/');
     213            0 :   const std::string user_name = path.substr(1, slash - 1);
     214            0 :   const std::string rest_path = path.substr(slash);
     215            0 :   OksSystem::User user;
     216            0 :   if (!user_name.empty()) {
     217            0 :     user = OksSystem::User(user_name);
     218              :   }
     219            0 :   return user.home() + rest_path;
     220            0 : } // home_directory
     221              : 
     222              : /** Builds a prettyfied version of permissions.
     223              :  * This should look similar to what \c ls returns with the -l flag
     224              :  * \param permissions the permission to beautify
     225              :  * \return a string containing the beautified permissions
     226              :  */
     227              : 
     228              : std::string
     229            0 : OksSystem::File::pretty_permissions(mode_t permissions)
     230              : {
     231            0 :   char buffer[11];
     232            0 :   buffer[0] = (permissions & S_ISUID) ? SETUID_CHAR_CODE : NOTHING_CHAR_CODE;
     233            0 :   buffer[1] = (permissions & S_IRUSR) ? READ_CHAR_CODE : NOTHING_CHAR_CODE;
     234            0 :   buffer[2] = (permissions & S_IWUSR) ? WRITE_CHAR_CODE : NOTHING_CHAR_CODE;
     235            0 :   buffer[3] = (permissions & S_IXUSR) ? EXECUTE_CHAR_CODE : NOTHING_CHAR_CODE;
     236            0 :   buffer[4] = (permissions & S_IRGRP) ? READ_CHAR_CODE : NOTHING_CHAR_CODE;
     237            0 :   buffer[5] = (permissions & S_IWGRP) ? WRITE_CHAR_CODE : NOTHING_CHAR_CODE;
     238            0 :   buffer[6] = (permissions & S_IXGRP) ? EXECUTE_CHAR_CODE : NOTHING_CHAR_CODE;
     239            0 :   buffer[7] = (permissions & S_IROTH) ? READ_CHAR_CODE : NOTHING_CHAR_CODE;
     240            0 :   buffer[8] = (permissions & S_IWOTH) ? WRITE_CHAR_CODE : NOTHING_CHAR_CODE;
     241            0 :   buffer[9] = (permissions & S_IXOTH) ? EXECUTE_CHAR_CODE : NOTHING_CHAR_CODE;
     242            0 :   buffer[10] = '\0';
     243            0 :   return std::string(buffer);
     244              : } // pretty_permissions
     245              : 
     246              : /** Builds a prettyfied version of flags used by the \c open OksSystem call
     247              :  * \param flags as passed to \c open
     248              :  * \return a string containing the beautified flags
     249              :  * \note This method only handles flags available accross plateforms.
     250              :  */
     251              : 
     252              : std::string
     253            0 : OksSystem::File::pretty_open_flag(int flags)
     254              : {
     255            0 :   std::ostringstream flag_str;
     256            0 :   if (flags & O_WRONLY) {
     257            0 :     flag_str << HUMAN_OPEN_STR[1];
     258            0 :   } else if (flags & O_RDWR) {
     259            0 :     flag_str << HUMAN_OPEN_STR[0] << "-" << HUMAN_OPEN_STR[1];
     260              :   } else {
     261            0 :     flag_str << HUMAN_OPEN_STR[0];
     262              :   }
     263            0 :   if (flags & O_NONBLOCK) {
     264            0 :     flag_str << "/" << HUMAN_OPEN_STR[2];
     265              :   }
     266            0 :   if (flags & O_APPEND) {
     267            0 :     flag_str << "/" << HUMAN_OPEN_STR[3];
     268              :   }
     269            0 :   if (flags & O_CREAT) {
     270            0 :     flag_str << "/" << HUMAN_OPEN_STR[4];
     271              :   }
     272            0 :   if (flags & O_TRUNC) {
     273            0 :     flag_str << "/" << HUMAN_OPEN_STR[5];
     274              :   }
     275            0 :   if (flags & O_EXCL) {
     276            0 :     flag_str << "/" << HUMAN_OPEN_STR[6];
     277              :   }
     278            0 :   flag_str << "(" << flags << ")";
     279            0 :   return flag_str.str();
     280            0 : } // pretty_open_permission
     281              : 
     282              : int
     283            0 : OksSystem::File::unit(int u)
     284              : {
     285            0 :   ERS_PRECONDITION(u >= 0);
     286            0 :   if (u == 0)
     287            0 :     return 1;
     288            0 :   return KILOBYTE * unit(u - 1);
     289              : } // unit
     290              : 
     291              : /** Builds a human readable textual description of a file size.
     292              :  * The file size is expressed in Gigabytes (GB), Megabytes (MB) and Kilobytes (KB) and Bytes (B).
     293              :  * \param size the size of the file
     294              :  * \param cut_small should the display only contain the highest quantity?
     295              :  * For example if a file is 1 gigabyte and 20 bytes, if \c cut_small is \c true, then
     296              :  * the 20 bytes are ignored.
     297              :  * \return a string containing the textual description
     298              :  */
     299              : 
     300              : std::string
     301            0 : OksSystem::File::pretty_size(size_t size, bool cut_small)
     302              : {
     303            0 :   if (0 == size)
     304            0 :     return "0";
     305            0 :   std::ostringstream size_str;
     306              :   bool writen_something = false;
     307            0 :   for (int i = 3; i >= 0; i--) {
     308            0 :     const unsigned int size_unit = unit(i);
     309            0 :     if (size > size_unit && !(cut_small && writen_something)) {
     310            0 :       const int amount = size / size_unit;
     311            0 :       size = size % size_unit;
     312            0 :       size_str << amount << SPACE_CHAR << HUMAN_SIZE_STR[i];
     313              :       writen_something = true;
     314              :     } // if unit is present
     315              :   } // loop
     316            0 :   return size_str.str();
     317            0 : } // pretty_size
     318              : 
     319              : // --------------------------------------
     320              : // Constructors
     321              : // --------------------------------------
     322              : 
     323              : /** Constructor
     324              :  * \note This method does not create a file, it simply builds an object describing a file
     325              :  */
     326              : 
     327            0 : OksSystem::File::File(const std::string& name)
     328              : {
     329            0 :   set_name(name);
     330            0 : } // File
     331              : 
     332              : /** Constructor
     333              :  * \overload
     334              :  */
     335              : 
     336            0 : OksSystem::File::File(const char* c_name)
     337              : {
     338            0 :   ERS_PRECONDITION(c_name);
     339            0 :   std::string name = std::string(c_name);
     340            0 :   set_name(name);
     341            0 : } // File
     342              : 
     343              : /** Constructor
     344              :  * \overload
     345              :  */
     346              : 
     347            0 : OksSystem::File::File(const File& other)
     348              : {
     349            0 :   set_name(other.m_full_name);
     350            0 : } // File
     351              : 
     352              : // --------------------------------------
     353              : // Operators
     354              : // --------------------------------------
     355              : 
     356            0 : OksSystem::File::operator std::string() const throw()
     357              : {
     358            0 :   return m_full_name;
     359              : } // operator std::string
     360              : 
     361            0 : OksSystem::File::operator const char*() const throw()
     362              : {
     363            0 :   return m_full_name.c_str();
     364              : } // operator const char*
     365              : 
     366              : /** Cast to boolean, checks if the file exists
     367              :  * \return \c true if the file exists
     368              :  */
     369              : 
     370            0 : OksSystem::File::operator bool() const throw()
     371              : {
     372            0 :   return exists();
     373              : } // operator bool
     374              : 
     375              : /** Comparison operator
     376              :  * As path are canonicalized, we simply compare the full paths.
     377              :  * \param other file to compare this file to
     378              :  * \return true if both file are equal
     379              :  * \note This comparison method does not taken hard links into account
     380              :  */
     381              : 
     382              : bool
     383            0 : OksSystem::File::equals(const File& other) const throw()
     384              : {
     385            0 :   return (m_full_name == other.m_full_name);
     386              : } // operator==
     387              : 
     388              : /** Cast to size type
     389              :  * \return the size of the file
     390              :  * \see size()
     391              :  */
     392              : 
     393            0 : OksSystem::File::operator size_t() const
     394              : {
     395            0 :   return size();
     396              : } // operator size_t
     397              : 
     398              : // --------------------------------------
     399              : // Methods
     400              : // --------------------------------------
     401              : 
     402              : /** Sets the name for a file.
     403              :  * The path name is first expanded and the canonlicalized.
     404              :  * Expension means the following
     405              :  * \li If the path starts with / nothing is done
     406              :  * \li If the path starts with ~ the username is resolved and the path starts from there
     407              :  * \li If the path starts with any other character, the working directory is prepended.
     408              :  *
     409              :  * The path is then made canonical, this implies removing all ./ and ../ sequences,
     410              :  * and resolving all symbolic links.
     411              :  * \param name the name of the file
     412              :  */
     413              : 
     414              : void
     415            0 : OksSystem::File::set_name(const std::string& name)
     416              : {
     417            0 :   ERS_PRECONDITION(!name.empty());
     418            0 :   const char c = name[0];
     419            0 :   std::string long_path;
     420            0 :   switch (c) {
     421            0 :     case '/':
     422            0 :       long_path = name;
     423              :       break;
     424            0 :     case '~':
     425            0 :       long_path = expand_home(name);
     426            0 :       break;
     427            0 :     default:
     428            0 :       long_path = working_directory() + "/" + name;
     429            0 :       break;
     430              :   } // switch
     431            0 :   char buffer[PATH_MAX];
     432            0 :   const char* result = realpath(long_path.c_str(), buffer);
     433            0 :   if (result == 0) { // could not resolve path
     434            0 :     m_full_name = long_path;
     435              :   } else { // we could canonicalize the path
     436            0 :     m_full_name = buffer;
     437              :   } //
     438            0 : } // set_name
     439              : 
     440              : /** \return the full (absolute) path of the file */
     441              : 
     442              : const std::string&
     443            0 : OksSystem::File::full_name() const throw()
     444              : {
     445            0 :   return m_full_name;
     446              : } // full_name
     447              : 
     448              : /** \return the full (absolute) path of the file */
     449              : 
     450              : const char*
     451            0 : OksSystem::File::c_full_name() const throw()
     452              : {
     453            0 :   return m_full_name.c_str();
     454              : } // c_full_name
     455              : 
     456              : /** \return the short name of the file - that is the name of the file in its directory */
     457              : 
     458              : std::string
     459            0 : OksSystem::File::short_name() const throw()
     460              : {
     461            0 :   return short_name(m_full_name);
     462              : } // short_name
     463              : 
     464              : /** Finds the name of the enclosing directory
     465              :  * \return the path of the directory containing the file
     466              :  */
     467              : 
     468              : std::string
     469            0 : OksSystem::File::parent_name() const throw()
     470              : {
     471            0 :   std::string::size_type size = m_full_name.size();
     472            0 :   std::string::size_type slash = m_full_name.rfind(SLASH_CHAR, size - 1);
     473            0 :   if (slash == std::string::npos || slash == 0)
     474            0 :     return ("/");
     475            0 :   return m_full_name.substr(0, slash);
     476              : } // directory
     477              : 
     478              : /** \return the extension of the file */
     479              : 
     480              : std::string
     481            0 : OksSystem::File::extension() const throw()
     482              : {
     483            0 :   return extension(m_full_name);
     484              : } // extension
     485              : 
     486              : int
     487            0 : OksSystem::File::depth() const throw()
     488              : {
     489            0 :   return depth(m_full_name);
     490              : } // depth
     491              : 
     492              : /** \return the parent directory */
     493              : 
     494              : OksSystem::File
     495            0 : OksSystem::File::parent() const
     496              : {
     497            0 :   return File(parent_name());
     498              : } // parent
     499              : 
     500              : OksSystem::File
     501            0 : OksSystem::File::child(const std::string& name) const
     502              : {
     503            0 :   std::string child_name = m_full_name + "/" + name;
     504            0 :   return OksSystem::File(child_name);
     505            0 : } // child
     506              : 
     507              : OksSystem::File
     508            0 : OksSystem::File::temporary(const std::string& prefix) const
     509              : {
     510            0 :   char* tmp_name = tempnam(m_full_name.c_str(), prefix.c_str());
     511            0 :   if (!tmp_name) {
     512            0 :     std::string message = "while creating a valid filename in directory " + m_full_name;
     513            0 :     throw OksSystem::OksSystemCallIssue(ERS_HERE, errno, "tempnam", message.c_str());
     514            0 :   }
     515            0 :   OksSystem::File tmp_file(tmp_name);
     516            0 :   free(tmp_name);
     517            0 :   return tmp_file;
     518              : } // temporary
     519              : 
     520              : /** Checks if the file exists in the fileOksSystem
     521              :  * \return \c true if the file exists, false otherwise
     522              :  * \exception ers::IOIssue if an error occurs
     523              :  */
     524              : 
     525              : bool
     526            0 : OksSystem::File::exists() const throw()
     527              : {
     528            0 :   struct stat file_status;
     529            0 :   const int result = stat(m_full_name.c_str(), &file_status);
     530            0 :   if (0 == result)
     531            0 :     return true;
     532              :   return false;
     533              : } // exists
     534              : 
     535              : /** Extracts the mode information of the file.
     536              :  * This is used to determine both the file type and the file permissions
     537              :  * \return the mode of the file
     538              :  * \exception OksSystem::FStatFail if fstat fails
     539              :  */
     540              : 
     541              : mode_t
     542            0 : OksSystem::File::get_mode() const
     543              : {
     544            0 :   struct stat file_status;
     545            0 :   const int result = stat(m_full_name.c_str(), &file_status);
     546            0 :   if (0 == result) {
     547            0 :     return file_status.st_mode;
     548              :   } // if
     549            0 :   std::string message = "on file/directory " + m_full_name;
     550            0 :   throw OksSystem::OksSystemCallIssue(ERS_HERE, errno, "stat", message.c_str());
     551            0 : } // mode
     552              : 
     553              : /** \return the permissions for the file
     554              :  * \exception ers::IOIssue if an error occurs or the file does not exist
     555              :  */
     556              : 
     557              : mode_t
     558            0 : OksSystem::File::permissions() const
     559              : {
     560            0 :   mode_t mode = get_mode();
     561            0 :   return (mode & 07777);
     562              : } // permissions
     563              : 
     564              : /** \return the prettfied permissions for the file
     565              :  * \exception ers::IOIssue if an error occurs or the file does not exist
     566              :  */
     567              : 
     568              : std::string
     569            0 : OksSystem::File::pretty_permissions() const
     570              : {
     571            0 :   return pretty_permissions(permissions());
     572              : } // pretty_permissions
     573              : 
     574              : /** Converts permissions into a string
     575              :  * \param permissions the permissions
     576              :  * \return a string contaning the permissions in octal form
     577              :  */
     578              : 
     579              : std::string
     580            0 : OksSystem::File::to_string(mode_t permissions) throw()
     581              : {
     582            0 :   std::ostringstream stream;
     583            0 :   stream.setf(std::ios::oct, std::ios::basefield);
     584            0 :   stream << permissions;
     585            0 :   return stream.str();
     586            0 : } // to_string
     587              : 
     588              : /** \return the size (in bytes) of the file
     589              :  * \exception OksSystem::IOIssue if an error occurs or the file does not exist
     590              :  */
     591              : 
     592              : size_t
     593            0 : OksSystem::File::size() const
     594              : {
     595            0 :   struct stat file_status;
     596            0 :   const int result = stat(m_full_name.c_str(), &file_status);
     597            0 :   if (0 == result)
     598            0 :     return file_status.st_size;
     599            0 :   std::string message = "on file/directory " + m_full_name;
     600            0 :   throw OksSystem::OksSystemCallIssue(ERS_HERE, errno, "stat", message.c_str());
     601            0 : } // size
     602              : 
     603              : /** \return the user-id of the owner of the file
     604              :  * \exception OksSystem::IOIssue if an error occurs or the file does not exist
     605              :  */
     606              : 
     607              : uid_t
     608            0 : OksSystem::File::owner_id() const
     609              : {
     610            0 :   struct stat file_status;
     611            0 :   const int result = stat(m_full_name.c_str(), &file_status);
     612            0 :   if (0 == result)
     613            0 :     return file_status.st_uid;
     614            0 :   std::string message = "on file/directory " + m_full_name;
     615            0 :   throw OksSystem::OksSystemCallIssue(ERS_HERE, errno, "stat", message.c_str());
     616            0 : } // owner_id
     617              : 
     618              : OksSystem::User
     619            0 : OksSystem::File::owner() const
     620              : {
     621            0 :   return User(owner_id());
     622              : } // owner
     623              : 
     624              : /** \return the group-id of the group of the file
     625              :  * \exception ers::IOIssue if an error occurs or the file does not exist
     626              :  */
     627              : 
     628              : gid_t
     629            0 : OksSystem::File::group() const
     630              : {
     631            0 :   struct stat file_status;
     632            0 :   const int result = stat(m_full_name.c_str(), &file_status);
     633            0 :   if (0 == result)
     634            0 :     return file_status.st_gid;
     635            0 :   std::string message = "on file/directory " + m_full_name;
     636            0 :   throw OksSystem::OksSystemCallIssue(ERS_HERE, errno, "stat", message.c_str());
     637            0 : } // owner
     638              : 
     639              : /** Checks if the file a regular file (i.e not a directory, named pipe or anything else).
     640              :  * \return \c true if the file is regular
     641              :  * \exception ers::IOIssue if an error occurs or the file does not exist
     642              :  */
     643              : 
     644              : bool
     645            0 : OksSystem::File::is_regular() const
     646              : {
     647            0 :   const mode_t mode = get_mode();
     648            0 :   return (mode & S_IFREG);
     649              : } // is_regular
     650              : 
     651              : /** Checks if the file a directory
     652              :  * \return \c true if the file is a directory
     653              :  * \exception ers::IOIssue if an error occurs or the file does not exist
     654              :  */
     655              : 
     656              : bool
     657            0 : OksSystem::File::is_directory() const
     658              : {
     659            0 :   const mode_t mode = get_mode();
     660            0 :   return (mode & S_IFDIR);
     661              : } // is_regular
     662              : 
     663              : /** Checks if the file a named pipe (FIFO)
     664              :  * \return \c true if the file is named pipe (FIFO)
     665              :  * \exception ers::IOIssue if an error occurs or the file does not exist
     666              :  */
     667              : 
     668              : bool
     669            0 : OksSystem::File::is_fifo() const
     670              : {
     671            0 :   const mode_t mode = get_mode();
     672            0 :   return (mode & S_IFIFO);
     673              : } // is_pipe
     674              : 
     675              : std::string
     676            0 : OksSystem::File::file_type() const
     677              : {
     678            0 :   OksSystem::Executable file_command(FILE_COMMAND_PATH);
     679            0 :   OksSystem::Executable::param_collection params;
     680            0 :   params.push_back("-b");
     681            0 :   params.push_back(full_name());
     682            0 :   return first_line(file_command.pipe_in(params));
     683            0 : } // file_type
     684              : 
     685              : /** Builds a vector containing all the files contained in a directory
     686              :  * \return a vector of files contained in the directory
     687              :  * \exception OksSystem::OpenFail if the directory could not be openend
     688              :  * \exception OksSystem::CloseFail if the directory cannot be closed
     689              :  */
     690              : 
     691              : OksSystem::File::file_list_t
     692            0 : OksSystem::File::directory() const
     693              : {
     694            0 :   file_list_t file_vector;
     695            0 :   DIR* directory_ptr = opendir(m_full_name.c_str());
     696            0 :   if (!directory_ptr) {
     697            0 :     std::string message = "on directory " + m_full_name;
     698            0 :     throw OksSystem::OksSystemCallIssue(ERS_HERE, errno, "opendir", message.c_str());
     699            0 :   }
     700            0 :   while (true) {
     701            0 :     struct dirent* directory_entry = readdir(directory_ptr);
     702            0 :     if (directory_entry) {
     703            0 :       const std::string name = directory_entry->d_name;
     704            0 :       if ((name != ".") && (name != "..")) {
     705            0 :         std::string path = m_full_name + "/" + name;
     706            0 :         OksSystem::File file(path);
     707            0 :         file_vector.push_back(file);
     708            0 :       } // if
     709            0 :     } else {
     710              :       break;
     711              :     } // if / else
     712            0 :   } // while
     713            0 :   int status = closedir(directory_ptr);
     714            0 :   if (status < 0) {
     715            0 :     std::string message = "on directory " + m_full_name;
     716            0 :     throw OksSystem::OksSystemCallIssue(ERS_HERE, errno, "closedir", message.c_str());
     717            0 :   }
     718            0 :   return file_vector;
     719            0 : } // directory
     720              : 
     721              : /** Unlinks (i.e deletes) a file.
     722              :  * \exception ers::IOIssue if an error occurs or the file does not exist
     723              :  */
     724              : 
     725              : void
     726            0 : OksSystem::File::unlink() const
     727              : {
     728            0 :   const int result = ::unlink(m_full_name.c_str());
     729            0 :   if (0 == result)
     730            0 :     return;
     731            0 :   throw OksSystem::RemoveFileIssue(ERS_HERE, errno, m_full_name.c_str());
     732              : } // unlink
     733              : 
     734              : void
     735            0 : OksSystem::File::rmdir() const
     736              : {
     737            0 :   const int result = ::rmdir(m_full_name.c_str());
     738            0 :   if (0 == result)
     739            0 :     return;
     740            0 :   std::string message = "on directory " + m_full_name;
     741            0 :   throw OksSystem::OksSystemCallIssue(ERS_HERE, errno, "rmdir", message.c_str());
     742            0 : } // rmdir
     743              : 
     744              : /** Recursively delete files and directories.
     745              :  * If the file is a directory, all its child are deleted recursively.
     746              :  * \exception OksSystem::UnlinkFail if \c unlink fails
     747              :  */
     748              : 
     749              : void
     750            0 : OksSystem::File::remove() const
     751              : {
     752            0 :   if (is_directory()) {
     753            0 :     file_list_t childs = directory();
     754            0 :     for (file_list_t::const_iterator p = childs.begin(); p != childs.end(); p++) {
     755            0 :       const File f = *p;
     756            0 :       if (f.exists()) {
     757            0 :         f.remove();
     758              :       }
     759            0 :     } // for
     760            0 :     rmdir();
     761            0 :   } else {
     762            0 :     unlink();
     763              :   }
     764            0 : } // remove
     765              : 
     766              : /** Renames or moves a file.
     767              :  * \param new_name the new name of the file
     768              :  * \exception ers::IOIssue if an error occurs or the file does not exist
     769              :  */
     770              : 
     771              : void
     772            0 : OksSystem::File::rename(const File& other) const
     773              : {
     774            0 :   const char* source = c_full_name();
     775            0 :   const char* dest = other.c_full_name();
     776            0 :   const int result = ::rename(source, dest);
     777            0 :   if (0 == result)
     778            0 :     return;
     779            0 :   throw OksSystem::RenameFileIssue(ERS_HERE, errno, source, dest);
     780              : } // rename
     781              : 
     782              : /** Sets the permissions of the file
     783              :  * \param permissions the new permissions
     784              :  * \exception ers::IOIssue if an error occurs or the file does not exist
     785              :  */
     786              : 
     787              : void
     788            0 : OksSystem::File::permissions(mode_t perm) const
     789              : {
     790            0 :   if (perm != permissions()) {
     791            0 :     const int result = ::chmod(m_full_name.c_str(), perm);
     792            0 :     if (0 == result) {
     793            0 :       return;
     794              :     }
     795            0 :     std::string message = "on file/directory " + m_full_name;
     796            0 :     throw OksSystem::OksSystemCallIssue(ERS_HERE, errno, "chmod", message.c_str());
     797            0 :   }
     798              : } // permissions
     799              : 
     800              : /** Creates a directory
     801              :  * The current object is taken as the name of the directory to create.
     802              :  * \param perm the permissions to associate with the directory
     803              :  * \note if the directory exists, the method attempts to do a \c chmod
     804              :  * to match the permissions
     805              :  */
     806              : 
     807              : void
     808            0 : OksSystem::File::make_dir(mode_t perm) const
     809              : {
     810              : 
     811            0 :   errno = 0;
     812            0 :   const int result = ::mkdir(m_full_name.c_str(), perm);
     813            0 :   int mkdir_error = errno;
     814              : 
     815            0 :   if (0 == result) {
     816            0 :     try {
     817            0 :       permissions(perm);
     818            0 :     } catch (OksSystem::OksSystemCallIssue& e) {
     819            0 :       std::string message = "on directory " + m_full_name;
     820            0 :       throw OksSystem::OksSystemCallIssue(ERS_HERE, errno, "mkdir -> chmod", message.c_str());
     821            0 :     }
     822              :     return;
     823              :   } else {
     824            0 :     if (exists()) {
     825            0 :       if (is_directory()) { // already exists we attempt a chmod
     826            0 :         try {
     827            0 :           permissions(perm);
     828            0 :         } catch (OksSystem::OksSystemCallIssue& e) {
     829              :           // ignore this case...
     830            0 :         }
     831            0 :         return;
     832              :       } // is directory
     833              :     } else { // exists
     834            0 :       std::string message = "on directory " + m_full_name;
     835            0 :       throw OksSystem::OksSystemCallIssue(ERS_HERE, mkdir_error, "mkdir", message.c_str());
     836            0 :     }
     837              :   }
     838              : 
     839              : } // makedir
     840              : 
     841              : /** Builds a full path.
     842              :  * The current object is taken as the name of a directory to create.
     843              :  * This method creates all the parent directories as needed
     844              :  * \param permissions the permissions to associate with the directory
     845              :  * \note If parent directories are created, their permissions will be those
     846              :  *       defined in \c permissions ORed with 0700.
     847              :  *       This is needed to ensure we can actually write into the directories
     848              :  *       we create.
     849              :  */
     850              : 
     851              : void
     852            0 : OksSystem::File::make_path(mode_t perm) const
     853              : {
     854            0 :   const File father = parent();
     855            0 :   if (!father.exists()) {
     856            0 :     mode_t father_permission = perm | S_IRWXU; // we need rights to write sons
     857            0 :     father.make_path(father_permission);
     858              :   } // if
     859            0 :   make_dir(perm);
     860            0 : } // makepath
     861              : 
     862              : /** Makes sure that the path for a file exists
     863              :  * This is done by calling \c make_path on the parent directory
     864              :  * \param permissions permissions used to create directories
     865              :  * \see OksSystem::File::make_path()
     866              :  */
     867              : 
     868              : void
     869            0 : OksSystem::File::ensure_path(mode_t perm) const
     870              : {
     871            0 :   const File father = parent();
     872            0 :   father.make_path(perm);
     873            0 : } // ensure_path
     874              : 
     875              : /** Creates a named pipe (FIFO)
     876              :  * \param perm the permission to give the pipe
     877              :  */
     878              : 
     879              : void
     880            0 : OksSystem::File::make_fifo(mode_t perm) const
     881              : {
     882            0 :   if (exists()) {
     883            0 :     if (is_fifo()) {
     884            0 :       if (perm != permissions()) {
     885            0 :         permissions(perm);
     886            0 :         return;
     887              :       } else {
     888              :         return;
     889              :       }
     890              :     } // is_fifo
     891              :   } // exists
     892            0 :   const int status = ::mkfifo(m_full_name.c_str(), perm);
     893            0 :   if (status == 0) {
     894            0 :     permissions(perm);
     895            0 :     return;
     896              :   }
     897            0 :   std::string message = "while creating FIFO " + m_full_name;
     898            0 :   throw OksSystem::OksSystemCallIssue(ERS_HERE, errno, "mkfifo", message.c_str());
     899            0 : } // makefifo
     900              : 
     901              : /** Conversion into a input stream pointer
     902              :  * This actually creates a new input stream that reads from the file.
     903              :  * \return a dynamically allocated input stream
     904              :  * \exception ers::IOIssue if an error occurs or the file does not exist
     905              :  */
     906              : 
     907              : std::istream*
     908            0 : OksSystem::File::input() const
     909              : {
     910            0 :   try {
     911            0 :     std::ifstream* stream = new std::ifstream(m_full_name.c_str());
     912            0 :     stream->exceptions(std::ios::failbit | std::ios::badbit);
     913            0 :     return stream;
     914            0 :   } catch (std::ios_base::failure& ex) {
     915            0 :     throw OksSystem::OpenFileIssue(ERS_HERE, errno, m_full_name.c_str(), ex);
     916            0 :   } // catch
     917              : } // std::istream*
     918              : 
     919              : /** Conversion into an output stream pointer
     920              :  * This actually creates a new output stream that writes to the file.
     921              :  * \return a dynamically allocated output stream
     922              :  * \param append is the file opened in append mode
     923              :  * \exception ers::IOIssue if an error occurs
     924              :  */
     925              : 
     926              : std::ostream*
     927            0 : OksSystem::File::output(bool append) const
     928              : {
     929            0 :   try {
     930            0 :     std::ios::openmode mode = std::ios::out;
     931            0 :     if (append) {
     932            0 :       mode |= std::ios::app;
     933              :     }
     934            0 :     std::ofstream* stream = new std::ofstream(m_full_name.c_str(), mode);
     935            0 :     stream->exceptions(std::ios::failbit | std::ios::badbit);
     936            0 :     return stream;
     937            0 :   } catch (std::ios_base::failure& ex) {
     938            0 :     throw OksSystem::OpenFileIssue(ERS_HERE, errno, m_full_name.c_str(), ex);
     939            0 :   } // catch
     940              : } // std::ostream*
     941              : 
     942              : /** Stream a file object into a STL stream.
     943              :  * \param stream destination stream.
     944              :  * \param file the file to write
     945              :  * \return the stream passed as parameter
     946              :  */
     947              : 
     948              : std::ostream&
     949            0 : operator<<(std::ostream& stream, const OksSystem::File& file)
     950              : {
     951            0 :   stream << OksSystem::File::FILE_PROTOCOL << ":/" << file.full_name();
     952            0 :   return stream;
     953              : } // operator<<
     954              : 
     955              : bool
     956            0 : operator==(const OksSystem::File& a, const OksSystem::File& b) throw()
     957              : {
     958            0 :   return a.equals(b);
     959              : } // operator ==
     960              : 
     961              : bool
     962            0 : operator!=(const OksSystem::File& a, const OksSystem::File& b) throw()
     963              : {
     964            0 :   return !a.equals(b);
     965              : } // operator !=
        

Generated by: LCOV version 2.0-1