LCOV - code coverage report
Current view: top level - src - filesys.cpp (source / functions) Hit Total Coverage
Test: report Lines: 79 280 28.2 %
Date: 2015-07-11 18:23:49 Functions: 10 23 43.5 %

          Line data    Source code
       1             : /*
       2             : Minetest
       3             : Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
       4             : 
       5             : This program is free software; you can redistribute it and/or modify
       6             : it under the terms of the GNU Lesser General Public License as published by
       7             : the Free Software Foundation; either version 2.1 of the License, or
       8             : (at your option) any later version.
       9             : 
      10             : This program is distributed in the hope that it will be useful,
      11             : but WITHOUT ANY WARRANTY; without even the implied warranty of
      12             : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      13             : GNU Lesser General Public License for more details.
      14             : 
      15             : You should have received a copy of the GNU Lesser General Public License along
      16             : with this program; if not, write to the Free Software Foundation, Inc.,
      17             : 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
      18             : */
      19             : 
      20             : #include "filesys.h"
      21             : #include "util/string.h"
      22             : #include <iostream>
      23             : #include <stdio.h>
      24             : #include <string.h>
      25             : #include <errno.h>
      26             : #include <fstream>
      27             : #include "log.h"
      28             : #include "config.h"
      29             : 
      30             : namespace fs
      31             : {
      32             : 
      33             : #ifdef _WIN32 // WINDOWS
      34             : 
      35             : #define _WIN32_WINNT 0x0501
      36             : #include <windows.h>
      37             : #include <shlwapi.h>
      38             : 
      39             : std::vector<DirListNode> GetDirListing(const std::string &pathstring)
      40             : {
      41             :         std::vector<DirListNode> listing;
      42             : 
      43             :         WIN32_FIND_DATA FindFileData;
      44             :         HANDLE hFind = INVALID_HANDLE_VALUE;
      45             :         DWORD dwError;
      46             : 
      47             :         std::string dirSpec = pathstring + "\\*";
      48             : 
      49             :         // Find the first file in the directory.
      50             :         hFind = FindFirstFile(dirSpec.c_str(), &FindFileData);
      51             : 
      52             :         if (hFind == INVALID_HANDLE_VALUE) {
      53             :                 dwError = GetLastError();
      54             :                 if (dwError != ERROR_FILE_NOT_FOUND && dwError != ERROR_PATH_NOT_FOUND) {
      55             :                         errorstream << "GetDirListing: FindFirstFile error."
      56             :                                         << " Error is " << dwError << std::endl;
      57             :                 }
      58             :         } else {
      59             :                 // NOTE:
      60             :                 // Be very sure to not include '..' in the results, it will
      61             :                 // result in an epic failure when deleting stuff.
      62             : 
      63             :                 DirListNode node;
      64             :                 node.name = FindFileData.cFileName;
      65             :                 node.dir = FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
      66             :                 if (node.name != "." && node.name != "..")
      67             :                         listing.push_back(node);
      68             : 
      69             :                 // List all the other files in the directory.
      70             :                 while (FindNextFile(hFind, &FindFileData) != 0) {
      71             :                         DirListNode node;
      72             :                         node.name = FindFileData.cFileName;
      73             :                         node.dir = FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
      74             :                         if(node.name != "." && node.name != "..")
      75             :                                 listing.push_back(node);
      76             :                 }
      77             : 
      78             :                 dwError = GetLastError();
      79             :                 FindClose(hFind);
      80             :                 if (dwError != ERROR_NO_MORE_FILES) {
      81             :                         errorstream << "GetDirListing: FindNextFile error."
      82             :                                         << " Error is " << dwError << std::endl;
      83             :                         listing.clear();
      84             :                         return listing;
      85             :                 }
      86             :         }
      87             :         return listing;
      88             : }
      89             : 
      90             : bool CreateDir(const std::string &path)
      91             : {
      92             :         bool r = CreateDirectory(path.c_str(), NULL);
      93             :         if(r == true)
      94             :                 return true;
      95             :         if(GetLastError() == ERROR_ALREADY_EXISTS)
      96             :                 return true;
      97             :         return false;
      98             : }
      99             : 
     100             : bool PathExists(const std::string &path)
     101             : {
     102             :         return (GetFileAttributes(path.c_str()) != INVALID_FILE_ATTRIBUTES);
     103             : }
     104             : 
     105             : bool IsPathAbsolute(const std::string &path)
     106             : {
     107             :         return !PathIsRelative(path.c_str());
     108             : }
     109             : 
     110             : bool IsDir(const std::string &path)
     111             : {
     112             :         DWORD attr = GetFileAttributes(path.c_str());
     113             :         return (attr != INVALID_FILE_ATTRIBUTES &&
     114             :                         (attr & FILE_ATTRIBUTE_DIRECTORY));
     115             : }
     116             : 
     117             : bool IsDirDelimiter(char c)
     118             : {
     119             :         return c == '/' || c == '\\';
     120             : }
     121             : 
     122             : bool RecursiveDelete(const std::string &path)
     123             : {
     124             :         infostream<<"Recursively deleting \""<<path<<"\""<<std::endl;
     125             : 
     126             :         DWORD attr = GetFileAttributes(path.c_str());
     127             :         bool is_directory = (attr != INVALID_FILE_ATTRIBUTES &&
     128             :                         (attr & FILE_ATTRIBUTE_DIRECTORY));
     129             :         if(!is_directory)
     130             :         {
     131             :                 infostream<<"RecursiveDelete: Deleting file "<<path<<std::endl;
     132             :                 //bool did = DeleteFile(path.c_str());
     133             :                 bool did = true;
     134             :                 if(!did){
     135             :                         errorstream<<"RecursiveDelete: Failed to delete file "
     136             :                                         <<path<<std::endl;
     137             :                         return false;
     138             :                 }
     139             :         }
     140             :         else
     141             :         {
     142             :                 infostream<<"RecursiveDelete: Deleting content of directory "
     143             :                                 <<path<<std::endl;
     144             :                 std::vector<DirListNode> content = GetDirListing(path);
     145             :                 for(int i=0; i<content.size(); i++){
     146             :                         const DirListNode &n = content[i];
     147             :                         std::string fullpath = path + DIR_DELIM + n.name;
     148             :                         bool did = RecursiveDelete(fullpath);
     149             :                         if(!did){
     150             :                                 errorstream<<"RecursiveDelete: Failed to recurse to "
     151             :                                                 <<fullpath<<std::endl;
     152             :                                 return false;
     153             :                         }
     154             :                 }
     155             :                 infostream<<"RecursiveDelete: Deleting directory "<<path<<std::endl;
     156             :                 //bool did = RemoveDirectory(path.c_str();
     157             :                 bool did = true;
     158             :                 if(!did){
     159             :                         errorstream<<"Failed to recursively delete directory "
     160             :                                         <<path<<std::endl;
     161             :                         return false;
     162             :                 }
     163             :         }
     164             :         return true;
     165             : }
     166             : 
     167             : bool DeleteSingleFileOrEmptyDirectory(const std::string &path)
     168             : {
     169             :         DWORD attr = GetFileAttributes(path.c_str());
     170             :         bool is_directory = (attr != INVALID_FILE_ATTRIBUTES &&
     171             :                         (attr & FILE_ATTRIBUTE_DIRECTORY));
     172             :         if(!is_directory)
     173             :         {
     174             :                 bool did = DeleteFile(path.c_str());
     175             :                 return did;
     176             :         }
     177             :         else
     178             :         {
     179             :                 bool did = RemoveDirectory(path.c_str());
     180             :                 return did;
     181             :         }
     182             : }
     183             : 
     184             : std::string TempPath()
     185             : {
     186             :         DWORD bufsize = GetTempPath(0, "");
     187             :         if(bufsize == 0){
     188             :                 errorstream<<"GetTempPath failed, error = "<<GetLastError()<<std::endl;
     189             :                 return "";
     190             :         }
     191             :         std::vector<char> buf(bufsize);
     192             :         DWORD len = GetTempPath(bufsize, &buf[0]);
     193             :         if(len == 0 || len > bufsize){
     194             :                 errorstream<<"GetTempPath failed, error = "<<GetLastError()<<std::endl;
     195             :                 return "";
     196             :         }
     197             :         return std::string(buf.begin(), buf.begin() + len);
     198             : }
     199             : 
     200             : #else // POSIX
     201             : 
     202             : #include <sys/types.h>
     203             : #include <dirent.h>
     204             : #include <sys/stat.h>
     205             : #include <sys/wait.h>
     206             : #include <unistd.h>
     207             : 
     208           5 : std::vector<DirListNode> GetDirListing(const std::string &pathstring)
     209             : {
     210           5 :         std::vector<DirListNode> listing;
     211             : 
     212             :         DIR *dp;
     213             :         struct dirent *dirp;
     214           5 :         if((dp = opendir(pathstring.c_str())) == NULL) {
     215             :                 //infostream<<"Error("<<errno<<") opening "<<pathstring<<std::endl;
     216           0 :                 return listing;
     217             :         }
     218             : 
     219          35 :         while ((dirp = readdir(dp)) != NULL) {
     220             :                 // NOTE:
     221             :                 // Be very sure to not include '..' in the results, it will
     222             :                 // result in an epic failure when deleting stuff.
     223          15 :                 if(strcmp(dirp->d_name, ".") == 0 || strcmp(dirp->d_name, "..") == 0)
     224          20 :                         continue;
     225             : 
     226          10 :                 DirListNode node;
     227           5 :                 node.name = dirp->d_name;
     228             : 
     229           5 :                 int isdir = -1; // -1 means unknown
     230             : 
     231             :                 /*
     232             :                         POSIX doesn't define d_type member of struct dirent and
     233             :                         certain filesystems on glibc/Linux will only return
     234             :                         DT_UNKNOWN for the d_type member.
     235             : 
     236             :                         Also we don't know whether symlinks are directories or not.
     237             :                 */
     238             : #ifdef _DIRENT_HAVE_D_TYPE
     239           5 :                 if(dirp->d_type != DT_UNKNOWN && dirp->d_type != DT_LNK)
     240           4 :                         isdir = (dirp->d_type == DT_DIR);
     241             : #endif /* _DIRENT_HAVE_D_TYPE */
     242             : 
     243             :                 /*
     244             :                         Was d_type DT_UNKNOWN, DT_LNK or nonexistent?
     245             :                         If so, try stat().
     246             :                 */
     247           5 :                 if(isdir == -1) {
     248             :                         struct stat statbuf;
     249           1 :                         if (stat((pathstring + "/" + node.name).c_str(), &statbuf))
     250           0 :                                 continue;
     251           1 :                         isdir = ((statbuf.st_mode & S_IFDIR) == S_IFDIR);
     252             :                 }
     253           5 :                 node.dir = isdir;
     254           5 :                 listing.push_back(node);
     255             :         }
     256           5 :         closedir(dp);
     257             : 
     258           5 :         return listing;
     259             : }
     260             : 
     261          13 : bool CreateDir(const std::string &path)
     262             : {
     263          13 :         int r = mkdir(path.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
     264          13 :         if(r == 0)
     265             :         {
     266           0 :                 return true;
     267             :         }
     268             :         else
     269             :         {
     270             :                 // If already exists, return true
     271          13 :                 if(errno == EEXIST)
     272          13 :                         return true;
     273           0 :                 return false;
     274             :         }
     275             : }
     276             : 
     277       58564 : bool PathExists(const std::string &path)
     278             : {
     279             :         struct stat st;
     280       58564 :         return (stat(path.c_str(),&st) == 0);
     281             : }
     282             : 
     283           0 : bool IsPathAbsolute(const std::string &path)
     284             : {
     285           0 :         return path[0] == '/';
     286             : }
     287             : 
     288           1 : bool IsDir(const std::string &path)
     289             : {
     290             :         struct stat statbuf;
     291           1 :         if(stat(path.c_str(), &statbuf))
     292           0 :                 return false; // Actually error; but certainly not a directory
     293           1 :         return ((statbuf.st_mode & S_IFDIR) == S_IFDIR);
     294             : }
     295             : 
     296         137 : bool IsDirDelimiter(char c)
     297             : {
     298         137 :         return c == '/';
     299             : }
     300             : 
     301           0 : bool RecursiveDelete(const std::string &path)
     302             : {
     303             :         /*
     304             :                 Execute the 'rm' command directly, by fork() and execve()
     305             :         */
     306             : 
     307           0 :         infostream<<"Removing \""<<path<<"\""<<std::endl;
     308             : 
     309             :         //return false;
     310             : 
     311           0 :         pid_t child_pid = fork();
     312             : 
     313           0 :         if(child_pid == 0)
     314             :         {
     315             :                 // Child
     316             :                 char argv_data[3][10000];
     317           0 :                 strcpy(argv_data[0], "/bin/rm");
     318           0 :                 strcpy(argv_data[1], "-rf");
     319           0 :                 strncpy(argv_data[2], path.c_str(), 10000);
     320             :                 char *argv[4];
     321           0 :                 argv[0] = argv_data[0];
     322           0 :                 argv[1] = argv_data[1];
     323           0 :                 argv[2] = argv_data[2];
     324           0 :                 argv[3] = NULL;
     325             : 
     326           0 :                 verbosestream<<"Executing '"<<argv[0]<<"' '"<<argv[1]<<"' '"
     327           0 :                                 <<argv[2]<<"'"<<std::endl;
     328             : 
     329           0 :                 execv(argv[0], argv);
     330             : 
     331             :                 // Execv shouldn't return. Failed.
     332           0 :                 _exit(1);
     333             :         }
     334             :         else
     335             :         {
     336             :                 // Parent
     337             :                 int child_status;
     338             :                 pid_t tpid;
     339           0 :                 do{
     340           0 :                         tpid = wait(&child_status);
     341             :                         //if(tpid != child_pid) process_terminated(tpid);
     342           0 :                 }while(tpid != child_pid);
     343           0 :                 return (child_status == 0);
     344             :         }
     345             : }
     346             : 
     347           0 : bool DeleteSingleFileOrEmptyDirectory(const std::string &path)
     348             : {
     349           0 :         if(IsDir(path)){
     350           0 :                 bool did = (rmdir(path.c_str()) == 0);
     351           0 :                 if(!did)
     352           0 :                         errorstream<<"rmdir errno: "<<errno<<": "<<strerror(errno)
     353           0 :                                         <<std::endl;
     354           0 :                 return did;
     355             :         } else {
     356           0 :                 bool did = (unlink(path.c_str()) == 0);
     357           0 :                 if(!did)
     358           0 :                         errorstream<<"unlink errno: "<<errno<<": "<<strerror(errno)
     359           0 :                                         <<std::endl;
     360           0 :                 return did;
     361             :         }
     362             : }
     363             : 
     364           0 : std::string TempPath()
     365             : {
     366             :         /*
     367             :                 Should the environment variables TMPDIR, TMP and TEMP
     368             :                 and the macro P_tmpdir (if defined by stdio.h) be checked
     369             :                 before falling back on /tmp?
     370             : 
     371             :                 Probably not, because this function is intended to be
     372             :                 compatible with lua's os.tmpname which under the default
     373             :                 configuration hardcodes mkstemp("/tmp/lua_XXXXXX").
     374             :         */
     375             : #ifdef __ANDROID__
     376             :         return DIR_DELIM "sdcard" DIR_DELIM PROJECT_NAME DIR_DELIM "tmp";
     377             : #else
     378           0 :         return DIR_DELIM "tmp";
     379             : #endif
     380             : }
     381             : 
     382             : #endif
     383             : 
     384           0 : void GetRecursiveSubPaths(const std::string &path, std::vector<std::string> &dst)
     385             : {
     386           0 :         std::vector<DirListNode> content = GetDirListing(path);
     387           0 :         for(unsigned int  i=0; i<content.size(); i++){
     388           0 :                 const DirListNode &n = content[i];
     389           0 :                 std::string fullpath = path + DIR_DELIM + n.name;
     390           0 :                 dst.push_back(fullpath);
     391           0 :                 if (n.dir) {
     392           0 :                         GetRecursiveSubPaths(fullpath, dst);
     393             :                 }
     394             :         }
     395           0 : }
     396             : 
     397           0 : bool DeletePaths(const std::vector<std::string> &paths)
     398             : {
     399           0 :         bool success = true;
     400             :         // Go backwards to succesfully delete the output of GetRecursiveSubPaths
     401           0 :         for(int i=paths.size()-1; i>=0; i--){
     402           0 :                 const std::string &path = paths[i];
     403           0 :                 bool did = DeleteSingleFileOrEmptyDirectory(path);
     404           0 :                 if(!did){
     405           0 :                         errorstream<<"Failed to delete "<<path<<std::endl;
     406           0 :                         success = false;
     407             :                 }
     408             :         }
     409           0 :         return success;
     410             : }
     411             : 
     412           0 : bool RecursiveDeleteContent(const std::string &path)
     413             : {
     414           0 :         infostream<<"Removing content of \""<<path<<"\""<<std::endl;
     415           0 :         std::vector<DirListNode> list = GetDirListing(path);
     416           0 :         for(unsigned int i=0; i<list.size(); i++)
     417             :         {
     418           0 :                 if(trim(list[i].name) == "." || trim(list[i].name) == "..")
     419           0 :                         continue;
     420           0 :                 std::string childpath = path + DIR_DELIM + list[i].name;
     421           0 :                 bool r = RecursiveDelete(childpath);
     422           0 :                 if(r == false)
     423             :                 {
     424           0 :                         errorstream<<"Removing \""<<childpath<<"\" failed"<<std::endl;
     425           0 :                         return false;
     426             :                 }
     427             :         }
     428           0 :         return true;
     429             : }
     430             : 
     431         150 : bool CreateAllDirs(const std::string &path)
     432             : {
     433             : 
     434         300 :         std::vector<std::string> tocreate;
     435         300 :         std::string basepath = path;
     436         150 :         while(!PathExists(basepath))
     437             :         {
     438           0 :                 tocreate.push_back(basepath);
     439           0 :                 basepath = RemoveLastPathComponent(basepath);
     440           0 :                 if(basepath.empty())
     441           0 :                         break;
     442             :         }
     443         150 :         for(int i=tocreate.size()-1;i>=0;i--)
     444           0 :                 if(!CreateDir(tocreate[i]))
     445           0 :                         return false;
     446         150 :         return true;
     447             : }
     448             : 
     449           0 : bool CopyFileContents(const std::string &source, const std::string &target)
     450             : {
     451           0 :         FILE *sourcefile = fopen(source.c_str(), "rb");
     452           0 :         if(sourcefile == NULL){
     453           0 :                 errorstream<<source<<": can't open for reading: "
     454           0 :                         <<strerror(errno)<<std::endl;
     455           0 :                 return false;
     456             :         }
     457             : 
     458           0 :         FILE *targetfile = fopen(target.c_str(), "wb");
     459           0 :         if(targetfile == NULL){
     460           0 :                 errorstream<<target<<": can't open for writing: "
     461           0 :                         <<strerror(errno)<<std::endl;
     462           0 :                 fclose(sourcefile);
     463           0 :                 return false;
     464             :         }
     465             : 
     466           0 :         size_t total = 0;
     467           0 :         bool retval = true;
     468           0 :         bool done = false;
     469             :         char readbuffer[BUFSIZ];
     470           0 :         while(!done){
     471             :                 size_t readbytes = fread(readbuffer, 1,
     472           0 :                                 sizeof(readbuffer), sourcefile);
     473           0 :                 total += readbytes;
     474           0 :                 if(ferror(sourcefile)){
     475           0 :                         errorstream<<source<<": IO error: "
     476           0 :                                 <<strerror(errno)<<std::endl;
     477           0 :                         retval = false;
     478           0 :                         done = true;
     479             :                 }
     480           0 :                 if(readbytes > 0){
     481           0 :                         fwrite(readbuffer, 1, readbytes, targetfile);
     482             :                 }
     483           0 :                 if(feof(sourcefile) || ferror(sourcefile)){
     484             :                         // flush destination file to catch write errors
     485             :                         // (e.g. disk full)
     486           0 :                         fflush(targetfile);
     487           0 :                         done = true;
     488             :                 }
     489           0 :                 if(ferror(targetfile)){
     490           0 :                         errorstream<<target<<": IO error: "
     491           0 :                                         <<strerror(errno)<<std::endl;
     492           0 :                         retval = false;
     493           0 :                         done = true;
     494             :                 }
     495             :         }
     496           0 :         infostream<<"copied "<<total<<" bytes from "
     497           0 :                 <<source<<" to "<<target<<std::endl;
     498           0 :         fclose(sourcefile);
     499           0 :         fclose(targetfile);
     500           0 :         return retval;
     501             : }
     502             : 
     503           0 : bool CopyDir(const std::string &source, const std::string &target)
     504             : {
     505           0 :         if(PathExists(source)){
     506           0 :                 if(!PathExists(target)){
     507           0 :                         fs::CreateAllDirs(target);
     508             :                 }
     509           0 :                 bool retval = true;
     510           0 :                 std::vector<DirListNode> content = fs::GetDirListing(source);
     511             : 
     512           0 :                 for(unsigned int i=0; i < content.size(); i++){
     513           0 :                         std::string sourcechild = source + DIR_DELIM + content[i].name;
     514           0 :                         std::string targetchild = target + DIR_DELIM + content[i].name;
     515           0 :                         if(content[i].dir){
     516           0 :                                 if(!fs::CopyDir(sourcechild, targetchild)){
     517           0 :                                         retval = false;
     518             :                                 }
     519             :                         }
     520             :                         else {
     521           0 :                                 if(!fs::CopyFileContents(sourcechild, targetchild)){
     522           0 :                                         retval = false;
     523             :                                 }
     524             :                         }
     525             :                 }
     526           0 :                 return retval;
     527             :         }
     528             :         else {
     529           0 :                 return false;
     530             :         }
     531             : }
     532             : 
     533           0 : bool PathStartsWith(const std::string &path, const std::string &prefix)
     534             : {
     535           0 :         size_t pathsize = path.size();
     536           0 :         size_t pathpos = 0;
     537           0 :         size_t prefixsize = prefix.size();
     538           0 :         size_t prefixpos = 0;
     539           0 :         for(;;){
     540             :                 bool delim1 = pathpos == pathsize
     541           0 :                         || IsDirDelimiter(path[pathpos]);
     542             :                 bool delim2 = prefixpos == prefixsize
     543           0 :                         || IsDirDelimiter(prefix[prefixpos]);
     544             : 
     545           0 :                 if(delim1 != delim2)
     546           0 :                         return false;
     547             : 
     548           0 :                 if(delim1){
     549           0 :                         while(pathpos < pathsize &&
     550           0 :                                         IsDirDelimiter(path[pathpos]))
     551           0 :                                 ++pathpos;
     552           0 :                         while(prefixpos < prefixsize &&
     553           0 :                                         IsDirDelimiter(prefix[prefixpos]))
     554           0 :                                 ++prefixpos;
     555           0 :                         if(prefixpos == prefixsize)
     556           0 :                                 return true;
     557           0 :                         if(pathpos == pathsize)
     558           0 :                                 return false;
     559             :                 }
     560             :                 else{
     561           0 :                         size_t len = 0;
     562           0 :                         do{
     563           0 :                                 char pathchar = path[pathpos+len];
     564           0 :                                 char prefixchar = prefix[prefixpos+len];
     565             :                                 if(FILESYS_CASE_INSENSITIVE){
     566             :                                         pathchar = tolower(pathchar);
     567             :                                         prefixchar = tolower(prefixchar);
     568             :                                 }
     569           0 :                                 if(pathchar != prefixchar)
     570           0 :                                         return false;
     571           0 :                                 ++len;
     572           0 :                         } while(pathpos+len < pathsize
     573           0 :                                         && !IsDirDelimiter(path[pathpos+len])
     574           0 :                                         && prefixpos+len < prefixsize
     575           0 :                                         && !IsDirDelimiter(
     576           0 :                                                 prefix[prefixpos+len]));
     577           0 :                         pathpos += len;
     578           0 :                         prefixpos += len;
     579             :                 }
     580             :         }
     581             : }
     582             : 
     583           0 : std::string RemoveLastPathComponent(const std::string &path,
     584             :                 std::string *removed, int count)
     585             : {
     586           0 :         if(removed)
     587           0 :                 *removed = "";
     588             : 
     589           0 :         size_t remaining = path.size();
     590             : 
     591           0 :         for(int i = 0; i < count; ++i){
     592             :                 // strip a dir delimiter
     593           0 :                 while(remaining != 0 && IsDirDelimiter(path[remaining-1]))
     594           0 :                         remaining--;
     595             :                 // strip a path component
     596           0 :                 size_t component_end = remaining;
     597           0 :                 while(remaining != 0 && !IsDirDelimiter(path[remaining-1]))
     598           0 :                         remaining--;
     599           0 :                 size_t component_start = remaining;
     600             :                 // strip a dir delimiter
     601           0 :                 while(remaining != 0 && IsDirDelimiter(path[remaining-1]))
     602           0 :                         remaining--;
     603           0 :                 if(removed){
     604             :                         std::string component = path.substr(component_start,
     605           0 :                                         component_end - component_start);
     606           0 :                         if(i)
     607           0 :                                 *removed = component + DIR_DELIM + *removed;
     608             :                         else
     609           0 :                                 *removed = component;
     610             :                 }
     611             :         }
     612           0 :         return path.substr(0, remaining);
     613             : }
     614             : 
     615           3 : std::string RemoveRelativePathComponents(std::string path)
     616             : {
     617           3 :         size_t pos = path.size();
     618           3 :         size_t dotdot_count = 0;
     619          39 :         while(pos != 0){
     620          18 :                 size_t component_with_delim_end = pos;
     621             :                 // skip a dir delimiter
     622          48 :                 while(pos != 0 && IsDirDelimiter(path[pos-1]))
     623          15 :                         pos--;
     624             :                 // strip a path component
     625          18 :                 size_t component_end = pos;
     626         188 :                 while(pos != 0 && !IsDirDelimiter(path[pos-1]))
     627          85 :                         pos--;
     628          18 :                 size_t component_start = pos;
     629             : 
     630             :                 std::string component = path.substr(component_start,
     631          36 :                                 component_end - component_start);
     632          18 :                 bool remove_this_component = false;
     633          18 :                 if(component == "."){
     634           0 :                         remove_this_component = true;
     635             :                 }
     636          18 :                 else if(component == ".."){
     637           1 :                         remove_this_component = true;
     638           1 :                         dotdot_count += 1;
     639             :                 }
     640          17 :                 else if(dotdot_count != 0){
     641           1 :                         remove_this_component = true;
     642           1 :                         dotdot_count -= 1;
     643             :                 }
     644             : 
     645          18 :                 if(remove_this_component){
     646           6 :                         while(pos != 0 && IsDirDelimiter(path[pos-1]))
     647           2 :                                 pos--;
     648           4 :                         path = path.substr(0, pos) + DIR_DELIM +
     649           4 :                                 path.substr(component_with_delim_end,
     650           2 :                                                 std::string::npos);
     651           2 :                         pos++;
     652             :                 }
     653             :         }
     654             : 
     655           3 :         if(dotdot_count > 0)
     656           0 :                 return "";
     657             : 
     658             :         // remove trailing dir delimiters
     659           3 :         pos = path.size();
     660           3 :         while(pos != 0 && IsDirDelimiter(path[pos-1]))
     661           0 :                 pos--;
     662           3 :         return path.substr(0, pos);
     663             : }
     664             : 
     665           0 : std::string AbsolutePath(const std::string &path)
     666             : {
     667             : #ifdef _WIN32
     668             :         char *abs_path = _fullpath(NULL, path.c_str(), MAX_PATH);
     669             : #else
     670           0 :         char *abs_path = realpath(path.c_str(), NULL);
     671             : #endif
     672           0 :         if (!abs_path) return "";
     673           0 :         std::string abs_path_str(abs_path);
     674           0 :         free(abs_path);
     675           0 :         return abs_path_str;
     676             : }
     677             : 
     678           0 : const char *GetFilenameFromPath(const char *path)
     679             : {
     680           0 :         const char *filename = strrchr(path, DIR_DELIM_CHAR);
     681           0 :         return filename ? filename + 1 : path;
     682             : }
     683             : 
     684           2 : bool safeWriteToFile(const std::string &path, const std::string &content)
     685             : {
     686           4 :         std::string tmp_file = path + ".~mt";
     687             : 
     688             :         // Write to a tmp file
     689           4 :         std::ofstream os(tmp_file.c_str(), std::ios::binary);
     690           2 :         if (!os.good())
     691           0 :                 return false;
     692           2 :         os << content;
     693           2 :         os.flush();
     694           2 :         os.close();
     695           2 :         if (os.fail()) {
     696           0 :                 remove(tmp_file.c_str());
     697           0 :                 return false;
     698             :         }
     699             : 
     700             :         // Copy file
     701           2 :         remove(path.c_str());
     702           2 :         if(rename(tmp_file.c_str(), path.c_str())) {
     703           0 :                 remove(tmp_file.c_str());
     704           0 :                 return false;
     705             :         } else {
     706           2 :                 return true;
     707             :         }
     708             : }
     709             : 
     710           3 : } // namespace fs
     711             : 

Generated by: LCOV version 1.11