forked from 0ad/0ad
Simplify sys_get_executable_name by using realpath
This was SVN commit r7104.
This commit is contained in:
parent
2114bf6795
commit
43950c2fde
@ -22,94 +22,7 @@
|
||||
|
||||
#define GNU_SOURCE
|
||||
#include "mocks/dlfcn.h"
|
||||
#include "mocks/boost_filesystem.h"
|
||||
|
||||
// TODO: This normalization code is copied from boost::filesystem,
|
||||
// where it is deprecated, presumably for good reasons (probably
|
||||
// because symlinks mean "x/../y" != "y" in general), and this file
|
||||
// is not an appropriate place for the code anyway, so it should be
|
||||
// rewritten or removed or something. (Also, the const_cast is evil.)
|
||||
namespace boost { namespace filesystem {
|
||||
|
||||
// Derived from boost/filesystem/path.hpp:
|
||||
// "Copyright Beman Dawes 2002-2005
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)"
|
||||
|
||||
template<class String, class Traits>
|
||||
basic_path<String, Traits> normalize_COPIED(const basic_path<String, Traits> &self)
|
||||
{
|
||||
typedef basic_path<String, Traits> path_type;
|
||||
typedef typename path_type::string_type string_type;
|
||||
typedef typename path_type::iterator iterator;
|
||||
|
||||
static const typename string_type::value_type dot_str[]
|
||||
= { dot<path>::value, 0 };
|
||||
|
||||
if ( self.empty() ) return self;
|
||||
|
||||
path temp;
|
||||
iterator start( self.begin() );
|
||||
iterator last( self.end() );
|
||||
iterator stop( last-- );
|
||||
for ( iterator itr( start ); itr != stop; ++itr )
|
||||
{
|
||||
// ignore "." except at start and last
|
||||
if ( itr->size() == 1
|
||||
&& (*itr)[0] == dot<path_type>::value
|
||||
&& itr != start
|
||||
&& itr != last ) continue;
|
||||
|
||||
// ignore a name and following ".."
|
||||
if ( !temp.empty()
|
||||
&& itr->size() == 2
|
||||
&& (*itr)[0] == dot<path_type>::value
|
||||
&& (*itr)[1] == dot<path_type>::value ) // dot dot
|
||||
{
|
||||
string_type lf( temp.leaf() );
|
||||
if ( lf.size() > 0
|
||||
&& (lf.size() != 1
|
||||
|| (lf[0] != dot<path_type>::value
|
||||
&& lf[0] != slash<path_type>::value))
|
||||
&& (lf.size() != 2
|
||||
|| (lf[0] != dot<path_type>::value
|
||||
&& lf[1] != dot<path_type>::value
|
||||
# ifdef BOOST_WINDOWS_PATH
|
||||
&& lf[1] != colon<path_type>::value
|
||||
# endif
|
||||
)
|
||||
)
|
||||
)
|
||||
{
|
||||
temp.remove_leaf();
|
||||
// if not root directory, must also remove "/" if any
|
||||
if ( temp.string().size() > 0
|
||||
&& temp.string()[temp.string().size()-1]
|
||||
== slash<path_type>::value )
|
||||
{
|
||||
typename string_type::size_type rds(
|
||||
detail::root_directory_start<String,Traits>( temp.string(),
|
||||
temp.string().size() ) );
|
||||
if ( rds == string_type::npos
|
||||
|| rds != temp.string().size()-1 )
|
||||
{ const_cast<String&>( temp.string() ).erase( temp.string().size()-1 ); }
|
||||
}
|
||||
|
||||
iterator next( itr );
|
||||
if ( temp.empty() && ++next != stop
|
||||
&& next == last && *last == dot_str ) temp /= dot_str;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
temp /= *itr;
|
||||
};
|
||||
|
||||
if ( temp.empty() ) temp /= dot_str;
|
||||
return temp;
|
||||
}
|
||||
|
||||
} }
|
||||
#include "mocks/unistd.h"
|
||||
|
||||
LibError sys_get_executable_name(char* n_path, size_t max_chars)
|
||||
{
|
||||
@ -125,12 +38,33 @@ LibError sys_get_executable_name(char* n_path, size_t max_chars)
|
||||
}
|
||||
path = dl_info.dli_fname;
|
||||
|
||||
// If this looks like a relative path, resolve against cwd.
|
||||
// If this looks like an absolute path, we still need to normalize it.
|
||||
// If this looks like an absolute path, use realpath to get the normalized
|
||||
// path (with no '.' or '..')
|
||||
if (path[0] == '/') {
|
||||
char* resolved = realpath(path, NULL);
|
||||
if (!resolved)
|
||||
return ERR::NO_SYS;
|
||||
strncpy(n_path, resolved, max_chars);
|
||||
free(resolved);
|
||||
return INFO::OK;
|
||||
}
|
||||
|
||||
// If this looks like a relative path, resolve against cwd and use realpath
|
||||
if (strchr(path, '/')) {
|
||||
fs::path p = fs::complete(fs::path(path), T::Boost_Filesystem_initial_path());
|
||||
fs::path n = fs::normalize_COPIED(p);
|
||||
strncpy(n_path, n.string().c_str(), max_chars);
|
||||
char cwd[PATH_MAX];
|
||||
if (!T::getcwd(cwd, PATH_MAX))
|
||||
return ERR::NO_SYS;
|
||||
|
||||
char absolute[PATH_MAX];
|
||||
int ret = snprintf(absolute, PATH_MAX, "%s/%s", cwd, path);
|
||||
if (ret < 0 || ret >= PATH_MAX)
|
||||
return ERR::NO_SYS; // path too long, or other error
|
||||
char* resolved = realpath(absolute, NULL);
|
||||
if (!resolved)
|
||||
return ERR::NO_SYS;
|
||||
|
||||
strncpy(n_path, resolved, max_chars);
|
||||
free(resolved);
|
||||
return INFO::OK;
|
||||
}
|
||||
|
||||
|
@ -23,7 +23,7 @@
|
||||
|
||||
#if OS_LINUX
|
||||
# include "mocks/dlfcn.h"
|
||||
# include "mocks/boost_filesystem.h"
|
||||
# include "mocks/unistd.h"
|
||||
#endif
|
||||
|
||||
#include <cxxtest/PsTestWrapper.h>
|
||||
@ -94,36 +94,73 @@ public:
|
||||
// implementations of sys_get_executable_name:
|
||||
|
||||
#if OS_LINUX
|
||||
// Since the implementation uses realpath, the tested files need to
|
||||
// really exist. So set up a directory tree for testing:
|
||||
|
||||
const char* tmpdir = getenv("TMPDIR");
|
||||
if (! tmpdir) tmpdir = P_tmpdir;
|
||||
|
||||
char root[PATH_MAX];
|
||||
sprintf_s(root, PATH_MAX, "%s/pyrogenesis-test-sysdep-XXXXXX", tmpdir);
|
||||
TS_ASSERT(mkdtemp(root));
|
||||
std::string rootstr(root);
|
||||
|
||||
const char* dirs[] = {
|
||||
"/example",
|
||||
"/example/a",
|
||||
"/example/a/b",
|
||||
"/example/a/b/c",
|
||||
"/example/a/b/d",
|
||||
"/example/a/e",
|
||||
"/example/a/f"
|
||||
};
|
||||
const char* files[] = {
|
||||
"/example/executable",
|
||||
"/example/a/f/executable",
|
||||
};
|
||||
for (size_t i = 0; i < ARRAY_SIZE(dirs); ++i)
|
||||
{
|
||||
std::string name = rootstr + dirs[i];
|
||||
TS_ASSERT_EQUALS(mkdir(name.c_str(), 0700), 0);
|
||||
}
|
||||
for (size_t i = 0; i < ARRAY_SIZE(files); ++i)
|
||||
{
|
||||
std::string name = rootstr + files[i];
|
||||
FILE* f = fopen(name.c_str(), "w");
|
||||
TS_ASSERT(f);
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
// Try with absolute paths
|
||||
{
|
||||
Mock_dladdr d("/example/executable");
|
||||
Mock_dladdr d(rootstr+"/example/executable");
|
||||
TS_ASSERT_EQUALS(sys_get_executable_name(path, PATH_MAX), INFO::OK);
|
||||
TS_ASSERT_STR_EQUALS(path, "/example/executable");
|
||||
TS_ASSERT_STR_EQUALS(path, rootstr+"/example/executable");
|
||||
}
|
||||
{
|
||||
Mock_dladdr d("/example/./a/b/../c/../../executable");
|
||||
Mock_dladdr d(rootstr+"/example/./a/b/../e/../../executable");
|
||||
TS_ASSERT_EQUALS(sys_get_executable_name(path, PATH_MAX), INFO::OK);
|
||||
TS_ASSERT_STR_EQUALS(path, "/example/executable");
|
||||
TS_ASSERT_STR_EQUALS(path, rootstr+"/example/executable");
|
||||
}
|
||||
|
||||
// Try with relative paths
|
||||
{
|
||||
Mock_dladdr d("./executable");
|
||||
Mock_initial_path m("/example");
|
||||
Mock_getcwd m(rootstr+"/example");
|
||||
TS_ASSERT_EQUALS(sys_get_executable_name(path, PATH_MAX), INFO::OK);
|
||||
TS_ASSERT_STR_EQUALS(path, "/example/executable");
|
||||
TS_ASSERT_STR_EQUALS(path, rootstr+"/example/executable");
|
||||
}
|
||||
{
|
||||
Mock_dladdr d("./executable");
|
||||
Mock_initial_path m("/example/");
|
||||
Mock_getcwd m(rootstr+"/example/");
|
||||
TS_ASSERT_EQUALS(sys_get_executable_name(path, PATH_MAX), INFO::OK);
|
||||
TS_ASSERT_STR_EQUALS(path, "/example/executable");
|
||||
TS_ASSERT_STR_EQUALS(path, rootstr+"/example/executable");
|
||||
}
|
||||
{
|
||||
Mock_dladdr d("../d/../../e/executable");
|
||||
Mock_initial_path m("/example/a/b/c");
|
||||
Mock_dladdr d("../d/../../f/executable");
|
||||
Mock_getcwd m(rootstr+"/example/a/b/c");
|
||||
TS_ASSERT_EQUALS(sys_get_executable_name(path, PATH_MAX), INFO::OK);
|
||||
TS_ASSERT_STR_EQUALS(path, "/example/a/e/executable");
|
||||
TS_ASSERT_STR_EQUALS(path, rootstr+"/example/a/f/executable");
|
||||
}
|
||||
|
||||
// Try with pathless names
|
||||
@ -131,6 +168,20 @@ public:
|
||||
Mock_dladdr d("executable");
|
||||
TS_ASSERT_EQUALS(sys_get_executable_name(path, PATH_MAX), ERR::NO_SYS);
|
||||
}
|
||||
|
||||
// Clean up the temporary files
|
||||
for (size_t i = 0; i < ARRAY_SIZE(files); ++i)
|
||||
{
|
||||
std::string name = rootstr + files[i];
|
||||
TS_ASSERT_EQUALS(unlink(name.c_str()), 0);
|
||||
}
|
||||
for (ssize_t i = ARRAY_SIZE(dirs)-1; i >= 0; --i) // reverse order
|
||||
{
|
||||
std::string name(root);
|
||||
name += dirs[i];
|
||||
TS_ASSERT_EQUALS(rmdir(name.c_str()), 0);
|
||||
}
|
||||
TS_ASSERT_EQUALS(rmdir(root), 0);
|
||||
#endif // OS_LINUX
|
||||
}
|
||||
|
||||
@ -139,24 +190,25 @@ public:
|
||||
class Mock_dladdr : public T::Base_dladdr
|
||||
{
|
||||
public:
|
||||
Mock_dladdr(const char* fname) : fname_(fname) { }
|
||||
Mock_dladdr(const std::string& fname) : fname_(fname) { }
|
||||
int dladdr(void *UNUSED(addr), Dl_info *info) {
|
||||
info->dli_fname = fname_;
|
||||
info->dli_fname = fname_.c_str();
|
||||
return 1;
|
||||
}
|
||||
private:
|
||||
const char* fname_;
|
||||
std::string fname_;
|
||||
};
|
||||
|
||||
class Mock_initial_path : public T::Base_Boost_Filesystem_initial_path
|
||||
class Mock_getcwd : public T::Base_getcwd
|
||||
{
|
||||
public:
|
||||
Mock_initial_path(const char* buf) : buf_(buf) { }
|
||||
fs::path Boost_Filesystem_initial_path() {
|
||||
return fs::path(buf_);
|
||||
Mock_getcwd(const std::string& buf) : buf_(buf) { }
|
||||
char* getcwd(char* buf, size_t size) {
|
||||
strncpy_s(buf, size, buf_.c_str(), buf_.length());
|
||||
return buf;
|
||||
}
|
||||
private:
|
||||
const char* buf_;
|
||||
std::string buf_;
|
||||
};
|
||||
#endif
|
||||
|
||||
|
@ -1,10 +0,0 @@
|
||||
#include "lib/external_libraries/boost_filesystem.h"
|
||||
#include <cxxtest/Mock.h>
|
||||
CXXTEST_MOCK(
|
||||
Boost_Filesystem_initial_path,
|
||||
boost::filesystem::path,
|
||||
Boost_Filesystem_initial_path,
|
||||
(),
|
||||
boost::filesystem::initial_path,
|
||||
()
|
||||
);
|
@ -8,8 +8,7 @@
|
||||
#endif
|
||||
#include "lib/precompiled.h"
|
||||
|
||||
#include "mocks/boost_filesystem.h"
|
||||
|
||||
#if OS_LINUX
|
||||
#include "mocks/dlfcn.h"
|
||||
#include "mocks/unistd.h"
|
||||
#endif // OS_LINUX
|
||||
|
@ -11,12 +11,12 @@
|
||||
// Cause calls to be redirected to the real function by default
|
||||
#define DEFAULT(name) static T::Real_##name real_##name
|
||||
|
||||
#include "mocks/boost_filesystem.h"
|
||||
DEFAULT(Boost_Filesystem_initial_path);
|
||||
|
||||
#if OS_LINUX
|
||||
|
||||
#include "mocks/dlfcn.h"
|
||||
DEFAULT(dladdr);
|
||||
|
||||
#include "mocks/unistd.h"
|
||||
DEFAULT(getcwd);
|
||||
|
||||
#endif // OS_LINUX
|
||||
|
7
source/mocks/unistd.h
Normal file
7
source/mocks/unistd.h
Normal file
@ -0,0 +1,7 @@
|
||||
#include <unistd.h>
|
||||
#include <cxxtest/Mock.h>
|
||||
CXXTEST_MOCK_GLOBAL(
|
||||
char *, getcwd,
|
||||
(char *buf, size_t size),
|
||||
(buf, size)
|
||||
);
|
Loading…
Reference in New Issue
Block a user