/* Copyright (C) 2021-2023 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: // file: // jar:file:! // zip:! 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 *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 *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 *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; }