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 <sys/param.h>
23 #include <stdarg.h>
24 #include <unistd.h>
25 #include <dirent.h> // readdir()
26 #include <sys/param.h> // MAXPATHLEN
27 #include <pthread.h> // mutex
28 #include <libgen.h> // dirname
29 #include <sys/types.h> // open
30 #include <sys/stat.h> // open
31 #include <errno.h> // errno
32 #include <fcntl.h> // open
33
34 #include "util.h"
35 #include "dbe_structs.h"
36 #include "StringBuilder.h"
37 #include "StringMap.h" // For directory names
38 #include "Application.h" // Only for get_prog_name
39 #include "vec.h"
40
41 void
tsadd(timestruc_t * result,timestruc_t * time)42 tsadd (timestruc_t *result, timestruc_t *time)
43 {
44 // This routine will add "time" to "result".
45 result->tv_sec += time->tv_sec;
46 result->tv_nsec += time->tv_nsec;
47 if (result->tv_nsec >= NANOSEC)
48 {
49 result->tv_nsec -= NANOSEC;
50 result->tv_sec++;
51 }
52 }
53
54 void
tssub(timestruc_t * result,timestruc_t * time1,timestruc_t * time2)55 tssub (timestruc_t *result, timestruc_t *time1, timestruc_t *time2)
56 {
57 // This routine will store "time1" - "time2" in "result".
58
59 if (time1->tv_nsec >= time2->tv_nsec)
60 {
61 result->tv_nsec = time1->tv_nsec - time2->tv_nsec;
62 if (time1->tv_sec >= time2->tv_sec)
63 result->tv_sec = time1->tv_sec - time2->tv_sec;
64 else
65 {
66 result->tv_sec = -1;
67 result->tv_nsec = 0;
68 }
69 }
70 else
71 {
72 result->tv_nsec = time1->tv_nsec + NANOSEC - time2->tv_nsec;
73 if (time1->tv_sec - 1 >= time2->tv_sec)
74 result->tv_sec = time1->tv_sec - 1 - time2->tv_sec;
75 else
76 {
77 result->tv_sec = -1;
78 result->tv_nsec = 0;
79 }
80 }
81 }
82
83 int
tscmp(timestruc_t * time1,timestruc_t * time2)84 tscmp (timestruc_t *time1, timestruc_t *time2)
85 {
86 // This routine will return 1 if "time1" is greater than "time2"
87 // and 0 if "time1" is equal to "time2" and -1 otherwise.
88 if (time1->tv_sec == time2->tv_sec)
89 return time1->tv_nsec > time2->tv_nsec ? 1 :
90 time1->tv_nsec == time2->tv_nsec ? 0 : -1;
91 else
92 return time1->tv_sec > time2->tv_sec ? 1 : -1;
93 }
94
95 void
int_max(int * maximum,int count)96 int_max (int *maximum, int count)
97 {
98 if (count > *maximum)
99 *maximum = count;
100 }
101
102 double
to_double()103 TValue::to_double ()
104 {
105 switch (tag)
106 {
107 case VT_DOUBLE:
108 return (double) d;
109 case VT_INT:
110 return (double) i;
111 case VT_ULLONG:
112 return (double) ull;
113 case VT_LLONG:
114 case VT_ADDRESS:
115 return (double) ll;
116 case VT_FLOAT:
117 return (double) f;
118 case VT_SHORT:
119 return (double) s;
120 default:
121 return 0.0;
122 }
123 }
124
125 int
to_int()126 TValue::to_int ()
127 {
128 switch (tag)
129 {
130 case VT_DOUBLE:
131 return (int) d;
132 case VT_INT:
133 return (int) i;
134 case VT_ULLONG:
135 return (int) ull;
136 case VT_LLONG:
137 case VT_ADDRESS:
138 return (int) ll;
139 case VT_FLOAT:
140 return (int) f;
141 case VT_SHORT:
142 return (int) s;
143 default:
144 return 0;
145 }
146 }
147
148 size_t
get_len()149 TValue::get_len ()
150 {
151 char buf[256];
152 return strlen (to_str (buf, sizeof (buf)));
153 }
154
155 char *
to_str(char * str,size_t strsz)156 TValue::to_str (char *str, size_t strsz)
157 {
158 switch (tag)
159 {
160 case VT_DOUBLE:
161 if (d == 0.)
162 {
163 if (sign)
164 snprintf (str, strsz, NTXT ("+0. "));
165 else
166 snprintf (str, strsz, NTXT ("0. "));
167 }
168 else if (sign)
169 snprintf (str, strsz, NTXT ("%+.3lf"), d);
170 else
171 snprintf (str, strsz, NTXT ("%.3lf"), d);
172 break;
173 case VT_INT:
174 snprintf (str, strsz, NTXT ("%u"), i);
175 break;
176 case VT_LLONG:
177 if (sign)
178 snprintf (str, strsz, NTXT ("%+lld"), ll);
179 else
180 snprintf (str, strsz, NTXT ("%lld"), ll);
181 break;
182 case VT_ULLONG:
183 snprintf (str, strsz, NTXT ("%llu"), ll);
184 break;
185 case VT_ADDRESS:
186 snprintf (str, strsz, NTXT ("%u:0x%08x"), ADDRESS_SEG (ll), ADDRESS_OFF (ll));
187 break;
188 case VT_FLOAT:
189 snprintf (str, strsz, NTXT ("%.3f"), f);
190 break;
191 case VT_SHORT:
192 snprintf (str, strsz, NTXT ("%hu"), s);
193 break;
194 case VT_LABEL:
195 return l; // 'str' is not used !!!
196 default:
197 *str = '\0';
198 break;
199 }
200
201 return str;
202 }
203
204 void
make_delta(TValue * v1,TValue * v2)205 TValue::make_delta (TValue *v1, TValue *v2)
206 {
207 assert (v1->tag == v2->tag);
208 tag = v1->tag;
209 sign = true;
210 switch (v1->tag)
211 {
212 case VT_INT:
213 i = v1->i - v2->i;
214 break;
215 case VT_LLONG:
216 ll = v1->ll - v2->ll;
217 break;
218 case VT_ULLONG:
219 case VT_ADDRESS:
220 tag = VT_LLONG;
221 ll = (long long) (v1->ull - v2->ull);
222 break;
223 case VT_FLOAT:
224 f = v1->f - v2->f;
225 break;
226 case VT_DOUBLE:
227 d = v1->d - v2->d;
228 break;
229 default:
230 assert (0);
231 break;
232 }
233 }
234
235 void
make_ratio(TValue * v1,TValue * v2)236 TValue::make_ratio (TValue *v1, TValue *v2)
237 {
238 assert (v1->tag == v2->tag);
239 double x1 = v1->to_double ();
240 double x2 = v2->to_double ();
241 sign = false;
242 if (x1 == 0.)
243 {
244 // if the numerator is 0, the ratio is 1. or 0. only
245 d = (x2 == 0.) ? 1. : 0.;
246 tag = VT_DOUBLE;
247 }
248 else
249 {
250 // EUGENE replace 99.999 with a variable that is known by both DBE and GUI
251 if (x1 > 99.999 * x2)
252 {
253 l = dbe_strdup (">99.999");
254 tag = VT_LABEL;
255 }
256 else if (x1 < -99.999 * x2)
257 {
258 l = dbe_strdup ("<-99.999");
259 tag = VT_LABEL;
260 }
261 else
262 {
263 d = x1 / x2;
264 tag = VT_DOUBLE;
265 }
266 }
267 }
268
269 int
compare(TValue * v)270 TValue::compare (TValue *v)
271 {
272 if (tag != v->tag)
273 { // Only for comparison (Ratio)
274 if (tag == VT_LABEL)
275 {
276 if (v->tag == VT_LABEL)
277 return strcoll (l, v->l);
278 return 1;
279 }
280 if (v->tag == VT_LABEL)
281 return -1;
282 return ll < v->ll ? -1 : (ll == v->ll ? 0 : 1);
283 }
284 switch (tag)
285 {
286 case VT_SHORT:
287 return s < v->s ? -1 : (s == v->s ? 0 : 1);
288 case VT_INT:
289 return i < v->i ? -1 : (i == v->i ? 0 : 1);
290 case VT_FLOAT:
291 return f < v->f ? -1 : (f == v->f ? 0 : 1);
292 case VT_DOUBLE:
293 return d < v->d ? -1 : (d == v->d ? 0 : 1);
294 case VT_LABEL:
295 return strcoll (l, v->l);
296 case VT_LLONG:
297 case VT_ULLONG:
298 case VT_ADDRESS:
299 case VT_HRTIME:
300 default:
301 return (ll < v->ll) ? -1 : ((ll == v->ll) ? 0 : 1);
302 }
303 }
304
305 char *
strstr_r(char * s1,const char * s2)306 strstr_r (char *s1, const char *s2)
307 {
308 char *str = NULL;
309 for (char *s = s1; s;)
310 {
311 s = strstr (s, s2);
312 if (s)
313 {
314 str = s;
315 s++;
316 }
317 }
318 return str;
319 }
320
321 // reversal order of strpbrk
322
323 char *
strrpbrk(const char * string,const char * brkset)324 strrpbrk (const char *string, const char *brkset)
325 {
326 const char *p;
327 const char *s;
328 for (s = string + strlen (string) - 1; s >= string; s--)
329 {
330 for (p = brkset; *p != '\0' && *p != *s; ++p)
331 ;
332 if (*p != '\0')
333 return ((char *) s);
334 }
335 return NULL;
336 }
337
338 char *
read_line(FILE * fptr)339 read_line (FILE *fptr)
340 {
341 // get an input line, no size limit
342 int line_sz = 128; // starting size
343 char *line = (char *) malloc (line_sz);
344
345 // read as much of the line as will fit in memory
346 line[0] = 0;
347 int len = 0;
348 for (;;)
349 {
350 while (fgets (line + len, line_sz - len, fptr) != NULL)
351 {
352 len = (int) strlen (line);
353 if (len == 0 || line[len - 1] == '\n')
354 break;
355 // increase the buffer
356 char *lineNew = (char *) malloc (2 * line_sz);
357 strncpy (lineNew, line, line_sz);
358 lineNew[line_sz] = '\0';
359 free (line);
360 line = lineNew;
361 line_sz *= 2;
362 if (line == NULL)
363 {
364 fprintf (stderr, GTXT (" Line too long -- out of memory; exiting\n"));
365 exit (1);
366 }
367 }
368 if (len == 0)
369 {
370 free (line);
371 return NULL;
372 }
373 // see if there's a continuation line
374 if ((len >= 2) && (line[len - 1] == '\n') && (line[len - 2] == '\\'))
375 {
376 // remove the trailing \ and the \n, and keep going
377 line[len - 2] = 0;
378 len -= 2;
379 }
380 else
381 break;
382 }
383 return line; // expecting the caller to free it
384 }
385
386 Vector<char *> *
split_str(char * str,char delimiter)387 split_str (char *str, char delimiter)
388 {
389 Vector<char *> *v = new Vector<char *>;
390 for (char *s = str; s;)
391 {
392 if (*s == '"')
393 {
394 char *next_s = NULL;
395 char *tok = parse_qstring (s, &next_s);
396 if (tok && *tok != '\0')
397 v->append (tok);
398 if (*next_s)
399 s = next_s + 1;
400 else
401 s = NULL;
402 }
403 else
404 {
405 char *next_s = strchr (s, delimiter);
406 if (next_s)
407 {
408 if (next_s != s)
409 v->append (dbe_strndup (s, next_s - s));
410 s = next_s + 1;
411 }
412 else
413 {
414 if (*s != '\0')
415 v->append (dbe_strdup (s));
416 s = NULL;
417 }
418 }
419 }
420 return v;
421 }
422
423 // get quoted string
424 char *
parse_qstring(char * in_str,char ** endptr)425 parse_qstring (char *in_str, char **endptr)
426 {
427 int i;
428 char c, c2;
429 char term;
430 char csnum[2 * MAXPATHLEN];
431
432 // Skip any leading blanks or tabs
433 while (*in_str == '\t' || *in_str == ' ')
434 in_str++;
435
436 int gtxt = 0;
437 if (*in_str == 'G' && *(in_str + 1) == 'T' && *(in_str + 2) == 'X'
438 && *(in_str + 3) == 'T' && *(in_str + 4) == '(')
439 {
440 gtxt = 1;
441 in_str += 5;
442 }
443 // non-quoted string
444 if (*in_str == '"')
445 term = '"';
446 else if (*in_str == '\'')
447 term = '\'';
448 else
449 return strtok_r (in_str, NTXT (" "), endptr);
450
451 StringBuilder sb;
452 while ((c = *(++in_str)) != '\0')
453 {
454 if (c == term) // the closing quote
455 break;
456 if (c == '\\')
457 { // handle any escaped characters
458 c2 = *(++in_str);
459 switch (c2)
460 {
461 case '\"':
462 sb.append ('\"');
463 break;
464 case '\'':
465 sb.append ('\'');
466 break;
467 case '\\':
468 sb.append ('\\');
469 break;
470 case 't':
471 sb.append ('\t');
472 break;
473 case 'r':
474 sb.append ('\r');
475 break;
476 case 'b':
477 sb.append ('\b');
478 break;
479 case 'f':
480 sb.append ('\f');
481 break;
482 case 'n':
483 sb.append ('\n');
484 break;
485 default:
486 if ((c2 >= '0') && (c2 <= '9'))
487 {
488 for (i = 0; i < MAXPATHLEN; i++)
489 {
490 if (((c2 < '0') || (c2 > '9')) && (c2 != 'x') &&
491 ((c2 < 'a') || (c2 > 'f')) &&
492 ((c2 < 'A') || (c2 > 'F')))
493 {
494 csnum[i] = '\0';
495 --in_str;
496 break;
497 }
498 else
499 {
500 csnum[i] = c2;
501 c2 = *(++in_str);
502 }
503 }
504 sb.append ((char) strtoul (csnum, endptr, 0));
505 }
506 else
507 sb.append (c2);
508 break;
509 }
510 }
511 else
512 sb.append (c);
513 }
514 if (c == term && gtxt && *in_str == ')')
515 in_str++;
516 if (*in_str == '\0')
517 *endptr = in_str;
518 else
519 *endptr = in_str + 1;
520 return sb.toString ();
521 }
522
523 // parse a file name of the form name`name2`
524 // returns name
525 // stores the pointer to named in fcontext
526 // returns NULL if the string is not properly formatted
527 char *
parse_fname(char * in_str,char ** fcontext)528 parse_fname (char *in_str, char **fcontext)
529 {
530 *fcontext = NULL;
531 int ch = '`';
532 if (in_str == NULL)
533 return NULL;
534 char *copy = strdup (in_str);
535 char *p = strchr (copy, ch);
536 if (p != NULL)
537 {
538 // yes, there's an embedded file name
539 *p = '\0';
540 p++;
541 // now find the terminating single quote
542 char *p1 = strchr (p, ch);
543 if (p1 == NULL)
544 {
545 // if we don't have the closing `, the format is incorrect
546 free (copy);
547 return NULL;
548 }
549 //remove the closing quote
550 *p1 = '\0';
551 // see if there's anything following it
552 if (*(p1 + 1) != 0)
553 {
554 // error in format
555 free (copy);
556 return NULL;
557 }
558 free (*fcontext);
559 *fcontext = strdup (p);
560 }
561 return copy;
562 }
563
564 int
get_paren(const char * name)565 get_paren (const char *name)
566 {
567 char buf[8192];
568 char *ptr;
569 int temp_level1, temp_level2;
570
571 temp_level1 = temp_level2 = 0;
572 snprintf (buf, sizeof (buf), NTXT ("%s"), name);
573 while ((ptr = strrpbrk (buf, "><)(")) != NULL)
574 {
575 if (*ptr == '>')
576 temp_level1++;
577 else if (*ptr == '<')
578 temp_level1--;
579 else if (*ptr == ')')
580 temp_level2++;
581 else
582 {
583 temp_level2--;
584 if (temp_level1 <= 0 && temp_level2 <= 0)
585 return (int) (ptr - buf);
586 }
587 *ptr = '\0';
588 }
589 return -1;
590 }
591
592 // CRC-64 based on x^64 + x^11 + x^2 + x + 1 polynomial.
593 // This algorithm doesn't perform well but is short and
594 // readable. We currently use it for a small amount of
595 // short strings. Should this change, another algorithm
596 // with better performance is to be used instead.
597 static uint64_t masks[256] = {
598 /* 0 */ 0x000000, 0x000807, 0x00100e, 0x001809, 0x00201c, 0x00281b,
599 /* 6 */ 0x003012, 0x003815, 0x004038, 0x00483f, 0x005036, 0x005831,
600 /* 12 */ 0x006024, 0x006823, 0x00702a, 0x00782d, 0x008070, 0x008877,
601 /* 18 */ 0x00907e, 0x009879, 0x00a06c, 0x00a86b, 0x00b062, 0x00b865,
602 /* 24 */ 0x00c048, 0x00c84f, 0x00d046, 0x00d841, 0x00e054, 0x00e853,
603 /* 30 */ 0x00f05a, 0x00f85d, 0x0100e0, 0x0108e7, 0x0110ee, 0x0118e9,
604 /* 36 */ 0x0120fc, 0x0128fb, 0x0130f2, 0x0138f5, 0x0140d8, 0x0148df,
605 /* 42 */ 0x0150d6, 0x0158d1, 0x0160c4, 0x0168c3, 0x0170ca, 0x0178cd,
606 /* 48 */ 0x018090, 0x018897, 0x01909e, 0x019899, 0x01a08c, 0x01a88b,
607 /* 54 */ 0x01b082, 0x01b885, 0x01c0a8, 0x01c8af, 0x01d0a6, 0x01d8a1,
608 /* 60 */ 0x01e0b4, 0x01e8b3, 0x01f0ba, 0x01f8bd, 0x0201c0, 0x0209c7,
609 /* 66 */ 0x0211ce, 0x0219c9, 0x0221dc, 0x0229db, 0x0231d2, 0x0239d5,
610 /* 72 */ 0x0241f8, 0x0249ff, 0x0251f6, 0x0259f1, 0x0261e4, 0x0269e3,
611 /* 78 */ 0x0271ea, 0x0279ed, 0x0281b0, 0x0289b7, 0x0291be, 0x0299b9,
612 /* 84 */ 0x02a1ac, 0x02a9ab, 0x02b1a2, 0x02b9a5, 0x02c188, 0x02c98f,
613 /* 90 */ 0x02d186, 0x02d981, 0x02e194, 0x02e993, 0x02f19a, 0x02f99d,
614 /* 96 */ 0x030120, 0x030927, 0x03112e, 0x031929, 0x03213c, 0x03293b,
615 /* 102 */ 0x033132, 0x033935, 0x034118, 0x03491f, 0x035116, 0x035911,
616 /* 108 */ 0x036104, 0x036903, 0x03710a, 0x03790d, 0x038150, 0x038957,
617 /* 114 */ 0x03915e, 0x039959, 0x03a14c, 0x03a94b, 0x03b142, 0x03b945,
618 /* 120 */ 0x03c168, 0x03c96f, 0x03d166, 0x03d961, 0x03e174, 0x03e973,
619 /* 126 */ 0x03f17a, 0x03f97d, 0x040380, 0x040b87, 0x04138e, 0x041b89,
620 /* 132 */ 0x04239c, 0x042b9b, 0x043392, 0x043b95, 0x0443b8, 0x044bbf,
621 /* 138 */ 0x0453b6, 0x045bb1, 0x0463a4, 0x046ba3, 0x0473aa, 0x047bad,
622 /* 144 */ 0x0483f0, 0x048bf7, 0x0493fe, 0x049bf9, 0x04a3ec, 0x04abeb,
623 /* 150 */ 0x04b3e2, 0x04bbe5, 0x04c3c8, 0x04cbcf, 0x04d3c6, 0x04dbc1,
624 /* 156 */ 0x04e3d4, 0x04ebd3, 0x04f3da, 0x04fbdd, 0x050360, 0x050b67,
625 /* 162 */ 0x05136e, 0x051b69, 0x05237c, 0x052b7b, 0x053372, 0x053b75,
626 /* 168 */ 0x054358, 0x054b5f, 0x055356, 0x055b51, 0x056344, 0x056b43,
627 /* 174 */ 0x05734a, 0x057b4d, 0x058310, 0x058b17, 0x05931e, 0x059b19,
628 /* 180 */ 0x05a30c, 0x05ab0b, 0x05b302, 0x05bb05, 0x05c328, 0x05cb2f,
629 /* 186 */ 0x05d326, 0x05db21, 0x05e334, 0x05eb33, 0x05f33a, 0x05fb3d,
630 /* 192 */ 0x060240, 0x060a47, 0x06124e, 0x061a49, 0x06225c, 0x062a5b,
631 /* 198 */ 0x063252, 0x063a55, 0x064278, 0x064a7f, 0x065276, 0x065a71,
632 /* 204 */ 0x066264, 0x066a63, 0x06726a, 0x067a6d, 0x068230, 0x068a37,
633 /* 210 */ 0x06923e, 0x069a39, 0x06a22c, 0x06aa2b, 0x06b222, 0x06ba25,
634 /* 216 */ 0x06c208, 0x06ca0f, 0x06d206, 0x06da01, 0x06e214, 0x06ea13,
635 /* 222 */ 0x06f21a, 0x06fa1d, 0x0702a0, 0x070aa7, 0x0712ae, 0x071aa9,
636 /* 228 */ 0x0722bc, 0x072abb, 0x0732b2, 0x073ab5, 0x074298, 0x074a9f,
637 /* 234 */ 0x075296, 0x075a91, 0x076284, 0x076a83, 0x07728a, 0x077a8d,
638 /* 240 */ 0x0782d0, 0x078ad7, 0x0792de, 0x079ad9, 0x07a2cc, 0x07aacb,
639 /* 246 */ 0x07b2c2, 0x07bac5, 0x07c2e8, 0x07caef, 0x07d2e6, 0x07dae1,
640 /* 252 */ 0x07e2f4, 0x07eaf3, 0x07f2fa, 0x07fafd
641 };
642
643 uint64_t
crc64(const char * str,size_t len)644 crc64 (const char *str, size_t len)
645 {
646 uint64_t res = 0LL;
647 for (size_t i = 0; i < len; i++)
648 {
649 unsigned char b = (unsigned char) ((res >> 56) ^ *str++);
650 res = res << 8;
651 res ^= masks [b];
652 }
653 return res;
654 }
655
656 /**
657 * Canonize path inside the string provided by the argument
658 * @param path
659 * @return path
660 */
661 char *
canonical_path(char * path)662 canonical_path (char *path)
663 {
664 char *s1, *s2;
665 if (!path)
666 return path;
667 s1 = path;
668 s2 = path;
669 while (*s1)
670 {
671 if (*s1 == '.' && s1[1] == '/')
672 { // remove .///
673 for (s1++; *s1; s1++)
674 if (*s1 != '/')
675 break;
676 }
677 else if (*s1 == '/')
678 { // replace /// with /
679 *(s2++) = *s1;
680 for (s1++; *s1; s1++)
681 if (*s1 != '/')
682 break;
683 }
684 else
685 {
686 while (*s1)
687 { // copy file or directory name
688 if (*s1 == '/')
689 break;
690 *(s2++) = *(s1++);
691 }
692 }
693 }
694 *s2 = 0;
695 if (s2 != path && (s2 - 1) != path && s2[-1] == '/') // remove last /
696 *(s2 - 1) = 0;
697 return path;
698 }
699
700 char *
get_relative_path(char * name)701 get_relative_path (char *name)
702 {
703 if (*name == '/' && theApplication)
704 {
705 char *cwd = theApplication->get_cur_dir ();
706 if (cwd)
707 {
708 size_t len = strlen (cwd);
709 if (len > 0 && len < strlen (name) && name[len] == '/'
710 && strncmp (cwd, name, len) == 0)
711 {
712 for (name += len + 1; *name == '/'; name++)
713 ;
714 return name;
715 }
716 }
717 }
718 return name;
719 }
720
721 /**
722 * Generate a relative link name from path_from to path_to
723 * Example:
724 * path_from=a/b/c/d
725 * path_to=a/b/e/f/g
726 * lname=../../e/f/g
727 * @param path_to
728 * @param path_from
729 * @return lname - relative link
730 */
731 char *
get_relative_link(const char * path_from,const char * path_to)732 get_relative_link (const char *path_from, const char *path_to)
733 {
734 if (!path_to)
735 path_to = ".";
736 if (!path_from)
737 path_from = ".";
738 char *s1 = dbe_strdup (path_to);
739 s1 = canonical_path (s1);
740 char *s2 = dbe_strdup (path_from);
741 s2 = canonical_path (s2);
742 long l = dbe_sstrlen (s1);
743 // try to find common directories
744 int common_slashes = 0;
745 int last_common_slash = -1;
746 for (int i = 0; i < l; i++)
747 {
748 if (s1[i] != s2[i]) break;
749 if (s1[i] == 0) break;
750 if (s1[i] == '/')
751 {
752 common_slashes++;
753 last_common_slash = i;
754 }
755 }
756 // find slashes in remaining path_to
757 int slashes = 0;
758 for (int i = last_common_slash + 1; i < l; i++)
759 {
760 if (s1[i] == '/')
761 {
762 // Exclude "/./" case
763 if (i > last_common_slash + 2)
764 {
765 if (s1[i - 1] == '.' && s1[i - 2] == '/')
766 continue;
767 }
768 else if (i > 0 && s1[i - 1] == '.')
769 continue;
770 slashes++;
771 }
772 }
773 // generate relative path
774 StringBuilder sb;
775 for (int i = 0; i < slashes; i++)
776 sb.append ("../");
777 sb.append (s2 + last_common_slash + 1);
778 char *lname = sb.toString ();
779 free (s1);
780 free (s2);
781 return lname;
782 }
783
784 char *
get_prog_name(int basename)785 get_prog_name (int basename)
786 {
787 char *nm = NULL;
788 if (theApplication)
789 {
790 nm = theApplication->get_name ();
791 if (nm && basename)
792 nm = get_basename (nm);
793 }
794 return nm;
795 }
796
797 char *
dbe_strndup(const char * str,size_t len)798 dbe_strndup (const char *str, size_t len)
799 {
800 if (str == NULL)
801 return NULL;
802 char *s = (char *) malloc (len + 1);
803 strncpy (s, str, len);
804 s[len] = '\0';
805 return s;
806 }
807
808 char *
dbe_sprintf(const char * fmt,...)809 dbe_sprintf (const char *fmt, ...)
810 {
811 char buffer[256];
812 int buf_size;
813 va_list vp;
814
815 va_start (vp, fmt);
816 buf_size = vsnprintf (buffer, sizeof (buffer), fmt, vp) + 1;
817 va_end (vp);
818 if (buf_size < (int) sizeof (buffer))
819 {
820 if (buf_size <= 1)
821 buffer[0] = 0;
822 return strdup (buffer);
823 }
824
825 va_start (vp, fmt);
826 char *buf = (char *) malloc (buf_size);
827 vsnprintf (buf, buf_size, fmt, vp);
828 va_end (vp);
829 return buf;
830 }
831
832 ssize_t
dbe_write(int f,const char * fmt,...)833 dbe_write (int f, const char *fmt, ...)
834 {
835 char buffer[256];
836 int buf_size;
837 va_list vp;
838
839 va_start (vp, fmt);
840 buf_size = vsnprintf (buffer, sizeof (buffer), fmt, vp) + 1;
841 va_end (vp);
842 if (buf_size < (int) sizeof (buffer))
843 {
844 if (buf_size <= 1)
845 buffer[0] = 0;
846 return write (f, buffer, strlen (buffer));
847 }
848
849 va_start (vp, fmt);
850 char *buf = (char *) malloc (buf_size);
851 vsnprintf (buf, buf_size, fmt, vp);
852 va_end (vp);
853 ssize_t val = write (f, buf, strlen (buf));
854 free (buf);
855 return val;
856 }
857
858 /* Worker Threads to avoid hanging on file servers */
859
860 /*
861 * Thread states
862 */
863 enum
864 {
865 THREAD_START,
866 THREAD_STARTED,
867 THREAD_CANCEL,
868 THREAD_CANCELED,
869 THREAD_CREATE,
870 THREAD_NOT_CREATED,
871 THREAD_FINISHED
872 };
873
874 /*
875 * Communication structure
876 */
877 struct worker_thread_info
878 {
879 pthread_t thread_id; /* ID returned by pthread_create() */
880 int thread_num; /* Application-defined thread # */
881 volatile int control; /* Thread state */
882 volatile int result; /* Return status */
883 dbe_stat_t statbuf; /* File info from stat64() */
884 const char *path; /* File */
885 };
886
887 static pthread_mutex_t worker_thread_lock = PTHREAD_MUTEX_INITIALIZER;
888 static int worker_thread_number = 0;
889 /**
890 * Call stat64() on current worker thread
891 * Check if control is not THREAD_CANCEL
892 * If control is THREAD_CANCEL return (exit thread)
893 * @param *wt_info
894 */
895 static void *
dbe_stat_on_thread(void * arg)896 dbe_stat_on_thread (void *arg)
897 {
898 struct worker_thread_info *wt_info = (struct worker_thread_info *) arg;
899 pthread_mutex_lock (&worker_thread_lock);
900 {
901 if (wt_info->control != THREAD_START)
902 {
903 // Already too late
904 pthread_mutex_unlock (&worker_thread_lock);
905 return 0;
906 }
907 wt_info->control = THREAD_STARTED;
908 }
909 pthread_mutex_unlock (&worker_thread_lock);
910 const char * path = wt_info->path;
911 int st = stat64 (path, &(wt_info->statbuf));
912 pthread_mutex_lock (&worker_thread_lock);
913 {
914 if (wt_info->control == THREAD_CANCEL)
915 {
916 // Too late.
917 pthread_mutex_unlock (&worker_thread_lock);
918 free (wt_info);
919 return 0;
920 }
921 wt_info->result = st;
922 wt_info->control = THREAD_FINISHED;
923 }
924 pthread_mutex_unlock (&worker_thread_lock);
925 return 0;
926 }
927
928 /**
929 * Create a worker thread to call specified function
930 * Wait for its result, but not longer than 5 seconds
931 * If the timeout happens, tell the thread to cancel
932 * @param path
933 * @param wt_info
934 * @return thread state
935 */
936 static int
dbe_dispatch_on_thread(const char * path,struct worker_thread_info * wt_info)937 dbe_dispatch_on_thread (const char *path, struct worker_thread_info *wt_info)
938 {
939 wt_info->result = 0;
940 wt_info->control = THREAD_START;
941 pthread_attr_t attr;
942 /* Initialize thread creation attributes */
943 int res = pthread_attr_init (&attr);
944 if (res != 0)
945 {
946 wt_info->control = THREAD_NOT_CREATED;
947 return THREAD_NOT_CREATED;
948 }
949 wt_info->thread_id = 0;
950 wt_info->path = path;
951 // Lock
952 pthread_mutex_lock (&worker_thread_lock);
953 worker_thread_number++;
954 wt_info->thread_num = worker_thread_number;
955 // Unlock
956 pthread_mutex_unlock (&worker_thread_lock);
957 // Create thread
958 res = pthread_create (&wt_info->thread_id, &attr, &dbe_stat_on_thread, wt_info);
959 if (res != 0)
960 {
961 wt_info->control = THREAD_NOT_CREATED;
962 pthread_attr_destroy (&attr);
963 return THREAD_NOT_CREATED;
964 }
965 // Wait for the thread to finish
966 res = 0;
967 useconds_t maxusec = 5000000; // 5 seconds
968 useconds_t deltausec = 1000; // 1 millisecond
969 int max = maxusec / deltausec;
970 for (int i = 0; i < max; i++)
971 {
972 if (THREAD_FINISHED == wt_info->control)
973 break; // We are done
974 usleep (deltausec);
975 }
976 // Lock
977 pthread_mutex_lock (&worker_thread_lock);
978 if (THREAD_FINISHED != wt_info->control)
979 {
980 // Cancel thread
981 wt_info->control = THREAD_CANCEL; // Cannot use wt_info after that!
982 res = THREAD_CANCEL;
983 }
984 // Unlock
985 pthread_mutex_unlock (&worker_thread_lock);
986 // Destroy the thread attributes object, since it is no longer needed
987 pthread_attr_destroy (&attr);
988 // Report that thread was canceled
989 if (THREAD_CANCEL == res)
990 return res; /* Cannot free memory allocated by thread */
991 // Free all thread resources
992 void *resources = 0;
993 res = pthread_join (wt_info->thread_id, &resources);
994 free (resources); /* Free memory allocated by thread */
995 return THREAD_FINISHED;
996 }
997
998 static pthread_mutex_t dirnames_lock = PTHREAD_MUTEX_INITIALIZER;
999 static Map<const char*, int> *dirnamesMap = NULL;
1000
1001 #define DIR_STATUS_EXISTS 0
1002 #define DIR_STATUS_UNKNOWN 2
1003
1004 /**
1005 * Check if this directory name is known
1006 * Return:
1007 * @param path
1008 * 0 - known, exists
1009 * 1 - known, does not exist
1010 * 2 - not known
1011 */
1012 static int
check_dirname(const char * path)1013 check_dirname (const char *path)
1014 {
1015 pthread_mutex_lock (&dirnames_lock);
1016 if (NULL == dirnamesMap)
1017 dirnamesMap = new StringMap<int>(128, 128);
1018 pthread_mutex_unlock (&dirnames_lock);
1019 int res = DIR_STATUS_UNKNOWN;
1020 if (path && *path)
1021 {
1022 char *fn = dbe_strdup (path);
1023 char *dn = dirname (fn);
1024 if (dn && *dn)
1025 res = dirnamesMap->get (dn);
1026 free (fn);
1027 }
1028 return res;
1029 }
1030
1031 /**
1032 * Save directory name and its status
1033 * @param path
1034 * @param status
1035 * @return
1036 */
1037 static void
extract_and_save_dirname(const char * path,int status)1038 extract_and_save_dirname (const char *path, int status)
1039 {
1040 pthread_mutex_lock (&dirnames_lock);
1041 if (NULL == dirnamesMap)
1042 dirnamesMap = new StringMap<int>(128, 128);
1043 pthread_mutex_unlock (&dirnames_lock);
1044 char *fn = dbe_strdup (path);
1045 if (fn && *fn != 0)
1046 {
1047 char *dn = dirname (fn);
1048 if (dn && (*dn != 0))
1049 {
1050 int st = 0; // exists
1051 if (0 != status)
1052 st = 1; // does not exist
1053 dirnamesMap->put (dn, st);
1054 }
1055 }
1056 free (fn);
1057 }
1058
1059 // get status for specified file
1060 static int
dbe_stat_internal(const char * path,dbe_stat_t * sbuf,bool file_only)1061 dbe_stat_internal (const char *path, dbe_stat_t *sbuf, bool file_only)
1062 {
1063 dbe_stat_t statbuf;
1064 int dir_status = check_dirname (path);
1065 if (dir_status == DIR_STATUS_UNKNOWN)
1066 {
1067 // Try to use a worker thread
1068 if (theApplication->get_number_of_worker_threads () > 0)
1069 {
1070 struct worker_thread_info *wt_info;
1071 wt_info = (worker_thread_info *) calloc (1, sizeof (worker_thread_info));
1072 if (wt_info != NULL)
1073 {
1074 int res = dbe_dispatch_on_thread (path, wt_info);
1075 if (THREAD_FINISHED == res)
1076 {
1077 int st = wt_info->result;
1078 extract_and_save_dirname (path, st);
1079 if (st == 0 && file_only)
1080 if (S_ISREG ((wt_info->statbuf).st_mode) == 0)
1081 st = -1; // It is not a regular file
1082 if (sbuf != NULL)
1083 *sbuf = wt_info->statbuf;
1084 free (wt_info);
1085 return st;
1086 }
1087 else
1088 {
1089 if (THREAD_CANCEL == res)
1090 {
1091 // Worker thread hung. Cannot free wt_info.
1092 // Allocated memory will be freed by worker thread.
1093 // save directory
1094 extract_and_save_dirname (path, 1);
1095 return 1; // stat64 failed
1096 }
1097 else // THREAD_NOT_CREATED - continue on current thread
1098 free (wt_info);
1099 }
1100 }
1101 }
1102 }
1103 else if (dir_status != DIR_STATUS_EXISTS)
1104 return -1; // does not exist
1105 if (sbuf == NULL)
1106 sbuf = &statbuf;
1107 int st = stat64 (path, sbuf);
1108 Dprintf (DEBUG_DBE_FILE, NTXT ("dbe_stat %d '%s'\n"), st, path);
1109 if (st == -1)
1110 return -1;
1111 else if (file_only && S_ISREG (sbuf->st_mode) == 0)
1112 return -1; // It is not ordinary file
1113 return st;
1114 }
1115
1116 // get status for the regular file
1117
1118 int
dbe_stat_file(const char * path,dbe_stat_t * sbuf)1119 dbe_stat_file (const char *path, dbe_stat_t *sbuf)
1120 {
1121 int res = dbe_stat_internal (path, sbuf, true);
1122 return res;
1123 }
1124
1125 // get status for specified file
1126
1127 int
dbe_stat(const char * path,dbe_stat_t * sbuf)1128 dbe_stat (const char *path, dbe_stat_t *sbuf)
1129 {
1130 int res = dbe_stat_internal (path, sbuf, false);
1131 return res;
1132 }
1133
1134 /**
1135 * Reads directory and prepares list of files according to the specified format
1136 * Supported formats:
1137 * "/bin/ls -a" - see 'man ls' for details
1138 * "/bin/ls -aF" - see 'man ls' for details
1139 * @param path
1140 * @param format
1141 * @return char * files
1142 */
1143 char *
dbe_read_dir(const char * path,const char * format)1144 dbe_read_dir (const char *path, const char *format)
1145 {
1146 StringBuilder sb;
1147 DIR *dir = opendir (path);
1148 if (dir == NULL)
1149 return sb.toString ();
1150 int format_aF = 0;
1151 if (!strcmp (format, NTXT ("/bin/ls -aF")))
1152 format_aF = 1;
1153 struct dirent *entry = NULL;
1154 if (format != NULL)
1155 {
1156 while ((entry = readdir (dir)) != NULL)
1157 {
1158 sb.append (entry->d_name);
1159 if (format_aF)
1160 {
1161 const char *attr = NTXT ("@"); // Link
1162 dbe_stat_t sbuf;
1163 sbuf.st_mode = 0;
1164 char filename[MAXPATHLEN + 1];
1165 snprintf (filename, sizeof (filename), NTXT ("%s/%s"), path, entry->d_name);
1166 dbe_stat (filename, &sbuf);
1167 if (S_IREAD & sbuf.st_mode)
1168 { // Readable
1169 if (S_ISDIR (sbuf.st_mode) != 0) // Directory
1170 attr = NTXT ("/");
1171 else if (S_ISREG (sbuf.st_mode) != 0) // Regular file
1172 attr = NTXT ("");
1173 }
1174 sb.append (attr);
1175 }
1176 sb.append (NTXT ("\n"));
1177 }
1178 }
1179 closedir (dir);
1180 return sb.toString ();
1181 }
1182
1183 /**
1184 * Gets list of processes according to the specified format
1185 * Supported formats:
1186 * "/bin/ps -ef" - see 'man ps' for details
1187 * @param format
1188 * @return char * processes
1189 */
1190 char *
dbe_get_processes(const char * format)1191 dbe_get_processes (const char *format)
1192 {
1193 StringBuilder sb;
1194 if (!strcmp (format, NTXT ("/bin/ps -ef")))
1195 {
1196 char buf[BUFSIZ];
1197 FILE *ptr = popen (format, "r");
1198 if (ptr != NULL)
1199 {
1200 while (fgets (buf, BUFSIZ, ptr) != NULL)
1201 sb.append (buf);
1202 pclose (ptr);
1203 }
1204 }
1205 return sb.toString ();
1206 }
1207
1208 /**
1209 * Creates the directory named by the specified path name, including any
1210 * necessary but nonexistent parent directories.
1211 * Uses system utility "/bin/mkdir -p"
1212 * Temporary limitation: path name should not contain spaces.
1213 * Returns message from "/bin/mkdir -p"
1214 * @param pathname
1215 * @return result
1216 */
1217 char *
dbe_create_directories(const char * pathname)1218 dbe_create_directories (const char *pathname)
1219 {
1220 StringBuilder sb;
1221 char *makedir = dbe_sprintf (NTXT ("/bin/mkdir -p %s 2>&1"), pathname);
1222 char out[BUFSIZ];
1223 FILE *ptr = popen (makedir, "r");
1224 if (ptr != NULL)
1225 {
1226 while (fgets (out, BUFSIZ, ptr) != NULL)
1227 sb.append (out);
1228 pclose (ptr);
1229 }
1230 free (makedir);
1231 DIR *dir = opendir (pathname);
1232 if (dir != NULL)
1233 {
1234 closedir (dir);
1235 return NULL; // success
1236 }
1237 else
1238 sb.append (NTXT ("\nError: Cannot open directory\n")); // DEBUG
1239 return sb.toString (); // error
1240 }
1241
1242 /**
1243 * Deletes the file or the directory named by the specified path name.
1244 * If this pathname denotes a directory, then the directory must be empty in order to be deleted.
1245 * Uses system utility "/bin/rm" or "/bin/rmdir"
1246 * Temporary limitation: path name should not contain spaces.
1247 * Returns error message from system utility
1248 * @param pathname
1249 * @return result
1250 */
1251 char *
dbe_delete_file(const char * pathname)1252 dbe_delete_file (const char *pathname)
1253 {
1254 StringBuilder sb;
1255 char *cmd = NULL;
1256 dbe_stat_t sbuf;
1257 sbuf.st_mode = 0;
1258 int st = dbe_stat (pathname, &sbuf);
1259 if (st == 0)
1260 { // Exists
1261 if (S_ISDIR (sbuf.st_mode) != 0) // Directory
1262 cmd = dbe_sprintf (NTXT ("/bin/rmdir %s 2>&1"), pathname);
1263 else if (S_ISREG (sbuf.st_mode) != 0) // Regular file
1264 cmd = dbe_sprintf (NTXT ("/bin/rm %s 2>&1"), pathname);
1265 }
1266 else
1267 return NULL; // Nothing to remove
1268 if (cmd != NULL)
1269 {
1270 char out[BUFSIZ];
1271 FILE *ptr = popen (cmd, "r");
1272 if (ptr != NULL)
1273 {
1274 while (fgets (out, BUFSIZ, ptr) != NULL)
1275 sb.append (out);
1276 pclose (ptr);
1277 }
1278 free (cmd);
1279 }
1280 else
1281 sb.sprintf (NTXT ("Error: cannot remove %s - not a regular file and not a directory\n"), pathname);
1282 return sb.toString ();
1283 }
1284
1285 char *
dbe_xml2str(const char * s)1286 dbe_xml2str (const char *s)
1287 {
1288 if (s == NULL)
1289 return NULL;
1290 StringBuilder sb;
1291 while (*s)
1292 {
1293 if (*s == '&')
1294 {
1295 if (strncmp (s, NTXT (" "), 6) == 0)
1296 {
1297 sb.append (' ');
1298 s += 6;
1299 continue;
1300 }
1301 else if (strncmp (s, NTXT ("""), 6) == 0)
1302 {
1303 sb.append ('"');
1304 s += 6;
1305 continue;
1306 }
1307 else if (strncmp (s, NTXT ("&"), 5) == 0)
1308 {
1309 sb.append ('&');
1310 s += 5;
1311 continue;
1312 }
1313 else if (strncmp (s, NTXT ("<"), 4) == 0)
1314 {
1315 sb.append ('<');
1316 s += 4;
1317 continue;
1318 }
1319 else if (strncmp (s, NTXT (">"), 4) == 0)
1320 {
1321 sb.append ('>');
1322 s += 4;
1323 continue;
1324 }
1325 }
1326 sb.append (*s);
1327 s++;
1328 }
1329 return sb.toString ();
1330 }
1331
1332 void
swapByteOrder(void * p,size_t sz)1333 swapByteOrder (void *p, size_t sz)
1334 {
1335 if (sz == 8)
1336 {
1337 uint64_t *pv = (uint64_t *) p;
1338 uint64_t v = *pv;
1339 v = ((v & 0x00000000FF000000) << 8) | ((v >> 8) & 0x00000000FF000000) |
1340 ((v & 0x0000000000FF0000) << 24) | ((v >> 24) & 0x0000000000FF0000) |
1341 ((v & 0x000000000000FF00) << 40) | ((v >> 40) & 0x000000000000FF00) |
1342 (v >> 56) | (v << 56);
1343 *pv = v;
1344 }
1345 else if (sz == 4)
1346 {
1347 uint32_t *pv = (uint32_t *) p;
1348 uint32_t v = *pv;
1349 v = (v >> 24) | (v << 24) | ((v & 0x0000FF00) << 8) | ((v >> 8) & 0x0000FF00);
1350 *pv = v;
1351 }
1352 else if (sz == 2)
1353 {
1354 uint16_t *pv = (uint16_t *) p;
1355 uint16_t v = *pv;
1356 v = (v >> 8) | (v << 8);
1357 *pv = v;
1358 }
1359 }
1360
1361 void
destroy(void * vec)1362 destroy (void *vec)
1363 {
1364 if (vec == NULL)
1365 return;
1366 Vector<void*> *array = (Vector<void*>*)vec;
1367 switch (array->type ())
1368 {
1369 case VEC_STRING:
1370 ((Vector<char *>*)array)->destroy ();
1371 break;
1372 case VEC_VOIDARR:
1373 case VEC_STRINGARR:
1374 case VEC_INTARR:
1375 case VEC_BOOLARR:
1376 case VEC_LLONGARR:
1377 case VEC_DOUBLEARR:
1378 for (long i = 0; i < array->size (); i++)
1379 destroy (array->fetch (i));
1380 break;
1381 case VEC_INTEGER:
1382 case VEC_CHAR:
1383 case VEC_BOOL:
1384 case VEC_DOUBLE:
1385 case VEC_LLONG:
1386 default:
1387 break;
1388 }
1389 delete array;
1390 }
1391
1392 int64_t
read_from_file(int fd,void * buffer,int64_t nbyte)1393 read_from_file (int fd, void *buffer, int64_t nbyte)
1394 {
1395 int64_t cnt = 0;
1396 char *buf = (char *) buffer;
1397 while (nbyte > 0)
1398 { // Sometimes system cannot read 'nbyte'
1399 ssize_t n = read (fd, (void *) (buf + cnt), (size_t) nbyte);
1400 if (n <= 0)
1401 break;
1402 nbyte -= n;
1403 cnt += n;
1404 }
1405 return cnt;
1406 }
1407
1408 /**
1409 * Create symbolic link to the path
1410 * @param path - path with spaces
1411 * @param dir - directory where the link should be created
1412 * @return symbolic link
1413 */
1414 char *
dbe_create_symlink_to_path(const char * path,const char * dir)1415 dbe_create_symlink_to_path (const char *path, const char *dir)
1416 {
1417 char *symbolic_link = NULL;
1418 if (NULL == path || NULL == dir)
1419 return NULL;
1420 int res = mkdir (dir, 0777);
1421 if (res != 0 && dbe_stat (dir, NULL) != 0)
1422 return NULL; // Cannot create directory
1423 long len = dbe_sstrlen (path);
1424 if (len <= 4)
1425 return NULL; // Unknown situation
1426 if (strcmp ((path + len - 4), "/bin") != 0) // Unknown situation
1427 return NULL;
1428 int max = 99; // Just an arbitrary number
1429 for (int i = 1; i <= max; i++)
1430 {
1431 // Try to create symbolic link
1432 char *d = dbe_sprintf ("%s/%d", dir, i);
1433 if (NULL == d)
1434 return NULL;
1435 res = mkdir (d, 0777);
1436 symbolic_link = dbe_sprintf ("%s/%s", d, "bin");
1437 free (d);
1438 if (NULL == symbolic_link) // Not enough memory
1439 return NULL;
1440 res = symlink (path, symbolic_link);
1441 if (res == 0) // Link is created - use it.
1442 break;
1443 // Check if such link already exists
1444 int e = errno;
1445 char buf[MAXPATHLEN + 1];
1446 memset (buf, 0, MAXPATHLEN + 1);
1447 ssize_t n = readlink (symbolic_link, buf, MAXPATHLEN);
1448 if (n == len && strcmp (path, buf) == 0) // Link is correct - use it.
1449 break;
1450 if (i == max)
1451 { // report the error
1452 fprintf (stderr, GTXT ("Error: symlink(%s, %s) returned error: %d\n"), path, symbolic_link, res);
1453 fprintf (stderr, GTXT ("Error: errno=%d (%s)\n"), e, strerror (e));
1454 fflush (stderr);
1455 }
1456 free (symbolic_link);
1457 symbolic_link = NULL;
1458 }
1459 return symbolic_link;
1460 }
1461
1462 // Compute checksum for specified file.
1463 // This code is from usr/src/cmd/cksum.c, adapted for us
1464 // crcposix -- compute posix.2 compatable 32 bit CRC
1465 //
1466 // The POSIX.2 (draft 10) CRC algorithm.
1467 // This is a 32 bit CRC with polynomial
1468 // x**32 + x**26 + x**23 + x**22 + x**16 + x**12 + x**11 + x**10 +
1469 // x**8 + x**7 + x**5 + x**4 + x**2 + x**1 + x**0
1470 //
1471 // layout is from the POSIX.2 Rationale
1472
1473 static uint32_t crctab_posix[256] = {
1474 0x00000000L,
1475 0x04C11DB7L, 0x09823B6EL, 0x0D4326D9L, 0x130476DCL, 0x17C56B6BL,
1476 0x1A864DB2L, 0x1E475005L, 0x2608EDB8L, 0x22C9F00FL, 0x2F8AD6D6L,
1477 0x2B4BCB61L, 0x350C9B64L, 0x31CD86D3L, 0x3C8EA00AL, 0x384FBDBDL,
1478 0x4C11DB70L, 0x48D0C6C7L, 0x4593E01EL, 0x4152FDA9L, 0x5F15ADACL,
1479 0x5BD4B01BL, 0x569796C2L, 0x52568B75L, 0x6A1936C8L, 0x6ED82B7FL,
1480 0x639B0DA6L, 0x675A1011L, 0x791D4014L, 0x7DDC5DA3L, 0x709F7B7AL,
1481 0x745E66CDL, 0x9823B6E0L, 0x9CE2AB57L, 0x91A18D8EL, 0x95609039L,
1482 0x8B27C03CL, 0x8FE6DD8BL, 0x82A5FB52L, 0x8664E6E5L, 0xBE2B5B58L,
1483 0xBAEA46EFL, 0xB7A96036L, 0xB3687D81L, 0xAD2F2D84L, 0xA9EE3033L,
1484 0xA4AD16EAL, 0xA06C0B5DL, 0xD4326D90L, 0xD0F37027L, 0xDDB056FEL,
1485 0xD9714B49L, 0xC7361B4CL, 0xC3F706FBL, 0xCEB42022L, 0xCA753D95L,
1486 0xF23A8028L, 0xF6FB9D9FL, 0xFBB8BB46L, 0xFF79A6F1L, 0xE13EF6F4L,
1487 0xE5FFEB43L, 0xE8BCCD9AL, 0xEC7DD02DL, 0x34867077L, 0x30476DC0L,
1488 0x3D044B19L, 0x39C556AEL, 0x278206ABL, 0x23431B1CL, 0x2E003DC5L,
1489 0x2AC12072L, 0x128E9DCFL, 0x164F8078L, 0x1B0CA6A1L, 0x1FCDBB16L,
1490 0x018AEB13L, 0x054BF6A4L, 0x0808D07DL, 0x0CC9CDCAL, 0x7897AB07L,
1491 0x7C56B6B0L, 0x71159069L, 0x75D48DDEL, 0x6B93DDDBL, 0x6F52C06CL,
1492 0x6211E6B5L, 0x66D0FB02L, 0x5E9F46BFL, 0x5A5E5B08L, 0x571D7DD1L,
1493 0x53DC6066L, 0x4D9B3063L, 0x495A2DD4L, 0x44190B0DL, 0x40D816BAL,
1494 0xACA5C697L, 0xA864DB20L, 0xA527FDF9L, 0xA1E6E04EL, 0xBFA1B04BL,
1495 0xBB60ADFCL, 0xB6238B25L, 0xB2E29692L, 0x8AAD2B2FL, 0x8E6C3698L,
1496 0x832F1041L, 0x87EE0DF6L, 0x99A95DF3L, 0x9D684044L, 0x902B669DL,
1497 0x94EA7B2AL, 0xE0B41DE7L, 0xE4750050L, 0xE9362689L, 0xEDF73B3EL,
1498 0xF3B06B3BL, 0xF771768CL, 0xFA325055L, 0xFEF34DE2L, 0xC6BCF05FL,
1499 0xC27DEDE8L, 0xCF3ECB31L, 0xCBFFD686L, 0xD5B88683L, 0xD1799B34L,
1500 0xDC3ABDEDL, 0xD8FBA05AL, 0x690CE0EEL, 0x6DCDFD59L, 0x608EDB80L,
1501 0x644FC637L, 0x7A089632L, 0x7EC98B85L, 0x738AAD5CL, 0x774BB0EBL,
1502 0x4F040D56L, 0x4BC510E1L, 0x46863638L, 0x42472B8FL, 0x5C007B8AL,
1503 0x58C1663DL, 0x558240E4L, 0x51435D53L, 0x251D3B9EL, 0x21DC2629L,
1504 0x2C9F00F0L, 0x285E1D47L, 0x36194D42L, 0x32D850F5L, 0x3F9B762CL,
1505 0x3B5A6B9BL, 0x0315D626L, 0x07D4CB91L, 0x0A97ED48L, 0x0E56F0FFL,
1506 0x1011A0FAL, 0x14D0BD4DL, 0x19939B94L, 0x1D528623L, 0xF12F560EL,
1507 0xF5EE4BB9L, 0xF8AD6D60L, 0xFC6C70D7L, 0xE22B20D2L, 0xE6EA3D65L,
1508 0xEBA91BBCL, 0xEF68060BL, 0xD727BBB6L, 0xD3E6A601L, 0xDEA580D8L,
1509 0xDA649D6FL, 0xC423CD6AL, 0xC0E2D0DDL, 0xCDA1F604L, 0xC960EBB3L,
1510 0xBD3E8D7EL, 0xB9FF90C9L, 0xB4BCB610L, 0xB07DABA7L, 0xAE3AFBA2L,
1511 0xAAFBE615L, 0xA7B8C0CCL, 0xA379DD7BL, 0x9B3660C6L, 0x9FF77D71L,
1512 0x92B45BA8L, 0x9675461FL, 0x8832161AL, 0x8CF30BADL, 0x81B02D74L,
1513 0x857130C3L, 0x5D8A9099L, 0x594B8D2EL, 0x5408ABF7L, 0x50C9B640L,
1514 0x4E8EE645L, 0x4A4FFBF2L, 0x470CDD2BL, 0x43CDC09CL, 0x7B827D21L,
1515 0x7F436096L, 0x7200464FL, 0x76C15BF8L, 0x68860BFDL, 0x6C47164AL,
1516 0x61043093L, 0x65C52D24L, 0x119B4BE9L, 0x155A565EL, 0x18197087L,
1517 0x1CD86D30L, 0x029F3D35L, 0x065E2082L, 0x0B1D065BL, 0x0FDC1BECL,
1518 0x3793A651L, 0x3352BBE6L, 0x3E119D3FL, 0x3AD08088L, 0x2497D08DL,
1519 0x2056CD3AL, 0x2D15EBE3L, 0x29D4F654L, 0xC5A92679L, 0xC1683BCEL,
1520 0xCC2B1D17L, 0xC8EA00A0L, 0xD6AD50A5L, 0xD26C4D12L, 0xDF2F6BCBL,
1521 0xDBEE767CL, 0xE3A1CBC1L, 0xE760D676L, 0xEA23F0AFL, 0xEEE2ED18L,
1522 0xF0A5BD1DL, 0xF464A0AAL, 0xF9278673L, 0xFDE69BC4L, 0x89B8FD09L,
1523 0x8D79E0BEL, 0x803AC667L, 0x84FBDBD0L, 0x9ABC8BD5L, 0x9E7D9662L,
1524 0x933EB0BBL, 0x97FFAD0CL, 0xAFB010B1L, 0xAB710D06L, 0xA6322BDFL,
1525 0xA2F33668L, 0xBCB4666DL, 0xB8757BDAL, 0xB5365D03L, 0xB1F740B4L
1526 };
1527
1528 static void
m_crcposix(uint32_t * crcp,unsigned char * bp,uint32_t n)1529 m_crcposix (uint32_t *crcp, unsigned char *bp, uint32_t n)
1530 {
1531 while (n-- > 0)
1532 *crcp = (*crcp << 8) ^ crctab_posix[(unsigned char) ((*crcp >> 24)^*bp++)];
1533 }
1534
1535 // Do CRC-POSIX function by calling a library entry point that has a
1536 // slightly different calling sequence.
1537 static uint32_t
docrcposix(uint32_t crcval,unsigned char * bp,uint32_t n)1538 docrcposix (uint32_t crcval, unsigned char *bp, uint32_t n)
1539 {
1540 m_crcposix (&crcval, bp, n);
1541 return (crcval);
1542 }
1543
1544 // Sum algorithms require various kinds of post-processing.
1545 // The 'S' and 'R' variables are from the POSIX.2 (Draft 8?) description
1546 // of the "sum" utility.
1547 static uint32_t
postprocess(uint32_t S,long long n)1548 postprocess (uint32_t S, long long n)
1549 {
1550 // POSIX tacks on significant bytes of the length so that
1551 // different length sequences of '\0' have different sums;
1552 // then it complements sum.
1553 unsigned char char_n[sizeof (n)];
1554 uint32_t i;
1555 for (i = 0; n != 0; n >>= 8, ++i)
1556 char_n[i] = (unsigned char) (n & 0xFF);
1557 return (~docrcposix (S, char_n, i));
1558 }
1559
1560 uint32_t
get_cksum(const char * pathname,char ** errmsg)1561 get_cksum (const char * pathname, char ** errmsg)
1562 {
1563 int fd = open (pathname, O_RDONLY);
1564 if (fd < 0)
1565 {
1566 if (errmsg)
1567 *errmsg = dbe_sprintf (GTXT ("*** Warning: Error opening file for reading: %s"), pathname);
1568 return 0; // error
1569 }
1570 uint32_t crcval = 0;
1571 long long bytes = 0;
1572 int64_t n;
1573 unsigned char buf[4096];
1574 while ((n = read_from_file (fd, (char *) buf, sizeof (buf))) > 0)
1575 {
1576 bytes += n;
1577 crcval = docrcposix (crcval, buf, n);
1578 }
1579 close (fd);
1580 crcval = postprocess (crcval, bytes);
1581 return crcval;
1582 }
1583