Merge remote-tracking branch 'origin/master' into topic/robin/dynamic-plugins-2.3

This commit is contained in:
Robin Sommer 2014-01-24 20:25:29 -08:00
commit 3f47c5bc87
277 changed files with 9933 additions and 4287 deletions

View file

@ -590,6 +590,33 @@ const char* fmt_access_time(double t)
return buf;
}
bool ensure_intermediate_dirs(const char* dirname)
{
if ( ! dirname || strlen(dirname) == 0 )
return false;
bool absolute = dirname[0] == '/';
string path = normalize_path(dirname);
vector<string> path_components;
tokenize_string(path, "/", &path_components);
string current_dir;
for ( size_t i = 0; i < path_components.size(); ++i )
{
if ( i > 0 || absolute )
current_dir += "/";
current_dir += path_components[i];
if ( ! ensure_dir(current_dir.c_str()) )
return false;
}
return true;
}
bool ensure_dir(const char *dirname)
{
struct stat st;
@ -972,90 +999,162 @@ string bro_prefixes()
const char* PACKAGE_LOADER = "__load__.bro";
// If filename is pointing to a directory that contains a file called
// 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)
FILE* open_file(const string& path, const string& mode)
{
if ( load_pkgs && is_dir(filename) )
{
char init_filename_buf[1024];
safe_snprintf(init_filename_buf, sizeof(init_filename_buf),
"%s/%s", filename, PACKAGE_LOADER);
if ( path.empty() )
return 0;
if ( access(init_filename_buf, R_OK) == 0 )
return copy_string(init_filename_buf);
}
FILE* rval = fopen(path.c_str(), mode.c_str());
return copy_string(filename);
}
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 )
if ( ! rval )
{
char buf[256];
strerror_r(errno, buf, sizeof(buf));
reporter->Error("Failed to open file %s: %s", filename, buf);
}
delete [] filename;
return f;
return rval;
}
// Canonicalizes a given 'file' that lives in 'path' into a flattened,
// dotted format. If the optional 'prefix' argument is given, it is
// prepended to the dotted-format, separated by another dot.
// If 'file' is __load__.bro, that part is discarded when constructing
// the final dotted-format.
string dot_canon(string path, string file, string prefix)
static bool can_read(const string& path)
{
string dottedform(prefix);
if ( prefix != "" )
dottedform.append(".");
dottedform.append(path);
char* tmp = copy_string(file.c_str());
char* bname = basename(tmp);
if ( ! streq(bname, PACKAGE_LOADER) )
return access(path.c_str(), R_OK) == 0;
}
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;
}
void SafePathOp::CheckValid(const char* op_result, const char* path,
bool error_aborts)
{
if ( op_result )
{
if ( path != "" )
dottedform.append(".");
dottedform.append(bname);
result = op_result;
error = false;
}
else
{
if ( error_aborts )
reporter->InternalError("Path operation failed on %s: %s",
path ? path : "<null>", strerror(errno));
else
error = true;
}
delete [] tmp;
size_t n;
while ( (n = dottedform.find("/")) != string::npos )
dottedform.replace(n, 1, ".");
return dottedform;
}
// returns a normalized version of a path, removing duplicate slashes,
// extraneous dots that refer to the current directory, and pops as many
// parent directories referred to by "../" as possible
const char* normalize_path(const char* path)
SafeDirname::SafeDirname(const char* path, bool error_aborts)
: SafePathOp()
{
DoFunc(path ? path : "", error_aborts);
}
SafeDirname::SafeDirname(const string& path, bool error_aborts)
: SafePathOp()
{
DoFunc(path, error_aborts);
}
void SafeDirname::DoFunc(const string& path, bool error_aborts)
{
char* tmp = copy_string(path.c_str());
CheckValid(dirname(tmp), tmp, error_aborts);
delete [] tmp;
}
SafeBasename::SafeBasename(const char* path, bool error_aborts)
: SafePathOp()
{
DoFunc(path ? path : "", error_aborts);
}
SafeBasename::SafeBasename(const string& path, bool error_aborts)
: SafePathOp()
{
DoFunc(path, error_aborts);
}
void SafeBasename::DoFunc(const string& path, bool error_aborts)
{
char* tmp = copy_string(path.c_str());
CheckValid(basename(tmp), tmp, error_aborts);
delete [] tmp;
}
string implode_string_vector(const std::vector<std::string>& v,
const std::string& delim)
{
string rval;
for ( size_t i = 0; i < v.size(); ++i )
{
if ( i > 0 )
rval += delim;
rval += v[i];
}
return rval;
}
string flatten_script_name(const string& name, const string& prefix)
{
string rval = prefix;
if ( ! rval.empty() )
rval.append(".");
if ( SafeBasename(name).result == PACKAGE_LOADER )
rval.append(SafeDirname(name).result);
else
rval.append(name);
size_t i;
while ( (i = rval.find('/')) != string::npos )
rval[i] = '.';
return rval;
}
vector<string>* tokenize_string(string input, const string& delim,
vector<string>* rval)
{
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;
string p(path);
vector<string> components, final_components;
string new_path;
if ( p[0] == '/' )
if ( path[0] == '/' )
new_path = "/";
while ( (n = p.find("/")) != string::npos )
{
components.push_back(p.substr(0, n));
p.erase(0, n + 1);
}
components.push_back(p);
tokenize_string(path, "/", &components);
vector<string>::const_iterator it;
for ( it = components.begin(); it != components.end(); ++it )
@ -1081,127 +1180,82 @@ const char* normalize_path(const char* path)
if ( new_path.size() > 1 && new_path[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
// 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)
string without_bropath_component(const string& path)
{
size_t p;
std::string my_subpath(full_filename);
string rval = normalize_path(path);
// get the parent directory of file (if not already a directory)
if ( ! is_dir(full_filename.c_str()) )
vector<string> paths;
tokenize_string(bro_path(), ":", &paths);
for ( size_t i = 0; i < paths.size(); ++i )
{
char* tmp = copy_string(full_filename.c_str());
my_subpath = dirname(tmp);
delete [] tmp;
string common = normalize_path(paths[i]);
if ( rval.find(common) != 0 )
continue;
// Found the containing directory.
rval.erase(0, common.size());
// Remove leading path separators.
while ( rval.size() && rval[0] == '/' )
rval.erase(0, 1);
return rval;
}
// 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,
// then check if it's a subpath of the build directory (where BIF scripts
// will get generated).
// If none of those, will just use the given directory.
if ( (p = my_subpath.find(BRO_SCRIPT_INSTALL_PATH)) != std::string::npos )
my_subpath.erase(0, strlen(BRO_SCRIPT_INSTALL_PATH));
else if ( (p = my_subpath.find(BRO_SCRIPT_SOURCE_PATH)) != std::string::npos )
my_subpath.erase(0, strlen(BRO_SCRIPT_SOURCE_PATH));
else if ( (p = my_subpath.find(BRO_BUILD_SOURCE_PATH)) != std::string::npos )
my_subpath.erase(0, strlen(BRO_BUILD_SOURCE_PATH));
else if ( (p = my_subpath.find(BRO_BUILD_SCRIPTS_PATH)) != std::string::npos )
my_subpath.erase(0, strlen(BRO_BUILD_SCRIPTS_PATH));
// if root path found, remove path separators until next path component
if ( p != std::string::npos )
while ( my_subpath.size() && my_subpath[0] == '/' )
my_subpath.erase(0, 1);
*subpath = normalize_path(my_subpath.c_str());
return rval;
}
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)
static string find_file_in_path(const string& filename, const string& path,
const string& opt_ext = "")
{
// 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 ( filename.empty() )
return string();
// If file name is an absolute path, searching within *path* is pointless.
if ( filename[0] == '/' )
{
if ( bropath_subpath )
{
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 ( current_scanned_file_path != "" && filename[0] == '.' )
safe_snprintf(path, sizeof(path), "%s:%s",
current_scanned_file_path.c_str(), bro_path().c_str());
else
safe_strncpy(path, bro_path().c_str(), 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';
if ( can_read(filename) )
return filename;
else
more = 0;
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;
return string();
}
if ( full_filename )
*full_filename = copy_string(filename);
if ( bropath_subpath )
{
char* tmp = copy_string(filename);
*bropath_subpath = copy_string(dirname(tmp));
delete [] tmp;
}
string abs_path = path + '/' + filename;
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)
@ -1649,48 +1703,28 @@ void operator delete[](void* v)
#endif
// Being selective of which components of MAGIC_NO_CHECK_BUILTIN are actually
// known to be problematic, but keeping rest of libmagic's builtin checks.
#define DISABLE_LIBMAGIC_BUILTIN_CHECKS ( \
/* MAGIC_NO_CHECK_COMPRESS | */ \
/* MAGIC_NO_CHECK_TAR | */ \
/* MAGIC_NO_CHECK_SOFT | */ \
/* MAGIC_NO_CHECK_APPTYPE | */ \
/* MAGIC_NO_CHECK_ELF | */ \
/* MAGIC_NO_CHECK_TEXT | */ \
MAGIC_NO_CHECK_CDF | \
MAGIC_NO_CHECK_TOKENS \
/* MAGIC_NO_CHECK_ENCODING */ \
)
void bro_init_magic(magic_t* cookie_ptr, int flags)
{
if ( ! cookie_ptr || *cookie_ptr )
return;
*cookie_ptr = magic_open(flags|DISABLE_LIBMAGIC_BUILTIN_CHECKS);
*cookie_ptr = magic_open(flags);
// Use our custom database for mime types, but the default database
// from libmagic for the verbose file type.
const char* database = (flags & MAGIC_MIME) ? bro_magic_path() : 0;
// Always use Bro's custom magic database.
const char* database = bro_magic_path();
if ( ! *cookie_ptr )
{
const char* err = magic_error(*cookie_ptr);
if ( ! err )
err = "unknown";
reporter->InternalError("can't init libmagic: %s", err);
reporter->InternalError("can't init libmagic: %s",
err ? err : "unknown");
}
else if ( magic_load(*cookie_ptr, database) < 0 )
{
const char* err = magic_error(*cookie_ptr);
if ( ! err )
err = "unknown";
const char* db_name = database ? database : "<default>";
reporter->InternalError("can't load magic file %s: %s", db_name, err);
reporter->InternalError("can't load magic file %s: %s", database,
err ? err : "unknown");
magic_close(*cookie_ptr);
*cookie_ptr = 0;
}