Fix rz_path_prefix not working when BINDIR is at the root directory or several folders deep (#2332)

* Add an option to provide a custom prefix for portable binaries
* Use bindir's depth to find the portable root path in rz_path_prefix
* Skip the prefix folder check if we are not in bindir
This commit is contained in:
yossizap 2022-02-22 03:08:56 +00:00 committed by GitHub
parent 0549b2b5fb
commit b744c8749a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 80 additions and 16 deletions

View file

@ -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@"

View file

@ -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

View file

@ -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) {

View file

@ -5,6 +5,7 @@
#include <rz_util/rz_file.h>
#include <rz_util/rz_sys.h>
#include <rz_util/rz_str.h>
#include <rz_util/rz_utf8.h>
/**
* \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;
}

View file

@ -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 <unistd.h>', []],
['execl', '#include <unistd.h>', []],
['system', '#include <stdlib.h>', []],
['realpath', '#include <stdlib.h>', []],
['fork', '#include <unistd.h>', []],
['nice', '#include <unistd.h>', []],
['copyfile', '#include <copyfile.h>', []],
@ -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