mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-04 02:09:44 +02:00
405 lines
10 KiB
C++
405 lines
10 KiB
C++
/* ###
|
|
* IP: GHIDRA
|
|
* NOTE: Calls to Windows APIs
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
#include "filemanage.hh"
|
|
|
|
#ifdef _WINDOWS
|
|
#include <windows.h>
|
|
|
|
#else
|
|
// POSIX functions for searching directories
|
|
extern "C" {
|
|
#include <unistd.h>
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <dirent.h>
|
|
}
|
|
#endif
|
|
|
|
namespace ghidra {
|
|
|
|
// Path name separator
|
|
#ifdef _WINDOWS
|
|
char FileManage::separator = '\\';
|
|
char FileManage::separatorClass[] = "/\\";
|
|
#else
|
|
char FileManage::separator = '/';
|
|
char FileManage::separatorClass[] = "/";
|
|
#endif
|
|
|
|
void FileManage::addDir2Path(const string &path)
|
|
|
|
{
|
|
if (path.size()>0) {
|
|
pathlist.push_back(path);
|
|
if (!isSeparator(path[path.size()-1]))
|
|
pathlist.back() += separator;
|
|
}
|
|
}
|
|
|
|
void FileManage::findFile(string &res,const string &name) const
|
|
|
|
{ // Search through paths to find file with given name
|
|
vector<string>::const_iterator iter;
|
|
|
|
if (isSeparator(name[0])) {
|
|
res = name;
|
|
ifstream s(res.c_str());
|
|
if (s) {
|
|
s.close();
|
|
return;
|
|
}
|
|
}
|
|
else {
|
|
for(iter=pathlist.begin();iter!=pathlist.end();++iter) {
|
|
res = *iter + name;
|
|
ifstream s(res.c_str());
|
|
if (s) {
|
|
s.close();
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
res.clear(); // Can't find it, return empty string
|
|
}
|
|
|
|
#ifdef _WINDOWS
|
|
void FileManage::addCurrentDir(void)
|
|
|
|
{
|
|
char dirname[256];
|
|
|
|
if (0!=GetCurrentDirectoryA(256,dirname)) {
|
|
string filename(dirname);
|
|
addDir2Path(filename);
|
|
}
|
|
}
|
|
|
|
#else
|
|
void FileManage::addCurrentDir(void)
|
|
|
|
{ // Add current working directory to path
|
|
char dirname[256];
|
|
char *buf;
|
|
|
|
buf = getcwd(dirname,256);
|
|
if ((char *)0 == buf) return;
|
|
string filename(buf);
|
|
addDir2Path(filename);
|
|
}
|
|
#endif
|
|
|
|
#ifdef _WINDOWS
|
|
bool FileManage::isDirectory(const string &path)
|
|
|
|
{
|
|
DWORD attribs = GetFileAttributes(path.c_str());
|
|
if (attribs == INVALID_FILE_ATTRIBUTES) return false;
|
|
return ((attribs & FILE_ATTRIBUTE_DIRECTORY)!=0);
|
|
}
|
|
|
|
#else
|
|
bool FileManage::isDirectory(const string &path)
|
|
|
|
{
|
|
struct stat buf;
|
|
if (stat(path.c_str(),&buf) < 0) {
|
|
return false;
|
|
}
|
|
return S_ISDIR(buf.st_mode);
|
|
}
|
|
|
|
#endif
|
|
|
|
#ifdef _WINDOWS
|
|
bool FileManage::isSeparator(char c)
|
|
|
|
{
|
|
return (c == '/' || c == '\\');
|
|
}
|
|
|
|
#else
|
|
bool FileManage::isSeparator(char c)
|
|
|
|
{
|
|
return c == separator;
|
|
}
|
|
|
|
#endif
|
|
|
|
#ifdef _WINDOWS
|
|
void FileManage::matchListDir(vector<string> &res,const string &match,bool isSuffix,const string &dirname,bool allowdot)
|
|
|
|
{
|
|
WIN32_FIND_DATAA FindFileData;
|
|
HANDLE hFind;
|
|
string dirfinal;
|
|
|
|
dirfinal = dirname;
|
|
if (!isSeparator(dirfinal[dirfinal.size()-1]))
|
|
dirfinal += separator;
|
|
string regex = dirfinal + '*';
|
|
|
|
hFind = FindFirstFileA(regex.c_str(),&FindFileData);
|
|
if (hFind == INVALID_HANDLE_VALUE) return;
|
|
do {
|
|
string fullname(FindFileData.cFileName);
|
|
if (match.size() <= fullname.size()) {
|
|
if (allowdot||(fullname[0] != '.')) {
|
|
if (isSuffix) {
|
|
if (0==fullname.compare(fullname.size()-match.size(),match.size(),match))
|
|
res.push_back(dirfinal + fullname);
|
|
}
|
|
else {
|
|
if (0==fullname.compare(0,match.size(),match))
|
|
res.push_back(dirfinal + fullname);
|
|
}
|
|
}
|
|
}
|
|
} while(0!=FindNextFileA(hFind,&FindFileData));
|
|
FindClose(hFind);
|
|
}
|
|
|
|
#else
|
|
void FileManage::matchListDir(vector<string> &res,const string &match,bool isSuffix,const string &dirname,bool allowdot)
|
|
|
|
{ // Look through files in a directory for those matching -match-
|
|
DIR *dir;
|
|
struct dirent *entry;
|
|
string dirfinal = dirname;
|
|
if (!isSeparator(dirfinal[dirfinal.size()-1]))
|
|
dirfinal += separator;
|
|
|
|
dir = opendir(dirfinal.c_str());
|
|
if (dir == (DIR *)0) return;
|
|
entry = readdir(dir);
|
|
while(entry != (struct dirent *)0) {
|
|
string fullname(entry->d_name);
|
|
if (match.size() <= fullname.size()) {
|
|
if (allowdot||(fullname[0] != '.')) {
|
|
if (isSuffix) {
|
|
if (0==fullname.compare( fullname.size()-match.size(),match.size(),match))
|
|
res.push_back( dirfinal + fullname );
|
|
}
|
|
else {
|
|
if (0==fullname.compare(0,match.size(),match))
|
|
res.push_back(dirfinal + fullname);
|
|
}
|
|
}
|
|
}
|
|
entry = readdir(dir);
|
|
}
|
|
closedir(dir);
|
|
}
|
|
#endif
|
|
|
|
void FileManage::matchList(vector<string> &res,const string &match,bool isSuffix) const
|
|
|
|
{
|
|
vector<string>::const_iterator iter;
|
|
|
|
for(iter=pathlist.begin();iter!=pathlist.end();++iter)
|
|
matchListDir(res,match,isSuffix,*iter,false);
|
|
}
|
|
|
|
#ifdef _WINDOWS
|
|
|
|
void FileManage::directoryList(vector<string> &res,const string &dirname,bool allowdot)
|
|
|
|
{
|
|
WIN32_FIND_DATAA FindFileData;
|
|
HANDLE hFind;
|
|
string dirfinal = dirname;
|
|
if (!isSeparator(dirfinal[dirfinal.size()-1]))
|
|
dirfinal += separator;
|
|
string regex = dirfinal + "*";
|
|
const char *s = regex.c_str();
|
|
|
|
|
|
hFind = FindFirstFileA(s,&FindFileData);
|
|
if (hFind == INVALID_HANDLE_VALUE) return;
|
|
do {
|
|
if ( (FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY ) {
|
|
string fullname(FindFileData.cFileName);
|
|
if (allowdot || (fullname[0] != '.'))
|
|
res.push_back(dirfinal + fullname);
|
|
}
|
|
} while(0!=FindNextFileA(hFind,&FindFileData));
|
|
FindClose(hFind);
|
|
}
|
|
|
|
#else
|
|
void FileManage::directoryList(vector<string> &res,const string &dirname,bool allowdot)
|
|
|
|
{ // List full pathnames of all directories under the directory -dir-
|
|
DIR *dir;
|
|
struct dirent *entry;
|
|
string dirfinal;
|
|
|
|
dirfinal = dirname;
|
|
if (!isSeparator(dirfinal[dirfinal.size()-1]))
|
|
dirfinal += separator;
|
|
|
|
dir = opendir(dirfinal.c_str());
|
|
if (dir == (DIR *)0) return;
|
|
entry = readdir(dir);
|
|
while(entry != (struct dirent *)0) {
|
|
if (entry->d_type == DT_DIR) {
|
|
string fullname(entry->d_name);
|
|
if ((fullname!=".")&&(fullname!="..")) {
|
|
if (allowdot || (fullname[0] != '.'))
|
|
res.push_back( dirfinal + fullname );
|
|
}
|
|
}
|
|
entry = readdir(dir);
|
|
}
|
|
closedir(dir);
|
|
}
|
|
|
|
#endif
|
|
|
|
void FileManage::scanDirectoryRecursive(vector<string> &res,const string &matchname,const string &rootpath,int maxdepth)
|
|
|
|
{
|
|
if (maxdepth == 0) return;
|
|
vector<string> subdir;
|
|
directoryList(subdir,rootpath);
|
|
vector<string>::const_iterator iter;
|
|
for(iter = subdir.begin();iter!=subdir.end();++iter) {
|
|
const string &curpath( *iter );
|
|
string::size_type pos = curpath.find_last_of(separatorClass);
|
|
if (pos == string::npos)
|
|
pos = 0;
|
|
else
|
|
pos = pos + 1;
|
|
if (curpath.compare(pos,string::npos,matchname)==0)
|
|
res.push_back(curpath);
|
|
else
|
|
scanDirectoryRecursive(res,matchname,curpath,maxdepth-1); // Recurse
|
|
}
|
|
}
|
|
|
|
void FileManage::splitPath(const string &full,string &path,string &base)
|
|
|
|
{ // Split path string -full- into its -base-name and -path- (relative or absolute)
|
|
// If there is no path, i.e. only a basename in full, then -path- will return as an empty string
|
|
// otherwise -path- will be non-empty and end in a separator character
|
|
string::size_type end = full.size()-1;
|
|
if (isSeparator(full[full.size()-1])) // Take into account terminating separator
|
|
end = full.size()-2;
|
|
string::size_type pos = full.find_last_of(separatorClass,end);
|
|
if (pos == string::npos) { // Didn't find any separator
|
|
base = full;
|
|
path.clear();
|
|
}
|
|
else {
|
|
string::size_type sz = (end - pos);
|
|
base = full.substr(pos+1,sz);
|
|
path = full.substr(0,pos+1);
|
|
}
|
|
}
|
|
|
|
string FileManage::buildPath(const vector<string> &pathels,int level)
|
|
|
|
{ // Build an absolute path using elements from -pathels-, in reverse order
|
|
// Build up to and including pathels[level]
|
|
ostringstream s;
|
|
|
|
for(int i=pathels.size()-1;i>=level;--i) {
|
|
s << separator;
|
|
s << pathels[i];
|
|
}
|
|
return s.str();
|
|
}
|
|
|
|
bool FileManage::testDevelopmentPath(const vector<string> &pathels,int level,string &root)
|
|
|
|
{ // Given pathels[level] is "Ghidra", determine if this is a Ghidra development layout
|
|
if (level + 2 >= pathels.size()) return false;
|
|
string parent = pathels[level + 1];
|
|
if (parent.size() < 11) return false;
|
|
string piecestr = parent.substr(0,7);
|
|
if (piecestr != "ghidra.") return false;
|
|
piecestr = parent.substr(parent.size() - 4);
|
|
if (piecestr != ".git") return false;
|
|
root = buildPath(pathels,level+2);
|
|
vector<string> testpaths1;
|
|
vector<string> testpaths2;
|
|
scanDirectoryRecursive(testpaths1,"ghidra.git",root,1);
|
|
if (testpaths1.size() != 1) return false;
|
|
scanDirectoryRecursive(testpaths2,"Ghidra",testpaths1[0],1);
|
|
return (testpaths2.size() == 1);
|
|
}
|
|
|
|
bool FileManage::testInstallPath(const vector<string> &pathels,int level,string &root)
|
|
|
|
{
|
|
if (level + 1 >= pathels.size()) return false;
|
|
root = buildPath(pathels,level+1);
|
|
vector<string> testpaths1;
|
|
vector<string> testpaths2;
|
|
scanDirectoryRecursive(testpaths1,"server",root,1);
|
|
if (testpaths1.size() != 1) return false;
|
|
scanDirectoryRecursive(testpaths2,"server.conf",testpaths1[0],1);
|
|
return (testpaths2.size() == 1);
|
|
}
|
|
|
|
string FileManage::discoverGhidraRoot(const char *argv0)
|
|
|
|
{ // Find the root of the ghidra distribution based on current working directory and passed in path
|
|
vector<string> pathels;
|
|
string cur(argv0);
|
|
string base;
|
|
int skiplevel = 0;
|
|
bool isAbs = isAbsolutePath(cur);
|
|
|
|
for(;;) {
|
|
int sizebefore = cur.size();
|
|
splitPath(cur,cur,base);
|
|
if (cur.size() == sizebefore) break;
|
|
if (base == ".")
|
|
skiplevel += 1;
|
|
else if (base == "..")
|
|
skiplevel += 2;
|
|
if (skiplevel > 0)
|
|
skiplevel -= 1;
|
|
else
|
|
pathels.push_back(base);
|
|
}
|
|
if (!isAbs) {
|
|
FileManage curdir;
|
|
curdir.addCurrentDir();
|
|
cur = curdir.pathlist[0];
|
|
for(;;) {
|
|
int sizebefore = cur.size();
|
|
splitPath(cur,cur,base);
|
|
if (cur.size() == sizebefore) break;
|
|
pathels.push_back(base);
|
|
}
|
|
}
|
|
|
|
for(int i=0;i<pathels.size();++i) {
|
|
if (pathels[i] != "Ghidra") continue;
|
|
string root;
|
|
if (testDevelopmentPath(pathels,i,root))
|
|
return root;
|
|
if (testInstallPath(pathels,i,root))
|
|
return root;
|
|
}
|
|
return "";
|
|
}
|
|
|
|
} // End namespace ghidra
|