/************************************************************************* ** FileSystem.cpp ** ** ** ** This file is part of dvisvgm -- the DVI to SVG converter ** ** Copyright (C) 2005-2013 Martin Gieseking ** ** ** ** This program is free software; you can redistribute it and/or ** ** modify it under the terms of the GNU General Public License as ** ** published by the Free Software Foundation; either version 3 of ** ** the License, or (at your option) any later version. ** ** ** ** This program is distributed in the hope that it will be useful, but ** ** WITHOUT ANY WARRANTY; without even the implied warranty of ** ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** ** GNU General Public License for more details. ** ** ** ** You should have received a copy of the GNU General Public License ** ** along with this program; if not, see . ** *************************************************************************/ #include #include #include #include "FileSystem.h" #include "macros.h" #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifdef HAVE_UNISTD_H #include #endif using namespace std; #ifdef __WIN32__ #include #include const char *FileSystem::DEVNULL = "nul"; const char FileSystem::PATHSEP = '\\'; #define unlink _unlink #else #include #include #include #include const char *FileSystem::DEVNULL = "/dev/null"; const char FileSystem::PATHSEP = '/'; #endif bool FileSystem::remove (const string &fname) { return unlink(fname.c_str()) == 0; } /** Copies a file. * @param[in] src path of file to copy * @param[in] dest path of target file * @param[in] remove_src remove file 'src' if true * @return true on success */ bool FileSystem::copy (const string &src, const string &dest, bool remove_src) { ifstream ifs(src.c_str(), ios::in|ios::binary); ofstream ofs(dest.c_str(), ios::out|ios::binary); if (ifs && ofs) { ofs << ifs.rdbuf(); if (!ifs.fail() && !ofs.fail() && remove_src) { ofs.close(); ifs.close(); return remove(src); } else return !remove_src; } return false; } bool FileSystem::rename (const string &oldname, const string &newname) { return ::rename(oldname.c_str(), newname.c_str()) == 0; } UInt64 FileSystem::filesize (const string &fname) { #ifdef __WIN32__ // unfortunately, stat doesn't work properly under Windows // so we have to use this freaky code WIN32_FILE_ATTRIBUTE_DATA attr; GetFileAttributesExA(fname.c_str(), GetFileExInfoStandard, &attr); return (static_cast(attr.nFileSizeHigh) << (8*sizeof(attr.nFileSizeLow))) | attr.nFileSizeLow; #else struct stat attr; return (stat(fname.c_str(), &attr) == 0) ? attr.st_size : 0; #endif } string FileSystem::adaptPathSeperators (string path) { for (size_t i=0; i < path.length(); i++) if (path[i] == PATHSEP) path[i] = '/'; return path; } string FileSystem::getcwd () { char buf[1024]; #ifdef __WIN32__ return adaptPathSeperators(_getcwd(buf, 1024)); #else return ::getcwd(buf, 1024); #endif } /** Changes the work directory. * @param[in] path to new work directory * @return true on success */ bool FileSystem::chdir (const char *dir) { bool success = false; if (dir) { #ifdef __WIN32__ success = (_chdir(dir) == 0); #else success = (chdir(dir) == 0); #endif } return success; } /** Returns the user's home directory. */ const char* FileSystem::userdir () { #ifdef __WIN32__ const char *drive=getenv("HOMEDRIVE"); const char *path=getenv("HOMEPATH"); if (drive && path) { static string ret = string(drive)+path; if (!ret.empty()) return ret.c_str(); } return 0; #else const char *dir=getenv("HOME"); if (!dir) { if (const char *user=getenv("USER")) { if (struct passwd *pw=getpwnam(user)) dir = pw->pw_dir; } } return dir; #endif } /** Private wrapper function for mkdir: creates a single folder. * @param[in] dir folder name * @return true on success */ static bool s_mkdir (const char *dir) { bool success = true; if (!FileSystem::exists(dir)) { #ifdef __WIN32__ success = (_mkdir(dir) == 0); #else success = (mkdir(dir, 0776) == 0); #endif } return success; } static bool inline s_rmdir (const char *dir) { #ifdef __WIN32__ return (_rmdir(dir) == 0); #else return (rmdir(dir) == 0); #endif } /** Removes leading and trailing whitespace from a string. */ static string trim (const string &str) { int first=0, last=str.length()-1; while (isspace(str[first])) first++; while (isspace(str[last])) last--; return str.substr(first, last-first+1); } /** Creates a new folder relative to the current work directory. If necessary, * the parent folders are also created. * @param[in] dir single folder name or path to folder * @return true if folder(s) could be created */ bool FileSystem::mkdir (const char *dir) { bool success = false; if (dir) { success = true; const string dirstr = adaptPathSeperators(trim(dir)); for (size_t pos=1; success && (pos = dirstr.find('/', pos)) != string::npos; pos++) success &= s_mkdir(dirstr.substr(0, pos).c_str()); success &= s_mkdir(dirstr.c_str()); } return success; } /** Removes a directory and its contents. * @param[in] dirname path to directory * @return true on success */ bool FileSystem::rmdir (const char *dirname) { bool ok = false; if (dirname && isDirectory(dirname)) { ok = true; #ifdef __WIN32__ string pattern = string(dirname) + "/*"; WIN32_FIND_DATA data; HANDLE h = FindFirstFile(pattern.c_str(), &data); bool ready = (h == INVALID_HANDLE_VALUE); while (!ready && ok) { const char *fname = data.cFileName; string path = string(dirname) + "/" + fname; if (isDirectory(path.c_str())) { if (strcmp(fname, ".") != 0 && strcmp(fname, "..") != 0) ok = rmdir(path.c_str()) && s_rmdir(path.c_str()); } else if (isFile(path.c_str())) ok = remove(path); else ok = false; ready = !FindNextFile(h, &data); } FindClose(h); #else if (DIR *dir = opendir(dirname)) { struct dirent *ent; while ((ent = readdir(dir)) && ok) { const char *fname = ent->d_name; string path = string(fname) + "/" + fname; if (isDirectory(path.c_str())) { if (strcmp(fname, ".") != 0 && strcmp(fname, "..") != 0) ok = rmdir(path.c_str()) && s_rmdir(path.c_str()); } else if (isFile(path.c_str())) ok = remove(path); else ok = false; } closedir(dir); } #endif ok = s_rmdir(dirname); } return ok; } /** Checks if a file or directory exits. */ bool FileSystem::exists (const char *fname) { if (!fname) return false; #ifdef __WIN32__ return GetFileAttributes(fname) != INVALID_FILE_ATTRIBUTES; #else struct stat attr; return stat(fname, &attr) == 0; #endif } /** Returns true if 'fname' references a directory. */ bool FileSystem::isDirectory (const char *fname) { if (!fname) return false; #ifdef __WIN32__ return GetFileAttributes(fname) & FILE_ATTRIBUTE_DIRECTORY; #else struct stat attr; return stat(fname, &attr) == 0 && S_ISDIR(attr.st_mode); #endif } /** Returns true if 'fname' references a file. */ bool FileSystem::isFile (const char *fname) { if (!fname) return false; #ifdef __WIN32__ ifstream ifs(fname); return ifs; #else struct stat attr; return stat(fname, &attr) == 0 && S_ISREG(attr.st_mode); #endif } int FileSystem::collect (const char *dirname, vector &entries) { entries.clear(); #ifdef __WIN32__ string pattern = string(dirname) + "/*"; WIN32_FIND_DATA data; HANDLE h = FindFirstFile(pattern.c_str(), &data); bool ready = (h == INVALID_HANDLE_VALUE); while (!ready) { string fname = data.cFileName; string path = string(dirname)+"/"+fname; string typechar = isFile(path.c_str()) ? "f" : isDirectory(path.c_str()) ? "d" : "?"; if (fname != "." && fname != "..") entries.push_back(typechar+fname); ready = !FindNextFile(h, &data); } FindClose(h); #else if (DIR *dir = opendir(dirname)) { struct dirent *ent; while ((ent = readdir(dir))) { string fname = ent->d_name; string path = string(dirname)+"/"+fname; string typechar = isFile(path.c_str()) ? "f" : isDirectory(path.c_str()) ? "d" : "?"; if (fname != "." && fname != "..") entries.push_back(typechar+fname); } closedir(dir); } #endif return entries.size(); }