Expand Up
@@ -6,13 +6,17 @@
#include < algorithm>
#include < chrono>
#include < cstddef>
#include < cstdint>
#include < cstdio>
#include < cstring>
#include < fcntl.h>
#include < filesystem>
#include < fstream>
#include < limits.h>
#include < stack>
#include < string>
#include < sys/stat.h>
#include < system_error>
#include < thread>
#include < vector>
Expand All
@@ -29,11 +33,10 @@
#include " Common/StringUtil.h"
#ifdef _WIN32
#include < windows .h>
#include < Windows .h>
#include < Shlwapi.h>
#include < commdlg.h> // for GetSaveFileName
#include < direct.h> // getcwd
#include < filesystem>
#include < io.h>
#include < objbase.h> // guid stuff
#include < shellapi.h>
Expand All
@@ -57,13 +60,8 @@
#include " jni/AndroidCommon/AndroidCommon.h"
#endif
#ifndef S_ISDIR
#define S_ISDIR (m ) (((m)&S_IFMT) == S_IFDIR)
#endif
namespace fs = std::filesystem;
// This namespace has various generic functions related to files and paths.
// The code still needs a ton of cleanup.
// REMEMBER: strdup considered harmful!
namespace File
{
#ifdef ANDROID
Expand All
@@ -82,16 +80,6 @@ static DolSecTranslocateIsTranslocatedURL s_is_translocated_url;
static DolSecTranslocateCreateOriginalPathForURL s_create_orig_path;
#endif
#ifdef _WIN32
FileInfo::FileInfo (const std::string& path)
{
m_exists = _tstat64 (UTF8ToTStr (path).c_str (), &m_stat) == 0 ;
}
FileInfo::FileInfo (const char * path) : FileInfo(std::string(path))
{
}
#else
FileInfo::FileInfo (const std::string& path) : FileInfo(path.c_str())
{
}
Expand All
@@ -100,27 +88,24 @@ FileInfo::FileInfo(const char* path)
{
#ifdef ANDROID
if (IsPathAndroidContent (path))
AndroidContentInit (path);
{
const jlong result = GetAndroidContentSizeAndIsDirectory (path);
m_status.type ((result == -2 ) ? fs::file_type::directory : fs::file_type::regular);
m_size = (result >= 0 ) ? result : 0 ;
m_exists = result != -1 ;
}
else
#endif
m_exists = stat (path, &m_stat) == 0 ;
}
#endif
FileInfo::FileInfo (int fd)
{
m_exists = fstat (fd, &m_stat) == 0 ;
}
#ifdef ANDROID
void FileInfo::AndroidContentInit (const std::string& path)
{
const jlong result = GetAndroidContentSizeAndIsDirectory (path);
m_exists = result != -1 ;
m_stat.st_mode = result == -2 ? S_IFDIR : S_IFREG;
m_stat.st_size = result >= 0 ? result : 0 ;
{
const auto fs_path = StringToPath (path);
std::error_code error;
m_status = fs::status (fs_path, error);
m_size = fs::file_size (fs_path, error);
if (error)
m_size = 0 ;
m_exists = fs::exists (m_status);
}
}
#endif
bool FileInfo::Exists () const
{
Expand All
@@ -129,17 +114,19 @@ bool FileInfo::Exists() const
bool FileInfo::IsDirectory () const
{
return m_exists ? S_ISDIR (m_stat. st_mode ) : false ;
return fs::is_directory (m_status) ;
}
bool FileInfo::IsFile () const
{
return m_exists ? !S_ISDIR (m_stat. st_mode ) : false ;
return Exists () ? !fs::is_directory (m_status ) : false ;
}
u64 FileInfo::GetSize () const
{
return IsFile () ? m_stat.st_size : 0 ;
if (!IsFile ())
return 0 ;
return m_size;
}
// Returns true if the path exists
Expand All
@@ -151,11 +138,7 @@ bool Exists(const std::string& path)
// Returns true if the path exists and is a directory
bool IsDirectory (const std::string& path)
{
#ifdef _WIN32
return PathIsDirectory (UTF8ToWString (path).c_str ());
#else
return FileInfo (path).IsDirectory ();
#endif
}
// Returns true if the path exists and is a file
Expand All
@@ -168,182 +151,127 @@ bool IsFile(const std::string& path)
// Doesn't supports deleting a directory
bool Delete (const std::string& filename, IfAbsentBehavior behavior)
{
DEBUG_LOG_FMT (COMMON, " Delete : file {}" , filename);
DEBUG_LOG_FMT (COMMON, " {} : file {}" , __func__ , filename);
#ifdef ANDROID
if (filename.starts_with (" content://" ))
{
const bool success = DeleteAndroidContent (filename);
if (!success)
WARN_LOG_FMT (COMMON, " Delete failed on {}" , filename);
WARN_LOG_FMT (COMMON, " {} failed on {}" , __func__ , filename);
return success;
}
#endif
const FileInfo file_info (filename);
auto native_path = StringToPath (filename);
std::error_code error;
auto status = fs::status (native_path, error);
// Return true because we care about the file not being there, not the actual delete.
if (!file_info. Exists ( ))
if (!fs::exists (status ))
{
if (behavior == IfAbsentBehavior::ConsoleWarning)
{
WARN_LOG_FMT (COMMON, " Delete : {} does not exist" , filename);
WARN_LOG_FMT (COMMON, " {} : {} does not exist" , __func__ , filename);
}
return true ;
}
// We can't delete a directory
if (file_info. IsDirectory ( ))
// fs::remove can only delete an empty directory. Legacy dolphin behavior is just to bail.
if (fs::is_directory (status ))
{
WARN_LOG_FMT (COMMON, " Delete failed: {} is a directory" , filename);
WARN_LOG_FMT (COMMON, " {} failed: {} is a directory" , __func__ , filename);
return false ;
}
#ifdef _WIN32
if (!DeleteFile (UTF8ToTStr (filename).c_str ()))
if (!fs::remove (native_path, error))
{
WARN_LOG_FMT (COMMON, " Delete: DeleteFile failed on {}: {}" , filename, GetLastErrorString ());
WARN_LOG_FMT (COMMON, " {}: failed on {}: {}" , __func__, filename, error. message ());
return false ;
}
#else
if (unlink (filename.c_str ()) == -1 )
{
WARN_LOG_FMT (COMMON, " Delete: unlink failed on {}: {}" , filename, LastStrerrorString ());
return false ;
}
#endif
return true ;
}
// Returns true if successful, or path already exists.
bool CreateDir (const std::string& path)
{
DEBUG_LOG_FMT (COMMON, " CreateDir: directory {}" , path);
#ifdef _WIN32
if (::CreateDirectory (UTF8ToTStr (path).c_str (), nullptr ))
return true ;
const DWORD error = GetLastError ();
if (error == ERROR_ALREADY_EXISTS)
{
WARN_LOG_FMT (COMMON, " CreateDir: CreateDirectory failed on {}: already exists" , path);
return true ;
}
ERROR_LOG_FMT (COMMON, " CreateDir: CreateDirectory failed on {}: {}" , path, error);
return false ;
#else
if (mkdir (path.c_str (), 0755 ) == 0 )
return true ;
const int err = errno;
if (err == EEXIST)
{
WARN_LOG_FMT (COMMON, " CreateDir: mkdir failed on {}: already exists" , path);
return true ;
}
DEBUG_LOG_FMT (COMMON, " {}: directory {}" , __func__, path);
ERROR_LOG_FMT (COMMON, " CreateDir: mkdir failed on {}: {}" , path, strerror (err));
return false ;
#endif
std::error_code error;
auto native_path = StringToPath (path);
bool success = fs::create_directory (native_path, error);
// If the path was not created, check if it was a pre-existing directory
if (!success && fs::is_directory (native_path))
success = true ;
if (!success)
ERROR_LOG_FMT (COMMON, " {}: failed on {}: {}" , __func__, path, error.message ());
return success;
}
// Creates the full path of fullPath returns true on success
bool CreateFullPath (const std::string& fullPath)
{
int panicCounter = 100 ;
DEBUG_LOG_FMT (COMMON, " CreateFullPath: path {}" , fullPath);
if (Exists (fullPath))
{
DEBUG_LOG_FMT (COMMON, " CreateFullPath: path exists {}" , fullPath);
return true ;
}
DEBUG_LOG_FMT (COMMON, " {}: path {}" , __func__, fullPath);
size_t position = 0 ;
while (true )
{
// Find next sub path
position = fullPath.find (DIR_SEP_CHR, position);
// we're done, yay!
if (position == fullPath.npos )
return true ;
// Include the '/' so the first call is CreateDir("/") rather than CreateDir("")
std::string const subPath (fullPath.substr (0 , position + 1 ));
if (!IsDirectory (subPath))
File::CreateDir (subPath);
// A safety check
panicCounter--;
if (panicCounter <= 0 )
{
ERROR_LOG_FMT (COMMON, " CreateFullPath: directory structure is too deep" );
return false ;
}
position++;
}
std::error_code error;
auto native_path = StringToPath (fullPath);
bool success = fs::create_directories (native_path, error);
// If the path was not created, check if it was a pre-existing directory
if (!success && fs::is_directory (native_path))
success = true ;
if (!success)
ERROR_LOG_FMT (COMMON, " {}: failed on {}: {}" , __func__, fullPath, error.message ());
return success;
}
// Deletes a directory filename, returns true on success
bool DeleteDir (const std::string& filename, IfAbsentBehavior behavior)
{
DEBUG_LOG_FMT (COMMON, " DeleteDir: directory {}" , filename);
DEBUG_LOG_FMT (COMMON, " {}: directory {}" , __func__, filename);
auto native_path = StringToPath (filename);
std::error_code error;
auto status = fs::status (native_path, error);
// Return true because we care about the directory not being there, not the actual delete.
if (!File::Exists (filename ))
if (!fs::exists (status ))
{
if (behavior == IfAbsentBehavior::ConsoleWarning)
{
WARN_LOG_FMT (COMMON, " DeleteDir : {} does not exist" , filename);
WARN_LOG_FMT (COMMON, " {} : {} does not exist" , __func__ , filename);
}
return true ;
}
// check if a directory
if (!IsDirectory (filename ))
if (!fs::is_directory (status ))
{
ERROR_LOG_FMT (COMMON, " DeleteDir : Not a directory {}" , filename);
ERROR_LOG_FMT (COMMON, " {} : Not a directory {}" , __func__ , filename);
return false ;
}
#ifdef _WIN32
if (::RemoveDirectory (UTF8ToTStr (filename).c_str ()))
return true ;
ERROR_LOG_FMT (COMMON, " DeleteDir: RemoveDirectory failed on {}: {}" , filename,
GetLastErrorString ());
#else
if (rmdir (filename.c_str ()) == 0 )
return true ;
ERROR_LOG_FMT (COMMON, " DeleteDir: rmdir failed on {}: {}" , filename, LastStrerrorString ());
#endif
if (!fs::remove (native_path, error))
{
WARN_LOG_FMT (COMMON, " {}: failed on {}: {}" , __func__, filename, error.message ());
return false ;
}
return false ;
return true ;
}
// renames file srcFilename to destFilename, returns true on success
bool Rename (const std::string& srcFilename, const std::string& destFilename)
{
DEBUG_LOG_FMT (COMMON, " Rename: {} --> {}" , srcFilename, destFilename);
#ifdef _WIN32
DEBUG_LOG_FMT (COMMON, " {}: {} --> {}" , __func__, srcFilename, destFilename);
std::error_code error;
std::filesystem::rename (UTF8ToWString (srcFilename), UTF8ToWString (destFilename), error);
std::filesystem::rename (StringToPath (srcFilename), StringToPath (destFilename), error);
if (error)
{
ERROR_LOG_FMT (COMMON, " Rename failed: {} --> {}: {}" , srcFilename, destFilename,
ERROR_LOG_FMT (COMMON, " {} failed: {} --> {}: {}" , __func__ , srcFilename, destFilename,
error.message ());
}
const bool success = !error;
#else
const bool success = rename (srcFilename.c_str (), destFilename.c_str ()) == 0 ;
if (!success)
{
ERROR_LOG_FMT (COMMON, " Rename failed {} --> {}: {}" , srcFilename, destFilename,
LastStrerrorString ());
}
#endif
return success;
return !error;
}
#ifndef _WIN32
Expand All
@@ -363,10 +291,14 @@ bool RenameSync(const std::string& srcFilename, const std::string& destFilename)
if (!Rename (srcFilename, destFilename))
return false ;
#ifdef _WIN32
int fd = _topen (UTF8ToTStr (srcFilename).c_str (), _O_RDONLY);
if (fd != -1 )
{
_commit (fd);
int fd = -1 ;
// XXX is this really needed?
errno_t err = _wsopen_s (&fd, UTF8ToWString (srcFilename).c_str (), _O_RDONLY, _SH_DENYNO,
_S_IREAD | _S_IWRITE);
if (!err && fd >= 0 )
{
if (_commit (fd) != 0 )
ERROR_LOG_FMT (COMMON, " {} sync failed on {}: {}" , __func__, srcFilename, err);
close (fd);
}
#else
Expand All
@@ -384,30 +316,18 @@ bool RenameSync(const std::string& srcFilename, const std::string& destFilename)
// copies file source_path to destination_path, returns true on success
bool Copy (const std::string& source_path, const std::string& destination_path)
{
DEBUG_LOG_FMT (COMMON, " Copy: {} --> {}" , source_path, destination_path);
#ifdef _WIN32
if (CopyFile (UTF8ToTStr (source_path).c_str (), UTF8ToTStr (destination_path).c_str (), FALSE ))
return true ;
ERROR_LOG_FMT (COMMON, " Copy: failed {} --> {}: {}" , source_path, destination_path,
GetLastErrorString ());
return false ;
#else
std::ifstream source{source_path, std::ios::binary};
std::ofstream destination{destination_path, std::ios::binary};
DEBUG_LOG_FMT (COMMON, " {}: {} --> {}" , __func__, source_path, destination_path);
// Only attempt to write with << if there is actually something in the file
if (source.peek () != std::ifstream::traits_type::eof ())
{
destination << source.rdbuf ();
return source.good () && destination.good ();
}
else
auto src_path = StringToPath (source_path);
auto dst_path = StringToPath (destination_path);
std::error_code error;
bool copied = fs::copy_file (src_path, dst_path, fs::copy_options::overwrite_existing, error);
if (!copied)
{
// We can't use source.good() here because eofbit will be set, so check for the other bits.
return !source. fail () && !source. bad () && destination. good ( );
ERROR_LOG_FMT (COMMON, " {}: failed {} --> {}: {} " , __func__, source_path, destination_path,
error. message () );
}
# endif
return copied;
}
// Returns the size of a file (or returns 0 if the path isn't a file that exists)
Expand All
@@ -416,12 +336,6 @@ u64 GetSize(const std::string& path)
return FileInfo (path).GetSize ();
}
// Overloaded GetSize, accepts file descriptor
u64 GetSize (const int fd)
{
return FileInfo (fd).GetSize ();
}
// Overloaded GetSize, accepts FILE*
u64 GetSize (FILE* f)
{
Expand Down
Expand Up
@@ -457,89 +371,25 @@ bool CreateEmptyFile(const std::string& filename)
return true ;
}
// Recursive or non-recursive list of files and directories under directory.
FSTEntry ScanDirectoryTree (std::string directory, bool recursive)
# ifdef ANDROID
static FSTEntry ScanDirectoryTreeAndroidContent (std::string directory, bool recursive)
{
#ifdef _WIN32
if (!directory.empty () && (directory.back () == ' /' || directory.back () == ' \\ ' ))
directory.pop_back ();
#else
if (!directory.empty () && directory.back () == ' /' )
directory.pop_back ();
#endif
DEBUG_LOG_FMT (COMMON, " ScanDirectoryTree: directory {}" , directory);
FSTEntry parent_entry;
parent_entry.physicalName = directory;
parent_entry.isDirectory = true ;
parent_entry.size = 0 ;
#ifdef _WIN32
// Find the first file in the directory.
WIN32_FIND_DATA ffd;
HANDLE hFind = FindFirstFile (UTF8ToTStr (directory + " \\ *" ).c_str (), &ffd);
if (hFind == INVALID_HANDLE_VALUE)
{
FindClose (hFind);
return parent_entry;
}
// Windows loop
do
{
const std::string virtual_name (TStrToUTF8 (ffd.cFileName ));
#else
DIR* dirp = nullptr ;
#ifdef ANDROID
std::vector<std::string> child_names;
if (IsPathAndroidContent (directory))
for (const auto & child_name : GetAndroidContentChildNames (directory))
{
child_names = GetAndroidContentChildNames (directory);
}
else
#endif
{
dirp = opendir (directory.c_str ());
if (!dirp)
return parent_entry;
}
#ifdef ANDROID
auto it = child_names.cbegin ();
#endif
// non Windows loop
while (true )
{
std::string virtual_name;
#ifdef ANDROID
if (!dirp)
{
if (it == child_names.cend ())
break ;
virtual_name = *it;
++it;
}
else
#endif
{
dirent* result = readdir (dirp);
if (!result)
break ;
virtual_name = result->d_name ;
}
#endif
if (virtual_name == " ." || virtual_name == " .." )
continue ;
auto physical_name = directory + DIR_SEP + virtual_name;
FSTEntry entry;
const auto physical_name = directory + DIR_SEP + child_name;
const FileInfo file_info (physical_name);
FSTEntry entry;
entry.isDirectory = file_info.IsDirectory ();
if (entry.isDirectory )
{
if (recursive)
entry = ScanDirectoryTree (physical_name, true );
entry = ScanDirectoryTreeAndroidContent (physical_name, true );
else
entry.size = 0 ;
parent_entry.size += entry.size ;
Expand All
@@ -548,177 +398,173 @@ FSTEntry ScanDirectoryTree(std::string directory, bool recursive)
{
entry.size = file_info.GetSize ();
}
entry.virtualName = virtual_name ;
entry.virtualName = child_name ;
entry.physicalName = physical_name;
++parent_entry.size ;
// Push into the tree
parent_entry.children .push_back (entry);
#ifdef _WIN32
} while (FindNextFile (hFind, &ffd) != 0 );
FindClose (hFind);
#else
}
if (dirp)
closedir (dirp);
#endif
return parent_entry;
}
#endif
// Deletes the given directory and anything under it. Returns true on success .
bool DeleteDirRecursively ( const std::string& directory)
// Recursive or non-recursive list of files and directories under directory .
FSTEntry ScanDirectoryTree ( std::string directory, bool recursive )
{
DEBUG_LOG_FMT (COMMON, " DeleteDirRecursively: {}" , directory);
bool success = true ;
DEBUG_LOG_FMT (COMMON, " {}: directory {}" , __func__, directory);
#ifdef ANDROID
if (IsPathAndroidContent (directory))
return ScanDirectoryTreeAndroidContent (directory, recursive);
#endif
auto path_to_physical_name = [](const fs::path& path) {
#ifdef _WIN32
// Find the first file in the directory.
WIN32_FIND_DATA ffd;
HANDLE hFind = FindFirstFile (UTF8ToTStr (directory + " \\ *" ).c_str (), &ffd);
// TODO Ideally this would not be needed - dolphin really should not have code directly mucking
// about with directory separators (for host paths - emulated paths may require it) and instead
// use fs::path to interact with them.
auto wpath = path.wstring ();
std::replace (wpath.begin (), wpath.end (), L' \\ ' , L' /' );
return WStringToUTF8 (wpath);
#else
return PathToString (path);
#endif
};
if (hFind == INVALID_HANDLE_VALUE)
{
FindClose (hFind);
return false ;
}
auto dirent_to_fstent = [&](const fs::directory_entry& entry) {
return FSTEntry{
.isDirectory = entry.is_directory (),
.size = entry.is_directory () ? 0 : entry.file_size (),
.physicalName = path_to_physical_name (entry.path ()),
.virtualName = PathToString (entry.path ().filename ()),
};
};
// Windows loop
do
{
const std::string virtualName (TStrToUTF8 (ffd.cFileName ));
#else
DIR* dirp = opendir (directory.c_str ());
if (!dirp)
return false ;
auto calc_dir_size = [](FSTEntry* dir) {
dir->size += dir->children .size ();
for (auto & child : dir->children )
if (child.isDirectory )
dir->size += child.size ;
};
// non Windows loop
while (dirent* result = readdir (dirp))
{
const std::string virtualName = result->d_name ;
#endif
const auto directory_path = StringToPath (directory);
// check for "." and ".."
if (((virtualName[ 0 ] == ' . ' ) && (virtualName[ 1 ] == ' \0 ' )) ||
((virtualName[ 0 ] == ' . ' ) && (virtualName[ 1 ] == ' . ' ) && (virtualName[ 2 ] == ' \0 ' )))
continue ;
FSTEntry parent_entry;
parent_entry. physicalName = path_to_physical_name (directory_path);
parent_entry. isDirectory = fs::is_directory (directory_path);
parent_entry. size = 0 ;
std::string newPath = directory + DIR_SEP_CHR + virtualName;
if (IsDirectory (newPath))
std::error_code error;
if (recursive)
{
int prev_depth = 0 ;
std::stack<FSTEntry*> dir_fsts;
dir_fsts.push (&parent_entry);
for (auto it = fs::recursive_directory_iterator (directory_path, error);
it != fs::recursive_directory_iterator (); it.increment (error))
{
if (!DeleteDirRecursively (newPath))
const int cur_depth = it.depth ();
if (cur_depth > prev_depth)
{
success = false ;
break ;
dir_fsts.push (&dir_fsts.top ()->children .back ());
}
}
else
{
if (!File::Delete (newPath))
else if (cur_depth < prev_depth)
{
success = false ;
break ;
while (dir_fsts.size () - 1 != cur_depth)
{
calc_dir_size (dir_fsts.top ());
dir_fsts.pop ();
}
}
dir_fsts.top ()->children .emplace_back (dirent_to_fstent (*it));
prev_depth = cur_depth;
}
while (dir_fsts.size ())
{
calc_dir_size (dir_fsts.top ());
dir_fsts.pop ();
}
}
else
{
for (auto it = fs::directory_iterator (directory_path, error); it != fs::directory_iterator ();
it.increment (error))
{
parent_entry.children .emplace_back (dirent_to_fstent (*it));
}
calc_dir_size (&parent_entry);
}
# ifdef _WIN32
} while ( FindNextFile (hFind, &ffd) != 0 );
FindClose (hFind);
# else
if (error)
{
// NOTE Possibly partial file list still returned
ERROR_LOG_FMT (COMMON, " {} error on {}: {} " , __func__, directory, error. message ());
}
closedir (dirp);
#endif
if (success)
File::DeleteDir (directory);
return parent_entry;
}
// Deletes the given directory and anything under it. Returns true on success.
bool DeleteDirRecursively (const std::string& directory)
{
DEBUG_LOG_FMT (COMMON, " {}: {}" , __func__, directory);
std::error_code error;
const std::uintmax_t num_removed = std::filesystem::remove_all (StringToPath (directory), error);
const bool success = num_removed != 0 && !error;
if (!success)
ERROR_LOG_FMT (COMMON, " {}: {} failed {}" , __func__, directory, error.message ());
return success;
}
// Create directory and copy contents (optionally overwrites existing files)
bool CopyDir (const std::string& source_path, const std::string& dest_path, const bool destructive)
{
if (source_path == dest_path)
auto src_path = StringToPath (source_path);
auto dst_path = StringToPath (dest_path);
if (fs::equivalent (src_path, dst_path))
return true ;
if (!Exists (source_path))
return false ;
// Shouldn't be used to short circuit operations after an earlier failure
bool everything_copied = true ;
if (!Exists (dest_path))
everything_copied = File::CreateFullPath (dest_path) && everything_copied;
#ifdef _WIN32
WIN32_FIND_DATA ffd;
HANDLE hFind = FindFirstFile (UTF8ToTStr (source_path + " \\ *" ).c_str (), &ffd);
if (hFind == INVALID_HANDLE_VALUE)
{
FindClose (hFind);
return false ;
}
do
{
const std::string virtualName (TStrToUTF8 (ffd.cFileName ));
#else
DIR* dirp = opendir (source_path.c_str ());
if (!dirp)
return false ;
DEBUG_LOG_FMT (COMMON, " {}: {} --> {}" , __func__, source_path, dest_path);
while (dirent* result = readdir (dirp))
auto options = fs::copy_options::recursive;
if (destructive)
options |= fs::copy_options::overwrite_existing;
std::error_code error;
bool copied = fs::copy_file (src_path, dst_path, options, error);
if (!copied)
{
const std::string virtualName (result->d_name );
#endif
// check for "." and ".."
if (virtualName == " ." || virtualName == " .." )
continue ;
const std::string source = source_path + DIR_SEP + virtualName;
const std::string dest = dest_path + DIR_SEP + virtualName;
if (IsDirectory (source))
{
if (!Exists (dest))
File::CreateFullPath (dest + DIR_SEP);
everything_copied = CopyDir (source, dest, destructive) && everything_copied;
}
else if (!destructive && !Exists (dest))
{
everything_copied = Copy (source, dest) && everything_copied;
}
else if (destructive)
{
everything_copied = Rename (source, dest) && everything_copied;
}
#ifdef _WIN32
} while (FindNextFile (hFind, &ffd) != 0 );
FindClose (hFind);
#else
ERROR_LOG_FMT (COMMON, " {}: failed {} --> {}: {}" , __func__, source_path, dest_path,
error.message ());
}
closedir (dirp);
#endif
return everything_copied;
return copied;
}
// Returns the current directory
std::string GetCurrentDir ()
{
// Get the current working directory (getcwd uses malloc)
char * dir = __getcwd ( nullptr , 0 );
if (!dir )
std::error_code error;
auto directory = PathToString ( fs::current_path (error) );
if (error )
{
ERROR_LOG_FMT (COMMON, " GetCurrentDirectory failed: {}" , LastStrerrorString ());
return " " ;
ERROR_LOG_FMT (COMMON, " {} failed: {}" , __func__, error. message ());
return {} ;
}
std::string strDir = dir;
free (dir);
return strDir;
return directory;
}
// Sets the current directory to the given directory
bool SetCurrentDir (const std::string& directory)
{
return __chdir (directory.c_str ()) == 0 ;
std::error_code error;
fs::current_path (StringToPath (directory), error);
if (error)
{
ERROR_LOG_FMT (COMMON, " {} failed: {}" , __func__, error.message ());
return false ;
}
return true ;
}
std::string CreateTempDir ()
Expand Down
Expand Up
@@ -754,18 +600,10 @@ std::string CreateTempDir()
std::string GetTempFilenameForAtomicWrite (std::string path)
{
#ifdef _WIN32
std::unique_ptr<TCHAR[], decltype (&std::free)> absbuf{
_tfullpath (nullptr , UTF8ToTStr (path).c_str (), 0 ), std::free};
if (absbuf != nullptr )
{
path = TStrToUTF8 (absbuf.get ());
}
#else
char absbuf[PATH_MAX];
if (realpath (path.c_str (), absbuf) != nullptr )
path = absbuf;
#endif
std::error_code error;
auto absolute_path = fs::absolute (StringToPath (path), error);
if (!error)
path = PathToString (absolute_path);
return std::move (path) + " .xxx" ;
}
Expand Down
Expand Up
@@ -818,48 +656,32 @@ std::string GetBundleDirectory()
std::string GetExePath ()
{
static const std::string dolphin_path = [] {
std::string result;
#ifdef _WIN32
auto dolphin_exe_path = GetModuleName (nullptr );
if (dolphin_exe_path)
{
std::unique_ptr<TCHAR[], decltype (&std::free)> dolphin_exe_expanded_path{
_tfullpath (nullptr , dolphin_exe_path->c_str (), 0 ), std::free};
if (dolphin_exe_expanded_path)
{
result = TStrToUTF8 (dolphin_exe_expanded_path.get ());
}
else
{
result = TStrToUTF8 (*dolphin_exe_path);
}
}
auto exe_path = GetModuleName (nullptr );
if (!exe_path)
return {};
std::error_code error;
auto exe_path_absolute = fs::absolute (exe_path.value (), error);
if (error)
return {};
return PathToString (exe_path_absolute);
#elif defined(__APPLE__)
result = GetBundleDirectory ();
return GetBundleDirectory ();
#else
char dolphin_exe_path[PATH_MAX];
ssize_t len = ::readlink (" /proc/self/exe" , dolphin_exe_path, sizeof (dolphin_exe_path));
if (len == -1 || len == sizeof (dolphin_exe_path))
{
len = 0 ;
}
dolphin_exe_path[len] = ' \0 ' ;
result = dolphin_exe_path;
char dolphin_exe_path[PATH_MAX];
ssize_t len = ::readlink (" /proc/self/exe" , dolphin_exe_path, sizeof (dolphin_exe_path));
if (len == -1 || len == sizeof (dolphin_exe_path))
{
len = 0 ;
}
dolphin_exe_path[len] = ' \0 ' ;
return dolphin_exe_path;
#endif
return result;
}();
return dolphin_path;
}
std::string GetExeDirectory ()
{
std::string exe_path = GetExePath ();
#ifdef _WIN32
return exe_path.substr (0 , exe_path.rfind (' \\ ' ));
#else
return exe_path.substr (0 , exe_path.rfind (' /' ));
#endif
return PathToString (StringToPath (GetExePath ()).parent_path ());
}
static std::string CreateSysDirectoryPath ()
Expand Down