Download src/Base/FileInfo.cpp from AbdulElahGwaith/FreeCAD: direct link, hf CLI and curl.
- Browser
- Download file 15.3 kB
-
https://huggingface.co/AbdulElahGwaith/FreeCAD/resolve/main/src/Base/FileInfo.cpp
- Command line
-
hf download hf://AbdulElahGwaith/FreeCAD/src/Base/FileInfo.cpp
-
curl -L -o FileInfo.cpp https://huggingface.co/AbdulElahGwaith/FreeCAD/resolve/main/src/Base/FileInfo.cpp
15.3 kB
| // SPDX-License-Identifier: LGPL-2.1-or-later | |
| /*************************************************************************** | |
| * Copyright (c) 2005 Jürgen Riegel <juergen.riegel@web.de> * | |
| * * | |
| * This file is part of the FreeCAD CAx development system. * | |
| * * | |
| * This program is free software; you can redistribute it and/or modify * | |
| * it under the terms of the GNU Library General Public License (LGPL) * | |
| * as published by the Free Software Foundation; either version 2 of * | |
| * the License, or (at your option) any later version. * | |
| * for detail see the LICENCE text file. * | |
| * * | |
| * FreeCAD 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 Library General Public License for more details. * | |
| * * | |
| * You should have received a copy of the GNU Library General Public * | |
| * License along with FreeCAD; if not, write to the Free Software * | |
| * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * | |
| * USA * | |
| * * | |
| ***************************************************************************/ | |
| using namespace Base; | |
| namespace fs = std::filesystem; | |
| //********************************************************************************** | |
| // helper | |
| std::string ConvertFromWideString(const std::wstring& string) | |
| { | |
| int neededSize = WideCharToMultiByte(CP_UTF8, 0, string.c_str(), -1, 0, 0, 0, 0); | |
| char* CharString = new char[static_cast<size_t>(neededSize)]; | |
| WideCharToMultiByte(CP_UTF8, 0, string.c_str(), -1, CharString, neededSize, 0, 0); | |
| std::string String(CharString); | |
| delete[] CharString; | |
| CharString = NULL; | |
| return String; | |
| } | |
| std::wstring ConvertToWideString(const std::string& string) | |
| { | |
| int neededSize = MultiByteToWideChar(CP_UTF8, 0, string.c_str(), -1, 0, 0); | |
| wchar_t* wideCharString = new wchar_t[static_cast<size_t>(neededSize)]; | |
| MultiByteToWideChar(CP_UTF8, 0, string.c_str(), -1, wideCharString, neededSize); | |
| std::wstring wideString(wideCharString); | |
| delete[] wideCharString; | |
| wideCharString = NULL; | |
| return wideString; | |
| } | |
| //********************************************************************************** | |
| // FileInfo | |
| FileInfo::FileInfo(const char* fileName) | |
| { | |
| setFile(fileName); | |
| } | |
| FileInfo::FileInfo(const std::string& fileName) | |
| { | |
| setFile(fileName.c_str()); | |
| } | |
| const std::string& FileInfo::getTempPath() | |
| { | |
| static std::string tempPath; | |
| if (tempPath.empty()) { | |
| fs::path tmp = fs::temp_directory_path(); | |
| tmp += fs::path::preferred_separator; | |
| tempPath = pathToString(tmp); | |
| } | |
| return tempPath; | |
| } | |
| std::string FileInfo::getTempFileName(const char* FileName, const char* Path) | |
| { | |
| // FIXME: To avoid race conditions we should rather return a file pointer | |
| // than a file name. | |
| wchar_t buf[MAX_PATH + 2]; | |
| // Path where the file is located | |
| std::wstring path; | |
| if (Path) { | |
| path = ConvertToWideString(std::string(Path)); | |
| } | |
| else { | |
| path = ConvertToWideString(getTempPath()); | |
| } | |
| // File name in the path | |
| std::wstring file; | |
| if (FileName) { | |
| file = ConvertToWideString(std::string(FileName)); | |
| } | |
| else { | |
| file = L"FCTempFile"; | |
| } | |
| // this already creates the file | |
| GetTempFileNameW(path.c_str(), file.c_str(), 0, buf); | |
| DeleteFileW(buf); | |
| return std::string(ConvertFromWideString(std::wstring(buf))); | |
| std::string buf; | |
| // Path where the file is located | |
| if (Path) { | |
| buf = Path; | |
| } | |
| else { | |
| buf = getTempPath(); | |
| } | |
| // File name in the path | |
| if (FileName) { | |
| buf += "/"; | |
| buf += FileName; | |
| buf += "XXXXXX"; | |
| } | |
| else { | |
| buf += "/fileXXXXXX"; | |
| } | |
| std::vector<char> vec; | |
| std::copy(buf.begin(), buf.end(), std::back_inserter(vec)); | |
| vec.push_back('\0'); | |
| /* coverity[secure_temp] mkstemp uses 0600 as the mode and is safe */ | |
| int id = mkstemp(vec.data()); | |
| if (id > -1) { | |
| FILE* file = fdopen(id, "w"); | |
| fclose(file); | |
| vec.pop_back(); // remove '\0' | |
| std::string str(vec.begin(), vec.end()); | |
| buf.swap(str); | |
| unlink(buf.c_str()); | |
| } | |
| return buf; | |
| } | |
| fs::path FileInfo::stringToPath(const std::string& str) | |
| { | |
| std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter; | |
| fs::path path(converter.from_bytes(str)); | |
| fs::path path(str); | |
| return path; | |
| } | |
| std::string FileInfo::pathToString(const fs::path& path) | |
| { | |
| std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter; | |
| return converter.to_bytes(path.wstring()); | |
| return path.string(); | |
| } | |
| void FileInfo::setFile(const char* name) | |
| { | |
| if (!name) { | |
| FileName.clear(); | |
| return; | |
| } | |
| FileName = name; | |
| // keep the UNC paths intact | |
| if (FileName.substr(0, 2) == std::string("\\\\")) { | |
| std::replace(FileName.begin() + 2, FileName.end(), '\\', '/'); | |
| } | |
| else { | |
| std::replace(FileName.begin(), FileName.end(), '\\', '/'); | |
| } | |
| } | |
| std::string FileInfo::filePath() const | |
| { | |
| return FileName; | |
| } | |
| std::string FileInfo::fileName() const | |
| { | |
| return FileName.substr(FileName.find_last_of('/') + 1); | |
| } | |
| std::string FileInfo::dirPath() const | |
| { | |
| std::size_t last_pos {}; | |
| std::string retval; | |
| last_pos = FileName.find_last_of('/'); | |
| if (last_pos != std::string::npos) { | |
| retval = FileName.substr(0, last_pos); | |
| } | |
| else { | |
| retval = pathToString(fs::current_path()); | |
| } | |
| return retval; | |
| } | |
| std::string FileInfo::fileNamePure() const | |
| { | |
| std::string temp = fileName(); | |
| std::string::size_type pos = temp.find_last_of('.'); | |
| if (pos != std::string::npos) { | |
| return temp.substr(0, pos); | |
| } | |
| return temp; | |
| } | |
| std::wstring FileInfo::toStdWString() const | |
| { | |
| // As FileName is UTF-8 is encoded we have to convert it | |
| // for Windows because the path names are UTF-16 encoded. | |
| return ConvertToWideString(FileName); | |
| // On other platforms it's discouraged to use wchar_t for file names | |
| throw Base::FileException("Cannot use FileInfo::toStdWString() on this platform"); | |
| } | |
| std::string FileInfo::extension() const | |
| { | |
| std::string::size_type pos = FileName.find_last_of('.'); | |
| if (pos == std::string::npos) { | |
| return {}; | |
| } | |
| return FileName.substr(pos + 1); | |
| } | |
| std::string FileInfo::completeExtension() const | |
| { | |
| std::string::size_type pos = FileName.find_first_of('.'); | |
| if (pos == std::string::npos) { | |
| return {}; | |
| } | |
| return FileName.substr(pos + 1); | |
| } | |
| bool FileInfo::hasExtension(const char* Ext) const | |
| { | |
| return _stricmp(Ext, extension().c_str()) == 0; | |
| return strcasecmp(Ext, extension().c_str()) == 0; | |
| } | |
| bool FileInfo::hasExtension(std::initializer_list<const char*> Exts) const | |
| { | |
| return std::ranges::any_of(Exts, [this](const char* ext) { return hasExtension(ext); }); | |
| } | |
| bool FileInfo::exists() const | |
| { | |
| fs::path path(stringToPath(FileName)); | |
| return fs::exists(path); | |
| } | |
| bool FileInfo::isReadable() const | |
| { | |
| fs::path path = stringToPath(FileName); | |
| if (!fs::exists(path)) { | |
| return false; | |
| } | |
| fs::file_status stat = fs::status(path); | |
| fs::perms perms = stat.permissions(); | |
| return (perms & fs::perms::owner_read) == fs::perms::owner_read; | |
| } | |
| bool directoryIsWritable(const fs::path& dir) | |
| { | |
| try { | |
| if (!fs::exists(dir) || !fs::is_directory(dir)) { | |
| return false; | |
| } | |
| fs::path test_file = dir / (".fs_perm_test_" + std::to_string(std::rand()) + ".tmp"); | |
| { | |
| std::ofstream ofs(test_file); | |
| if (!ofs) { | |
| return false; | |
| } | |
| } | |
| std::error_code ec; | |
| fs::remove(test_file, ec); | |
| return true; | |
| } | |
| catch (...) { | |
| return false; | |
| } | |
| } | |
| bool FileInfo::isWritable() const | |
| { | |
| fs::path path = stringToPath(FileName); | |
| if (!fs::exists(path)) { | |
| return false; | |
| } | |
| if (fs::is_directory(path)) { | |
| return directoryIsWritable(path); | |
| } | |
| // convert filename from UTF-8 to windows WSTRING | |
| std::wstring fileNameWstring = toStdWString(); | |
| // requires import of <windows.h> | |
| DWORD attributes = GetFileAttributes(fileNameWstring.c_str()); | |
| if (attributes == INVALID_FILE_ATTRIBUTES) { | |
| // Log the error? | |
| std::clog << "GetFileAttributes failed for file: " << FileName << '\n'; | |
| // usually indicates some kind of network file issue, so the file is probably not writable | |
| return false; | |
| } | |
| if ((attributes & FILE_ATTRIBUTE_READONLY) != 0) { | |
| return false; | |
| } | |
| // TEST if file is truly writable, because windows ACL does not map well to POSIX perms, | |
| // and there are other potential blockers (app or shared file locks, etc) | |
| HANDLE hFile = CreateFileW( | |
| fileNameWstring.c_str(), | |
| GENERIC_WRITE, | |
| 0, // ----> no sharing: fail if anyone else has it open | |
| nullptr, | |
| OPEN_EXISTING, | |
| FILE_ATTRIBUTE_NORMAL, | |
| nullptr | |
| ); | |
| if (hFile == INVALID_HANDLE_VALUE) { | |
| DWORD err = GetLastError(); | |
| if (err == ERROR_SHARING_VIOLATION || err == ERROR_LOCK_VIOLATION) { | |
| return false; | |
| } | |
| return false; | |
| } | |
| if (!CloseHandle(hFile)) { | |
| std::clog << "CloseHandle failed for file: " << FileName | |
| << " while checking for write access." << '\n'; | |
| } | |
| fs::file_status stat = fs::status(path); | |
| fs::perms perms = stat.permissions(); | |
| return (perms & fs::perms::owner_write) == fs::perms::owner_write; | |
| } | |
| bool FileInfo::setPermissions(Permissions perms) | |
| { | |
| fs::perms mode = fs::perms::none; | |
| if (perms & FileInfo::ReadOnly) { | |
| mode |= fs::perms::owner_read; | |
| } | |
| if (perms & FileInfo::WriteOnly) { | |
| mode |= fs::perms::owner_write; | |
| } | |
| if (mode == fs::perms::none) { // bad argument | |
| return false; | |
| } | |
| fs::path file_path = stringToPath(FileName); | |
| if (!fs::exists(file_path)) { | |
| return false; | |
| } | |
| fs::permissions(file_path, mode); | |
| fs::file_status stat = fs::status(file_path); | |
| return stat.permissions() == mode; | |
| } | |
| bool FileInfo::isFile() const | |
| { | |
| fs::path path = stringToPath(FileName); | |
| if (fs::exists(path)) { | |
| return fs::is_regular_file(path); | |
| } | |
| // TODO: Check for valid file name | |
| return true; | |
| } | |
| bool FileInfo::isDir() const | |
| { | |
| fs::path path = stringToPath(FileName); | |
| if (fs::exists(path)) { | |
| return fs::is_directory(path); | |
| } | |
| return false; | |
| } | |
| unsigned int FileInfo::size() const | |
| { | |
| unsigned int bytes {}; | |
| fs::path path = stringToPath(FileName); | |
| if (fs::exists(path)) { | |
| bytes = fs::file_size(path); | |
| } | |
| return bytes; | |
| } | |
| template<typename TP> | |
| std::time_t to_time_t(TP tp) | |
| { | |
| using namespace std::chrono; | |
| auto sctp = time_point_cast<system_clock::duration>(tp - TP::clock::now() + system_clock::now()); | |
| return system_clock::to_time_t(sctp); | |
| } | |
| TimeInfo FileInfo::lastModified() const | |
| { | |
| TimeInfo ti = TimeInfo::null(); | |
| if (exists()) { | |
| fs::path path = stringToPath(FileName); | |
| ti.setTime_t(to_time_t(fs::last_write_time(path))); | |
| } | |
| return ti; | |
| } | |
| bool FileInfo::deleteFile() const | |
| { | |
| try { | |
| fs::path path = stringToPath(FileName); | |
| return fs::remove(path); | |
| } | |
| catch (const fs::filesystem_error& e) { | |
| std::clog << e.what() << '\n'; | |
| return false; | |
| } | |
| } | |
| bool FileInfo::renameFile(const char* NewName) | |
| { | |
| try { | |
| fs::path old_path = stringToPath(FileName); | |
| fs::path new_path = stringToPath(NewName); | |
| fs::rename(old_path, new_path); | |
| FileName = NewName; | |
| return true; | |
| } | |
| catch (const fs::filesystem_error& e) { | |
| std::clog << "Error in renameFile: " << e.what() << '\n'; | |
| return false; | |
| } | |
| } | |
| bool FileInfo::copyTo(const char* NewName) const | |
| { | |
| try { | |
| fs::path old_path = stringToPath(FileName); | |
| fs::path new_path = stringToPath(NewName); | |
| fs::copy(old_path, new_path); | |
| return true; | |
| } | |
| catch (const fs::filesystem_error&) { | |
| return false; | |
| } | |
| } | |
| bool FileInfo::createDirectory() const | |
| { | |
| try { | |
| fs::path path(stringToPath(FileName)); | |
| return fs::create_directory(path); | |
| } | |
| catch (const fs::filesystem_error&) { | |
| return false; | |
| } | |
| } | |
| bool FileInfo::createDirectories() const | |
| { | |
| try { | |
| fs::path path(stringToPath(FileName)); | |
| if (fs::exists(path)) { | |
| return true; | |
| } | |
| return fs::create_directories(path); | |
| } | |
| catch (const fs::filesystem_error&) { | |
| return false; | |
| } | |
| } | |
| bool FileInfo::deleteDirectory() const | |
| { | |
| if (!isDir()) { | |
| return false; | |
| } | |
| try { | |
| fs::path path = stringToPath(FileName); | |
| return fs::remove(path); | |
| } | |
| catch (const fs::filesystem_error& e) { | |
| std::clog << e.what() << '\n'; | |
| return false; | |
| } | |
| } | |
| bool FileInfo::deleteDirectoryRecursive() const | |
| { | |
| if (!isDir()) { | |
| return false; | |
| } | |
| try { | |
| fs::path path = stringToPath(FileName); | |
| return fs::remove_all(path) > 0; | |
| } | |
| catch (const fs::filesystem_error& e) { | |
| std::clog << e.what() << '\n'; | |
| return false; | |
| } | |
| } | |
| std::vector<Base::FileInfo> FileInfo::getDirectoryContent() const | |
| { | |
| std::error_code ec; | |
| std::vector<Base::FileInfo> list; | |
| fs::path path = stringToPath(FileName); | |
| for (const fs::directory_entry& f : fs::directory_iterator {path, ec}) { | |
| list.emplace_back(pathToString(f.path())); | |
| } | |
| return list; | |
| } | |