diff --git a/docs/Lua API.rst b/docs/Lua API.rst index e017e0a8c..80fd0add6 100644 --- a/docs/Lua API.rst +++ b/docs/Lua API.rst @@ -2160,6 +2160,14 @@ unless otherwise noted. Changes the current directory to ``path``. Use with caution. +* ``dfhack.filesystem.restore_cwd()`` + + Restores the current working directory to what it was when DF started. + +* ``dfhack.filesystem.get_initial_cwd()`` + + Returns the value of the working directory when DF was started. + * ``dfhack.filesystem.mkdir(path)`` Creates a new directory. Returns ``false`` if unsuccessful, including if ``path`` already exists. diff --git a/docs/changelog.txt b/docs/changelog.txt index 79179ce5e..9cbecf9ec 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -34,6 +34,7 @@ changelog.txt uses a syntax similar to RST, with a few special sequences: # Future ## Fixes +- Fixed an issue on some Linux systems where DFHack installed through a package manager would attempt to write files to a non-writable folder (notably when running `exportlegends` or `gui/autogems`) - `buildingplan`: artifacts are now successfully matched when max quality is set to ``artifacts`` - `buildingplan`: no longer erroneously matches items to buildings while the game is paused - `dwarfmonitor`: fixed a crash when opening the ``prefs`` screen if units have vague preferences diff --git a/library/Core.cpp b/library/Core.cpp index c6ce9ea48..ff4ccc98e 100644 --- a/library/Core.cpp +++ b/library/Core.cpp @@ -1618,7 +1618,10 @@ bool Core::Init() freopen("stderr.log", "w", stderr); #endif - fprintf(stderr, "DFHack build: %s\n", Version::git_description()); + Filesystem::init(); + + cerr << "DFHack build: " << Version::git_description() << "\n" + << "Starting with working directory: " << Filesystem::getcwd() << endl; // find out what we are... #ifdef LINUX_BUILD diff --git a/library/LuaApi.cpp b/library/LuaApi.cpp index c863a8d4d..431ab3ae5 100644 --- a/library/LuaApi.cpp +++ b/library/LuaApi.cpp @@ -2371,6 +2371,8 @@ static const luaL_Reg dfhack_screen_funcs[] = { static const LuaWrapper::FunctionReg dfhack_filesystem_module[] = { WRAPM(Filesystem, getcwd), + WRAPM(Filesystem, restore_cwd), + WRAPM(Filesystem, get_initial_cwd), WRAPM(Filesystem, chdir), WRAPM(Filesystem, mkdir), WRAPM(Filesystem, mkdir_recursive), diff --git a/library/Process-linux.cpp b/library/Process-linux.cpp index 45e655948..be3ebb5df 100644 --- a/library/Process-linux.cpp +++ b/library/Process-linux.cpp @@ -22,29 +22,28 @@ must not be misrepresented as being the original software. distribution. */ -#include "Internal.h" - +#include +#include #include #include +#include +#include +#include #include #include #include - -#include #include -#include -#include -#include -#include -using namespace std; -#include +#include "Error.h" +#include "Internal.h" +#include "md5wrapper.h" #include "MemAccess.h" #include "Memory.h" -#include "VersionInfoFactory.h" +#include "modules/Filesystem.h" #include "VersionInfo.h" -#include "Error.h" -#include +#include "VersionInfoFactory.h" + +using namespace std; using namespace DFHack; Process::Process(const VersionInfoFactory& known_versions) : identified(false), my_pe(0) @@ -181,28 +180,7 @@ uint32_t Process::getTickCount() string Process::getPath() { - static string cached_path; - if (cached_path.empty()) - { - const char *exe_name = "/proc/self/exe"; - char exe_path[1024]; - int length = readlink(exe_name, exe_path, sizeof(exe_path)); - if (length > 0) - { - exe_path[length] = '\0'; - string path_string = exe_path; - // DF lives in libs, so move up a folder - cached_path = path_string.substr(0, path_string.find_last_of("/", path_string.find_last_of("/") - 1)); - } - else - { - perror("readlink(/proc/self/exe) failed"); - fprintf(stderr, " length=%i\n", length); - cached_path = "."; - } - fprintf(stderr, "Resolved DF root to %s\n", cached_path.c_str()); - } - return cached_path; + return Filesystem::get_initial_cwd(); } int Process::getPID() diff --git a/library/include/modules/Filesystem.h b/library/include/modules/Filesystem.h index c9218ba33..8e7bab9b2 100644 --- a/library/include/modules/Filesystem.h +++ b/library/include/modules/Filesystem.h @@ -146,8 +146,11 @@ enum _filetype { namespace DFHack { namespace Filesystem { + DFHACK_EXPORT void init (); DFHACK_EXPORT bool chdir (std::string path); DFHACK_EXPORT std::string getcwd (); + DFHACK_EXPORT bool restore_cwd (); + DFHACK_EXPORT std::string get_initial_cwd (); DFHACK_EXPORT bool mkdir (std::string path); // returns true on success or if directory already exists DFHACK_EXPORT bool mkdir_recursive (std::string path); diff --git a/library/modules/Filesystem.cpp b/library/modules/Filesystem.cpp index c0d0860ad..e0d0bc8c2 100644 --- a/library/modules/Filesystem.cpp +++ b/library/modules/Filesystem.cpp @@ -52,8 +52,21 @@ SOFTWARE. using namespace DFHack; +static bool initialized = false; +static std::string initial_cwd; + +void Filesystem::init () +{ + if (!initialized) + { + initialized = true; + initial_cwd = Filesystem::getcwd(); + } +} + bool Filesystem::chdir (std::string path) { + Filesystem::init(); return ::chdir(path.c_str()) == 0; } @@ -71,6 +84,17 @@ std::string Filesystem::getcwd () return result; } +bool Filesystem::restore_cwd () +{ + return Filesystem::chdir(initial_cwd); +} + +std::string Filesystem::get_initial_cwd () +{ + Filesystem::init(); + return initial_cwd; +} + bool Filesystem::mkdir (std::string path) { int fail; diff --git a/scripts b/scripts index a2b0c7c41..ccf1d035a 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit a2b0c7c41919b54933858482f1daa1dae6a6664b +Subproject commit ccf1d035a653c991b669fccc8293ecbab449548f diff --git a/test/core.lua b/test/core.lua index 6cde334d4..ba104c90a 100644 --- a/test/core.lua +++ b/test/core.lua @@ -13,6 +13,10 @@ function test.getDFPath() expect.eq(clean_path(dfhack.getDFPath()), old_cwd) end +function test.get_initial_cwd() + expect.eq(clean_path(dfhack.filesystem.get_initial_cwd()), clean_path(dfhack.getDFPath())) +end + function test.getDFPath_chdir() dfhack.with_finalize(restore_cwd, function() fs.chdir('data')