diff --git a/src/fileutils.cpp b/src/fileutils.cpp index f2c3869b8b2ea203b517fcadbe68454186a47f2e..a5e25066d066b17e737a6d36a40760fe27d26120 100644 --- a/src/fileutils.cpp +++ b/src/fileutils.cpp @@ -42,7 +42,9 @@ #if defined(__ANDROID__) || (defined(TARGET_OS_IOS) && TARGET_OS_IOS) #include "client/ring_signal.h" #endif + #ifdef _WIN32 +#include <windows.h> #include "string_utils.h" #endif @@ -227,9 +229,27 @@ getFileLock(const std::string& path) return fileLocks[path]; } -bool isFile (const std::string& path) { - struct stat s; - return (stat (path.c_str(), &s) == 0) and not (s.st_mode & S_IFDIR); +bool isFile(const std::string& path, bool resolveSymlink) +{ + if (resolveSymlink) { + struct stat s; + if (stat(path.c_str(), &s) == 0) + return S_ISREG(s.st_mode); + } else { +#ifdef _WIN32 + DWORD attr = GetFileAttributesA(path.c_str()); + if ((attr != INVALID_FILE_ATTRIBUTES) && + !(attr & FILE_ATTRIBUTE_DIRECTORY) && + !(attr & FILE_ATTRIBUTE_REPARSE_POINT)) + return true; +#else + struct stat s; + if (lstat(path.c_str(), &s) == 0) + return S_ISREG(s.st_mode); +#endif + } + + return false; } bool isDirectory(const std::string& path) @@ -705,8 +725,140 @@ recursive_mkdir(const std::string& path, mode_t mode) return true; } +#ifdef _WIN32 +bool +eraseFile_win32(const std::string& path, bool dosync) +{ + HANDLE h = CreateFileA(path.c_str(), GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); + if (h == INVALID_HANDLE_VALUE) { + JAMI_WARN("Can not open file %s for erasing.", path.c_str()); + return false; + } + + LARGE_INTEGER size; + if (!GetFileSizeEx(h, &size)) { + JAMI_WARN("Can not erase file %s: GetFileSizeEx() failed.", path.c_str()); + CloseHandle(h); + return false; + } + if (size.QuadPart == 0) { + CloseHandle(h); + return false; + } + + uint64_t size_blocks = size.QuadPart / ERASE_BLOCK; + if (size.QuadPart % ERASE_BLOCK) + size_blocks++; + + char* buffer; + try { + buffer = new char[ERASE_BLOCK]; + } + catch (std::bad_alloc& ba) { + JAMI_WARN("Can not allocate buffer for erasing %s.", path.c_str()); + CloseHandle(h); + return false; + } + memset(buffer, 0x00, ERASE_BLOCK); + + OVERLAPPED ovlp; + if (size.QuadPart < (1024-42)) { // a small file can be stored in the MFT record + ovlp.Offset = 0; + ovlp.OffsetHigh = 0; + WriteFile(h, buffer, (DWORD)size.QuadPart, 0, &ovlp); + FlushFileBuffers(h); + } + for (uint64_t i = 0; i < size_blocks; i++) { + uint64_t offset = i * ERASE_BLOCK; + ovlp.Offset = offset & 0x00000000FFFFFFFF; + ovlp.OffsetHigh = offset >> 32; + WriteFile(h, buffer, ERASE_BLOCK, 0, &ovlp); + } + + delete[] buffer; + + if (dosync) + FlushFileBuffers(h); + + CloseHandle(h); + return true; +} + +#else + +bool +eraseFile_posix(const std::string& path, bool dosync) +{ + int fd = open(path.c_str(), O_WRONLY); + if (fd == -1) { + JAMI_WARN("Can not open file %s for erasing.", path.c_str()); + return false; + } + + struct stat st; + if (fstat(fd, &st) == -1) { + JAMI_WARN("Can not erase file %s: fstat() failed.", path.c_str()); + close(fd); + return false; + } + + if (st.st_size == 0) { + close(fd); + return false; + } + + uintmax_t size_blocks = st.st_size / ERASE_BLOCK; + if (st.st_size % ERASE_BLOCK) + size_blocks++; + + char* buffer; + try { + buffer = new char[ERASE_BLOCK]; + } + catch (std::bad_alloc& ba) { + JAMI_WARN("Can not allocate buffer for erasing %s.", path.c_str()); + close(fd); + return false; + } + memset(buffer, 0x00, ERASE_BLOCK); + + for (uintmax_t i = 0; i < size_blocks; i++) { + lseek(fd, i * ERASE_BLOCK, SEEK_SET); + write(fd, buffer, ERASE_BLOCK); + } + + delete[] buffer; + + if (dosync) + fsync(fd); + + close(fd); + return true; +} +#endif + +bool +eraseFile(const std::string& path, bool dosync) +{ +#ifdef _WIN32 + return eraseFile_win32(path, dosync); +#else + return eraseFile_posix(path, dosync); +#endif +} + +int +remove(const std::string& path, bool erase) +{ + if (erase and isFile(path, false)) { + eraseFile(path, true); + } + + return std::remove(path.c_str()); +} + int -removeAll(const std::string& path) +removeAll(const std::string& path, bool erase) { if (path.empty()) return -1; @@ -715,9 +867,9 @@ removeAll(const std::string& path) if (dir.back() != DIR_SEPARATOR_CH) dir += DIR_SEPARATOR_CH; for (auto& entry : fileutils::readDirectory(dir)) - removeAll(dir + entry); + removeAll(dir + entry, erase); } - return remove(path); + return remove(path, erase); } }} // namespace jami::fileutils diff --git a/src/fileutils.h b/src/fileutils.h index c1faccd301eb9740c443a67e0c54e274eb0e39c8..06a561f0b16e817ec0cf99ce8c883239965d0ca5 100644 --- a/src/fileutils.h +++ b/src/fileutils.h @@ -41,7 +41,7 @@ #define XDG_CACHE_HOME (PROTECTED_GETENV("XDG_CACHE_HOME")) #define PIDFILE ".ring.pid" - +#define ERASE_BLOCK 4096 #ifndef _WIN32 #include <sys/stat.h> // mode_t @@ -89,9 +89,8 @@ namespace jami { namespace fileutils { */ std::string getFullPath(const std::string& base, const std::string& path); - bool isFile(const std::string& path); + bool isFile(const std::string& path, bool resolveSymlink = true); bool isDirectory(const std::string& path); - bool isSymLink(const std::string& path); std::chrono::system_clock::time_point writeTime(const std::string& path); @@ -124,15 +123,16 @@ namespace jami { namespace fileutils { FileHandle create_pidfile(); /** - * Direct binding on std::remove, with std::string as argument + * Remove a file with optional erasing of content. + * Return the same value as std::remove(). */ - static inline int remove(const std::string& path) { return std::remove(path.c_str()); } + int remove(const std::string& path, bool erase = false); /** * Prune given directory's content and remove it, symlinks are not followed. * Return 0 if succeed, -1 if directory is not removed (content can be removed partially). */ - int removeAll(const std::string& path); + int removeAll(const std::string& path, bool erase = false); }} // namespace jami::fileutils diff --git a/src/jamidht/jamiaccount.cpp b/src/jamidht/jamiaccount.cpp index 32111bb1639e094541fd1873bb6df0e25cf5bda4..d087d8a075ce5dbbb56c2c4e16f7a61e261a96a7 100644 --- a/src/jamidht/jamiaccount.cpp +++ b/src/jamidht/jamiaccount.cpp @@ -335,7 +335,7 @@ JamiAccount::flush() fileutils::removeAll(dataPath_); fileutils::removeAll(cachePath_); - fileutils::removeAll(idPath_); + fileutils::removeAll(idPath_, true); } std::shared_ptr<SIPCall>