xref: /netbsd-src/external/gpl3/binutils/dist/gprofng/src/DbeFile.cc (revision cb63e24e8d6aae7ddac1859a9015f48b1d8bd90e)
1 /* Copyright (C) 2021-2024 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 
DbeFile(const char * filename)29 DbeFile::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 
~DbeFile()45 DbeFile::~DbeFile ()
46 {
47   free (name);
48   free (location);
49   free (orig_location);
50   free (location_info);
51 }
52 
53 void
set_need_refind(bool val)54 DbeFile::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 
64 void
set_location(const char * filename)65 DbeFile::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 
80 char *
get_location_info()81 DbeFile::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 
116 char *
getResolvedPath()117 DbeFile::getResolvedPath ()
118 {
119   if (get_location ())
120     return location;
121   return name;
122 }
123 
124 DbeFile *
getJarDbeFile(char * fnm,int sym)125 DbeFile::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 
147 char *
get_location(bool find_needed)148 DbeFile::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 
281 int
check_access(const char * filename)282 DbeFile::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 
301 bool
isJarOrZip(const char * fnm)302 DbeFile::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 
309 char *
find_file(const char * filename)310 DbeFile::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 
334 DbeJarFile *
get_jar_file()335 DbeFile::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 
346 char *
find_package_name(const char * filename,const char * dirname)347 DbeFile::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 
356 char *
find_in_directory(const char * filename,const char * dirname)357 DbeFile::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 
368 char *
find_in_jar_file(const char * filename,DbeJarFile * jfile)369 DbeFile::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 
392 bool
find_in_pathmap(char * filename)393 DbeFile::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 
416 void
find_in_archives(char * filename)417 DbeFile::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 
438 void
find_in_setpath(char * filename,Vector<char * > * searchPath)439 DbeFile::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 
492 void
find_in_classpath(char * filename,Vector<DbeFile * > * classPath)493 DbeFile::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 
515 dbe_stat_t *
get_stat()516 DbeFile::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 
527 bool
compare(DbeFile * df)528 DbeFile::compare (DbeFile *df)
529 {
530   if (df == NULL)
531     return false;
532   dbe_stat_t *st1 = get_stat ();
533   dbe_stat_t *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