/* Minetest Copyright (C) 2013 celeron55, Perttu Ahola This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "filesys.h" #include "strfnd.h" #include #include #include #include #include "log.h" namespace fs { #ifdef _WIN32 // WINDOWS #define _WIN32_WINNT 0x0501 #include #include #include #include #define BUFSIZE MAX_PATH std::vector GetDirListing(std::string pathstring) { std::vector listing; WIN32_FIND_DATA FindFileData; HANDLE hFind = INVALID_HANDLE_VALUE; DWORD dwError; LPTSTR DirSpec; INT retval; DirSpec = (LPTSTR) malloc (BUFSIZE); if( DirSpec == NULL ) { errorstream<<"GetDirListing: Insufficient memory available"< (BUFSIZE - 2)) { errorstream<<"GetDirListing: Input directory is too large."< content = GetDirListing(path); for(int i=0; i buf(bufsize); DWORD len = GetTempPath(bufsize, &buf[0]); if(len == 0 || len > bufsize){ errorstream<<"GetTempPath failed, error = "< #include #include #include #include std::vector GetDirListing(std::string pathstring) { std::vector listing; DIR *dp; struct dirent *dirp; if((dp = opendir(pathstring.c_str())) == NULL) { //infostream<<"Error("<d_name[0]!='.'){ DirListNode node; node.name = dirp->d_name; if(node.name == "." || node.name == "..") continue; int isdir = -1; // -1 means unknown /* POSIX doesn't define d_type member of struct dirent and certain filesystems on glibc/Linux will only return DT_UNKNOWN for the d_type member. Also we don't know whether symlinks are directories or not. */ #ifdef _DIRENT_HAVE_D_TYPE if(dirp->d_type != DT_UNKNOWN && dirp->d_type != DT_LNK) isdir = (dirp->d_type == DT_DIR); #endif /* _DIRENT_HAVE_D_TYPE */ /* Was d_type DT_UNKNOWN, DT_LNK or nonexistent? If so, try stat(). */ if(isdir == -1) { struct stat statbuf; if (stat((pathstring + "/" + node.name).c_str(), &statbuf)) continue; isdir = ((statbuf.st_mode & S_IFDIR) == S_IFDIR); } node.dir = isdir; listing.push_back(node); } } closedir(dp); return listing; } bool CreateDir(std::string path) { int r = mkdir(path.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); if(r == 0) { return true; } else { // If already exists, return true if(errno == EEXIST) return true; return false; } } bool PathExists(std::string path) { struct stat st; return (stat(path.c_str(),&st) == 0); } bool IsDir(std::string path) { struct stat statbuf; if(stat(path.c_str(), &statbuf)) return false; // Actually error; but certainly not a directory return ((statbuf.st_mode & S_IFDIR) == S_IFDIR); } bool IsDirDelimiter(char c) { return c == '/'; } bool RecursiveDelete(std::string path) { /* Execute the 'rm' command directly, by fork() and execve() */ infostream<<"Removing \""< &dst) { std::vector content = GetDirListing(path); for(unsigned int i=0; i &paths) { bool success = true; // Go backwards to succesfully delete the output of GetRecursiveSubPaths for(int i=paths.size()-1; i>=0; i--){ const std::string &path = paths[i]; bool did = DeleteSingleFileOrEmptyDirectory(path); if(!did){ errorstream<<"Failed to delete "< list = GetDirListing(path); for(unsigned int i=0; i tocreate; std::string basepath = path; while(!PathExists(basepath)) { tocreate.push_back(basepath); basepath = RemoveLastPathComponent(basepath); if(basepath.empty()) break; } for(int i=tocreate.size()-1;i>=0;i--) if(!CreateDir(tocreate[i])) return false; return true; } bool CopyFileContents(std::string source, std::string target) { FILE *sourcefile = fopen(source.c_str(), "rb"); if(sourcefile == NULL){ errorstream< 0){ fwrite(readbuffer, 1, readbytes, targetfile); } if(feof(sourcefile) || ferror(sourcefile)){ // flush destination file to catch write errors // (e.g. disk full) fflush(targetfile); done = true; } if(ferror(targetfile)){ errorstream< content = fs::GetDirListing(source); for(unsigned int i=0; i < content.size(); i++){ std::string sourcechild = source + DIR_DELIM + content[i].name; std::string targetchild = target + DIR_DELIM + content[i].name; if(content[i].dir){ if(!fs::CopyDir(sourcechild, targetchild)){ retval = false; } } else { if(!fs::CopyFileContents(sourcechild, targetchild)){ retval = false; } } } return retval; } else { return false; } } bool PathStartsWith(std::string path, std::string prefix) { size_t pathsize = path.size(); size_t pathpos = 0; size_t prefixsize = prefix.size(); size_t prefixpos = 0; for(;;){ bool delim1 = pathpos == pathsize || IsDirDelimiter(path[pathpos]); bool delim2 = prefixpos == prefixsize || IsDirDelimiter(prefix[prefixpos]); if(delim1 != delim2) return false; if(delim1){ while(pathpos < pathsize && IsDirDelimiter(path[pathpos])) ++pathpos; while(prefixpos < prefixsize && IsDirDelimiter(prefix[prefixpos])) ++prefixpos; if(prefixpos == prefixsize) return true; if(pathpos == pathsize) return false; } else{ size_t len = 0; do{ char pathchar = path[pathpos+len]; char prefixchar = prefix[prefixpos+len]; if(FILESYS_CASE_INSENSITIVE){ pathchar = tolower(pathchar); prefixchar = tolower(prefixchar); } if(pathchar != prefixchar) return false; ++len; } while(pathpos+len < pathsize && !IsDirDelimiter(path[pathpos+len]) && prefixpos+len < prefixsize && !IsDirDelimiter( prefix[prefixsize+len])); pathpos += len; prefixpos += len; } } } std::string RemoveLastPathComponent(std::string path, std::string *removed, int count) { if(removed) *removed = ""; size_t remaining = path.size(); for(int i = 0; i < count; ++i){ // strip a dir delimiter while(remaining != 0 && IsDirDelimiter(path[remaining-1])) remaining--; // strip a path component size_t component_end = remaining; while(remaining != 0 && !IsDirDelimiter(path[remaining-1])) remaining--; size_t component_start = remaining; // strip a dir delimiter while(remaining != 0 && IsDirDelimiter(path[remaining-1])) remaining--; if(removed){ std::string component = path.substr(component_start, component_end - component_start); if(i) *removed = component + DIR_DELIM + *removed; else *removed = component; } } return path.substr(0, remaining); } std::string RemoveRelativePathComponents(std::string path) { size_t pos = path.size(); size_t dotdot_count = 0; while(pos != 0){ size_t component_with_delim_end = pos; // skip a dir delimiter while(pos != 0 && IsDirDelimiter(path[pos-1])) pos--; // strip a path component size_t component_end = pos; while(pos != 0 && !IsDirDelimiter(path[pos-1])) pos--; size_t component_start = pos; std::string component = path.substr(component_start, component_end - component_start); bool remove_this_component = false; if(component == "."){ remove_this_component = true; } else if(component == ".."){ remove_this_component = true; dotdot_count += 1; } else if(dotdot_count != 0){ remove_this_component = true; dotdot_count -= 1; } if(remove_this_component){ while(pos != 0 && IsDirDelimiter(path[pos-1])) pos--; path = path.substr(0, pos) + DIR_DELIM + path.substr(component_with_delim_end, std::string::npos); pos++; } } if(dotdot_count > 0) return ""; // remove trailing dir delimiters pos = path.size(); while(pos != 0 && IsDirDelimiter(path[pos-1])) pos--; return path.substr(0, pos); } } // namespace fs