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 <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 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 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 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 96 int_max (int *maximum, int count) 97 { 98 if (count > *maximum) 99 *maximum = count; 100 } 101 102 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 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 149 TValue::get_len () 150 { 151 char buf[256]; 152 return strlen (to_str (buf, sizeof (buf))); 153 } 154 155 char * 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 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 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 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 * 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 * 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 * 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 *> * 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 * 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 * 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 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 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 * 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 * 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 * 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 * 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 * 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 * 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 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 struct stat64 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 * 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 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 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 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 1061 dbe_stat_internal (const char *path, struct stat64 *sbuf, bool file_only) 1062 { 1063 struct stat64 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 1119 dbe_stat_file (const char *path, struct stat64 *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 1128 dbe_stat (const char *path, struct stat64 *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 * 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 struct stat64 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 * 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 * 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 * 1252 dbe_delete_file (const char *pathname) 1253 { 1254 StringBuilder sb; 1255 char *cmd = NULL; 1256 struct stat64 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 * 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 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 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 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 * 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 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 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 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 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