blob: 9e1fe1c20172c927b0dc67672dcc9d1a205f0809 [file] [log] [blame]
/* Copyright (C) 2021 Free Software Foundation, Inc.
Contributed by Oracle.
This file is part of GNU Binutils.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, 51 Franklin Street - Fifth Floor, Boston,
MA 02110-1301, USA. */
#include "config.h"
#include "util.h"
#include "DbeSession.h"
#include "Experiment.h"
#include "DbeFile.h"
#include "ExpGroup.h"
#include "DbeJarFile.h"
DbeFile::DbeFile (const char *filename)
{
filetype = 0;
name = dbe_strdup (filename);
name = canonical_path (name);
orig_location = NULL;
location = NULL;
location_info = NULL;
jarFile = NULL;
container = NULL;
need_refind = true;
inArchive = false;
sbuf.st_atim.tv_sec = 0;
experiment = NULL;
}
DbeFile::~DbeFile ()
{
free (name);
free (location);
free (orig_location);
free (location_info);
}
void
DbeFile::set_need_refind (bool val)
{
if (val != need_refind)
{
free (location_info);
location_info = NULL;
need_refind = val;
}
}
void
DbeFile::set_location (const char *filename)
{
free (location);
location = NULL;
if (filename)
{
if (strncmp (filename, NTXT ("./"), 2) == 0)
filename += 2;
location = canonical_path (dbe_strdup (filename));
}
free (location_info);
location_info = NULL;
set_need_refind (false);
}
char *
DbeFile::get_location_info ()
{
if (location_info == NULL)
{
char *fnm = get_name ();
char *loc = get_location ();
Dprintf (DEBUG_DBE_FILE, NTXT ("DbeFile::get_location_info: %s %s\n"),
STR (fnm), STR (loc));
if (loc == NULL)
{
if (filetype & F_FICTION)
location_info = dbe_strdup (fnm);
else
location_info = dbe_sprintf (GTXT ("%s (not found)"),
get_relative_path (fnm));
}
else
{
char *r_fnm = get_relative_path (fnm);
char *r_loc = get_relative_path (loc);
if (strcmp (r_fnm, r_loc) == 0)
location_info = dbe_strdup (r_fnm);
else
{
char *bname = get_basename (r_fnm);
if (strcmp (bname, r_loc) == 0) // found in current directory
location_info = dbe_strdup (bname);
else
location_info = dbe_sprintf (GTXT ("%s (found as %s)"), bname, r_loc);
}
}
}
return location_info;
}
char *
DbeFile::getResolvedPath ()
{
if (get_location ())
return location;
return name;
}
DbeFile *
DbeFile::getJarDbeFile (char *fnm, int sym)
{
Dprintf (DEBUG_DBE_FILE, NTXT ("DbeFile::getJarDbeFile: %s fnm='%s' sym=%d\n"),
STR (name), STR (fnm), sym);
DbeFile *df = NULL;
if (sym)
{
char *s = strchr (fnm, sym);
if (s)
{
s = dbe_strndup (fnm, s - fnm);
df = dbeSession->getDbeFile (s, F_JAR_FILE | F_FILE);
free (s);
}
}
if (df == NULL)
df = dbeSession->getDbeFile (fnm, F_JAR_FILE | F_FILE);
if (df && (df->experiment == NULL))
df->experiment = experiment;
return df;
}
char *
DbeFile::get_location (bool find_needed)
{
Dprintf (DEBUG_DBE_FILE, NTXT ("get_location 0x%x %s\n"), filetype, STR (name));
if (!find_needed)
return need_refind ? NULL : location;
if (location || !need_refind)
return location;
set_need_refind (false);
if ((filetype & F_FICTION) != 0)
return NULL;
if (filetype == F_DIR_OR_JAR)
{
find_in_archives (name);
if (location)
{
filetype |= F_JAR_FILE | F_FILE;
return location;
}
find_in_pathmap (name);
if (location)
return location;
if (check_access (name) == F_DIRECTORY)
{
filetype |= F_DIRECTORY;
set_location (name);
return location;
}
}
if ((filetype & F_FILE) != 0)
{
if (experiment)
{
char *fnm = experiment->checkFileInArchive (name, false);
if (fnm)
{
set_location (fnm);
inArchive = true;
sbuf.st_mtime = 0; // Don't check timestamps
free (fnm);
return location;
}
if ((filetype & F_JAVACLASS) != 0)
{
if (orig_location)
{
Dprintf (DEBUG_DBE_FILE, NTXT ("DbeFile::get_location:%d name='%s' orig_location='%s'\n"),
(int) __LINE__, name, orig_location);
// Parse a fileName attribute. There are 4 possibilities:
// file:<Class_Name>
// file:<name_of_jar_or_zip_file>
// jar:file:<name_of_jar_or_zip_file>!<Class_Name>
// zip:<name_of_jar_or_zip_file>!<Class_Name>
DbeFile *jar_df = NULL;
if (strncmp (orig_location, NTXT ("zip:"), 4) == 0)
jar_df = getJarDbeFile (orig_location + 4, '!');
else if (strncmp (orig_location, NTXT ("jar:file:"), 9) == 0)
jar_df = getJarDbeFile (orig_location + 9, '!');
else if (strncmp (orig_location, NTXT ("file:"), 5) == 0
&& isJarOrZip (orig_location + 5))
jar_df = getJarDbeFile (orig_location + 5, 0);
if (jar_df)
{
if (find_in_jar_file (name, jar_df->get_jar_file ()))
{
Dprintf (DEBUG_DBE_FILE, NTXT ("DbeFile::get_location:%d FOUND name='%s' location='%s' jar='%s'\n"),
(int) __LINE__, name, STR (location), STR (jar_df->get_location ()));
inArchive = jar_df->inArchive;
container = jar_df;
return location;
}
}
if (strncmp (orig_location, NTXT ("file:"), 5) == 0
&& !isJarOrZip (orig_location + 5))
{
DbeFile *df = new DbeFile (orig_location + 5);
df->filetype = DbeFile::F_FILE;
df->experiment = experiment;
fnm = df->get_location ();
if (fnm)
{
set_location (fnm);
inArchive = df->inArchive;
sbuf.st_mtime = df->sbuf.st_mtime;
Dprintf (DEBUG_DBE_FILE, NTXT ("DbeFile::get_location:%d FOUND name='%s' orig_location='%s' location='%s'\n"),
(int) __LINE__, name, orig_location, fnm);
delete df;
return location;
}
delete df;
}
}
fnm = dbe_sprintf (NTXT ("%s/%s/%s"), experiment->get_expt_name (), SP_DYNAMIC_CLASSES, name);
if (find_file (fnm))
{
inArchive = true;
sbuf.st_mtime = 0; // Don't check timestamps
Dprintf (DEBUG_DBE_FILE, NTXT ("DbeFile::get_location:%d FOUND name='%s' location='%s'\n"),
(int) __LINE__, name, fnm);
free (fnm);
return location;
}
free (fnm);
}
}
}
if (dbeSession->archive_mode)
{
find_file (name);
if (location)
return location;
}
bool inPathMap = find_in_pathmap (name);
if (location)
return location;
find_in_setpath (name, dbeSession->get_search_path ());
if (location)
return location;
if ((filetype & (F_JAVACLASS | F_JAVA_SOURCE)) != 0)
{
find_in_classpath (name, dbeSession->get_classpath ());
if (location)
return location;
}
if (!inPathMap)
find_file (name);
Dprintf (DEBUG_DBE_FILE && (location == NULL),
"DbeFile::get_location:%d NOT FOUND name='%s'\n", __LINE__, name);
return location;
}
int
DbeFile::check_access (const char *filename)
{
if (filename == NULL)
return F_NOT_FOUND;
int st = dbe_stat (filename, &sbuf);
Dprintf (DEBUG_DBE_FILE, NTXT ("check_access: %d 0x%x %s\n"), st, filetype, filename);
if (st == 0)
{
if (S_ISDIR (sbuf.st_mode))
return F_DIRECTORY;
else if (S_ISREG (sbuf.st_mode))
return F_FILE;
return F_UNKNOWN; // Symbolic link or unknown type of file
}
sbuf.st_atim.tv_sec = 0;
sbuf.st_mtime = 0; // Don't check timestamps
return F_NOT_FOUND; // File not found
}
bool
DbeFile::isJarOrZip (const char *fnm)
{
size_t len = strlen (fnm) - 4;
return len > 0 && (strcmp (fnm + len, NTXT (".jar")) == 0
|| strcmp (fnm + len, NTXT (".zip")) == 0);
}
char *
DbeFile::find_file (const char *filename)
{
switch (check_access (filename))
{
case F_DIRECTORY:
if (filetype == F_DIR_OR_JAR)
filetype |= F_DIRECTORY;
if ((filetype & F_DIRECTORY) != 0)
set_location (filename);
break;
case F_FILE:
if (filetype == F_DIR_OR_JAR)
{
filetype |= F_FILE;
if (isJarOrZip (filename))
filetype |= F_JAR_FILE;
}
if ((filetype & F_DIRECTORY) == 0)
set_location (filename);
break;
}
return location;
}
DbeJarFile *
DbeFile::get_jar_file ()
{
if (jarFile == NULL)
{
char *fnm = get_location ();
if (fnm)
jarFile = dbeSession->get_JarFile (fnm);
}
return jarFile;
}
char *
DbeFile::find_package_name (const char *filename, const char *dirname)
{
char *nm = dbe_sprintf (NTXT ("%s/%s"), dirname, filename);
if (!find_in_pathmap (nm))
find_file (nm);
free (nm);
return location;
}
char *
DbeFile::find_in_directory (const char *filename, const char *dirname)
{
if (filename && dirname)
{
char *nm = dbe_sprintf (NTXT ("%s/%s"), dirname, filename);
find_file (nm);
free (nm);
}
return location;
}
char *
DbeFile::find_in_jar_file (const char *filename, DbeJarFile *jfile)
{
// Read .jar or .zip
if (jfile == NULL)
return NULL;
int entry = jfile->get_entry (filename);
if (entry >= 0)
{
char *fnm = dbeSession->get_tmp_file_name (filename, true);
long long fsize = jfile->copy (fnm, entry);
if (fsize >= 0)
{
dbeSession->tmp_files->append (fnm);
set_location (fnm);
sbuf.st_size = fsize;
sbuf.st_mtime = 0; // Don't check timestamps
fnm = NULL;
}
free (fnm);
}
return location;
}
bool
DbeFile::find_in_pathmap (char *filename)
{
Vector<pathmap_t*> *pathmaps = dbeSession->get_pathmaps ();
bool inPathMap = false;
if (strncmp (filename, NTXT ("./"), 2) == 0)
filename += 2;
for (int i = 0, sz = pathmaps ? pathmaps->size () : 0; i < sz; i++)
{
pathmap_t *pmp = pathmaps->fetch (i);
size_t len = strlen (pmp->old_prefix);
if (strncmp (pmp->old_prefix, filename, len) == 0
&& (filename[len] == '/' || filename[len] == '\0'))
{
inPathMap = true;
if (find_in_directory (filename + len, pmp->new_prefix))
{
return inPathMap;
}
}
}
return inPathMap;
}
void
DbeFile::find_in_archives (char *filename)
{
for (int i1 = 0, sz1 = dbeSession->expGroups->size (); i1 < sz1; i1++)
{
ExpGroup *gr = dbeSession->expGroups->fetch (i1);
if (gr->founder)
{
char *nm = gr->founder->checkFileInArchive (filename, false);
if (nm)
{
find_file (nm);
if (location)
{
sbuf.st_mtime = 0; // Don't check timestamps
return;
}
}
}
}
}
void
DbeFile::find_in_setpath (char *filename, Vector<char*> *searchPath)
{
char *base = get_basename (filename);
for (int i = 0, sz = searchPath ? searchPath->size () : 0; i < sz; i++)
{
char *spath = searchPath->fetch (i);
// Check file in each experiment directory
if (streq (spath, "$") || streq (spath, NTXT ("$expts")))
{
// find only in founders and only LoadObj.
for (int i1 = 0, sz1 = dbeSession->expGroups->size (); i1 < sz1; i1++)
{
ExpGroup *gr = dbeSession->expGroups->fetch (i1);
char *exp_name = gr->founder->get_expt_name ();
if (gr->founder)
{
if ((filetype & (F_JAVACLASS | F_JAVA_SOURCE)) != 0)
{
// Find with the package name
if (find_in_directory (filename, exp_name))
return;
}
if (find_in_directory (base, exp_name))
return;
}
}
continue;
}
DbeFile *df = dbeSession->getDbeFile (spath, DbeFile::F_DIR_OR_JAR);
if (df->get_location () == NULL)
continue;
if ((filetype & (F_JAVACLASS | F_JAVA_SOURCE)) != 0)
{
if ((df->filetype & F_JAR_FILE) != 0)
{
if (find_in_jar_file (filename, df->get_jar_file ()))
{
container = df;
return;
}
continue;
}
else if ((df->filetype & F_DIRECTORY) != 0)
// Find with the package name
if (find_package_name (filename, spath))
return;
}
if ((df->filetype & F_DIRECTORY) != 0)
if (find_in_directory (base, df->get_location ()))
return;
}
}
void
DbeFile::find_in_classpath (char *filename, Vector<DbeFile*> *classPath)
{
for (int i = 0, sz = classPath ? classPath->size () : 0; i < sz; i++)
{
DbeFile *df = classPath->fetch (i);
if (df->get_location () == NULL)
continue;
if ((df->filetype & F_JAR_FILE) != 0)
{
if (find_in_jar_file (filename, df->get_jar_file ()))
{
container = df;
return;
}
}
else if ((df->filetype & F_DIRECTORY) != 0)
// Find with the package name
if (find_package_name (filename, df->get_name ()))
return;
}
}
struct stat64 *
DbeFile::get_stat ()
{
if (sbuf.st_atim.tv_sec == 0)
{
int st = check_access (get_location (false));
if (st == F_NOT_FOUND)
return NULL;
}
return &sbuf;
}
bool
DbeFile::compare (DbeFile *df)
{
if (df == NULL)
return false;
struct stat64 *st1 = get_stat ();
struct stat64 *st2 = df->get_stat ();
if (st1 == NULL || st2 == NULL)
return false;
if (st1->st_size != st2->st_size)
return false;
if (st1->st_mtim.tv_sec != st2->st_mtim.tv_sec)
return false;
return true;
}