<commit_before>/* 
 * File:   FileIO.cpp
 * Author: kjell/weberr13
 * 
 * https://github.com/weberr13/FileIO
 * Created on August 15, 2013, 2:28 PM
 */



#include "FileIO.h"
#include "DirectoryReader.h"
#include <sstream>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/sendfile.h>
#include <ctime>
#include <cstdio>
#include <cstdlib>
#include <cerrno>
#include <cstring>
#include <string>

namespace FileIO {
   volatile int* gFlagInterrupt = nullptr;
   
   
   /**
    * Makes it possible to set an interrupt handler flag to break possibly
    * lengthy operations such as MoveFile or CleanDirectoryOfFileContents
    * @param interrupted interrupt handler flag
    */
   void SetInterruptFlag(volatile int* interrupted) {
      gFlagInterrupt = interrupted;
   }
   
   /**
    * @return true if interrupt flag is initialized AND set to signal an interrupt
    */
   bool Interrupted() {
      if (nullptr == gFlagInterrupt) {
         return false;
      }
      
      return (*gFlagInterrupt > 0);
   }
   
   
   /**
    * Reads the stats for the path to see if it is a mountpoint
    * @param pathToDirectory that may be a mountpoint
    * @param returns Result<true> if it is a mountpoint
    */
   Result<bool> IsMountPoint(const std::string& pathToDirectory) {
      // A mount point must be a block-device, folder and with a separate device-ID from its ".." parent
      
      struct stat info;
      if (0 != stat(pathToDirectory.c_str(), &info)) {
         return Result<bool>{false, {"Cannot stat read location: " + pathToDirectory}};
      }
      
      if (!S_ISDIR(info.st_mode)) {
         return Result<bool>{false, {"Directory + [" + pathToDirectory + "] does not exist"}};
      }       
      
      std::string parentPath = pathToDirectory;
      if('/' != parentPath.back()){
         parentPath.append("/..");
      } else {
         parentPath.append("..");   
      }
     
      struct stat parent; 
      if (0 != stat(parentPath.c_str(), &parent)) {
         return Result<bool>{false, {"Cannot stat read parent location: [" + parentPath +"]"}};
      }
      
      //  st_dev: device number. st_ino: inode number
      const bool isMountPoint = (info.st_dev != parent.st_dev) || (info.st_dev == parent.st_dev && info.st_ino == parent.st_ino);
      if (!isMountPoint) {
         return Result<bool>{false, {"[" + parentPath + "] is not a mountpoint"}};
      }
      
      return Result<bool>{true};
   }

  /**
    * Reads content of binary  file
    * @param pathToFile to read
    * @return Result<std::vector<uint8_t>> all the content of the file, and/or an error string 
    *         if something went wrong 
    */
   Result<std::vector<uint8_t>> ReadBinaryFileContent(const std::string& pathToFile) {
      std::ifstream in(pathToFile, std::ifstream::binary);
      if (!in) {
         std::string error{"Cannot read-open file: "};
         error.append(pathToFile);
         return Result<std::vector<uint8_t>>{{}, error};
      }

      std::shared_ptr<void> fileCloser(nullptr, [&](void *) { // RAII file close
         if (in) {
            in.close();
         }
      }); //fileCloser RAII


      std::vector<char> contents;
      in.seekg(0, std::ios::end);
      auto end = in.tellg();
      in.seekg(0, std::ios::beg);

      // Attempt to read it the fastest way possible.
      if (-1 != end) {  // tellg() --> pos_type{-1} if reading the end failed.
         contents.resize(end);
         in.read(&contents[0], contents.size());
      } else {
         // Could not calculate with ifstream::tellg(). Is it a RAM file?
         // Fallback solution to slower iteratator approach
         contents.assign((std::istreambuf_iterator<char>(in)),
         (std::istreambuf_iterator<char>()));
      }

      // return copy of the read result.
      return Result<std::vector<uint8_t>>{{contents.begin(), contents.end()}};
   }


   /**
    * Reads content of Ascii file
    * @param pathToFile to read
    * @return Result<std::string> all the content of the file, and/or an error string 
    *         if something went wrong 
    */<commit_msg>Add a try-catch for an ifstream call that failed once.<commit_after>/* 
 * File:   FileIO.cpp
 * Author: kjell/weberr13
 * 
 * https://github.com/weberr13/FileIO
 * Created on August 15, 2013, 2:28 PM
 */



#include "FileIO.h"
#include "DirectoryReader.h"
#include <sstream>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/sendfile.h>
#include <ctime>
#include <cstdio>
#include <cstdlib>
#include <cerrno>
#include <cstring>
#include <string>

namespace FileIO {
   volatile int* gFlagInterrupt = nullptr;
   
   
   /**
    * Makes it possible to set an interrupt handler flag to break possibly
    * lengthy operations such as MoveFile or CleanDirectoryOfFileContents
    * @param interrupted interrupt handler flag
    */
   void SetInterruptFlag(volatile int* interrupted) {
      gFlagInterrupt = interrupted;
   }
   
   /**
    * @return true if interrupt flag is initialized AND set to signal an interrupt
    */
   bool Interrupted() {
      if (nullptr == gFlagInterrupt) {
         return false;
      }
      
      return (*gFlagInterrupt > 0);
   }
   
   
   /**
    * Reads the stats for the path to see if it is a mountpoint
    * @param pathToDirectory that may be a mountpoint
    * @param returns Result<true> if it is a mountpoint
    */
   Result<bool> IsMountPoint(const std::string& pathToDirectory) {
      // A mount point must be a block-device, folder and with a separate device-ID from its ".." parent
      
      struct stat info;
      if (0 != stat(pathToDirectory.c_str(), &info)) {
         return Result<bool>{false, {"Cannot stat read location: " + pathToDirectory}};
      }
      
      if (!S_ISDIR(info.st_mode)) {
         return Result<bool>{false, {"Directory + [" + pathToDirectory + "] does not exist"}};
      }       
      
      std::string parentPath = pathToDirectory;
      if('/' != parentPath.back()){
         parentPath.append("/..");
      } else {
         parentPath.append("..");   
      }
     
      struct stat parent; 
      if (0 != stat(parentPath.c_str(), &parent)) {
         return Result<bool>{false, {"Cannot stat read parent location: [" + parentPath +"]"}};
      }
      
      //  st_dev: device number. st_ino: inode number
      const bool isMountPoint = (info.st_dev != parent.st_dev) || (info.st_dev == parent.st_dev && info.st_ino == parent.st_ino);
      if (!isMountPoint) {
         return Result<bool>{false, {"[" + parentPath + "] is not a mountpoint"}};
      }
      
      return Result<bool>{true};
   }

  /**
    * Reads content of binary  file
    * @param pathToFile to read
    * @return Result<std::vector<uint8_t>> all the content of the file, and/or an error string 
    *         if something went wrong 
    */
   Result<std::vector<uint8_t>> ReadBinaryFileContent(const std::string& pathToFile) {
      std::ifstream in(pathToFile, std::ifstream::binary);
      if (!in) {
         std::string error{"Cannot read-open file: "};
         error.append(pathToFile);
         return Result<std::vector<uint8_t>>{{}, error};
      }

      std::shared_ptr<void> fileCloser(nullptr, [&](void *) { // RAII file close
         if (in) {
            in.close();
         }
      }); //fileCloser RAII


      std::vector<char> contents;
      in.seekg(0, std::ios::end);
      auto end = in.tellg();
      in.seekg(0, std::ios::beg);

      // Attempt to read it the fastest way possible.
      if (-1 != end) {  // tellg() --> pos_type{-1} if reading the end failed.
         contents.resize(end);
         try {
            in.read(&contents[0], contents.size());
         } catch (std::iostream::failure& e) {
            std::string error{"Failed to read file: "};
            error += e.what();
            return Result<std::vector<uint8_t>>{{}, error};
         }
      } else {
         // Could not calculate with ifstream::tellg(). Is it a RAM file?
         // Fallback solution to slower iteratator approach
         contents.assign((std::istreambuf_iterator<char>(in)),
         (std::istreambuf_iterator<char>()));
      }

      // return copy of the read result.
      return Result<std::vector<uint8_t>>{{contents.begin(), contents.end()}};
   }


   /**
    * Reads content of Ascii file
    * @param pathToFile to read
    * @return Result<std::string> all the content of the file, and/or an error string 
    *         if something went wrong 
    */
{'fraction_non_alphanumeric': 0.13348256361922714, 'fraction_numerical': 0.0060084825636192276, 'mean_word_length': 2.4326728669632027, 'pattern_counts': {'":': 0, '<': 65, '<?xml version=': 0, '>': 69, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2304159', 'n_tokens_mistral': 2643, 'n_tokens_neox': 2568, 'n_words': 731}