| /* Copyright (C) 2021-2024 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; |
| } |
| } |
| |
| dbe_stat_t * |
| 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; |
| dbe_stat_t *st1 = get_stat (); |
| dbe_stat_t *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; |
| } |