Make @load statements recognize relative paths.

For example a script can do "@load ./foo" to load a script named
foo.bro that lives in the same directory or "@load ../bar" to load
a script named bar.bro in the parent directory, even if those
directories are not contained in BROPATH.
This commit is contained in:
Jon Siwek 2011-07-14 11:35:23 -05:00
parent 2045f1e366
commit e5e3bf28ec
4 changed files with 38 additions and 1 deletions

View file

@ -9,6 +9,7 @@
#include <string>
#include <algorithm>
#include <sys/stat.h>
#include <libgen.h>
#include "input.h"
#include "util.h"
@ -39,6 +40,7 @@ int line_number = 1;
const char* filename = 0;
BroDoc* current_reST_doc = 0;
static BroDoc* last_reST_doc = 0;
string current_scanned_file_path;
char last_tok[128];
@ -102,6 +104,7 @@ public:
int line;
int level;
BroDoc* doc;
string path;
};
// A stack of input buffers we're scanning. file_stack[len-1] is the
@ -613,6 +616,10 @@ static int load_files_with_prefix(const char* orig_file)
else
file_stack.append(new FileInfo);
char* tmp = copy_string(full_filename);
current_scanned_file_path = dirname(tmp);
delete [] tmp;
if ( generate_documentation )
{
current_reST_doc = new BroDoc(bropath_subpath, full_filename);
@ -895,6 +902,7 @@ FileInfo::FileInfo(string arg_restore_module)
name = ::filename;
line = ::line_number;
doc = ::current_reST_doc;
path = current_scanned_file_path;
}
FileInfo::~FileInfo()
@ -907,6 +915,7 @@ FileInfo::~FileInfo()
yylloc.first_line = yylloc.last_line = line_number = line;
last_reST_doc = current_reST_doc;
current_reST_doc = doc;
current_scanned_file_path = path;
if ( restore_module != "" )
current_module = restore_module;

View file

@ -868,11 +868,20 @@ void get_policy_subpath(const char* dir, const char* file, const char** subpath)
delete [] tmp;
}
extern string current_scanned_file_path;
FILE* search_for_file(const char* filename, const char* ext,
const char** full_filename, bool load_pkgs,
const char** bropath_subpath)
{
if ( filename[0] == '/' || filename[0] == '.' )
// If the file is a literal absolute path we don't have to search,
// just return the result of trying to open it. If the file is
// 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
// on what path the currently-loading script is in as well as the
// standard BROPATH paths.
if ( filename[0] == '/' ||
(filename[0] == '.' && access(filename, R_OK) == 0) )
{
if ( bropath_subpath )
{
@ -886,6 +895,12 @@ FILE* search_for_file(const char* filename, const char* ext,
char path[1024], full_filename_buf[1024];
safe_strncpy(path, bro_path(), sizeof(path));
// append the currently loading script's path to BROPATH so that
// @loads can be referenced relatively
if ( current_scanned_file_path != "" )
safe_snprintf(path, sizeof(path), "%s:%s", path,
current_scanned_file_path.c_str());
char* dir_beginning = path;
char* dir_ending = path;
int more = *dir_beginning != '\0';

View file

@ -0,0 +1,3 @@
bar loaded
baz loaded
foo loaded

View file

@ -0,0 +1,10 @@
# A test of relative-path-based @load'ing
# @TEST-EXEC: mkdir foo
# @TEST-EXEC: echo "@load ./bar" > foo/foo.bro
# @TEST-EXEC: echo "@load ../baz" >> foo/foo.bro
# @TEST-EXEC: echo 'print "foo loaded";' >> foo/foo.bro
# @TEST-EXEC: echo 'print "bar loaded";' > foo/bar.bro
# @TEST-EXEC: echo 'print "baz loaded";' > baz.bro
# @TEST-EXEC: bro foo/foo >output
# @TEST-EXEC: btest-diff output