Refactor search_for_file() util function.

It was getting too bloated and allocated memory in ways that were
difficult to understand how to manage.  Separated out primarily in to
new find_file() and open_file()/open_package() functions.

Also renamed other util functions for path-related things.
This commit is contained in:
Jon Siwek 2013-10-07 15:01:03 -05:00
parent 68227f112d
commit 90477df973
9 changed files with 331 additions and 304 deletions

View file

@ -85,6 +85,7 @@ BroDoc::~BroDoc()
void BroDoc::AddImport(const std::string& s) void BroDoc::AddImport(const std::string& s)
{ {
/*
std::string lname(s); std::string lname(s);
// First strip any .bro extension. // First strip any .bro extension.
size_t ext_pos = lname.find(".bro"); size_t ext_pos = lname.find(".bro");
@ -142,6 +143,7 @@ void BroDoc::AddImport(const std::string& s)
delete [] full_filename; delete [] full_filename;
delete [] subpath; delete [] subpath;
*/
} }
void BroDoc::SetPacketFilter(const std::string& s) void BroDoc::SetPacketFilter(const std::string& s)

View file

@ -342,18 +342,16 @@ vector<ParseLocationRec> parse_location_string(const string& s)
if ( ! sscanf(line_string.c_str(), "%d", &plr.line) ) if ( ! sscanf(line_string.c_str(), "%d", &plr.line) )
plr.type = plrUnknown; plr.type = plrUnknown;
FILE* throwaway = search_for_file(filename.c_str(), "bro", string path(find_file(filename, bro_path(), "bro"));
&full_filename, true, 0);
if ( ! throwaway ) if ( path.empty() )
{ {
debug_msg("No such policy file: %s.\n", filename.c_str()); debug_msg("No such policy file: %s.\n", filename.c_str());
plr.type = plrUnknown; plr.type = plrUnknown;
return result; return result;
} }
fclose(throwaway); loc_filename = copy_string(path.c_str());
loc_filename = full_filename;
plr.type = plrFileAndLine; plr.type = plrFileAndLine;
} }
} }

View file

@ -4,6 +4,7 @@
#define net_h #define net_h
#include "net_util.h" #include "net_util.h"
#include "util.h"
#include "BPF_Program.h" #include "BPF_Program.h"
#include "List.h" #include "List.h"
#include "PktSrc.h" #include "PktSrc.h"
@ -97,15 +98,14 @@ struct ScannedFile {
ino_t inode; ino_t inode;
int include_level; int include_level;
string name; string name;
string subpath; // Path in BROPATH's policy/ containing the file.
bool skipped; // This ScannedFile was @unload'd. bool skipped; // This ScannedFile was @unload'd.
bool prefixes_checked; // If loading prefixes for this file has been tried. bool prefixes_checked; // If loading prefixes for this file has been tried.
ScannedFile(ino_t arg_inode, int arg_include_level, string arg_name, ScannedFile(ino_t arg_inode, int arg_include_level, const string& arg_name,
string arg_subpath = "", bool arg_skipped = false, bool arg_skipped = false,
bool arg_prefixes_checked = false) bool arg_prefixes_checked = false)
: inode(arg_inode), include_level(arg_include_level), : inode(arg_inode), include_level(arg_include_level),
name(arg_name), subpath(arg_subpath), skipped(arg_skipped), name(arg_name), skipped(arg_skipped),
prefixes_checked(arg_prefixes_checked) prefixes_checked(arg_prefixes_checked)
{ } { }
}; };

View file

@ -294,7 +294,8 @@ void OSFingerprint::load_config(const char* file)
uint32 ln=0; uint32 ln=0;
char buf[MAXLINE]; char buf[MAXLINE];
char* p; char* p;
FILE* c = search_for_file(file, "osf", 0, false, 0);
FILE* c = open_file(find_file(file, bro_path(), "osf"));
if (!c) if (!c)
{ {

View file

@ -226,7 +226,7 @@ bool RuleMatcher::ReadFiles(const name_list& files)
for ( int i = 0; i < files.length(); ++i ) for ( int i = 0; i < files.length(); ++i )
{ {
rules_in = search_for_file(files[i], "sig", 0, false, 0); rules_in = open_file(find_file(files[i], bro_path(), "sig"));
if ( ! rules_in ) if ( ! rules_in )
{ {
reporter->Error("Can't open signature file %s", files[i]); reporter->Error("Can't open signature file %s", files[i]);

View file

@ -20,8 +20,8 @@ void Manager::GenerateDocs() const
void Manager::File(const std::string& path) void Manager::File(const std::string& path)
{ {
// TODO // TODO
// determine bropath subpath
// can be a file or directory? // can be a file or directory?
// determine path within BROPATH
} }
void Manager::ScriptDependency(const std::string& path, const std::string& dep) void Manager::ScriptDependency(const std::string& path, const std::string& dep)

View file

@ -31,7 +31,6 @@
#include "broxygen/Manager.h" #include "broxygen/Manager.h"
extern YYLTYPE yylloc; // holds start line and column of token extern YYLTYPE yylloc; // holds start line and column of token
extern int print_loaded_scripts;
// Track the @if... depth. // Track the @if... depth.
ptr_compat_int current_depth = 0; ptr_compat_int current_depth = 0;
@ -52,31 +51,38 @@ char last_tok[128];
if ( ((result = fread(buf, 1, max_size, yyin)) == 0) && ferror(yyin) ) \ if ( ((result = fread(buf, 1, max_size, yyin)) == 0) && ferror(yyin) ) \
reporter->Error("read failed with \"%s\"", strerror(errno)); reporter->Error("read failed with \"%s\"", strerror(errno));
static string get_dirname(const char* path) static string find_relative_file(const string& filename, const string& ext)
{ {
if ( ! path ) if ( filename.empty() )
return ""; return string();
char* tmp = copy_string(path); if ( filename[0] == '.' )
string rval = dirname(tmp); return find_file(filename, safe_dirname(::filename), ext);
delete[] tmp; else
return rval; return find_file(filename, bro_path(), ext);
} }
static ino_t get_inode_num(FILE* f, const char* filename) static ino_t get_inode_num(FILE* f, const string& path)
{ {
struct stat b; struct stat b;
if ( fstat(fileno(f), &b) ) if ( fstat(fileno(f), &b) )
{ reporter->FatalError("fstat of %s failed: %s\n", path.c_str(),
reporter->Error("failed to fstat fd of %s: %s\n", filename, strerror(errno));
strerror(errno));
exit(1);
}
return b.st_ino; return b.st_ino;
} }
static ino_t get_inode_num(const string& path)
{
FILE* f = open_file(path);
if ( ! f )
reporter->FatalError("failed to open %s\n", path.c_str());
return get_inode_num(f, path);
}
class FileInfo { class FileInfo {
public: public:
FileInfo(string restore_module = ""); FileInfo(string restore_module = "");
@ -265,7 +271,7 @@ when return TOK_WHEN;
@DEBUG return TOK_DEBUG; // marks input for debugger @DEBUG return TOK_DEBUG; // marks input for debugger
@DIR { @DIR {
string rval = get_dirname(::filename); string rval(safe_dirname(::filename));
if ( ! rval.empty() && rval[0] == '.' ) if ( ! rval.empty() && rval[0] == '.' )
{ {
@ -299,42 +305,29 @@ when return TOK_WHEN;
} }
@load-sigs{WS}{FILE} { @load-sigs{WS}{FILE} {
const char* new_sig_file = skip_whitespace(yytext + 10); const char* file = skip_whitespace(yytext + 10);
const char* full_filename = 0; string path(find_relative_file(file, "sig"));
FILE* f = search_for_file(new_sig_file, "sig", &full_filename, false, 0,
get_dirname(::filename));
if ( f ) if ( path.empty() )
{
sig_files.push_back(full_filename);
fclose(f);
delete [] full_filename;
}
else
reporter->Error("failed to find file associated with @load-sigs %s", reporter->Error("failed to find file associated with @load-sigs %s",
new_sig_file); file);
else
sig_files.push_back(copy_string(path.c_str()));
} }
@unload{WS}{FILE} { @unload{WS}{FILE} {
// Skip "@unload". // Skip "@unload".
const char* new_file = skip_whitespace(yytext + 7); const char* file = skip_whitespace(yytext + 7);
string path(find_relative_file(file, "bro"));
// All we have to do is pretend we've already scanned it.
const char* full_filename;
FILE* f = search_for_file(new_file, "bro", &full_filename, true, 0,
get_dirname(::filename));
if ( f )
{
ScannedFile sf(get_inode_num(f, full_filename), file_stack.length(), full_filename, "", true);
files_scanned.push_back(sf);
fclose(f);
delete [] full_filename;
}
if ( path.empty() )
reporter->Error("failed find file associated with @unload %s", file);
else else
reporter->Error("failed find file associated with @unload %s", new_file); {
// All we have to do is pretend we've already scanned it.
ScannedFile sf(get_inode_num(path), file_stack.length(), path, true);
files_scanned.push_back(sf);
}
} }
@prefixes{WS}("+"?)={WS}{PREFIX} { @prefixes{WS}("+"?)={WS}{PREFIX} {
@ -488,22 +481,35 @@ YYLTYPE GetCurrentLocation()
return currloc; return currloc;
} }
static bool already_scanned(ino_t i)
{
list<ScannedFile>::const_iterator it;
for ( it = files_scanned.begin(); it != files_scanned.end(); ++it )
if ( it->inode == i )
return true;
return false;
}
static bool already_scanned(const string& path)
{
return already_scanned(get_inode_num(path));
}
static int load_files(const char* orig_file) static int load_files(const char* orig_file)
{ {
// Whether we pushed on a FileInfo that will restore the // Whether we pushed on a FileInfo that will restore the
// current module after the final file has been scanned. // current module after the final file has been scanned.
bool did_module_restore = false; bool did_module_restore = false;
string file_path;
const char* full_filename = "<internal error>"; FILE* f = 0;
const char* bropath_subpath = "<internal error>";
const char* bropath_subpath_delete = 0;
FILE* f;
if ( streq(orig_file, "-") ) if ( streq(orig_file, "-") )
{ {
f = stdin; f = stdin;
full_filename = "<stdin>"; file_path = "<stdin>";
bropath_subpath = "";
if ( g_policy_debug ) if ( g_policy_debug )
{ {
@ -514,90 +520,62 @@ static int load_files(const char* orig_file)
else else
{ {
f = search_for_file(orig_file, "bro", &full_filename, true, &bropath_subpath, get_dirname(::filename)); file_path = find_relative_file(orig_file, "bro");
bropath_subpath_delete = bropath_subpath; // This will be deleted.
}
if ( f ) if ( file_path.empty() )
{ reporter->FatalError("can't find %s", orig_file);
ino_t i = get_inode_num(f, full_filename);
std::list<ScannedFile>::const_iterator it;
for ( it = files_scanned.begin(); it != files_scanned.end(); ++it ) if ( is_dir(file_path.c_str()) )
{ f = open_package(file_path);
if ( it->inode == i )
{
if ( f != stdin )
{
fclose(f);
delete [] full_filename;
delete [] bropath_subpath_delete;
}
return 0;
}
}
ScannedFile sf(i, file_stack.length(), full_filename, bropath_subpath);
files_scanned.push_back(sf);
if ( g_policy_debug )
{
// Add the filename to the file mapping
// table (Debug.h).
Filemap* map = new Filemap;
// Make sure it wasn't already read in.
HashKey* key = new HashKey(full_filename);
if ( g_dbgfilemaps.Lookup(key) )
{
// reporter->Warning("Not re-reading policy file; check BRO_PREFIXES:", full_filename);
fclose(f);
delete key;
return 0;
}
else
{
g_dbgfilemaps.Insert(key, map);
}
if ( full_filename )
LoadPolicyFileText(full_filename);
}
// Remember where we were. If this is the first
// file being pushed on the stack, i.e., the *last*
// one that will be processed, then we want to
// restore the module scope in which this @load
// was done when we're finished processing it.
if ( ! did_module_restore )
{
file_stack.append(new FileInfo(current_module));
did_module_restore = true;
}
else else
file_stack.append(new FileInfo); f = open_file(file_path);
broxygen_mgr->File(full_filename); if ( ! f )
reporter->FatalError("can't open %s", file_path.c_str());
delete [] bropath_subpath_delete;
// "orig_file", could be an alias for yytext, which is ephemeral
// and will be zapped after the yy_switch_to_buffer() below.
yy_switch_to_buffer(yy_create_buffer(f, YY_BUF_SIZE));
yylloc.first_line = yylloc.last_line = line_number = 1;
// Don't delete the old filename - it's pointed to by
// every BroObj created when parsing it.
yylloc.filename = filename = full_filename;
} }
else ino_t i = get_inode_num(f, file_path);
if ( already_scanned(i) )
return 0;
ScannedFile sf(i, file_stack.length(), file_path);
files_scanned.push_back(sf);
if ( g_policy_debug && ! file_path.empty() )
{ {
reporter->Error("can't open %s", full_filename); // Add the filename to the file mapping table (Debug.h).
exit(1); Filemap* map = new Filemap;
HashKey* key = new HashKey(file_path.c_str());
g_dbgfilemaps.Insert(key, map);
LoadPolicyFileText(file_path.c_str());
} }
// Remember where we were. If this is the first
// file being pushed on the stack, i.e., the *last*
// one that will be processed, then we want to
// restore the module scope in which this @load
// was done when we're finished processing it.
if ( ! did_module_restore )
{
file_stack.append(new FileInfo(current_module));
did_module_restore = true;
}
else
file_stack.append(new FileInfo);
broxygen_mgr->File(file_path);
// "orig_file", could be an alias for yytext, which is ephemeral
// and will be zapped after the yy_switch_to_buffer() below.
yy_switch_to_buffer(yy_create_buffer(f, YY_BUF_SIZE));
yylloc.first_line = yylloc.last_line = line_number = 1;
// Don't delete the old filename - it's pointed to by
// every BroObj created when parsing it.
yylloc.filename = filename = copy_string(file_path.c_str());
return 1; return 1;
} }
@ -773,24 +751,22 @@ int yywrap()
if ( ! prefixes[i][0] ) if ( ! prefixes[i][0] )
continue; continue;
string s; string sub(find_dir_in_bropath(it->name));
s = dot_canon(it->subpath.c_str(), it->name.c_str(), prefixes[i]); string flat(flatten_script_name(sub, it->name, prefixes[i]));
FILE* f = search_for_file(s.c_str(), "bro", 0, false, 0, string path(find_relative_file(flat, "bro"));
get_dirname(::filename));
if ( ! path.empty() )
{
add_input_file(path.c_str());
found_prefixed_files = true;
}
//printf("====== prefix search ======\n"); //printf("====== prefix search ======\n");
//printf("File : %s\n", it->name.c_str()); //printf("File : %s\n", it->name.c_str());
//printf("Path : %s\n", it->subpath.c_str()); //printf("Path : %s\n", sub.c_str());
//printf("Dotted: %s\n", s.c_str()); //printf("Dotted: %s\n", flat.c_str());
//printf("Found : %s\n", f ? "T" : "F"); //printf("Found : %s\n", f ? "T" : "F");
//printf("===========================\n"); //printf("===========================\n");
if ( f )
{
add_input_file(s.c_str());
found_prefixed_files = true;
fclose(f);
}
} }
} }

View file

@ -917,90 +917,127 @@ string bro_prefixes()
const char* PACKAGE_LOADER = "__load__.bro"; const char* PACKAGE_LOADER = "__load__.bro";
// If filename is pointing to a directory that contains a file called FILE* open_file(const string& path, const string& mode)
// PACKAGE_LOADER, returns the files path. Otherwise returns filename itself.
// In both cases, the returned string is newly allocated.
static const char* check_for_dir(const char* filename, bool load_pkgs)
{ {
if ( load_pkgs && is_dir(filename) ) if ( path.empty() )
{ return 0;
char init_filename_buf[1024];
safe_snprintf(init_filename_buf, sizeof(init_filename_buf),
"%s/%s", filename, PACKAGE_LOADER);
if ( access(init_filename_buf, R_OK) == 0 ) FILE* rval = fopen(path.c_str(), mode.c_str());
return copy_string(init_filename_buf);
}
return copy_string(filename); if ( ! rval )
}
static FILE* open_file(const char* filename, const char** full_filename, bool load_pkgs)
{
filename = check_for_dir(filename, load_pkgs);
if ( full_filename )
*full_filename = copy_string(filename);
FILE* f = fopen(filename, "r");
if ( ! f )
{ {
char buf[256]; char buf[256];
strerror_r(errno, buf, sizeof(buf)); strerror_r(errno, buf, sizeof(buf));
reporter->Error("Failed to open file %s: %s", filename, buf); reporter->Error("Failed to open file %s: %s", filename, buf);
} }
delete [] filename; return rval;
return f;
} }
// Canonicalizes a given 'file' that lives in 'path' into a flattened, static bool can_read(const string& path)
// dotted format. If the optional 'prefix' argument is given, it is {
// prepended to the dotted-format, separated by another dot. return access(path.c_str(), R_OK) == 0;
// If 'file' is __load__.bro, that part is discarded when constructing }
// the final dotted-format.
string dot_canon(string path, string file, string prefix) FILE* open_package(string& path, const string& mode)
{
string arg_path(path);
path.append("/").append(PACKAGE_LOADER);
if ( can_read(path) )
return open_file(path, mode);
reporter->Error("Failed to open package '%s': missing '%s' file",
arg_path.c_str(), PACKAGE_LOADER);
return 0;
}
string safe_dirname(const char* path)
{
if ( ! path )
return ".";
return safe_dirname(string(path));
}
string safe_dirname(const string& path)
{
char* tmp = copy_string(path.c_str());
string rval(dirname(tmp));
delete [] tmp;
return rval;
}
string safe_basename(const char* path)
{
if ( ! path )
return ".";
return safe_basename(string(path));
}
string safe_basename(const string& path)
{
char* tmp = copy_string(path.c_str());
string rval(basename(tmp));
delete [] tmp;
return rval;
}
string flatten_script_name(const string& dir, const string& file,
const string& prefix)
{ {
string dottedform(prefix); string dottedform(prefix);
if ( prefix != "" ) if ( prefix != "" )
dottedform.append("."); dottedform.append(".");
dottedform.append(path);
char* tmp = copy_string(file.c_str()); dottedform.append(dir);
char* bname = basename(tmp); string bname(safe_basename(file));
if ( ! streq(bname, PACKAGE_LOADER) )
if ( bname != string(PACKAGE_LOADER) )
{ {
if ( path != "" ) if ( dir != "" )
dottedform.append("."); dottedform.append(".");
dottedform.append(bname); dottedform.append(bname);
} }
delete [] tmp;
size_t n; size_t n;
while ( (n = dottedform.find("/")) != string::npos ) while ( (n = dottedform.find("/")) != string::npos )
dottedform.replace(n, 1, "."); dottedform.replace(n, 1, ".");
return dottedform; return dottedform;
} }
// returns a normalized version of a path, removing duplicate slashes, static vector<string>* tokenize_string(string input, const string& delim,
// extraneous dots that refer to the current directory, and pops as many vector<string>* rval)
// parent directories referred to by "../" as possible {
const char* normalize_path(const char* path) if ( ! rval )
rval = new vector<string>();
size_t n;
while ( (n = input.find(delim)) != string::npos )
{
rval->push_back(input.substr(0, n));
input.erase(0, n + 1);
}
rval->push_back(input);
return rval;
}
string normalize_path(const string& path)
{ {
size_t n; size_t n;
string p(path);
vector<string> components, final_components; vector<string> components, final_components;
string new_path; string new_path;
if ( p[0] == '/' ) if ( path[0] == '/' )
new_path = "/"; new_path = "/";
while ( (n = p.find("/")) != string::npos ) tokenize_string(path, "/", &components);
{
components.push_back(p.substr(0, n));
p.erase(0, n + 1);
}
components.push_back(p);
vector<string>::const_iterator it; vector<string>::const_iterator it;
for ( it = components.begin(); it != components.end(); ++it ) for ( it = components.begin(); it != components.end(); ++it )
@ -1026,125 +1063,86 @@ const char* normalize_path(const char* path)
if ( new_path.size() > 1 && new_path[new_path.size() - 1] == '/' ) if ( new_path.size() > 1 && new_path[new_path.size() - 1] == '/' )
new_path.erase(new_path.size() - 1); new_path.erase(new_path.size() - 1);
return copy_string(new_path.c_str()); return new_path;
} }
// Returns the subpath of the root Bro script install/source/build directory in string find_dir_in_bropath(const string& path)
// which the loaded file is located. If it's not under a subpath of that
// directory (e.g. cwd or custom path) then the full path is returned.
void get_script_subpath(const std::string& full_filename, const char** subpath)
{ {
size_t p; size_t p;
std::string my_subpath(full_filename); string rval(path);
// get the parent directory of file (if not already a directory) // get the parent directory of file (if not already a directory)
if ( ! is_dir(full_filename.c_str()) ) if ( ! is_dir(path.c_str()) )
{ rval = safe_dirname(path);
char* tmp = copy_string(full_filename.c_str());
my_subpath = dirname(tmp);
delete [] tmp;
}
// first check if this is some subpath of the installed scripts root path, // first check if this is some subpath of the installed scripts root path,
// if not check if it's a subpath of the script source root path, // if not check if it's a subpath of the script source root path,
// then check if it's a subpath of the build directory (where BIF scripts // then check if it's a subpath of the build directory (where BIF scripts
// will get generated). // will get generated).
// If none of those, will just use the given directory. // If none of those, will just use the given directory.
if ( (p = my_subpath.find(BRO_SCRIPT_INSTALL_PATH)) != std::string::npos ) if ( (p = rval.find(BRO_SCRIPT_INSTALL_PATH)) != std::string::npos )
my_subpath.erase(0, strlen(BRO_SCRIPT_INSTALL_PATH)); rval.erase(0, strlen(BRO_SCRIPT_INSTALL_PATH));
else if ( (p = my_subpath.find(BRO_SCRIPT_SOURCE_PATH)) != std::string::npos ) else if ( (p = rval.find(BRO_SCRIPT_SOURCE_PATH)) != std::string::npos )
my_subpath.erase(0, strlen(BRO_SCRIPT_SOURCE_PATH)); rval.erase(0, strlen(BRO_SCRIPT_SOURCE_PATH));
else if ( (p = my_subpath.find(BRO_BUILD_SOURCE_PATH)) != std::string::npos ) else if ( (p = rval.find(BRO_BUILD_SOURCE_PATH)) != std::string::npos )
my_subpath.erase(0, strlen(BRO_BUILD_SOURCE_PATH)); rval.erase(0, strlen(BRO_BUILD_SOURCE_PATH));
else if ( (p = my_subpath.find(BRO_BUILD_SCRIPTS_PATH)) != std::string::npos ) else if ( (p = rval.find(BRO_BUILD_SCRIPTS_PATH)) != std::string::npos )
my_subpath.erase(0, strlen(BRO_BUILD_SCRIPTS_PATH)); rval.erase(0, strlen(BRO_BUILD_SCRIPTS_PATH));
// if root path found, remove path separators until next path component // if root path found, remove path separators until next path component
if ( p != std::string::npos ) if ( p != std::string::npos )
while ( my_subpath.size() && my_subpath[0] == '/' ) while ( rval.size() && rval[0] == '/' )
my_subpath.erase(0, 1); rval.erase(0, 1);
*subpath = normalize_path(my_subpath.c_str()); return normalize_path(rval);
} }
FILE* search_for_file(const char* filename, const char* ext, static string find_file_in_path(const string& filename, const string& path,
const char** full_filename, bool load_pkgs, const string& opt_ext = "")
const char** bropath_subpath, string prepend_to_search_path)
{ {
// If the file is a literal absolute path we don't have to search, if ( filename.empty() )
// just return the result of trying to open it. If the file is return string();
// might be a relative path, check first if it's a real file that
// can be referenced from cwd, else we'll try to search for it based // If file name is an absolute path, searching within *path* is pointless.
// on what path the currently-loading script is in as well as the if ( filename[0] == '/' )
// standard BROPATH paths.
if ( filename[0] == '/' ||
(filename[0] == '.' && access(filename, R_OK) == 0) )
{ {
if ( bropath_subpath ) if ( can_read(filename) )
{ return filename;
char* tmp = copy_string(filename);
*bropath_subpath = copy_string(dirname(tmp));
delete [] tmp;
}
return open_file(filename, full_filename, load_pkgs);
}
char path[1024], full_filename_buf[1024];
// Prepend the currently loading script's path to BROPATH so that
// @loads can be referenced relatively.
if ( ! prepend_to_search_path.empty() && filename[0] == '.' )
safe_snprintf(path, sizeof(path), "%s:%s",
prepend_to_search_path.c_str(), bro_path());
else
safe_strncpy(path, bro_path(), sizeof(path));
char* dir_beginning = path;
char* dir_ending = path;
int more = *dir_beginning != '\0';
while ( more )
{
while ( *dir_ending && *dir_ending != ':' )
++dir_ending;
if ( *dir_ending == ':' )
*dir_ending = '\0';
else else
more = 0; return string();
safe_snprintf(full_filename_buf, sizeof(full_filename_buf),
"%s/%s.%s", dir_beginning, filename, ext);
if ( access(full_filename_buf, R_OK) == 0 &&
! is_dir(full_filename_buf) )
{
if ( bropath_subpath )
get_script_subpath(full_filename_buf, bropath_subpath);
return open_file(full_filename_buf, full_filename, load_pkgs);
}
safe_snprintf(full_filename_buf, sizeof(full_filename_buf),
"%s/%s", dir_beginning, filename);
if ( access(full_filename_buf, R_OK) == 0 )
{
if ( bropath_subpath )
get_script_subpath(full_filename_buf, bropath_subpath);
return open_file(full_filename_buf, full_filename, load_pkgs);
}
dir_beginning = ++dir_ending;
} }
if ( full_filename ) string abs_path(path + '/' + filename);
*full_filename = copy_string(filename);
if ( bropath_subpath )
{
char* tmp = copy_string(filename);
*bropath_subpath = copy_string(dirname(tmp));
delete [] tmp;
}
return 0; if ( ! opt_ext.empty() )
{
string with_ext(abs_path + '.' + opt_ext);
if ( can_read(with_ext) )
return with_ext;
}
if ( can_read(abs_path) )
return abs_path;
return string();
}
string find_file(const string& filename, const string& path_set,
const string& opt_ext)
{
vector<string> paths;
tokenize_string(path_set, ":", &paths);
for ( size_t n = 0; n < paths.size(); ++n )
{
string f = find_file_in_path(filename, paths[n], opt_ext);
if ( ! f.empty() )
return f;
}
return string();
} }
FILE* rotate_file(const char* name, RecordVal* rotate_info) FILE* rotate_file(const char* name, RecordVal* rotate_info)

View file

@ -205,12 +205,64 @@ extern int int_list_cmp(const void* v1, const void* v2);
extern const char* bro_path(); extern const char* bro_path();
extern const char* bro_magic_path(); extern const char* bro_magic_path();
extern std::string bro_prefixes(); extern std::string bro_prefixes();
std::string dot_canon(std::string path, std::string file, std::string prefix = "");
const char* normalize_path(const char* path); // Wrappers for dirname(3) that won't modify argument.
void get_script_subpath(const std::string& full_filename, const char** subpath); std::string safe_dirname(const char* path);
extern FILE* search_for_file(const char* filename, const char* ext, std::string safe_dirname(const std::string& path);
const char** full_filename, bool load_pkgs, const char** bropath_subpath,
std::string prepend_to_search_path = ""); // Wrappers for basename(3) that won't modify argument.
std::string safe_basename(const char* path);
std::string safe_basename(const std::string& path);
/**
* Flatten a script name by replacing '/' path separators with '.'.
* @param dir A directory containing \a file.
* @param file A path to a Bro script. If it is a __load__.bro, that part
* is discarded when constructing the flattened the name.
* @param prefix A string to prepend to the flattened script name.
* @return The flattened script name.
*/
std::string flatten_script_name(const std::string& dir,
const std::string& file,
const std::string& prefix = "");
/**
* Return a canonical/shortened path string by removing superfluous elements
* (path delimiters, dots referring to CWD or parent dir).
* @param path A filesystem path.
* @return A canonical/shortened version of \a path.
*/
std::string normalize_path(const std::string& path);
/**
* Locate a file/direcotry within BROPATH.
* @param path A file/directory to locate within BROPATH.
* @return The directory within BROPATH that \a path located or an absolute
* path to \a path if it couldn't be located in BROPATH
*/
std::string find_dir_in_bropath(const std::string& path);
/**
* Locate a file within a given search path.
* @param filename Name of a file to find.
* @param path_set Colon-delimited set of paths to search for the file.
* @param opt_ext A filename extension/suffix to allow.
* @return Path to the found file, or an empty string if not found.
*/
std::string find_file(const std::string& filename, const std::string& path_set,
const std::string& opt_ext = "");
// Wrapper around fopen(3). Emits an error when failing to open.
FILE* open_file(const std::string& path, const std::string& mode = "r");
/** Opens a Bro script package.
* @param path Location of a Bro script package (a directory). Will be changed
* to the path of the package's loader script.
* @param mode An fopen(3) mode.
* @return The return value of fopen(3) on the loader script or null if one
* doesn't exist.
*/
FILE* open_package(std::string& path, const std::string& mode = "r");
// Renames the given file to a new temporary name, and opens a new file with // Renames the given file to a new temporary name, and opens a new file with
// the original name. Returns new file or NULL on error. Inits rotate_info if // the original name. Returns new file or NULL on error. Inits rotate_info if