1/* Copyright (C) 2021 Free Software Foundation, Inc. 2 Contributed by Oracle. 3 4 This file is part of GNU Binutils. 5 6 This program is free software; you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by 8 the Free Software Foundation; either version 3, or (at your option) 9 any later version. 10 11 This program is distributed in the hope that it will be useful, 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 GNU General Public License for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with this program; if not, write to the Free Software 18 Foundation, 51 Franklin Street - Fifth Floor, Boston, 19 MA 02110-1301, USA. */ 20 21#include "config.h" 22#include "util.h" 23#include "DbeSession.h" 24#include "Experiment.h" 25#include "DbeFile.h" 26#include "ExpGroup.h" 27#include "DbeJarFile.h" 28 29DbeFile::DbeFile (const char *filename) 30{ 31 filetype = 0; 32 name = dbe_strdup (filename); 33 name = canonical_path (name); 34 orig_location = NULL; 35 location = NULL; 36 location_info = NULL; 37 jarFile = NULL; 38 container = NULL; 39 need_refind = true; 40 inArchive = false; 41 sbuf.st_atim.tv_sec = 0; 42 experiment = NULL; 43} 44 45DbeFile::~DbeFile () 46{ 47 free (name); 48 free (location); 49 free (orig_location); 50 free (location_info); 51} 52 53void 54DbeFile::set_need_refind (bool val) 55{ 56 if (val != need_refind) 57 { 58 free (location_info); 59 location_info = NULL; 60 need_refind = val; 61 } 62} 63 64void 65DbeFile::set_location (const char *filename) 66{ 67 free (location); 68 location = NULL; 69 if (filename) 70 { 71 if (strncmp (filename, NTXT ("./"), 2) == 0) 72 filename += 2; 73 location = canonical_path (dbe_strdup (filename)); 74 } 75 free (location_info); 76 location_info = NULL; 77 set_need_refind (false); 78} 79 80char * 81DbeFile::get_location_info () 82{ 83 if (location_info == NULL) 84 { 85 char *fnm = get_name (); 86 char *loc = get_location (); 87 Dprintf (DEBUG_DBE_FILE, NTXT ("DbeFile::get_location_info: %s %s\n"), 88 STR (fnm), STR (loc)); 89 if (loc == NULL) 90 { 91 if (filetype & F_FICTION) 92 location_info = dbe_strdup (fnm); 93 else 94 location_info = dbe_sprintf (GTXT ("%s (not found)"), 95 get_relative_path (fnm)); 96 } 97 else 98 { 99 char *r_fnm = get_relative_path (fnm); 100 char *r_loc = get_relative_path (loc); 101 if (strcmp (r_fnm, r_loc) == 0) 102 location_info = dbe_strdup (r_fnm); 103 else 104 { 105 char *bname = get_basename (r_fnm); 106 if (strcmp (bname, r_loc) == 0) // found in current directory 107 location_info = dbe_strdup (bname); 108 else 109 location_info = dbe_sprintf (GTXT ("%s (found as %s)"), bname, r_loc); 110 } 111 } 112 } 113 return location_info; 114} 115 116char * 117DbeFile::getResolvedPath () 118{ 119 if (get_location ()) 120 return location; 121 return name; 122} 123 124DbeFile * 125DbeFile::getJarDbeFile (char *fnm, int sym) 126{ 127 Dprintf (DEBUG_DBE_FILE, NTXT ("DbeFile::getJarDbeFile: %s fnm='%s' sym=%d\n"), 128 STR (name), STR (fnm), sym); 129 DbeFile *df = NULL; 130 if (sym) 131 { 132 char *s = strchr (fnm, sym); 133 if (s) 134 { 135 s = dbe_strndup (fnm, s - fnm); 136 df = dbeSession->getDbeFile (s, F_JAR_FILE | F_FILE); 137 free (s); 138 } 139 } 140 if (df == NULL) 141 df = dbeSession->getDbeFile (fnm, F_JAR_FILE | F_FILE); 142 if (df && (df->experiment == NULL)) 143 df->experiment = experiment; 144 return df; 145} 146 147char * 148DbeFile::get_location (bool find_needed) 149{ 150 Dprintf (DEBUG_DBE_FILE, NTXT ("get_location 0x%x %s\n"), filetype, STR (name)); 151 if (!find_needed) 152 return need_refind ? NULL : location; 153 if (location || !need_refind) 154 return location; 155 set_need_refind (false); 156 if ((filetype & F_FICTION) != 0) 157 return NULL; 158 if (filetype == F_DIR_OR_JAR) 159 { 160 find_in_archives (name); 161 if (location) 162 { 163 filetype |= F_JAR_FILE | F_FILE; 164 return location; 165 } 166 find_in_pathmap (name); 167 if (location) 168 return location; 169 if (check_access (name) == F_DIRECTORY) 170 { 171 filetype |= F_DIRECTORY; 172 set_location (name); 173 return location; 174 } 175 } 176 177 if ((filetype & F_FILE) != 0) 178 { 179 if (experiment) 180 { 181 char *fnm = experiment->checkFileInArchive (name, false); 182 if (fnm) 183 { 184 set_location (fnm); 185 inArchive = true; 186 sbuf.st_mtime = 0; // Don't check timestamps 187 free (fnm); 188 return location; 189 } 190 if ((filetype & F_JAVACLASS) != 0) 191 { 192 if (orig_location) 193 { 194 Dprintf (DEBUG_DBE_FILE, NTXT ("DbeFile::get_location:%d name='%s' orig_location='%s'\n"), 195 (int) __LINE__, name, orig_location); 196 // Parse a fileName attribute. There are 4 possibilities: 197 // file:<Class_Name> 198 // file:<name_of_jar_or_zip_file> 199 // jar:file:<name_of_jar_or_zip_file>!<Class_Name> 200 // zip:<name_of_jar_or_zip_file>!<Class_Name> 201 DbeFile *jar_df = NULL; 202 if (strncmp (orig_location, NTXT ("zip:"), 4) == 0) 203 jar_df = getJarDbeFile (orig_location + 4, '!'); 204 else if (strncmp (orig_location, NTXT ("jar:file:"), 9) == 0) 205 jar_df = getJarDbeFile (orig_location + 9, '!'); 206 else if (strncmp (orig_location, NTXT ("file:"), 5) == 0 207 && isJarOrZip (orig_location + 5)) 208 jar_df = getJarDbeFile (orig_location + 5, 0); 209 if (jar_df) 210 { 211 if (find_in_jar_file (name, jar_df->get_jar_file ())) 212 { 213 Dprintf (DEBUG_DBE_FILE, NTXT ("DbeFile::get_location:%d FOUND name='%s' location='%s' jar='%s'\n"), 214 (int) __LINE__, name, STR (location), STR (jar_df->get_location ())); 215 inArchive = jar_df->inArchive; 216 container = jar_df; 217 return location; 218 } 219 } 220 if (strncmp (orig_location, NTXT ("file:"), 5) == 0 221 && !isJarOrZip (orig_location + 5)) 222 { 223 DbeFile *df = new DbeFile (orig_location + 5); 224 df->filetype = DbeFile::F_FILE; 225 df->experiment = experiment; 226 fnm = df->get_location (); 227 if (fnm) 228 { 229 set_location (fnm); 230 inArchive = df->inArchive; 231 sbuf.st_mtime = df->sbuf.st_mtime; 232 Dprintf (DEBUG_DBE_FILE, NTXT ("DbeFile::get_location:%d FOUND name='%s' orig_location='%s' location='%s'\n"), 233 (int) __LINE__, name, orig_location, fnm); 234 delete df; 235 return location; 236 } 237 delete df; 238 } 239 } 240 fnm = dbe_sprintf (NTXT ("%s/%s/%s"), experiment->get_expt_name (), SP_DYNAMIC_CLASSES, name); 241 if (find_file (fnm)) 242 { 243 inArchive = true; 244 sbuf.st_mtime = 0; // Don't check timestamps 245 Dprintf (DEBUG_DBE_FILE, NTXT ("DbeFile::get_location:%d FOUND name='%s' location='%s'\n"), 246 (int) __LINE__, name, fnm); 247 free (fnm); 248 return location; 249 } 250 free (fnm); 251 } 252 } 253 } 254 255 if (dbeSession->archive_mode) 256 { 257 find_file (name); 258 if (location) 259 return location; 260 } 261 262 bool inPathMap = find_in_pathmap (name); 263 if (location) 264 return location; 265 find_in_setpath (name, dbeSession->get_search_path ()); 266 if (location) 267 return location; 268 if ((filetype & (F_JAVACLASS | F_JAVA_SOURCE)) != 0) 269 { 270 find_in_classpath (name, dbeSession->get_classpath ()); 271 if (location) 272 return location; 273 } 274 if (!inPathMap) 275 find_file (name); 276 Dprintf (DEBUG_DBE_FILE && (location == NULL), 277 "DbeFile::get_location:%d NOT FOUND name='%s'\n", __LINE__, name); 278 return location; 279} 280 281int 282DbeFile::check_access (const char *filename) 283{ 284 if (filename == NULL) 285 return F_NOT_FOUND; 286 int st = dbe_stat (filename, &sbuf); 287 Dprintf (DEBUG_DBE_FILE, NTXT ("check_access: %d 0x%x %s\n"), st, filetype, filename); 288 if (st == 0) 289 { 290 if (S_ISDIR (sbuf.st_mode)) 291 return F_DIRECTORY; 292 else if (S_ISREG (sbuf.st_mode)) 293 return F_FILE; 294 return F_UNKNOWN; // Symbolic link or unknown type of file 295 } 296 sbuf.st_atim.tv_sec = 0; 297 sbuf.st_mtime = 0; // Don't check timestamps 298 return F_NOT_FOUND; // File not found 299} 300 301bool 302DbeFile::isJarOrZip (const char *fnm) 303{ 304 size_t len = strlen (fnm) - 4; 305 return len > 0 && (strcmp (fnm + len, NTXT (".jar")) == 0 306 || strcmp (fnm + len, NTXT (".zip")) == 0); 307} 308 309char * 310DbeFile::find_file (const char *filename) 311{ 312 switch (check_access (filename)) 313 { 314 case F_DIRECTORY: 315 if (filetype == F_DIR_OR_JAR) 316 filetype |= F_DIRECTORY; 317 if ((filetype & F_DIRECTORY) != 0) 318 set_location (filename); 319 break; 320 case F_FILE: 321 if (filetype == F_DIR_OR_JAR) 322 { 323 filetype |= F_FILE; 324 if (isJarOrZip (filename)) 325 filetype |= F_JAR_FILE; 326 } 327 if ((filetype & F_DIRECTORY) == 0) 328 set_location (filename); 329 break; 330 } 331 return location; 332} 333 334DbeJarFile * 335DbeFile::get_jar_file () 336{ 337 if (jarFile == NULL) 338 { 339 char *fnm = get_location (); 340 if (fnm) 341 jarFile = dbeSession->get_JarFile (fnm); 342 } 343 return jarFile; 344} 345 346char * 347DbeFile::find_package_name (const char *filename, const char *dirname) 348{ 349 char *nm = dbe_sprintf (NTXT ("%s/%s"), dirname, filename); 350 if (!find_in_pathmap (nm)) 351 find_file (nm); 352 free (nm); 353 return location; 354} 355 356char * 357DbeFile::find_in_directory (const char *filename, const char *dirname) 358{ 359 if (filename && dirname) 360 { 361 char *nm = dbe_sprintf (NTXT ("%s/%s"), dirname, filename); 362 find_file (nm); 363 free (nm); 364 } 365 return location; 366} 367 368char * 369DbeFile::find_in_jar_file (const char *filename, DbeJarFile *jfile) 370{ 371 // Read .jar or .zip 372 if (jfile == NULL) 373 return NULL; 374 int entry = jfile->get_entry (filename); 375 if (entry >= 0) 376 { 377 char *fnm = dbeSession->get_tmp_file_name (filename, true); 378 long long fsize = jfile->copy (fnm, entry); 379 if (fsize >= 0) 380 { 381 dbeSession->tmp_files->append (fnm); 382 set_location (fnm); 383 sbuf.st_size = fsize; 384 sbuf.st_mtime = 0; // Don't check timestamps 385 fnm = NULL; 386 } 387 free (fnm); 388 } 389 return location; 390} 391 392bool 393DbeFile::find_in_pathmap (char *filename) 394{ 395 Vector<pathmap_t*> *pathmaps = dbeSession->get_pathmaps (); 396 bool inPathMap = false; 397 if (strncmp (filename, NTXT ("./"), 2) == 0) 398 filename += 2; 399 for (int i = 0, sz = pathmaps ? pathmaps->size () : 0; i < sz; i++) 400 { 401 pathmap_t *pmp = pathmaps->fetch (i); 402 size_t len = strlen (pmp->old_prefix); 403 if (strncmp (pmp->old_prefix, filename, len) == 0 404 && (filename[len] == '/' || filename[len] == '\0')) 405 { 406 inPathMap = true; 407 if (find_in_directory (filename + len, pmp->new_prefix)) 408 { 409 return inPathMap; 410 } 411 } 412 } 413 return inPathMap; 414} 415 416void 417DbeFile::find_in_archives (char *filename) 418{ 419 for (int i1 = 0, sz1 = dbeSession->expGroups->size (); i1 < sz1; i1++) 420 { 421 ExpGroup *gr = dbeSession->expGroups->fetch (i1); 422 if (gr->founder) 423 { 424 char *nm = gr->founder->checkFileInArchive (filename, false); 425 if (nm) 426 { 427 find_file (nm); 428 if (location) 429 { 430 sbuf.st_mtime = 0; // Don't check timestamps 431 return; 432 } 433 } 434 } 435 } 436} 437 438void 439DbeFile::find_in_setpath (char *filename, Vector<char*> *searchPath) 440{ 441 char *base = get_basename (filename); 442 for (int i = 0, sz = searchPath ? searchPath->size () : 0; i < sz; i++) 443 { 444 char *spath = searchPath->fetch (i); 445 // Check file in each experiment directory 446 if (streq (spath, "$") || streq (spath, NTXT ("$expts"))) 447 { 448 // find only in founders and only LoadObj. 449 for (int i1 = 0, sz1 = dbeSession->expGroups->size (); i1 < sz1; i1++) 450 { 451 ExpGroup *gr = dbeSession->expGroups->fetch (i1); 452 char *exp_name = gr->founder->get_expt_name (); 453 if (gr->founder) 454 { 455 if ((filetype & (F_JAVACLASS | F_JAVA_SOURCE)) != 0) 456 { 457 // Find with the package name 458 if (find_in_directory (filename, exp_name)) 459 return; 460 } 461 if (find_in_directory (base, exp_name)) 462 return; 463 } 464 } 465 continue; 466 } 467 DbeFile *df = dbeSession->getDbeFile (spath, DbeFile::F_DIR_OR_JAR); 468 if (df->get_location () == NULL) 469 continue; 470 if ((filetype & (F_JAVACLASS | F_JAVA_SOURCE)) != 0) 471 { 472 if ((df->filetype & F_JAR_FILE) != 0) 473 { 474 if (find_in_jar_file (filename, df->get_jar_file ())) 475 { 476 container = df; 477 return; 478 } 479 continue; 480 } 481 else if ((df->filetype & F_DIRECTORY) != 0) 482 // Find with the package name 483 if (find_package_name (filename, spath)) 484 return; 485 } 486 if ((df->filetype & F_DIRECTORY) != 0) 487 if (find_in_directory (base, df->get_location ())) 488 return; 489 } 490} 491 492void 493DbeFile::find_in_classpath (char *filename, Vector<DbeFile*> *classPath) 494{ 495 for (int i = 0, sz = classPath ? classPath->size () : 0; i < sz; i++) 496 { 497 DbeFile *df = classPath->fetch (i); 498 if (df->get_location () == NULL) 499 continue; 500 if ((df->filetype & F_JAR_FILE) != 0) 501 { 502 if (find_in_jar_file (filename, df->get_jar_file ())) 503 { 504 container = df; 505 return; 506 } 507 } 508 else if ((df->filetype & F_DIRECTORY) != 0) 509 // Find with the package name 510 if (find_package_name (filename, df->get_name ())) 511 return; 512 } 513} 514 515struct stat64 * 516DbeFile::get_stat () 517{ 518 if (sbuf.st_atim.tv_sec == 0) 519 { 520 int st = check_access (get_location (false)); 521 if (st == F_NOT_FOUND) 522 return NULL; 523 } 524 return &sbuf; 525} 526 527bool 528DbeFile::compare (DbeFile *df) 529{ 530 if (df == NULL) 531 return false; 532 struct stat64 *st1 = get_stat (); 533 struct stat64 *st2 = df->get_stat (); 534 if (st1 == NULL || st2 == NULL) 535 return false; 536 if (st1->st_size != st2->st_size) 537 return false; 538 if (st1->st_mtim.tv_sec != st2->st_mtim.tv_sec) 539 return false; 540 return true; 541} 542