diff --git a/librz/include/rz_userconf.h.in b/librz/include/rz_userconf.h.in index a756d12ca7..cf3e6f3e18 100644 --- a/librz/include/rz_userconf.h.in +++ b/librz/include/rz_userconf.h.in @@ -20,6 +20,7 @@ #define HAVE_EXECVP @HAVE_EXECVP@ #define HAVE_EXECL @HAVE_EXECL@ #define HAVE_SYSTEM @HAVE_SYSTEM@ +#define HAVE_REALPATH @HAVE_REALPATH@ #define HAVE_PIPE2 @HAVE_PIPE2@ #define HAVE_ENVIRON @HAVE_ENVIRON@ #define HAVE_OPENPTY @HAVE_OPENPTY@ @@ -54,6 +55,8 @@ #define RZ_DATDIR "@DATADIR@" #define RZ_WWWROOT "@WWWROOT@" +#define RZ_BINDIR_DEPTH @BINDIR_DEPTH@ + #define RZ_PLUGINS "@PLUGINS@" #define RZ_DATADIR "@DATADIR_RZ@" #define RZ_SDB "@SDB@" diff --git a/librz/include/rz_util/rz_path.h b/librz/include/rz_util/rz_path.h index 277a1e6615..448972181e 100644 --- a/librz/include/rz_util/rz_path.h +++ b/librz/include/rz_util/rz_path.h @@ -26,6 +26,8 @@ RZ_API RZ_OWN char *rz_path_home_history(void); RZ_API RZ_OWN char *rz_path_home_expand(RZ_NULLABLE const char *path); +RZ_API RZ_OWN char *rz_path_realpath(RZ_NULLABLE const char *path); + #ifdef __cplusplus } #endif diff --git a/librz/util/file.c b/librz/util/file.c index bf388c8fdc..92fb67d878 100644 --- a/librz/util/file.c +++ b/librz/util/file.c @@ -231,7 +231,7 @@ RZ_API char *rz_file_abspath_rel(const char *cwd, const char *file) { ret = tmp; } #endif -#if __UNIX__ +#if HAVE_REALPATH char rp[PATH_MAX] = { 0 }; char *abspath = realpath(ret, rp); // second arg == NULL is only an extension if (abspath) { diff --git a/librz/util/path.c b/librz/util/path.c index d1828966dc..9892095923 100644 --- a/librz/util/path.c +++ b/librz/util/path.c @@ -5,6 +5,7 @@ #include #include #include +#include /** * \brief Return \p path prefixed by the Rizin install prefix @@ -15,23 +16,37 @@ RZ_API RZ_OWN char *rz_path_prefix(RZ_NULLABLE const char *path) { #if RZ_IS_PORTABLE char *pid_to_path = rz_sys_pid_to_path(rz_sys_getpid()); - if (pid_to_path) { - char *t = rz_file_dirname(pid_to_path); - free(pid_to_path); - // When rz_path_prefix is called from a unit test or from a - // not-yet-instazled rizin binary this would return the wrong path. - // In those cases, just return RZ_PREFIX. - char *result = NULL; - if (rz_str_endswith(t, RZ_SYS_DIR RZ_BINDIR)) { - char *r = rz_file_dirname(t); - result = rz_file_path_join(r, path); - free(r); + if (!pid_to_path) { + goto prefix; + } + char *bindir = rz_path_realpath(RZ_JOIN_2_PATHS(RZ_PREFIX, RZ_BINDIR)); + if (!bindir) { + goto prefix; + } + + char *it = rz_file_dirname(pid_to_path); + free(pid_to_path); + + bool in_bindir = rz_str_endswith(it, rz_file_basename(bindir)); + free(bindir); + // When rz_path_prefix is called from a unit test or from a + // not-yet-installed rizin binary this would return the wrong path. + // In those cases, just return RZ_PREFIX. + if (in_bindir) { + for (int i = 0; i < RZ_BINDIR_DEPTH; i++) { + char *tmp = it; + it = rz_file_dirname(tmp); + free(tmp); } - free(t); - if (result) { + + if (rz_file_is_directory(it)) { + char *result = rz_file_path_join(it, path); + free(it); return result; } } + free(it); +prefix: #endif return rz_file_path_join(RZ_PREFIX, path); } @@ -180,3 +195,33 @@ RZ_API RZ_OWN char *rz_path_home_expand(RZ_NULLABLE const char *path) { return rz_path_home(path + 1); } + +/** + * \brief Return a canonicalized absolute path. Expands all symbolic links and resolves + * references to /./, /../ and extra '/' characters. + * + * \param path Original file path. + * \return New canonicalized absolute path. + */ +RZ_API RZ_OWN char *rz_path_realpath(RZ_NULLABLE const char *path) { + if (!path) { + return NULL; + } +#if HAVE_REALPATH + char buf[PATH_MAX] = { 0 }; + const char *rp = realpath(path, buf); + if (rp) { + return strdup(rp); + } +#elif __WINDOWS__ + wchar_t buf[MAX_PATH] = { 0 }; + + wchar_t *wpath = rz_utf8_to_utf16(path); + DWORD len = GetFullPathNameW(wpath, MAX_PATH, buf, NULL); + free(wpath); + if (len > 0 && len < MAX_PATH - 1) { + return rz_utf16_to_utf8_l(buf, len); + } +#endif + return NULL; +} diff --git a/meson.build b/meson.build index 380c56df08..73b1f5bfd2 100644 --- a/meson.build +++ b/meson.build @@ -1,7 +1,7 @@ project('rizin', 'c', version: 'v0.4.0-git', license: 'LGPL3', - meson_version: '>=0.55.3', + meson_version: '>=0.58.0', default_options: [ 'buildtype=debugoptimized', 'b_vscrt=from_buildtype', @@ -214,6 +214,12 @@ else rizin_bindings = rizin_libdir / 'rizin-bindings' endif +# Calcualte BINDIR's depth to be able to find the root directory during runtime +# in portable builds +py_cmd = 'import os; print(len(os.path.normpath(r"@0@").split(os.sep)) - len(os.path.normpath(r"@1@").split(os.sep)))'.format(rizin_prefix / rizin_bindir, rizin_prefix) +py_cmd = run_command(py3_exe, '-c', py_cmd) +bindir_depth = py_cmd.stdout().strip() + opts_overwrite = [ 'rizin_wwwroot', 'rizin_sdb', @@ -379,6 +385,7 @@ userconf.set10('USE_LIB_XXHASH', xxhash_dep.found()) userconf.set10('DEBUGGER', has_debugger) userconf.set('PREFIX', rizin_prefix) userconf.set('BINDIR', rizin_bindir) +userconf.set('BINDIR_DEPTH', bindir_depth) userconf.set('LIBDIR', rizin_libdir) userconf.set('INCLUDEDIR', rizin_incdir) userconf.set('DATADIR_RZ', rizin_datdir_rz) @@ -456,6 +463,7 @@ foreach item : [ ['execvp', '#include ', []], ['execl', '#include ', []], ['system', '#include ', []], + ['realpath', '#include ', []], ['fork', '#include ', []], ['nice', '#include ', []], ['copyfile', '#include ', []], @@ -610,7 +618,13 @@ rpath_exe = '' rpath_lib = '' rpath_summary = 'disabled' if use_rpath - rpath_exe = '$ORIGIN/../' + get_option('libdir') + # Use bindir depth to create a path to the rootdir from bindir + path_to_rootdir='' + foreach i : range(bindir_depth.to_int()) + path_to_rootdir += '../' + endforeach + + rpath_exe = '$ORIGIN/' + path_to_rootdir + get_option('libdir') rpath_lib = '$ORIGIN' rpath_summary = 'relative' elif use_rpath_absolute