forked from Imagelibrary/binutils-gdb
This adds 'Innovative Computing Labs' as an external author to update-copyright.py, to cover the copyright notice in gprofng/common/opteron_pcbe.c, and uses that plus another external author 'Oracle and' to update gprofng copyright dates. I'm not going to commit 'Oracle and' as an accepted author, but that covers the string "Copyright (c) 2006, 2012, Oracle and/or its affiliates. All rights reserved." found in gprofng/testsuite/gprofng.display/jsynprog files.
1583 lines
39 KiB
C++
1583 lines
39 KiB
C++
/* Copyright (C) 2021-2023 Free Software Foundation, Inc.
|
|
Contributed by Oracle.
|
|
|
|
This file is part of GNU Binutils.
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 3, or (at your option)
|
|
any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, 51 Franklin Street - Fifth Floor, Boston,
|
|
MA 02110-1301, USA. */
|
|
|
|
#include "config.h"
|
|
#include <sys/param.h>
|
|
#include <stdarg.h>
|
|
#include <unistd.h>
|
|
#include <dirent.h> // readdir()
|
|
#include <sys/param.h> // MAXPATHLEN
|
|
#include <pthread.h> // mutex
|
|
#include <libgen.h> // dirname
|
|
#include <sys/types.h> // open
|
|
#include <sys/stat.h> // open
|
|
#include <errno.h> // errno
|
|
#include <fcntl.h> // open
|
|
|
|
#include "util.h"
|
|
#include "dbe_structs.h"
|
|
#include "StringBuilder.h"
|
|
#include "StringMap.h" // For directory names
|
|
#include "Application.h" // Only for get_prog_name
|
|
#include "vec.h"
|
|
|
|
void
|
|
tsadd (timestruc_t *result, timestruc_t *time)
|
|
{
|
|
// This routine will add "time" to "result".
|
|
result->tv_sec += time->tv_sec;
|
|
result->tv_nsec += time->tv_nsec;
|
|
if (result->tv_nsec >= NANOSEC)
|
|
{
|
|
result->tv_nsec -= NANOSEC;
|
|
result->tv_sec++;
|
|
}
|
|
}
|
|
|
|
void
|
|
tssub (timestruc_t *result, timestruc_t *time1, timestruc_t *time2)
|
|
{
|
|
// This routine will store "time1" - "time2" in "result".
|
|
|
|
if (time1->tv_nsec >= time2->tv_nsec)
|
|
{
|
|
result->tv_nsec = time1->tv_nsec - time2->tv_nsec;
|
|
if (time1->tv_sec >= time2->tv_sec)
|
|
result->tv_sec = time1->tv_sec - time2->tv_sec;
|
|
else
|
|
{
|
|
result->tv_sec = -1;
|
|
result->tv_nsec = 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
result->tv_nsec = time1->tv_nsec + NANOSEC - time2->tv_nsec;
|
|
if (time1->tv_sec - 1 >= time2->tv_sec)
|
|
result->tv_sec = time1->tv_sec - 1 - time2->tv_sec;
|
|
else
|
|
{
|
|
result->tv_sec = -1;
|
|
result->tv_nsec = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
int
|
|
tscmp (timestruc_t *time1, timestruc_t *time2)
|
|
{
|
|
// This routine will return 1 if "time1" is greater than "time2"
|
|
// and 0 if "time1" is equal to "time2" and -1 otherwise.
|
|
if (time1->tv_sec == time2->tv_sec)
|
|
return time1->tv_nsec > time2->tv_nsec ? 1 :
|
|
time1->tv_nsec == time2->tv_nsec ? 0 : -1;
|
|
else
|
|
return time1->tv_sec > time2->tv_sec ? 1 : -1;
|
|
}
|
|
|
|
void
|
|
int_max (int *maximum, int count)
|
|
{
|
|
if (count > *maximum)
|
|
*maximum = count;
|
|
}
|
|
|
|
double
|
|
TValue::to_double ()
|
|
{
|
|
switch (tag)
|
|
{
|
|
case VT_DOUBLE:
|
|
return (double) d;
|
|
case VT_INT:
|
|
return (double) i;
|
|
case VT_ULLONG:
|
|
return (double) ull;
|
|
case VT_LLONG:
|
|
case VT_ADDRESS:
|
|
return (double) ll;
|
|
case VT_FLOAT:
|
|
return (double) f;
|
|
case VT_SHORT:
|
|
return (double) s;
|
|
default:
|
|
return 0.0;
|
|
}
|
|
}
|
|
|
|
int
|
|
TValue::to_int ()
|
|
{
|
|
switch (tag)
|
|
{
|
|
case VT_DOUBLE:
|
|
return (int) d;
|
|
case VT_INT:
|
|
return (int) i;
|
|
case VT_ULLONG:
|
|
return (int) ull;
|
|
case VT_LLONG:
|
|
case VT_ADDRESS:
|
|
return (int) ll;
|
|
case VT_FLOAT:
|
|
return (int) f;
|
|
case VT_SHORT:
|
|
return (int) s;
|
|
default:
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
size_t
|
|
TValue::get_len ()
|
|
{
|
|
char buf[256];
|
|
return strlen (to_str (buf, sizeof (buf)));
|
|
}
|
|
|
|
char *
|
|
TValue::to_str (char *str, size_t strsz)
|
|
{
|
|
switch (tag)
|
|
{
|
|
case VT_DOUBLE:
|
|
if (d == 0.)
|
|
{
|
|
if (sign)
|
|
snprintf (str, strsz, NTXT ("+0. "));
|
|
else
|
|
snprintf (str, strsz, NTXT ("0. "));
|
|
}
|
|
else if (sign)
|
|
snprintf (str, strsz, NTXT ("%+.3lf"), d);
|
|
else
|
|
snprintf (str, strsz, NTXT ("%.3lf"), d);
|
|
break;
|
|
case VT_INT:
|
|
snprintf (str, strsz, NTXT ("%u"), i);
|
|
break;
|
|
case VT_LLONG:
|
|
if (sign)
|
|
snprintf (str, strsz, NTXT ("%+lld"), ll);
|
|
else
|
|
snprintf (str, strsz, NTXT ("%lld"), ll);
|
|
break;
|
|
case VT_ULLONG:
|
|
snprintf (str, strsz, NTXT ("%llu"), ll);
|
|
break;
|
|
case VT_ADDRESS:
|
|
snprintf (str, strsz, NTXT ("%u:0x%08x"), ADDRESS_SEG (ll), ADDRESS_OFF (ll));
|
|
break;
|
|
case VT_FLOAT:
|
|
snprintf (str, strsz, NTXT ("%.3f"), f);
|
|
break;
|
|
case VT_SHORT:
|
|
snprintf (str, strsz, NTXT ("%hu"), s);
|
|
break;
|
|
case VT_LABEL:
|
|
return l; // 'str' is not used !!!
|
|
default:
|
|
*str = '\0';
|
|
break;
|
|
}
|
|
|
|
return str;
|
|
}
|
|
|
|
void
|
|
TValue::make_delta (TValue *v1, TValue *v2)
|
|
{
|
|
assert (v1->tag == v2->tag);
|
|
tag = v1->tag;
|
|
sign = true;
|
|
switch (v1->tag)
|
|
{
|
|
case VT_INT:
|
|
i = v1->i - v2->i;
|
|
break;
|
|
case VT_LLONG:
|
|
ll = v1->ll - v2->ll;
|
|
break;
|
|
case VT_ULLONG:
|
|
case VT_ADDRESS:
|
|
tag = VT_LLONG;
|
|
ll = (long long) (v1->ull - v2->ull);
|
|
break;
|
|
case VT_FLOAT:
|
|
f = v1->f - v2->f;
|
|
break;
|
|
case VT_DOUBLE:
|
|
d = v1->d - v2->d;
|
|
break;
|
|
default:
|
|
assert (0);
|
|
break;
|
|
}
|
|
}
|
|
|
|
void
|
|
TValue::make_ratio (TValue *v1, TValue *v2)
|
|
{
|
|
assert (v1->tag == v2->tag);
|
|
double x1 = v1->to_double ();
|
|
double x2 = v2->to_double ();
|
|
sign = false;
|
|
if (x1 == 0.)
|
|
{
|
|
// if the numerator is 0, the ratio is 1. or 0. only
|
|
d = (x2 == 0.) ? 1. : 0.;
|
|
tag = VT_DOUBLE;
|
|
}
|
|
else
|
|
{
|
|
// EUGENE replace 99.999 with a variable that is known by both DBE and GUI
|
|
if (x1 > 99.999 * x2)
|
|
{
|
|
l = dbe_strdup (">99.999");
|
|
tag = VT_LABEL;
|
|
}
|
|
else if (x1 < -99.999 * x2)
|
|
{
|
|
l = dbe_strdup ("<-99.999");
|
|
tag = VT_LABEL;
|
|
}
|
|
else
|
|
{
|
|
d = x1 / x2;
|
|
tag = VT_DOUBLE;
|
|
}
|
|
}
|
|
}
|
|
|
|
int
|
|
TValue::compare (TValue *v)
|
|
{
|
|
if (tag != v->tag)
|
|
{ // Only for comparison (Ratio)
|
|
if (tag == VT_LABEL)
|
|
{
|
|
if (v->tag == VT_LABEL)
|
|
return strcoll (l, v->l);
|
|
return 1;
|
|
}
|
|
if (v->tag == VT_LABEL)
|
|
return -1;
|
|
return ll < v->ll ? -1 : (ll == v->ll ? 0 : 1);
|
|
}
|
|
switch (tag)
|
|
{
|
|
case VT_SHORT:
|
|
return s < v->s ? -1 : (s == v->s ? 0 : 1);
|
|
case VT_INT:
|
|
return i < v->i ? -1 : (i == v->i ? 0 : 1);
|
|
case VT_FLOAT:
|
|
return f < v->f ? -1 : (f == v->f ? 0 : 1);
|
|
case VT_DOUBLE:
|
|
return d < v->d ? -1 : (d == v->d ? 0 : 1);
|
|
case VT_LABEL:
|
|
return strcoll (l, v->l);
|
|
case VT_LLONG:
|
|
case VT_ULLONG:
|
|
case VT_ADDRESS:
|
|
case VT_HRTIME:
|
|
default:
|
|
return (ll < v->ll) ? -1 : ((ll == v->ll) ? 0 : 1);
|
|
}
|
|
}
|
|
|
|
char *
|
|
strstr_r (char *s1, const char *s2)
|
|
{
|
|
char *str = NULL;
|
|
for (char *s = s1; s;)
|
|
{
|
|
s = strstr (s, s2);
|
|
if (s)
|
|
{
|
|
str = s;
|
|
s++;
|
|
}
|
|
}
|
|
return str;
|
|
}
|
|
|
|
// reversal order of strpbrk
|
|
|
|
char *
|
|
strrpbrk (const char *string, const char *brkset)
|
|
{
|
|
const char *p;
|
|
const char *s;
|
|
for (s = string + strlen (string) - 1; s >= string; s--)
|
|
{
|
|
for (p = brkset; *p != '\0' && *p != *s; ++p)
|
|
;
|
|
if (*p != '\0')
|
|
return ((char *) s);
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
char *
|
|
read_line (FILE *fptr)
|
|
{
|
|
// get an input line, no size limit
|
|
int line_sz = 128; // starting size
|
|
char *line = (char *) malloc (line_sz);
|
|
|
|
// read as much of the line as will fit in memory
|
|
line[0] = 0;
|
|
int len = 0;
|
|
for (;;)
|
|
{
|
|
while (fgets (line + len, line_sz - len, fptr) != NULL)
|
|
{
|
|
len = (int) strlen (line);
|
|
if (len == 0 || line[len - 1] == '\n')
|
|
break;
|
|
// increase the buffer
|
|
char *lineNew = (char *) malloc (2 * line_sz);
|
|
strncpy (lineNew, line, line_sz);
|
|
lineNew[line_sz] = '\0';
|
|
free (line);
|
|
line = lineNew;
|
|
line_sz *= 2;
|
|
if (line == NULL)
|
|
{
|
|
fprintf (stderr, GTXT (" Line too long -- out of memory; exiting\n"));
|
|
exit (1);
|
|
}
|
|
}
|
|
if (len == 0)
|
|
{
|
|
free (line);
|
|
return NULL;
|
|
}
|
|
// see if there's a continuation line
|
|
if ((len >= 2) && (line[len - 1] == '\n') && (line[len - 2] == '\\'))
|
|
{
|
|
// remove the trailing \ and the \n, and keep going
|
|
line[len - 2] = 0;
|
|
len -= 2;
|
|
}
|
|
else
|
|
break;
|
|
}
|
|
return line; // expecting the caller to free it
|
|
}
|
|
|
|
Vector<char *> *
|
|
split_str (char *str, char delimiter)
|
|
{
|
|
Vector<char *> *v = new Vector<char *>;
|
|
for (char *s = str; s;)
|
|
{
|
|
if (*s == '"')
|
|
{
|
|
char *next_s = NULL;
|
|
char *tok = parse_qstring (s, &next_s);
|
|
if (tok && *tok != '\0')
|
|
v->append (tok);
|
|
if (*next_s)
|
|
s = next_s + 1;
|
|
else
|
|
s = NULL;
|
|
}
|
|
else
|
|
{
|
|
char *next_s = strchr (s, delimiter);
|
|
if (next_s)
|
|
{
|
|
if (next_s != s)
|
|
v->append (dbe_strndup (s, next_s - s));
|
|
s = next_s + 1;
|
|
}
|
|
else
|
|
{
|
|
if (*s != '\0')
|
|
v->append (dbe_strdup (s));
|
|
s = NULL;
|
|
}
|
|
}
|
|
}
|
|
return v;
|
|
}
|
|
|
|
// get quoted string
|
|
char *
|
|
parse_qstring (char *in_str, char **endptr)
|
|
{
|
|
int i;
|
|
char c, c2;
|
|
char term;
|
|
char csnum[2 * MAXPATHLEN];
|
|
|
|
// Skip any leading blanks or tabs
|
|
while (*in_str == '\t' || *in_str == ' ')
|
|
in_str++;
|
|
|
|
int gtxt = 0;
|
|
if (*in_str == 'G' && *(in_str + 1) == 'T' && *(in_str + 2) == 'X'
|
|
&& *(in_str + 3) == 'T' && *(in_str + 4) == '(')
|
|
{
|
|
gtxt = 1;
|
|
in_str += 5;
|
|
}
|
|
// non-quoted string
|
|
if (*in_str == '"')
|
|
term = '"';
|
|
else if (*in_str == '\'')
|
|
term = '\'';
|
|
else
|
|
return strtok_r (in_str, NTXT (" "), endptr);
|
|
|
|
StringBuilder sb;
|
|
while ((c = *(++in_str)) != '\0')
|
|
{
|
|
if (c == term) // the closing quote
|
|
break;
|
|
if (c == '\\')
|
|
{ // handle any escaped characters
|
|
c2 = *(++in_str);
|
|
switch (c2)
|
|
{
|
|
case '\"':
|
|
sb.append ('\"');
|
|
break;
|
|
case '\'':
|
|
sb.append ('\'');
|
|
break;
|
|
case '\\':
|
|
sb.append ('\\');
|
|
break;
|
|
case 't':
|
|
sb.append ('\t');
|
|
break;
|
|
case 'r':
|
|
sb.append ('\r');
|
|
break;
|
|
case 'b':
|
|
sb.append ('\b');
|
|
break;
|
|
case 'f':
|
|
sb.append ('\f');
|
|
break;
|
|
case 'n':
|
|
sb.append ('\n');
|
|
break;
|
|
default:
|
|
if ((c2 >= '0') && (c2 <= '9'))
|
|
{
|
|
for (i = 0; i < MAXPATHLEN; i++)
|
|
{
|
|
if (((c2 < '0') || (c2 > '9')) && (c2 != 'x') &&
|
|
((c2 < 'a') || (c2 > 'f')) &&
|
|
((c2 < 'A') || (c2 > 'F')))
|
|
{
|
|
csnum[i] = '\0';
|
|
--in_str;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
csnum[i] = c2;
|
|
c2 = *(++in_str);
|
|
}
|
|
}
|
|
sb.append ((char) strtoul (csnum, endptr, 0));
|
|
}
|
|
else
|
|
sb.append (c2);
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
sb.append (c);
|
|
}
|
|
if (c == term && gtxt && *in_str == ')')
|
|
in_str++;
|
|
if (*in_str == '\0')
|
|
*endptr = in_str;
|
|
else
|
|
*endptr = in_str + 1;
|
|
return sb.toString ();
|
|
}
|
|
|
|
// parse a file name of the form name`name2`
|
|
// returns name
|
|
// stores the pointer to named in fcontext
|
|
// returns NULL if the string is not properly formatted
|
|
char *
|
|
parse_fname (char *in_str, char **fcontext)
|
|
{
|
|
*fcontext = NULL;
|
|
int ch = '`';
|
|
if (in_str == NULL)
|
|
return NULL;
|
|
char *copy = strdup (in_str);
|
|
char *p = strchr (copy, ch);
|
|
if (p != NULL)
|
|
{
|
|
// yes, there's an embedded file name
|
|
*p = '\0';
|
|
p++;
|
|
// now find the terminating single quote
|
|
char *p1 = strchr (p, ch);
|
|
if (p1 == NULL)
|
|
{
|
|
// if we don't have the closing `, the format is incorrect
|
|
free (copy);
|
|
return NULL;
|
|
}
|
|
//remove the closing quote
|
|
*p1 = '\0';
|
|
// see if there's anything following it
|
|
if (*(p1 + 1) != 0)
|
|
{
|
|
// error in format
|
|
free (copy);
|
|
return NULL;
|
|
}
|
|
free (*fcontext);
|
|
*fcontext = strdup (p);
|
|
}
|
|
return copy;
|
|
}
|
|
|
|
int
|
|
get_paren (const char *name)
|
|
{
|
|
char buf[8192];
|
|
char *ptr;
|
|
int temp_level1, temp_level2;
|
|
|
|
temp_level1 = temp_level2 = 0;
|
|
snprintf (buf, sizeof (buf), NTXT ("%s"), name);
|
|
while ((ptr = strrpbrk (buf, "><)(")) != NULL)
|
|
{
|
|
if (*ptr == '>')
|
|
temp_level1++;
|
|
else if (*ptr == '<')
|
|
temp_level1--;
|
|
else if (*ptr == ')')
|
|
temp_level2++;
|
|
else
|
|
{
|
|
temp_level2--;
|
|
if (temp_level1 <= 0 && temp_level2 <= 0)
|
|
return (int) (ptr - buf);
|
|
}
|
|
*ptr = '\0';
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
// CRC-64 based on x^64 + x^11 + x^2 + x + 1 polynomial.
|
|
// This algorithm doesn't perform well but is short and
|
|
// readable. We currently use it for a small amount of
|
|
// short strings. Should this change, another algorithm
|
|
// with better performance is to be used instead.
|
|
static uint64_t masks[256] = {
|
|
/* 0 */ 0x000000, 0x000807, 0x00100e, 0x001809, 0x00201c, 0x00281b,
|
|
/* 6 */ 0x003012, 0x003815, 0x004038, 0x00483f, 0x005036, 0x005831,
|
|
/* 12 */ 0x006024, 0x006823, 0x00702a, 0x00782d, 0x008070, 0x008877,
|
|
/* 18 */ 0x00907e, 0x009879, 0x00a06c, 0x00a86b, 0x00b062, 0x00b865,
|
|
/* 24 */ 0x00c048, 0x00c84f, 0x00d046, 0x00d841, 0x00e054, 0x00e853,
|
|
/* 30 */ 0x00f05a, 0x00f85d, 0x0100e0, 0x0108e7, 0x0110ee, 0x0118e9,
|
|
/* 36 */ 0x0120fc, 0x0128fb, 0x0130f2, 0x0138f5, 0x0140d8, 0x0148df,
|
|
/* 42 */ 0x0150d6, 0x0158d1, 0x0160c4, 0x0168c3, 0x0170ca, 0x0178cd,
|
|
/* 48 */ 0x018090, 0x018897, 0x01909e, 0x019899, 0x01a08c, 0x01a88b,
|
|
/* 54 */ 0x01b082, 0x01b885, 0x01c0a8, 0x01c8af, 0x01d0a6, 0x01d8a1,
|
|
/* 60 */ 0x01e0b4, 0x01e8b3, 0x01f0ba, 0x01f8bd, 0x0201c0, 0x0209c7,
|
|
/* 66 */ 0x0211ce, 0x0219c9, 0x0221dc, 0x0229db, 0x0231d2, 0x0239d5,
|
|
/* 72 */ 0x0241f8, 0x0249ff, 0x0251f6, 0x0259f1, 0x0261e4, 0x0269e3,
|
|
/* 78 */ 0x0271ea, 0x0279ed, 0x0281b0, 0x0289b7, 0x0291be, 0x0299b9,
|
|
/* 84 */ 0x02a1ac, 0x02a9ab, 0x02b1a2, 0x02b9a5, 0x02c188, 0x02c98f,
|
|
/* 90 */ 0x02d186, 0x02d981, 0x02e194, 0x02e993, 0x02f19a, 0x02f99d,
|
|
/* 96 */ 0x030120, 0x030927, 0x03112e, 0x031929, 0x03213c, 0x03293b,
|
|
/* 102 */ 0x033132, 0x033935, 0x034118, 0x03491f, 0x035116, 0x035911,
|
|
/* 108 */ 0x036104, 0x036903, 0x03710a, 0x03790d, 0x038150, 0x038957,
|
|
/* 114 */ 0x03915e, 0x039959, 0x03a14c, 0x03a94b, 0x03b142, 0x03b945,
|
|
/* 120 */ 0x03c168, 0x03c96f, 0x03d166, 0x03d961, 0x03e174, 0x03e973,
|
|
/* 126 */ 0x03f17a, 0x03f97d, 0x040380, 0x040b87, 0x04138e, 0x041b89,
|
|
/* 132 */ 0x04239c, 0x042b9b, 0x043392, 0x043b95, 0x0443b8, 0x044bbf,
|
|
/* 138 */ 0x0453b6, 0x045bb1, 0x0463a4, 0x046ba3, 0x0473aa, 0x047bad,
|
|
/* 144 */ 0x0483f0, 0x048bf7, 0x0493fe, 0x049bf9, 0x04a3ec, 0x04abeb,
|
|
/* 150 */ 0x04b3e2, 0x04bbe5, 0x04c3c8, 0x04cbcf, 0x04d3c6, 0x04dbc1,
|
|
/* 156 */ 0x04e3d4, 0x04ebd3, 0x04f3da, 0x04fbdd, 0x050360, 0x050b67,
|
|
/* 162 */ 0x05136e, 0x051b69, 0x05237c, 0x052b7b, 0x053372, 0x053b75,
|
|
/* 168 */ 0x054358, 0x054b5f, 0x055356, 0x055b51, 0x056344, 0x056b43,
|
|
/* 174 */ 0x05734a, 0x057b4d, 0x058310, 0x058b17, 0x05931e, 0x059b19,
|
|
/* 180 */ 0x05a30c, 0x05ab0b, 0x05b302, 0x05bb05, 0x05c328, 0x05cb2f,
|
|
/* 186 */ 0x05d326, 0x05db21, 0x05e334, 0x05eb33, 0x05f33a, 0x05fb3d,
|
|
/* 192 */ 0x060240, 0x060a47, 0x06124e, 0x061a49, 0x06225c, 0x062a5b,
|
|
/* 198 */ 0x063252, 0x063a55, 0x064278, 0x064a7f, 0x065276, 0x065a71,
|
|
/* 204 */ 0x066264, 0x066a63, 0x06726a, 0x067a6d, 0x068230, 0x068a37,
|
|
/* 210 */ 0x06923e, 0x069a39, 0x06a22c, 0x06aa2b, 0x06b222, 0x06ba25,
|
|
/* 216 */ 0x06c208, 0x06ca0f, 0x06d206, 0x06da01, 0x06e214, 0x06ea13,
|
|
/* 222 */ 0x06f21a, 0x06fa1d, 0x0702a0, 0x070aa7, 0x0712ae, 0x071aa9,
|
|
/* 228 */ 0x0722bc, 0x072abb, 0x0732b2, 0x073ab5, 0x074298, 0x074a9f,
|
|
/* 234 */ 0x075296, 0x075a91, 0x076284, 0x076a83, 0x07728a, 0x077a8d,
|
|
/* 240 */ 0x0782d0, 0x078ad7, 0x0792de, 0x079ad9, 0x07a2cc, 0x07aacb,
|
|
/* 246 */ 0x07b2c2, 0x07bac5, 0x07c2e8, 0x07caef, 0x07d2e6, 0x07dae1,
|
|
/* 252 */ 0x07e2f4, 0x07eaf3, 0x07f2fa, 0x07fafd
|
|
};
|
|
|
|
uint64_t
|
|
crc64 (const char *str, size_t len)
|
|
{
|
|
uint64_t res = 0LL;
|
|
for (size_t i = 0; i < len; i++)
|
|
{
|
|
unsigned char b = (unsigned char) ((res >> 56) ^ *str++);
|
|
res = res << 8;
|
|
res ^= masks [b];
|
|
}
|
|
return res;
|
|
}
|
|
|
|
/**
|
|
* Canonize path inside the string provided by the argument
|
|
* @param path
|
|
* @return path
|
|
*/
|
|
char *
|
|
canonical_path (char *path)
|
|
{
|
|
char *s1, *s2;
|
|
if (!path)
|
|
return path;
|
|
s1 = path;
|
|
s2 = path;
|
|
while (*s1)
|
|
{
|
|
if (*s1 == '.' && s1[1] == '/')
|
|
{ // remove .///
|
|
for (s1++; *s1; s1++)
|
|
if (*s1 != '/')
|
|
break;
|
|
}
|
|
else if (*s1 == '/')
|
|
{ // replace /// with /
|
|
*(s2++) = *s1;
|
|
for (s1++; *s1; s1++)
|
|
if (*s1 != '/')
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
while (*s1)
|
|
{ // copy file or directory name
|
|
if (*s1 == '/')
|
|
break;
|
|
*(s2++) = *(s1++);
|
|
}
|
|
}
|
|
}
|
|
*s2 = 0;
|
|
if (s2 != path && (s2 - 1) != path && s2[-1] == '/') // remove last /
|
|
*(s2 - 1) = 0;
|
|
return path;
|
|
}
|
|
|
|
char *
|
|
get_relative_path (char *name)
|
|
{
|
|
if (*name == '/' && theApplication)
|
|
{
|
|
char *cwd = theApplication->get_cur_dir ();
|
|
if (cwd)
|
|
{
|
|
size_t len = strlen (cwd);
|
|
if (len > 0 && len < strlen (name) && name[len] == '/'
|
|
&& strncmp (cwd, name, len) == 0)
|
|
{
|
|
for (name += len + 1; *name == '/'; name++)
|
|
;
|
|
return name;
|
|
}
|
|
}
|
|
}
|
|
return name;
|
|
}
|
|
|
|
/**
|
|
* Generate a relative link name from path_from to path_to
|
|
* Example:
|
|
* path_from=a/b/c/d
|
|
* path_to=a/b/e/f/g
|
|
* lname=../../e/f/g
|
|
* @param path_to
|
|
* @param path_from
|
|
* @return lname - relative link
|
|
*/
|
|
char *
|
|
get_relative_link (const char *path_from, const char *path_to)
|
|
{
|
|
if (!path_to)
|
|
path_to = ".";
|
|
if (!path_from)
|
|
path_from = ".";
|
|
char *s1 = dbe_strdup (path_to);
|
|
s1 = canonical_path (s1);
|
|
char *s2 = dbe_strdup (path_from);
|
|
s2 = canonical_path (s2);
|
|
long l = dbe_sstrlen (s1);
|
|
// try to find common directories
|
|
int common_slashes = 0;
|
|
int last_common_slash = -1;
|
|
for (int i = 0; i < l; i++)
|
|
{
|
|
if (s1[i] != s2[i]) break;
|
|
if (s1[i] == 0) break;
|
|
if (s1[i] == '/')
|
|
{
|
|
common_slashes++;
|
|
last_common_slash = i;
|
|
}
|
|
}
|
|
// find slashes in remaining path_to
|
|
int slashes = 0;
|
|
for (int i = last_common_slash + 1; i < l; i++)
|
|
{
|
|
if (s1[i] == '/')
|
|
{
|
|
// Exclude "/./" case
|
|
if (i > last_common_slash + 2)
|
|
{
|
|
if (s1[i - 1] == '.' && s1[i - 2] == '/')
|
|
continue;
|
|
}
|
|
else if (i > 0 && s1[i - 1] == '.')
|
|
continue;
|
|
slashes++;
|
|
}
|
|
}
|
|
// generate relative path
|
|
StringBuilder sb;
|
|
for (int i = 0; i < slashes; i++)
|
|
sb.append ("../");
|
|
sb.append (s2 + last_common_slash + 1);
|
|
char *lname = sb.toString ();
|
|
free (s1);
|
|
free (s2);
|
|
return lname;
|
|
}
|
|
|
|
char *
|
|
get_prog_name (int basename)
|
|
{
|
|
char *nm = NULL;
|
|
if (theApplication)
|
|
{
|
|
nm = theApplication->get_name ();
|
|
if (nm && basename)
|
|
nm = get_basename (nm);
|
|
}
|
|
return nm;
|
|
}
|
|
|
|
char *
|
|
dbe_strndup (const char *str, size_t len)
|
|
{
|
|
if (str == NULL)
|
|
return NULL;
|
|
char *s = (char *) malloc (len + 1);
|
|
strncpy (s, str, len);
|
|
s[len] = '\0';
|
|
return s;
|
|
}
|
|
|
|
char *
|
|
dbe_sprintf (const char *fmt, ...)
|
|
{
|
|
char buffer[256];
|
|
int buf_size;
|
|
va_list vp;
|
|
|
|
va_start (vp, fmt);
|
|
buf_size = vsnprintf (buffer, sizeof (buffer), fmt, vp) + 1;
|
|
va_end (vp);
|
|
if (buf_size < (int) sizeof (buffer))
|
|
{
|
|
if (buf_size <= 1)
|
|
buffer[0] = 0;
|
|
return strdup (buffer);
|
|
}
|
|
|
|
va_start (vp, fmt);
|
|
char *buf = (char *) malloc (buf_size);
|
|
vsnprintf (buf, buf_size, fmt, vp);
|
|
va_end (vp);
|
|
return buf;
|
|
}
|
|
|
|
ssize_t
|
|
dbe_write (int f, const char *fmt, ...)
|
|
{
|
|
char buffer[256];
|
|
int buf_size;
|
|
va_list vp;
|
|
|
|
va_start (vp, fmt);
|
|
buf_size = vsnprintf (buffer, sizeof (buffer), fmt, vp) + 1;
|
|
va_end (vp);
|
|
if (buf_size < (int) sizeof (buffer))
|
|
{
|
|
if (buf_size <= 1)
|
|
buffer[0] = 0;
|
|
return write (f, buffer, strlen (buffer));
|
|
}
|
|
|
|
va_start (vp, fmt);
|
|
char *buf = (char *) malloc (buf_size);
|
|
vsnprintf (buf, buf_size, fmt, vp);
|
|
va_end (vp);
|
|
ssize_t val = write (f, buf, strlen (buf));
|
|
free (buf);
|
|
return val;
|
|
}
|
|
|
|
/* Worker Threads to avoid hanging on file servers */
|
|
|
|
/*
|
|
* Thread states
|
|
*/
|
|
enum
|
|
{
|
|
THREAD_START,
|
|
THREAD_STARTED,
|
|
THREAD_CANCEL,
|
|
THREAD_CANCELED,
|
|
THREAD_CREATE,
|
|
THREAD_NOT_CREATED,
|
|
THREAD_FINISHED
|
|
};
|
|
|
|
/*
|
|
* Communication structure
|
|
*/
|
|
struct worker_thread_info
|
|
{
|
|
pthread_t thread_id; /* ID returned by pthread_create() */
|
|
int thread_num; /* Application-defined thread # */
|
|
volatile int control; /* Thread state */
|
|
volatile int result; /* Return status */
|
|
struct stat64 statbuf; /* File info from stat64() */
|
|
const char *path; /* File */
|
|
};
|
|
|
|
static pthread_mutex_t worker_thread_lock = PTHREAD_MUTEX_INITIALIZER;
|
|
static int worker_thread_number = 0;
|
|
/**
|
|
* Call stat64() on current worker thread
|
|
* Check if control is not THREAD_CANCEL
|
|
* If control is THREAD_CANCEL return (exit thread)
|
|
* @param *wt_info
|
|
*/
|
|
static void *
|
|
dbe_stat_on_thread (void *arg)
|
|
{
|
|
struct worker_thread_info *wt_info = (struct worker_thread_info *) arg;
|
|
pthread_mutex_lock (&worker_thread_lock);
|
|
{
|
|
if (wt_info->control != THREAD_START)
|
|
{
|
|
// Already too late
|
|
pthread_mutex_unlock (&worker_thread_lock);
|
|
return 0;
|
|
}
|
|
wt_info->control = THREAD_STARTED;
|
|
}
|
|
pthread_mutex_unlock (&worker_thread_lock);
|
|
const char * path = wt_info->path;
|
|
int st = stat64 (path, &(wt_info->statbuf));
|
|
pthread_mutex_lock (&worker_thread_lock);
|
|
{
|
|
if (wt_info->control == THREAD_CANCEL)
|
|
{
|
|
// Too late.
|
|
pthread_mutex_unlock (&worker_thread_lock);
|
|
free (wt_info);
|
|
return 0;
|
|
}
|
|
wt_info->result = st;
|
|
wt_info->control = THREAD_FINISHED;
|
|
}
|
|
pthread_mutex_unlock (&worker_thread_lock);
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* Create a worker thread to call specified function
|
|
* Wait for its result, but not longer than 5 seconds
|
|
* If the timeout happens, tell the thread to cancel
|
|
* @param path
|
|
* @param wt_info
|
|
* @return thread state
|
|
*/
|
|
static int
|
|
dbe_dispatch_on_thread (const char *path, struct worker_thread_info *wt_info)
|
|
{
|
|
wt_info->result = 0;
|
|
wt_info->control = THREAD_START;
|
|
pthread_attr_t attr;
|
|
/* Initialize thread creation attributes */
|
|
int res = pthread_attr_init (&attr);
|
|
if (res != 0)
|
|
{
|
|
wt_info->control = THREAD_NOT_CREATED;
|
|
return THREAD_NOT_CREATED;
|
|
}
|
|
wt_info->thread_id = 0;
|
|
wt_info->path = path;
|
|
// Lock
|
|
pthread_mutex_lock (&worker_thread_lock);
|
|
worker_thread_number++;
|
|
wt_info->thread_num = worker_thread_number;
|
|
// Unlock
|
|
pthread_mutex_unlock (&worker_thread_lock);
|
|
// Create thread
|
|
res = pthread_create (&wt_info->thread_id, &attr, &dbe_stat_on_thread, wt_info);
|
|
if (res != 0)
|
|
{
|
|
wt_info->control = THREAD_NOT_CREATED;
|
|
pthread_attr_destroy (&attr);
|
|
return THREAD_NOT_CREATED;
|
|
}
|
|
// Wait for the thread to finish
|
|
res = 0;
|
|
useconds_t maxusec = 5000000; // 5 seconds
|
|
useconds_t deltausec = 1000; // 1 millisecond
|
|
int max = maxusec / deltausec;
|
|
for (int i = 0; i < max; i++)
|
|
{
|
|
if (THREAD_FINISHED == wt_info->control)
|
|
break; // We are done
|
|
usleep (deltausec);
|
|
}
|
|
// Lock
|
|
pthread_mutex_lock (&worker_thread_lock);
|
|
if (THREAD_FINISHED != wt_info->control)
|
|
{
|
|
// Cancel thread
|
|
wt_info->control = THREAD_CANCEL; // Cannot use wt_info after that!
|
|
res = THREAD_CANCEL;
|
|
}
|
|
// Unlock
|
|
pthread_mutex_unlock (&worker_thread_lock);
|
|
// Destroy the thread attributes object, since it is no longer needed
|
|
pthread_attr_destroy (&attr);
|
|
// Report that thread was canceled
|
|
if (THREAD_CANCEL == res)
|
|
return res; /* Cannot free memory allocated by thread */
|
|
// Free all thread resources
|
|
void *resources = 0;
|
|
res = pthread_join (wt_info->thread_id, &resources);
|
|
free (resources); /* Free memory allocated by thread */
|
|
return THREAD_FINISHED;
|
|
}
|
|
|
|
static pthread_mutex_t dirnames_lock = PTHREAD_MUTEX_INITIALIZER;
|
|
static Map<const char*, int> *dirnamesMap = NULL;
|
|
|
|
#define DIR_STATUS_EXISTS 0
|
|
#define DIR_STATUS_UNKNOWN 2
|
|
|
|
/**
|
|
* Check if this directory name is known
|
|
* Return:
|
|
* @param path
|
|
* 0 - known, exists
|
|
* 1 - known, does not exist
|
|
* 2 - not known
|
|
*/
|
|
static int
|
|
check_dirname (const char *path)
|
|
{
|
|
pthread_mutex_lock (&dirnames_lock);
|
|
if (NULL == dirnamesMap)
|
|
dirnamesMap = new StringMap<int>(128, 128);
|
|
pthread_mutex_unlock (&dirnames_lock);
|
|
int res = DIR_STATUS_UNKNOWN;
|
|
if (path && *path)
|
|
{
|
|
char *fn = dbe_strdup (path);
|
|
char *dn = dirname (fn);
|
|
if (dn && *dn)
|
|
res = dirnamesMap->get (dn);
|
|
free (fn);
|
|
}
|
|
return res;
|
|
}
|
|
|
|
/**
|
|
* Save directory name and its status
|
|
* @param path
|
|
* @param status
|
|
* @return
|
|
*/
|
|
static void
|
|
extract_and_save_dirname (const char *path, int status)
|
|
{
|
|
pthread_mutex_lock (&dirnames_lock);
|
|
if (NULL == dirnamesMap)
|
|
dirnamesMap = new StringMap<int>(128, 128);
|
|
pthread_mutex_unlock (&dirnames_lock);
|
|
char *fn = dbe_strdup (path);
|
|
if (fn && *fn != 0)
|
|
{
|
|
char *dn = dirname (fn);
|
|
if (dn && (*dn != 0))
|
|
{
|
|
int st = 0; // exists
|
|
if (0 != status)
|
|
st = 1; // does not exist
|
|
dirnamesMap->put (dn, st);
|
|
}
|
|
}
|
|
free (fn);
|
|
}
|
|
|
|
// get status for specified file
|
|
static int
|
|
dbe_stat_internal (const char *path, struct stat64 *sbuf, bool file_only)
|
|
{
|
|
struct stat64 statbuf;
|
|
int dir_status = check_dirname (path);
|
|
if (dir_status == DIR_STATUS_UNKNOWN)
|
|
{
|
|
// Try to use a worker thread
|
|
if (theApplication->get_number_of_worker_threads () > 0)
|
|
{
|
|
struct worker_thread_info *wt_info;
|
|
wt_info = (worker_thread_info *) calloc (1, sizeof (worker_thread_info));
|
|
if (wt_info != NULL)
|
|
{
|
|
int res = dbe_dispatch_on_thread (path, wt_info);
|
|
if (THREAD_FINISHED == res)
|
|
{
|
|
int st = wt_info->result;
|
|
extract_and_save_dirname (path, st);
|
|
if (st == 0 && file_only)
|
|
if (S_ISREG ((wt_info->statbuf).st_mode) == 0)
|
|
st = -1; // It is not a regular file
|
|
if (sbuf != NULL)
|
|
*sbuf = wt_info->statbuf;
|
|
free (wt_info);
|
|
return st;
|
|
}
|
|
else
|
|
{
|
|
if (THREAD_CANCEL == res)
|
|
{
|
|
// Worker thread hung. Cannot free wt_info.
|
|
// Allocated memory will be freed by worker thread.
|
|
// save directory
|
|
extract_and_save_dirname (path, 1);
|
|
return 1; // stat64 failed
|
|
}
|
|
else // THREAD_NOT_CREATED - continue on current thread
|
|
free (wt_info);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if (dir_status != DIR_STATUS_EXISTS)
|
|
return -1; // does not exist
|
|
if (sbuf == NULL)
|
|
sbuf = &statbuf;
|
|
int st = stat64 (path, sbuf);
|
|
Dprintf (DEBUG_DBE_FILE, NTXT ("dbe_stat %d '%s'\n"), st, path);
|
|
if (st == -1)
|
|
return -1;
|
|
else if (file_only && S_ISREG (sbuf->st_mode) == 0)
|
|
return -1; // It is not ordinary file
|
|
return st;
|
|
}
|
|
|
|
// get status for the regular file
|
|
|
|
int
|
|
dbe_stat_file (const char *path, struct stat64 *sbuf)
|
|
{
|
|
int res = dbe_stat_internal (path, sbuf, true);
|
|
return res;
|
|
}
|
|
|
|
// get status for specified file
|
|
|
|
int
|
|
dbe_stat (const char *path, struct stat64 *sbuf)
|
|
{
|
|
int res = dbe_stat_internal (path, sbuf, false);
|
|
return res;
|
|
}
|
|
|
|
/**
|
|
* Reads directory and prepares list of files according to the specified format
|
|
* Supported formats:
|
|
* "/bin/ls -a" - see 'man ls' for details
|
|
* "/bin/ls -aF" - see 'man ls' for details
|
|
* @param path
|
|
* @param format
|
|
* @return char * files
|
|
*/
|
|
char *
|
|
dbe_read_dir (const char *path, const char *format)
|
|
{
|
|
StringBuilder sb;
|
|
DIR *dir = opendir (path);
|
|
if (dir == NULL)
|
|
return sb.toString ();
|
|
int format_aF = 0;
|
|
if (!strcmp (format, NTXT ("/bin/ls -aF")))
|
|
format_aF = 1;
|
|
struct dirent *entry = NULL;
|
|
if (format != NULL)
|
|
{
|
|
while ((entry = readdir (dir)) != NULL)
|
|
{
|
|
sb.append (entry->d_name);
|
|
if (format_aF)
|
|
{
|
|
const char *attr = NTXT ("@"); // Link
|
|
struct stat64 sbuf;
|
|
sbuf.st_mode = 0;
|
|
char filename[MAXPATHLEN + 1];
|
|
snprintf (filename, sizeof (filename), NTXT ("%s/%s"), path, entry->d_name);
|
|
dbe_stat (filename, &sbuf);
|
|
if (S_IREAD & sbuf.st_mode)
|
|
{ // Readable
|
|
if (S_ISDIR (sbuf.st_mode) != 0) // Directory
|
|
attr = NTXT ("/");
|
|
else if (S_ISREG (sbuf.st_mode) != 0) // Regular file
|
|
attr = NTXT ("");
|
|
}
|
|
sb.append (attr);
|
|
}
|
|
sb.append (NTXT ("\n"));
|
|
}
|
|
}
|
|
closedir (dir);
|
|
return sb.toString ();
|
|
}
|
|
|
|
/**
|
|
* Gets list of processes according to the specified format
|
|
* Supported formats:
|
|
* "/bin/ps -ef" - see 'man ps' for details
|
|
* @param format
|
|
* @return char * processes
|
|
*/
|
|
char *
|
|
dbe_get_processes (const char *format)
|
|
{
|
|
StringBuilder sb;
|
|
if (!strcmp (format, NTXT ("/bin/ps -ef")))
|
|
{
|
|
char buf[BUFSIZ];
|
|
FILE *ptr = popen (format, "r");
|
|
if (ptr != NULL)
|
|
{
|
|
while (fgets (buf, BUFSIZ, ptr) != NULL)
|
|
sb.append (buf);
|
|
pclose (ptr);
|
|
}
|
|
}
|
|
return sb.toString ();
|
|
}
|
|
|
|
/**
|
|
* Creates the directory named by the specified path name, including any
|
|
* necessary but nonexistent parent directories.
|
|
* Uses system utility "/bin/mkdir -p"
|
|
* Temporary limitation: path name should not contain spaces.
|
|
* Returns message from "/bin/mkdir -p"
|
|
* @param pathname
|
|
* @return result
|
|
*/
|
|
char *
|
|
dbe_create_directories (const char *pathname)
|
|
{
|
|
StringBuilder sb;
|
|
char *makedir = dbe_sprintf (NTXT ("/bin/mkdir -p %s 2>&1"), pathname);
|
|
char out[BUFSIZ];
|
|
FILE *ptr = popen (makedir, "r");
|
|
if (ptr != NULL)
|
|
{
|
|
while (fgets (out, BUFSIZ, ptr) != NULL)
|
|
sb.append (out);
|
|
pclose (ptr);
|
|
}
|
|
free (makedir);
|
|
DIR *dir = opendir (pathname);
|
|
if (dir != NULL)
|
|
{
|
|
closedir (dir);
|
|
return NULL; // success
|
|
}
|
|
else
|
|
sb.append (NTXT ("\nError: Cannot open directory\n")); // DEBUG
|
|
return sb.toString (); // error
|
|
}
|
|
|
|
/**
|
|
* Deletes the file or the directory named by the specified path name.
|
|
* If this pathname denotes a directory, then the directory must be empty in order to be deleted.
|
|
* Uses system utility "/bin/rm" or "/bin/rmdir"
|
|
* Temporary limitation: path name should not contain spaces.
|
|
* Returns error message from system utility
|
|
* @param pathname
|
|
* @return result
|
|
*/
|
|
char *
|
|
dbe_delete_file (const char *pathname)
|
|
{
|
|
StringBuilder sb;
|
|
char *cmd = NULL;
|
|
struct stat64 sbuf;
|
|
sbuf.st_mode = 0;
|
|
int st = dbe_stat (pathname, &sbuf);
|
|
if (st == 0)
|
|
{ // Exists
|
|
if (S_ISDIR (sbuf.st_mode) != 0) // Directory
|
|
cmd = dbe_sprintf (NTXT ("/bin/rmdir %s 2>&1"), pathname);
|
|
else if (S_ISREG (sbuf.st_mode) != 0) // Regular file
|
|
cmd = dbe_sprintf (NTXT ("/bin/rm %s 2>&1"), pathname);
|
|
}
|
|
else
|
|
return NULL; // Nothing to remove
|
|
if (cmd != NULL)
|
|
{
|
|
char out[BUFSIZ];
|
|
FILE *ptr = popen (cmd, "r");
|
|
if (ptr != NULL)
|
|
{
|
|
while (fgets (out, BUFSIZ, ptr) != NULL)
|
|
sb.append (out);
|
|
pclose (ptr);
|
|
}
|
|
free (cmd);
|
|
}
|
|
else
|
|
sb.sprintf (NTXT ("Error: cannot remove %s - not a regular file and not a directory\n"), pathname);
|
|
return sb.toString ();
|
|
}
|
|
|
|
char *
|
|
dbe_xml2str (const char *s)
|
|
{
|
|
if (s == NULL)
|
|
return NULL;
|
|
StringBuilder sb;
|
|
while (*s)
|
|
{
|
|
if (*s == '&')
|
|
{
|
|
if (strncmp (s, NTXT (" "), 6) == 0)
|
|
{
|
|
sb.append (' ');
|
|
s += 6;
|
|
continue;
|
|
}
|
|
else if (strncmp (s, NTXT ("""), 6) == 0)
|
|
{
|
|
sb.append ('"');
|
|
s += 6;
|
|
continue;
|
|
}
|
|
else if (strncmp (s, NTXT ("&"), 5) == 0)
|
|
{
|
|
sb.append ('&');
|
|
s += 5;
|
|
continue;
|
|
}
|
|
else if (strncmp (s, NTXT ("<"), 4) == 0)
|
|
{
|
|
sb.append ('<');
|
|
s += 4;
|
|
continue;
|
|
}
|
|
else if (strncmp (s, NTXT (">"), 4) == 0)
|
|
{
|
|
sb.append ('>');
|
|
s += 4;
|
|
continue;
|
|
}
|
|
}
|
|
sb.append (*s);
|
|
s++;
|
|
}
|
|
return sb.toString ();
|
|
}
|
|
|
|
void
|
|
swapByteOrder (void *p, size_t sz)
|
|
{
|
|
if (sz == 8)
|
|
{
|
|
uint64_t *pv = (uint64_t *) p;
|
|
uint64_t v = *pv;
|
|
v = ((v & 0x00000000FF000000) << 8) | ((v >> 8) & 0x00000000FF000000) |
|
|
((v & 0x0000000000FF0000) << 24) | ((v >> 24) & 0x0000000000FF0000) |
|
|
((v & 0x000000000000FF00) << 40) | ((v >> 40) & 0x000000000000FF00) |
|
|
(v >> 56) | (v << 56);
|
|
*pv = v;
|
|
}
|
|
else if (sz == 4)
|
|
{
|
|
uint32_t *pv = (uint32_t *) p;
|
|
uint32_t v = *pv;
|
|
v = (v >> 24) | (v << 24) | ((v & 0x0000FF00) << 8) | ((v >> 8) & 0x0000FF00);
|
|
*pv = v;
|
|
}
|
|
else if (sz == 2)
|
|
{
|
|
uint16_t *pv = (uint16_t *) p;
|
|
uint16_t v = *pv;
|
|
v = (v >> 8) | (v << 8);
|
|
*pv = v;
|
|
}
|
|
}
|
|
|
|
void
|
|
destroy (void *vec)
|
|
{
|
|
if (vec == NULL)
|
|
return;
|
|
Vector<void*> *array = (Vector<void*>*)vec;
|
|
switch (array->type ())
|
|
{
|
|
case VEC_STRING:
|
|
((Vector<char *>*)array)->destroy ();
|
|
break;
|
|
case VEC_VOIDARR:
|
|
case VEC_STRINGARR:
|
|
case VEC_INTARR:
|
|
case VEC_BOOLARR:
|
|
case VEC_LLONGARR:
|
|
case VEC_DOUBLEARR:
|
|
for (long i = 0; i < array->size (); i++)
|
|
destroy (array->fetch (i));
|
|
break;
|
|
case VEC_INTEGER:
|
|
case VEC_CHAR:
|
|
case VEC_BOOL:
|
|
case VEC_DOUBLE:
|
|
case VEC_LLONG:
|
|
default:
|
|
break;
|
|
}
|
|
delete array;
|
|
}
|
|
|
|
int64_t
|
|
read_from_file (int fd, void *buffer, int64_t nbyte)
|
|
{
|
|
int64_t cnt = 0;
|
|
char *buf = (char *) buffer;
|
|
while (nbyte > 0)
|
|
{ // Sometimes system cannot read 'nbyte'
|
|
ssize_t n = read (fd, (void *) (buf + cnt), (size_t) nbyte);
|
|
if (n <= 0)
|
|
break;
|
|
nbyte -= n;
|
|
cnt += n;
|
|
}
|
|
return cnt;
|
|
}
|
|
|
|
/**
|
|
* Create symbolic link to the path
|
|
* @param path - path with spaces
|
|
* @param dir - directory where the link should be created
|
|
* @return symbolic link
|
|
*/
|
|
char *
|
|
dbe_create_symlink_to_path (const char *path, const char *dir)
|
|
{
|
|
char *symbolic_link = NULL;
|
|
if (NULL == path || NULL == dir)
|
|
return NULL;
|
|
int res = mkdir (dir, 0777);
|
|
if (res != 0 && dbe_stat (dir, NULL) != 0)
|
|
return NULL; // Cannot create directory
|
|
long len = dbe_sstrlen (path);
|
|
if (len <= 4)
|
|
return NULL; // Unknown situation
|
|
if (strcmp ((path + len - 4), "/bin") != 0) // Unknown situation
|
|
return NULL;
|
|
int max = 99; // Just an arbitrary number
|
|
for (int i = 1; i <= max; i++)
|
|
{
|
|
// Try to create symbolic link
|
|
char *d = dbe_sprintf ("%s/%d", dir, i);
|
|
if (NULL == d)
|
|
return NULL;
|
|
res = mkdir (d, 0777);
|
|
symbolic_link = dbe_sprintf ("%s/%s", d, "bin");
|
|
free (d);
|
|
if (NULL == symbolic_link) // Not enough memory
|
|
return NULL;
|
|
res = symlink (path, symbolic_link);
|
|
if (res == 0) // Link is created - use it.
|
|
break;
|
|
// Check if such link already exists
|
|
int e = errno;
|
|
char buf[MAXPATHLEN + 1];
|
|
memset (buf, 0, MAXPATHLEN + 1);
|
|
ssize_t n = readlink (symbolic_link, buf, MAXPATHLEN);
|
|
if (n == len && strcmp (path, buf) == 0) // Link is correct - use it.
|
|
break;
|
|
if (i == max)
|
|
{ // report the error
|
|
fprintf (stderr, GTXT ("Error: symlink(%s, %s) returned error: %d\n"), path, symbolic_link, res);
|
|
fprintf (stderr, GTXT ("Error: errno=%d (%s)\n"), e, strerror (e));
|
|
fflush (stderr);
|
|
}
|
|
free (symbolic_link);
|
|
symbolic_link = NULL;
|
|
}
|
|
return symbolic_link;
|
|
}
|
|
|
|
// Compute checksum for specified file.
|
|
// This code is from usr/src/cmd/cksum.c, adapted for us
|
|
// crcposix -- compute posix.2 compatable 32 bit CRC
|
|
//
|
|
// The POSIX.2 (draft 10) CRC algorithm.
|
|
// This is a 32 bit CRC with polynomial
|
|
// x**32 + x**26 + x**23 + x**22 + x**16 + x**12 + x**11 + x**10 +
|
|
// x**8 + x**7 + x**5 + x**4 + x**2 + x**1 + x**0
|
|
//
|
|
// layout is from the POSIX.2 Rationale
|
|
|
|
static uint32_t crctab_posix[256] = {
|
|
0x00000000L,
|
|
0x04C11DB7L, 0x09823B6EL, 0x0D4326D9L, 0x130476DCL, 0x17C56B6BL,
|
|
0x1A864DB2L, 0x1E475005L, 0x2608EDB8L, 0x22C9F00FL, 0x2F8AD6D6L,
|
|
0x2B4BCB61L, 0x350C9B64L, 0x31CD86D3L, 0x3C8EA00AL, 0x384FBDBDL,
|
|
0x4C11DB70L, 0x48D0C6C7L, 0x4593E01EL, 0x4152FDA9L, 0x5F15ADACL,
|
|
0x5BD4B01BL, 0x569796C2L, 0x52568B75L, 0x6A1936C8L, 0x6ED82B7FL,
|
|
0x639B0DA6L, 0x675A1011L, 0x791D4014L, 0x7DDC5DA3L, 0x709F7B7AL,
|
|
0x745E66CDL, 0x9823B6E0L, 0x9CE2AB57L, 0x91A18D8EL, 0x95609039L,
|
|
0x8B27C03CL, 0x8FE6DD8BL, 0x82A5FB52L, 0x8664E6E5L, 0xBE2B5B58L,
|
|
0xBAEA46EFL, 0xB7A96036L, 0xB3687D81L, 0xAD2F2D84L, 0xA9EE3033L,
|
|
0xA4AD16EAL, 0xA06C0B5DL, 0xD4326D90L, 0xD0F37027L, 0xDDB056FEL,
|
|
0xD9714B49L, 0xC7361B4CL, 0xC3F706FBL, 0xCEB42022L, 0xCA753D95L,
|
|
0xF23A8028L, 0xF6FB9D9FL, 0xFBB8BB46L, 0xFF79A6F1L, 0xE13EF6F4L,
|
|
0xE5FFEB43L, 0xE8BCCD9AL, 0xEC7DD02DL, 0x34867077L, 0x30476DC0L,
|
|
0x3D044B19L, 0x39C556AEL, 0x278206ABL, 0x23431B1CL, 0x2E003DC5L,
|
|
0x2AC12072L, 0x128E9DCFL, 0x164F8078L, 0x1B0CA6A1L, 0x1FCDBB16L,
|
|
0x018AEB13L, 0x054BF6A4L, 0x0808D07DL, 0x0CC9CDCAL, 0x7897AB07L,
|
|
0x7C56B6B0L, 0x71159069L, 0x75D48DDEL, 0x6B93DDDBL, 0x6F52C06CL,
|
|
0x6211E6B5L, 0x66D0FB02L, 0x5E9F46BFL, 0x5A5E5B08L, 0x571D7DD1L,
|
|
0x53DC6066L, 0x4D9B3063L, 0x495A2DD4L, 0x44190B0DL, 0x40D816BAL,
|
|
0xACA5C697L, 0xA864DB20L, 0xA527FDF9L, 0xA1E6E04EL, 0xBFA1B04BL,
|
|
0xBB60ADFCL, 0xB6238B25L, 0xB2E29692L, 0x8AAD2B2FL, 0x8E6C3698L,
|
|
0x832F1041L, 0x87EE0DF6L, 0x99A95DF3L, 0x9D684044L, 0x902B669DL,
|
|
0x94EA7B2AL, 0xE0B41DE7L, 0xE4750050L, 0xE9362689L, 0xEDF73B3EL,
|
|
0xF3B06B3BL, 0xF771768CL, 0xFA325055L, 0xFEF34DE2L, 0xC6BCF05FL,
|
|
0xC27DEDE8L, 0xCF3ECB31L, 0xCBFFD686L, 0xD5B88683L, 0xD1799B34L,
|
|
0xDC3ABDEDL, 0xD8FBA05AL, 0x690CE0EEL, 0x6DCDFD59L, 0x608EDB80L,
|
|
0x644FC637L, 0x7A089632L, 0x7EC98B85L, 0x738AAD5CL, 0x774BB0EBL,
|
|
0x4F040D56L, 0x4BC510E1L, 0x46863638L, 0x42472B8FL, 0x5C007B8AL,
|
|
0x58C1663DL, 0x558240E4L, 0x51435D53L, 0x251D3B9EL, 0x21DC2629L,
|
|
0x2C9F00F0L, 0x285E1D47L, 0x36194D42L, 0x32D850F5L, 0x3F9B762CL,
|
|
0x3B5A6B9BL, 0x0315D626L, 0x07D4CB91L, 0x0A97ED48L, 0x0E56F0FFL,
|
|
0x1011A0FAL, 0x14D0BD4DL, 0x19939B94L, 0x1D528623L, 0xF12F560EL,
|
|
0xF5EE4BB9L, 0xF8AD6D60L, 0xFC6C70D7L, 0xE22B20D2L, 0xE6EA3D65L,
|
|
0xEBA91BBCL, 0xEF68060BL, 0xD727BBB6L, 0xD3E6A601L, 0xDEA580D8L,
|
|
0xDA649D6FL, 0xC423CD6AL, 0xC0E2D0DDL, 0xCDA1F604L, 0xC960EBB3L,
|
|
0xBD3E8D7EL, 0xB9FF90C9L, 0xB4BCB610L, 0xB07DABA7L, 0xAE3AFBA2L,
|
|
0xAAFBE615L, 0xA7B8C0CCL, 0xA379DD7BL, 0x9B3660C6L, 0x9FF77D71L,
|
|
0x92B45BA8L, 0x9675461FL, 0x8832161AL, 0x8CF30BADL, 0x81B02D74L,
|
|
0x857130C3L, 0x5D8A9099L, 0x594B8D2EL, 0x5408ABF7L, 0x50C9B640L,
|
|
0x4E8EE645L, 0x4A4FFBF2L, 0x470CDD2BL, 0x43CDC09CL, 0x7B827D21L,
|
|
0x7F436096L, 0x7200464FL, 0x76C15BF8L, 0x68860BFDL, 0x6C47164AL,
|
|
0x61043093L, 0x65C52D24L, 0x119B4BE9L, 0x155A565EL, 0x18197087L,
|
|
0x1CD86D30L, 0x029F3D35L, 0x065E2082L, 0x0B1D065BL, 0x0FDC1BECL,
|
|
0x3793A651L, 0x3352BBE6L, 0x3E119D3FL, 0x3AD08088L, 0x2497D08DL,
|
|
0x2056CD3AL, 0x2D15EBE3L, 0x29D4F654L, 0xC5A92679L, 0xC1683BCEL,
|
|
0xCC2B1D17L, 0xC8EA00A0L, 0xD6AD50A5L, 0xD26C4D12L, 0xDF2F6BCBL,
|
|
0xDBEE767CL, 0xE3A1CBC1L, 0xE760D676L, 0xEA23F0AFL, 0xEEE2ED18L,
|
|
0xF0A5BD1DL, 0xF464A0AAL, 0xF9278673L, 0xFDE69BC4L, 0x89B8FD09L,
|
|
0x8D79E0BEL, 0x803AC667L, 0x84FBDBD0L, 0x9ABC8BD5L, 0x9E7D9662L,
|
|
0x933EB0BBL, 0x97FFAD0CL, 0xAFB010B1L, 0xAB710D06L, 0xA6322BDFL,
|
|
0xA2F33668L, 0xBCB4666DL, 0xB8757BDAL, 0xB5365D03L, 0xB1F740B4L
|
|
};
|
|
|
|
static void
|
|
m_crcposix (uint32_t *crcp, unsigned char *bp, uint32_t n)
|
|
{
|
|
while (n-- > 0)
|
|
*crcp = (*crcp << 8) ^ crctab_posix[(unsigned char) ((*crcp >> 24)^*bp++)];
|
|
}
|
|
|
|
// Do CRC-POSIX function by calling a library entry point that has a
|
|
// slightly different calling sequence.
|
|
static uint32_t
|
|
docrcposix (uint32_t crcval, unsigned char *bp, uint32_t n)
|
|
{
|
|
m_crcposix (&crcval, bp, n);
|
|
return (crcval);
|
|
}
|
|
|
|
// Sum algorithms require various kinds of post-processing.
|
|
// The 'S' and 'R' variables are from the POSIX.2 (Draft 8?) description
|
|
// of the "sum" utility.
|
|
static uint32_t
|
|
postprocess (uint32_t S, long long n)
|
|
{
|
|
// POSIX tacks on significant bytes of the length so that
|
|
// different length sequences of '\0' have different sums;
|
|
// then it complements sum.
|
|
unsigned char char_n[sizeof (n)];
|
|
uint32_t i;
|
|
for (i = 0; n != 0; n >>= 8, ++i)
|
|
char_n[i] = (unsigned char) (n & 0xFF);
|
|
return (~docrcposix (S, char_n, i));
|
|
}
|
|
|
|
uint32_t
|
|
get_cksum (const char * pathname, char ** errmsg)
|
|
{
|
|
int fd = open (pathname, O_RDONLY);
|
|
if (fd < 0)
|
|
{
|
|
if (errmsg)
|
|
*errmsg = dbe_sprintf (GTXT ("*** Warning: Error opening file for reading: %s"), pathname);
|
|
return 0; // error
|
|
}
|
|
uint32_t crcval = 0;
|
|
long long bytes = 0;
|
|
int64_t n;
|
|
unsigned char buf[4096];
|
|
while ((n = read_from_file (fd, (char *) buf, sizeof (buf))) > 0)
|
|
{
|
|
bytes += n;
|
|
crcval = docrcposix (crcval, buf, n);
|
|
}
|
|
close (fd);
|
|
crcval = postprocess (crcval, bytes);
|
|
return crcval;
|
|
}
|