2014-04-12 17:10:43 +02:00
|
|
|
|
/*
|
|
|
|
|
* common.c:
|
|
|
|
|
*
|
|
|
|
|
* See the README file for copyright information and how to reach the author.
|
|
|
|
|
*
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include <sys/stat.h>
|
2014-05-09 01:05:21 +02:00
|
|
|
|
#include <sys/time.h>
|
2014-04-12 17:10:43 +02:00
|
|
|
|
|
|
|
|
|
#ifdef USEUUID
|
|
|
|
|
# include <uuid/uuid.h>
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#include <stdarg.h>
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
#include <syslog.h>
|
|
|
|
|
#include <unistd.h>
|
|
|
|
|
#include <zlib.h>
|
2014-05-09 01:05:21 +02:00
|
|
|
|
#include <errno.h>
|
2014-04-12 17:10:43 +02:00
|
|
|
|
|
|
|
|
|
#ifdef USELIBARCHIVE
|
|
|
|
|
# include <archive.h>
|
|
|
|
|
# include <archive_entry.h>
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#include "common.h"
|
|
|
|
|
#include "config.h"
|
|
|
|
|
|
2014-05-09 16:53:56 +02:00
|
|
|
|
cMyMutex logMutex;
|
2014-04-12 17:10:43 +02:00
|
|
|
|
|
|
|
|
|
//***************************************************************************
|
|
|
|
|
// Debug
|
|
|
|
|
//***************************************************************************
|
|
|
|
|
|
2014-05-09 16:53:56 +02:00
|
|
|
|
const char* getLogPrefix()
|
|
|
|
|
{
|
|
|
|
|
return logPrefix;
|
|
|
|
|
}
|
|
|
|
|
|
2014-04-12 17:10:43 +02:00
|
|
|
|
void tell(int eloquence, const char* format, ...)
|
|
|
|
|
{
|
|
|
|
|
if (EPG2VDRConfig.loglevel < eloquence)
|
|
|
|
|
return ;
|
|
|
|
|
|
|
|
|
|
const int sizeBuffer = 100000;
|
|
|
|
|
char t[sizeBuffer+100]; *t = 0;
|
|
|
|
|
va_list ap;
|
|
|
|
|
|
2014-05-09 16:53:56 +02:00
|
|
|
|
logMutex.Lock();
|
2014-04-12 17:10:43 +02:00
|
|
|
|
|
|
|
|
|
va_start(ap, format);
|
|
|
|
|
|
2014-05-09 16:53:56 +02:00
|
|
|
|
if (getLogPrefix())
|
|
|
|
|
snprintf(t, sizeBuffer, "%s", getLogPrefix());
|
2014-04-12 17:10:43 +02:00
|
|
|
|
|
|
|
|
|
vsnprintf(t+strlen(t), sizeBuffer-strlen(t), format, ap);
|
|
|
|
|
|
|
|
|
|
if (EPG2VDRConfig.logstdout)
|
|
|
|
|
{
|
|
|
|
|
char buf[50+TB];
|
2014-05-09 01:05:21 +02:00
|
|
|
|
timeval tp;
|
|
|
|
|
|
|
|
|
|
gettimeofday(&tp, 0);
|
|
|
|
|
|
|
|
|
|
tm* tm = localtime(&tp.tv_sec);
|
|
|
|
|
|
|
|
|
|
sprintf(buf,"%2.2d:%2.2d:%2.2d,%3.3ld ",
|
|
|
|
|
tm->tm_hour, tm->tm_min, tm->tm_sec,
|
|
|
|
|
tp.tv_usec / 1000);
|
|
|
|
|
|
2014-05-09 16:53:56 +02:00
|
|
|
|
printf("%s %s\n", buf, t);
|
2014-04-12 17:10:43 +02:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
syslog(LOG_ERR, "%s", t);
|
|
|
|
|
|
2014-05-09 16:53:56 +02:00
|
|
|
|
logMutex.Unlock();
|
|
|
|
|
|
2014-04-12 17:10:43 +02:00
|
|
|
|
va_end(ap);
|
|
|
|
|
}
|
|
|
|
|
|
2014-05-09 01:05:21 +02:00
|
|
|
|
//***************************************************************************
|
|
|
|
|
// Save Realloc
|
|
|
|
|
//***************************************************************************
|
|
|
|
|
|
|
|
|
|
char* srealloc(void* ptr, size_t size)
|
|
|
|
|
{
|
|
|
|
|
void* n = realloc(ptr, size);
|
|
|
|
|
|
|
|
|
|
if (!n)
|
|
|
|
|
{
|
|
|
|
|
free(ptr);
|
|
|
|
|
ptr = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return (char*)n;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//***************************************************************************
|
|
|
|
|
// us now
|
|
|
|
|
//***************************************************************************
|
|
|
|
|
|
|
|
|
|
double usNow()
|
|
|
|
|
{
|
|
|
|
|
struct timeval tp;
|
|
|
|
|
|
|
|
|
|
gettimeofday(&tp, 0);
|
|
|
|
|
|
|
|
|
|
return tp.tv_sec * 1000000.0 + tp.tv_usec;
|
|
|
|
|
}
|
|
|
|
|
|
2014-04-12 17:10:43 +02:00
|
|
|
|
//***************************************************************************
|
|
|
|
|
// Host ID
|
|
|
|
|
//***************************************************************************
|
|
|
|
|
|
|
|
|
|
unsigned int getHostId()
|
|
|
|
|
{
|
|
|
|
|
static unsigned int id = gethostid() & 0xFFFFFFFF;
|
|
|
|
|
return id;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//***************************************************************************
|
|
|
|
|
// String Operations
|
|
|
|
|
//***************************************************************************
|
|
|
|
|
|
|
|
|
|
void toUpper(std::string& str)
|
|
|
|
|
{
|
|
|
|
|
const char* s = str.c_str();
|
|
|
|
|
int lenSrc = str.length();
|
|
|
|
|
|
|
|
|
|
char* dest = (char*)malloc(lenSrc+TB); *dest = 0;
|
|
|
|
|
char* d = dest;
|
|
|
|
|
|
|
|
|
|
int csSrc; // size of character
|
|
|
|
|
|
|
|
|
|
for (int ps = 0; ps < lenSrc; ps += csSrc)
|
|
|
|
|
{
|
|
|
|
|
csSrc = max(mblen(&s[ps], lenSrc-ps), 1);
|
|
|
|
|
|
|
|
|
|
if (csSrc == 1)
|
|
|
|
|
*d++ = toupper(s[ps]);
|
|
|
|
|
else if (csSrc == 2 && s[ps] == (char)0xc3 && s[ps+1] >= (char)0xa0)
|
|
|
|
|
{
|
|
|
|
|
*d++ = s[ps];
|
|
|
|
|
*d++ = s[ps+1] - 32;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
for (int i = 0; i < csSrc; i++)
|
|
|
|
|
*d++ = s[ps+i];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
*d = 0;
|
|
|
|
|
|
|
|
|
|
str = dest;
|
|
|
|
|
free(dest);
|
|
|
|
|
}
|
|
|
|
|
|
2014-05-09 01:05:21 +02:00
|
|
|
|
//***************************************************************************
|
|
|
|
|
// To Case (UTF-8 save)
|
|
|
|
|
//***************************************************************************
|
|
|
|
|
|
|
|
|
|
const char* toCase(Case cs, char* str)
|
|
|
|
|
{
|
|
|
|
|
char* s = str;
|
|
|
|
|
int lenSrc = strlen(str);
|
|
|
|
|
|
|
|
|
|
int csSrc; // size of character
|
|
|
|
|
|
|
|
|
|
for (int ps = 0; ps < lenSrc; ps += csSrc)
|
|
|
|
|
{
|
|
|
|
|
csSrc = max(mblen(&s[ps], lenSrc-ps), 1);
|
|
|
|
|
|
|
|
|
|
if (csSrc == 1)
|
|
|
|
|
s[ps] = cs == cUpper ? toupper(s[ps]) : tolower(s[ps]);
|
|
|
|
|
else if (csSrc == 2 && s[ps] == (char)0xc3 && s[ps+1] >= (char)0xa0)
|
|
|
|
|
{
|
|
|
|
|
s[ps] = s[ps];
|
|
|
|
|
s[ps+1] = cs == cUpper ? toupper(s[ps+1]) : tolower(s[ps+1]);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
for (int i = 0; i < csSrc; i++)
|
|
|
|
|
s[ps+i] = s[ps+i];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return str;
|
|
|
|
|
}
|
|
|
|
|
|
2014-04-12 17:10:43 +02:00
|
|
|
|
void removeChars(std::string& str, const char* ignore)
|
|
|
|
|
{
|
|
|
|
|
const char* s = str.c_str();
|
|
|
|
|
int lenSrc = str.length();
|
|
|
|
|
int lenIgn = strlen(ignore);
|
|
|
|
|
|
|
|
|
|
char* dest = (char*)malloc(lenSrc+TB); *dest = 0;
|
|
|
|
|
char* d = dest;
|
|
|
|
|
|
|
|
|
|
int csSrc; // size of character
|
|
|
|
|
int csIgn; //
|
|
|
|
|
|
|
|
|
|
for (int ps = 0; ps < lenSrc; ps += csSrc)
|
|
|
|
|
{
|
|
|
|
|
int skip = no;
|
|
|
|
|
|
|
|
|
|
csSrc = max(mblen(&s[ps], lenSrc-ps), 1);
|
|
|
|
|
|
|
|
|
|
for (int pi = 0; pi < lenIgn; pi += csIgn)
|
|
|
|
|
{
|
|
|
|
|
csIgn = max(mblen(&ignore[pi], lenIgn-pi), 1);
|
|
|
|
|
|
|
|
|
|
if (csSrc == csIgn && strncmp(&s[ps], &ignore[pi], csSrc) == 0)
|
|
|
|
|
{
|
|
|
|
|
skip = yes;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!skip)
|
|
|
|
|
{
|
|
|
|
|
for (int i = 0; i < csSrc; i++)
|
|
|
|
|
*d++ = s[ps+i];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
*d = 0;
|
|
|
|
|
|
|
|
|
|
str = dest;
|
|
|
|
|
free(dest);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void removeCharsExcept(std::string& str, const char* except)
|
|
|
|
|
{
|
|
|
|
|
const char* s = str.c_str();
|
|
|
|
|
int lenSrc = str.length();
|
|
|
|
|
int lenIgn = strlen(except);
|
|
|
|
|
|
|
|
|
|
char* dest = (char*)malloc(lenSrc+TB); *dest = 0;
|
|
|
|
|
char* d = dest;
|
|
|
|
|
|
|
|
|
|
int csSrc; // size of character
|
|
|
|
|
int csIgn; //
|
|
|
|
|
|
|
|
|
|
for (int ps = 0; ps < lenSrc; ps += csSrc)
|
|
|
|
|
{
|
|
|
|
|
int skip = yes;
|
|
|
|
|
|
|
|
|
|
csSrc = max(mblen(&s[ps], lenSrc-ps), 1);
|
|
|
|
|
|
|
|
|
|
for (int pi = 0; pi < lenIgn; pi += csIgn)
|
|
|
|
|
{
|
|
|
|
|
csIgn = max(mblen(&except[pi], lenIgn-pi), 1);
|
|
|
|
|
|
|
|
|
|
if (csSrc == csIgn && strncmp(&s[ps], &except[pi], csSrc) == 0)
|
|
|
|
|
{
|
|
|
|
|
skip = no;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!skip)
|
|
|
|
|
{
|
|
|
|
|
for (int i = 0; i < csSrc; i++)
|
|
|
|
|
*d++ = s[ps+i];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
*d = 0;
|
|
|
|
|
|
|
|
|
|
str = dest;
|
|
|
|
|
free(dest);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void removeWord(std::string& pattern, std::string word)
|
|
|
|
|
{
|
|
|
|
|
size_t pos;
|
|
|
|
|
|
|
|
|
|
if ((pos = pattern.find(word)) != std::string::npos)
|
|
|
|
|
pattern.swap(pattern.erase(pos, word.length()));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//***************************************************************************
|
|
|
|
|
// String Manipulation
|
|
|
|
|
//***************************************************************************
|
|
|
|
|
|
|
|
|
|
void prepareCompressed(std::string& pattern)
|
|
|
|
|
{
|
|
|
|
|
// const char* ignore = " (),.;:-_+*!#?=&%$<>§/'`´@~\"[]{}";
|
|
|
|
|
const char* notignore = "ABCDEFGHIJKLMNOPQRSTUVWXYZßÖÄÜöäü0123456789";
|
|
|
|
|
|
|
|
|
|
toUpper(pattern);
|
|
|
|
|
removeWord(pattern, " TEIL ");
|
|
|
|
|
removeWord(pattern, " FOLGE ");
|
|
|
|
|
removeCharsExcept(pattern, notignore);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//***************************************************************************
|
|
|
|
|
// Left Trim
|
|
|
|
|
//***************************************************************************
|
|
|
|
|
|
|
|
|
|
char* lTrim(char* buf)
|
|
|
|
|
{
|
|
|
|
|
if (buf)
|
|
|
|
|
{
|
|
|
|
|
char *tp = buf;
|
|
|
|
|
|
|
|
|
|
while (*tp && strchr("\n\r\t ",*tp))
|
|
|
|
|
tp++;
|
|
|
|
|
|
|
|
|
|
memmove(buf, tp, strlen(tp) +1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return buf;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//*************************************************************************
|
|
|
|
|
// Right Trim
|
|
|
|
|
//*************************************************************************
|
|
|
|
|
|
|
|
|
|
char* rTrim(char* buf)
|
|
|
|
|
{
|
|
|
|
|
if (buf)
|
|
|
|
|
{
|
|
|
|
|
char *tp = buf + strlen(buf);
|
|
|
|
|
|
|
|
|
|
while (tp >= buf && strchr("\n\r\t ",*tp))
|
|
|
|
|
tp--;
|
|
|
|
|
|
|
|
|
|
*(tp+1) = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return buf;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//*************************************************************************
|
|
|
|
|
// All Trim
|
|
|
|
|
//*************************************************************************
|
|
|
|
|
|
|
|
|
|
char* allTrim(char* buf)
|
|
|
|
|
{
|
|
|
|
|
return lTrim(rTrim(buf));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//***************************************************************************
|
|
|
|
|
// Number to String
|
|
|
|
|
//***************************************************************************
|
|
|
|
|
|
|
|
|
|
std::string num2Str(int num)
|
|
|
|
|
{
|
|
|
|
|
char txt[16];
|
|
|
|
|
|
|
|
|
|
snprintf(txt, sizeof(txt), "%d", num);
|
|
|
|
|
|
|
|
|
|
return std::string(txt);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//***************************************************************************
|
|
|
|
|
// Long to Pretty Time
|
|
|
|
|
//***************************************************************************
|
|
|
|
|
|
|
|
|
|
std::string l2pTime(time_t t)
|
|
|
|
|
{
|
|
|
|
|
char txt[30];
|
|
|
|
|
tm* tmp = localtime(&t);
|
|
|
|
|
|
|
|
|
|
strftime(txt, sizeof(txt), "%d.%m.%Y %T", tmp);
|
|
|
|
|
|
|
|
|
|
return std::string(txt);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//***************************************************************************
|
|
|
|
|
// MS to Duration
|
|
|
|
|
//***************************************************************************
|
|
|
|
|
|
|
|
|
|
std::string ms2Dur(uint64_t t)
|
|
|
|
|
{
|
|
|
|
|
char txt[30];
|
|
|
|
|
|
|
|
|
|
int s = t / 1000;
|
|
|
|
|
int ms = t % 1000;
|
|
|
|
|
|
|
|
|
|
snprintf(txt, sizeof(txt), "%d.%03d seconds", s, ms);
|
|
|
|
|
|
|
|
|
|
return std::string(txt);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//***************************************************************************
|
|
|
|
|
// Char to Char-String
|
|
|
|
|
//***************************************************************************
|
|
|
|
|
|
|
|
|
|
const char* c2s(char c, char* buf)
|
|
|
|
|
{
|
|
|
|
|
sprintf(buf, "%c", c);
|
|
|
|
|
|
|
|
|
|
return buf;
|
|
|
|
|
}
|
|
|
|
|
|
2014-05-09 01:05:21 +02:00
|
|
|
|
//***************************************************************************
|
|
|
|
|
// Store To File
|
|
|
|
|
//***************************************************************************
|
|
|
|
|
|
|
|
|
|
int storeToFile(const char* filename, const char* data, int size)
|
|
|
|
|
{
|
|
|
|
|
FILE* fout;
|
|
|
|
|
|
|
|
|
|
if ((fout = fopen(filename, "w+")))
|
|
|
|
|
{
|
|
|
|
|
fwrite(data, sizeof(char), size, fout);
|
|
|
|
|
fclose(fout);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
tell(0, "Error, can't store '%s' to filesystem '%s'", filename, strerror(errno));
|
|
|
|
|
return fail;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return success;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//***************************************************************************
|
|
|
|
|
// Load From File
|
|
|
|
|
//***************************************************************************
|
|
|
|
|
|
|
|
|
|
int loadFromFile(const char* infile, MemoryStruct* data)
|
|
|
|
|
{
|
|
|
|
|
FILE* fin;
|
|
|
|
|
struct stat sb;
|
|
|
|
|
|
|
|
|
|
data->clear();
|
|
|
|
|
|
|
|
|
|
if (!fileExists(infile))
|
|
|
|
|
{
|
|
|
|
|
tell(0, "File '%s' not found'", infile);
|
|
|
|
|
return fail;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (stat(infile, &sb) < 0)
|
|
|
|
|
{
|
|
|
|
|
tell(0, "Can't get info of '%s', error was '%s'", infile, strerror(errno));
|
|
|
|
|
return fail;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ((fin = fopen(infile, "r")))
|
|
|
|
|
{
|
|
|
|
|
const char* sfx = suffixOf(infile);
|
|
|
|
|
|
|
|
|
|
data->size = sb.st_size;
|
|
|
|
|
data->modTime = sb.st_mtime;
|
|
|
|
|
data->memory = (char*)malloc(data->size);
|
|
|
|
|
fread(data->memory, sizeof(char), data->size, fin);
|
|
|
|
|
fclose(fin);
|
|
|
|
|
sprintf(data->tag, "%ld", data->size);
|
|
|
|
|
|
|
|
|
|
if (strcmp(sfx, "gz") == 0)
|
|
|
|
|
sprintf(data->contentEncoding, "gzip");
|
|
|
|
|
|
|
|
|
|
if (strcmp(sfx, "js") == 0)
|
|
|
|
|
sprintf(data->contentType, "application/javascript");
|
|
|
|
|
|
|
|
|
|
else if (strcmp(sfx, "png") == 0 || strcmp(sfx, "jpg") == 0 || strcmp(sfx, "gif") == 0)
|
|
|
|
|
sprintf(data->contentType, "image/%s", sfx);
|
|
|
|
|
|
|
|
|
|
else if (strcmp(sfx, "ico") == 0)
|
|
|
|
|
strcpy(data->contentType, "image/x-icon");
|
|
|
|
|
|
|
|
|
|
else
|
|
|
|
|
sprintf(data->contentType, "text/%s", sfx);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
tell(0, "Error, can't open '%s' for reading, error was '%s'", infile, strerror(errno));
|
|
|
|
|
return fail;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return success;
|
|
|
|
|
}
|
|
|
|
|
|
2014-04-12 17:10:43 +02:00
|
|
|
|
//***************************************************************************
|
|
|
|
|
// TOOLS
|
|
|
|
|
//***************************************************************************
|
|
|
|
|
|
|
|
|
|
int isEmpty(const char* str)
|
|
|
|
|
{
|
|
|
|
|
return !str || !*str;
|
|
|
|
|
}
|
|
|
|
|
|
2014-05-09 01:05:21 +02:00
|
|
|
|
const char* notNull(const char* str)
|
|
|
|
|
{
|
|
|
|
|
if (!str)
|
|
|
|
|
return "<null>";
|
|
|
|
|
|
|
|
|
|
return str;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int isZero(const char* str)
|
|
|
|
|
{
|
|
|
|
|
const char* p = str;
|
|
|
|
|
|
|
|
|
|
while (p && *p)
|
|
|
|
|
{
|
|
|
|
|
if (*p != '0')
|
|
|
|
|
return no;
|
|
|
|
|
|
|
|
|
|
p++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return yes;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//***************************************************************************
|
|
|
|
|
//
|
|
|
|
|
//***************************************************************************
|
|
|
|
|
|
2014-04-12 17:10:43 +02:00
|
|
|
|
char* sstrcpy(char* dest, const char* src, int max)
|
|
|
|
|
{
|
|
|
|
|
if (!dest || !src)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
strncpy(dest, src, max);
|
|
|
|
|
dest[max-1] = 0;
|
|
|
|
|
|
|
|
|
|
return dest;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int isLink(const char* path)
|
|
|
|
|
{
|
|
|
|
|
struct stat sb;
|
|
|
|
|
|
|
|
|
|
if (lstat(path, &sb) == 0)
|
|
|
|
|
return S_ISLNK(sb.st_mode);
|
|
|
|
|
|
2014-05-09 01:05:21 +02:00
|
|
|
|
tell(0, "Error: Detecting state for '%s' failed, error was '%s'", path, strerror(errno));
|
2014-04-12 17:10:43 +02:00
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2014-05-09 01:05:21 +02:00
|
|
|
|
const char* suffixOf(const char* path)
|
|
|
|
|
{
|
|
|
|
|
const char* p;
|
|
|
|
|
|
|
|
|
|
if (path && (p = strrchr(path, '.')))
|
|
|
|
|
return p+1;
|
|
|
|
|
|
|
|
|
|
return "";
|
|
|
|
|
}
|
|
|
|
|
|
2014-04-12 17:10:43 +02:00
|
|
|
|
int fileSize(const char* path)
|
|
|
|
|
{
|
|
|
|
|
struct stat sb;
|
|
|
|
|
|
|
|
|
|
if (lstat(path, &sb) == 0)
|
|
|
|
|
return sb.st_size;
|
|
|
|
|
|
2014-05-09 01:05:21 +02:00
|
|
|
|
tell(0, "Error: Detecting state for '%s' failed, error was '%s'", path, strerror(errno));
|
2014-04-12 17:10:43 +02:00
|
|
|
|
|
2014-05-09 01:05:21 +02:00
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
time_t fileModTime(const char* path)
|
|
|
|
|
{
|
|
|
|
|
struct stat sb;
|
|
|
|
|
|
|
|
|
|
if (lstat(path, &sb) == 0)
|
|
|
|
|
return sb.st_mtime;
|
|
|
|
|
|
|
|
|
|
tell(0, "Error: Detecting state for '%s' failed, error was '%s'", path, strerror(errno));
|
|
|
|
|
|
|
|
|
|
return 0;
|
2014-04-12 17:10:43 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int fileExists(const char* path)
|
|
|
|
|
{
|
|
|
|
|
return access(path, F_OK) == 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int createLink(const char* link, const char* dest, int force)
|
|
|
|
|
{
|
|
|
|
|
if (!fileExists(link) || force)
|
|
|
|
|
{
|
|
|
|
|
// may be the link exists and point to a wrong or already deleted destination ...
|
|
|
|
|
// .. therefore we delete the link at first
|
|
|
|
|
|
|
|
|
|
unlink(link);
|
|
|
|
|
|
|
|
|
|
if (symlink(dest, link) != 0)
|
|
|
|
|
{
|
2014-05-09 01:05:21 +02:00
|
|
|
|
tell(0, "Failed to create symlink '%s', error was '%s'", link, strerror(errno));
|
2014-04-12 17:10:43 +02:00
|
|
|
|
return fail;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return success;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//***************************************************************************
|
|
|
|
|
// Remove File
|
|
|
|
|
//***************************************************************************
|
|
|
|
|
|
|
|
|
|
int removeFile(const char* filename)
|
|
|
|
|
{
|
|
|
|
|
int lnk = isLink(filename);
|
|
|
|
|
|
|
|
|
|
if (unlink(filename) != 0)
|
|
|
|
|
{
|
2014-05-09 01:05:21 +02:00
|
|
|
|
tell(0, "Can't remove file '%s', '%s'", filename, strerror(errno));
|
2014-04-12 17:10:43 +02:00
|
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
tell(3, "Removed %s '%s'", lnk ? "link" : "file", filename);
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//***************************************************************************
|
|
|
|
|
// Check Dir
|
|
|
|
|
//***************************************************************************
|
|
|
|
|
|
|
|
|
|
int chkDir(const char* path)
|
|
|
|
|
{
|
|
|
|
|
struct stat fs;
|
|
|
|
|
|
|
|
|
|
if (stat(path, &fs) != 0 || !S_ISDIR(fs.st_mode))
|
|
|
|
|
{
|
|
|
|
|
tell(0, "Creating directory '%s'", path);
|
|
|
|
|
|
|
|
|
|
if (mkdir(path, ACCESSPERMS) == -1)
|
|
|
|
|
{
|
2014-05-09 01:05:21 +02:00
|
|
|
|
tell(0, "Can't create directory '%s'", strerror(errno));
|
2014-04-12 17:10:43 +02:00
|
|
|
|
return fail;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return success;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#ifdef USELIBXML
|
|
|
|
|
|
|
|
|
|
//***************************************************************************
|
|
|
|
|
// Load XSLT
|
|
|
|
|
//***************************************************************************
|
|
|
|
|
|
|
|
|
|
xsltStylesheetPtr loadXSLT(const char* name, const char* path, int utf8)
|
|
|
|
|
{
|
|
|
|
|
xsltStylesheetPtr stylesheet;
|
|
|
|
|
char* xsltfile;
|
|
|
|
|
|
|
|
|
|
asprintf(&xsltfile, "%s/%s-%s.xsl", path, name, utf8 ? "utf-8" : "iso-8859-1");
|
|
|
|
|
|
|
|
|
|
if ((stylesheet = xsltParseStylesheetFile((const xmlChar*)xsltfile)) == 0)
|
|
|
|
|
tell(0, "Error: Can't load xsltfile %s", xsltfile);
|
|
|
|
|
else
|
|
|
|
|
tell(0, "Info: Stylesheet '%s' loaded", xsltfile);
|
|
|
|
|
|
|
|
|
|
free(xsltfile);
|
|
|
|
|
return stylesheet;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
//***************************************************************************
|
|
|
|
|
// Gnu Unzip
|
|
|
|
|
//***************************************************************************
|
|
|
|
|
|
|
|
|
|
int gunzip(MemoryStruct* zippedData, MemoryStruct* unzippedData)
|
|
|
|
|
{
|
|
|
|
|
const int growthStep = 1024;
|
|
|
|
|
|
|
|
|
|
z_stream stream = {0,0,0,0,0,0,0,0,0,0,0,Z_NULL,Z_NULL,Z_NULL};
|
|
|
|
|
unsigned int resultSize = 0;
|
|
|
|
|
int res = 0;
|
|
|
|
|
|
|
|
|
|
unzippedData->clear();
|
|
|
|
|
|
|
|
|
|
// determining the size in this way is taken from the sources of the gzip utility.
|
|
|
|
|
|
|
|
|
|
memcpy(&unzippedData->size, zippedData->memory + zippedData->size -4, 4);
|
|
|
|
|
unzippedData->memory = (char*)malloc(unzippedData->size);
|
|
|
|
|
|
|
|
|
|
// zlib initialisation
|
|
|
|
|
|
|
|
|
|
stream.avail_in = zippedData->size;
|
|
|
|
|
stream.next_in = (Bytef*)zippedData->memory;
|
|
|
|
|
stream.avail_out = unzippedData->size;
|
|
|
|
|
stream.next_out = (Bytef*)unzippedData->memory;
|
|
|
|
|
|
|
|
|
|
// The '+ 32' tells zlib to process zlib&gzlib headers
|
|
|
|
|
|
|
|
|
|
res = inflateInit2(&stream, MAX_WBITS + 32);
|
|
|
|
|
|
|
|
|
|
if (res != Z_OK)
|
|
|
|
|
{
|
|
|
|
|
tellZipError(res, " during zlib initialisation", stream.msg);
|
|
|
|
|
inflateEnd(&stream);
|
|
|
|
|
return fail;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// skip the header
|
|
|
|
|
|
|
|
|
|
res = inflate(&stream, Z_BLOCK);
|
|
|
|
|
|
|
|
|
|
if (res != Z_OK)
|
|
|
|
|
{
|
|
|
|
|
tellZipError(res, " while skipping the header", stream.msg);
|
|
|
|
|
inflateEnd(&stream);
|
|
|
|
|
return fail;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
while (res == Z_OK)
|
|
|
|
|
{
|
|
|
|
|
if (stream.avail_out == 0)
|
|
|
|
|
{
|
|
|
|
|
unzippedData->size += growthStep;
|
|
|
|
|
unzippedData->memory = (char*)realloc(unzippedData->memory, unzippedData->size);
|
|
|
|
|
|
|
|
|
|
// Set the stream pointers to the potentially changed buffer!
|
|
|
|
|
|
|
|
|
|
stream.avail_out = resultSize - stream.total_out;
|
|
|
|
|
stream.next_out = (Bytef*)(unzippedData + stream.total_out);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
res = inflate(&stream, Z_SYNC_FLUSH);
|
|
|
|
|
resultSize = stream.total_out;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (res != Z_STREAM_END)
|
|
|
|
|
{
|
|
|
|
|
tellZipError(res, " during inflating", stream.msg);
|
|
|
|
|
inflateEnd(&stream);
|
|
|
|
|
return fail;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
unzippedData->size = resultSize;
|
|
|
|
|
inflateEnd(&stream);
|
|
|
|
|
|
|
|
|
|
return success;
|
|
|
|
|
}
|
|
|
|
|
|
2014-05-09 01:05:21 +02:00
|
|
|
|
//***************************************************************************
|
|
|
|
|
// gzip
|
|
|
|
|
//***************************************************************************
|
|
|
|
|
|
|
|
|
|
int _gzip(Bytef* dest, uLongf* destLen, const Bytef* source, uLong sourceLen)
|
|
|
|
|
{
|
|
|
|
|
z_stream stream;
|
|
|
|
|
int res;
|
|
|
|
|
|
|
|
|
|
stream.next_in = (Bytef *)source;
|
|
|
|
|
stream.avail_in = (uInt)sourceLen;
|
|
|
|
|
stream.next_out = dest;
|
|
|
|
|
stream.avail_out = (uInt)*destLen;
|
|
|
|
|
if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR;
|
|
|
|
|
|
|
|
|
|
stream.zalloc = (alloc_func)0;
|
|
|
|
|
stream.zfree = (free_func)0;
|
|
|
|
|
stream.opaque = (voidpf)0;
|
|
|
|
|
|
|
|
|
|
if ((res = deflateInit2(&stream, Z_DEFAULT_COMPRESSION, Z_DEFLATED, 15 + 16, 8, Z_DEFAULT_STRATEGY)) != Z_OK)
|
|
|
|
|
return res;
|
|
|
|
|
|
|
|
|
|
res = deflate(&stream, Z_FINISH);
|
|
|
|
|
|
|
|
|
|
if (res != Z_STREAM_END)
|
|
|
|
|
{
|
|
|
|
|
deflateEnd(&stream);
|
|
|
|
|
return res == Z_OK ? Z_BUF_ERROR : res;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
*destLen = stream.total_out;
|
|
|
|
|
res = deflateEnd(&stream);
|
|
|
|
|
|
|
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int gzip(MemoryStruct* data, MemoryStruct* zippedData)
|
|
|
|
|
{
|
|
|
|
|
int res;
|
|
|
|
|
uLong sizeMax = compressBound(data->size) + 512;
|
|
|
|
|
|
|
|
|
|
zippedData->clear();
|
|
|
|
|
zippedData->memory = (char*)malloc(sizeMax);
|
|
|
|
|
|
|
|
|
|
if ((res = _gzip((Bytef*)zippedData->memory, &sizeMax, (Bytef*)data->memory, data->size)) != Z_OK)
|
|
|
|
|
{
|
|
|
|
|
tellZipError(res, " during compression", "");
|
|
|
|
|
return fail;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
zippedData->copyAttributes(data);
|
|
|
|
|
zippedData->size = sizeMax;
|
|
|
|
|
sprintf(zippedData->contentEncoding, "gzip");
|
|
|
|
|
|
|
|
|
|
return success;
|
|
|
|
|
}
|
|
|
|
|
|
2014-04-12 17:10:43 +02:00
|
|
|
|
//*************************************************************************
|
|
|
|
|
// tellZipError
|
|
|
|
|
//*************************************************************************
|
|
|
|
|
|
|
|
|
|
void tellZipError(int errorCode, const char* op, const char* msg)
|
|
|
|
|
{
|
|
|
|
|
if (!op) op = "";
|
|
|
|
|
if (!msg) msg = "None";
|
|
|
|
|
|
|
|
|
|
switch (errorCode)
|
|
|
|
|
{
|
|
|
|
|
case Z_OK: return;
|
|
|
|
|
case Z_STREAM_END: return;
|
2014-05-09 01:05:21 +02:00
|
|
|
|
case Z_MEM_ERROR: tell(0, "Error: Not enough memory to zip/unzip file%s!\n", op); return;
|
|
|
|
|
case Z_BUF_ERROR: tell(0, "Error: Couldn't zip/unzip data due to output buffer size problem%s!\n", op); return;
|
2014-04-12 17:10:43 +02:00
|
|
|
|
case Z_DATA_ERROR: tell(0, "Error: Zipped input data corrupted%s! Details: %s\n", op, msg); return;
|
|
|
|
|
case Z_STREAM_ERROR: tell(0, "Error: Invalid stream structure%s. Details: %s\n", op, msg); return;
|
2014-05-09 01:05:21 +02:00
|
|
|
|
default: tell(0, "Error: Couldn't zip/unzip data for unknown reason (%6d)%s!\n", errorCode, op); return;
|
2014-04-12 17:10:43 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//*************************************************************************
|
|
|
|
|
// Host Data
|
|
|
|
|
//*************************************************************************
|
|
|
|
|
|
|
|
|
|
#include <sys/utsname.h>
|
|
|
|
|
#include <netdb.h>
|
|
|
|
|
#include <ifaddrs.h>
|
|
|
|
|
|
|
|
|
|
static struct utsname info;
|
|
|
|
|
|
|
|
|
|
const char* getHostName()
|
|
|
|
|
{
|
|
|
|
|
// get info from kernel
|
|
|
|
|
|
|
|
|
|
if (uname(&info) == -1)
|
|
|
|
|
return "";
|
|
|
|
|
|
|
|
|
|
return info.nodename;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const char* getFirstIp()
|
|
|
|
|
{
|
|
|
|
|
struct ifaddrs *ifaddr, *ifa;
|
|
|
|
|
static char host[NI_MAXHOST] = "";
|
|
|
|
|
|
|
|
|
|
if (getifaddrs(&ifaddr) == -1)
|
|
|
|
|
{
|
|
|
|
|
tell(0, "getifaddrs() failed");
|
|
|
|
|
return "";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// walk through linked interface list
|
|
|
|
|
|
|
|
|
|
for (ifa = ifaddr; ifa; ifa = ifa->ifa_next)
|
|
|
|
|
{
|
|
|
|
|
if (!ifa->ifa_addr)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
// For an AF_INET interfaces
|
|
|
|
|
|
|
|
|
|
if (ifa->ifa_addr->sa_family == AF_INET) // || ifa->ifa_addr->sa_family == AF_INET6)
|
|
|
|
|
{
|
|
|
|
|
int res = getnameinfo(ifa->ifa_addr,
|
|
|
|
|
(ifa->ifa_addr->sa_family == AF_INET) ? sizeof(struct sockaddr_in) :
|
|
|
|
|
sizeof(struct sockaddr_in6),
|
|
|
|
|
host, NI_MAXHOST, 0, 0, NI_NUMERICHOST);
|
|
|
|
|
|
|
|
|
|
if (res)
|
|
|
|
|
{
|
|
|
|
|
tell(0, "getnameinfo() failed: %s", gai_strerror(res));
|
|
|
|
|
return "";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// skip loopback interface
|
|
|
|
|
|
|
|
|
|
if (strcmp(host, "127.0.0.1") == 0)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
tell(5, "%-8s %-15s %s", ifa->ifa_name, host,
|
|
|
|
|
ifa->ifa_addr->sa_family == AF_INET ? " (AF_INET)" :
|
|
|
|
|
ifa->ifa_addr->sa_family == AF_INET6 ? " (AF_INET6)" : "");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
freeifaddrs(ifaddr);
|
|
|
|
|
|
|
|
|
|
return host;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#ifdef USELIBARCHIVE
|
|
|
|
|
|
|
|
|
|
//***************************************************************************
|
|
|
|
|
// unzip <file> and get data of first content which name matches <filter>
|
|
|
|
|
//***************************************************************************
|
|
|
|
|
|
|
|
|
|
int unzip(const char* file, const char* filter, char*& buffer, int& size, char* entryName)
|
|
|
|
|
{
|
|
|
|
|
const int step = 1024*10;
|
|
|
|
|
|
|
|
|
|
int bufSize = 0;
|
|
|
|
|
int r;
|
|
|
|
|
int res;
|
|
|
|
|
|
|
|
|
|
struct archive_entry* entry;
|
|
|
|
|
struct archive* a = archive_read_new();
|
|
|
|
|
|
|
|
|
|
*entryName = 0;
|
|
|
|
|
buffer = 0;
|
|
|
|
|
size = 0;
|
|
|
|
|
|
|
|
|
|
archive_read_support_filter_all(a);
|
|
|
|
|
archive_read_support_format_all(a);
|
|
|
|
|
|
|
|
|
|
r = archive_read_open_filename(a, file, 10204);
|
|
|
|
|
|
|
|
|
|
if (r != ARCHIVE_OK)
|
|
|
|
|
{
|
2014-05-09 01:05:21 +02:00
|
|
|
|
tell(0, "Error: Open '%s' failed - %s", file, strerror(errno));
|
2014-04-12 17:10:43 +02:00
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
while (archive_read_next_header(a, &entry) == ARCHIVE_OK)
|
|
|
|
|
{
|
|
|
|
|
strcpy(entryName, archive_entry_pathname(entry));
|
|
|
|
|
|
|
|
|
|
if (strstr(entryName, filter))
|
|
|
|
|
{
|
|
|
|
|
bufSize = step;
|
|
|
|
|
buffer = (char*)malloc(bufSize+1);
|
|
|
|
|
|
|
|
|
|
while ((res = archive_read_data(a, buffer+size, step)) > 0)
|
|
|
|
|
{
|
|
|
|
|
size += res;
|
|
|
|
|
bufSize += step;
|
|
|
|
|
|
|
|
|
|
buffer = (char*)realloc(buffer, bufSize+1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
buffer[size] = 0;
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
r = archive_read_free(a);
|
|
|
|
|
|
|
|
|
|
if (r != ARCHIVE_OK)
|
|
|
|
|
{
|
|
|
|
|
size = 0;
|
|
|
|
|
free(buffer);
|
|
|
|
|
return fail;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return size > 0 ? success : fail;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
//***************************************************************************
|
2014-05-09 16:53:56 +02:00
|
|
|
|
// cMyMutex
|
|
|
|
|
//***************************************************************************
|
|
|
|
|
|
|
|
|
|
cMyMutex::cMyMutex (void)
|
|
|
|
|
{
|
|
|
|
|
locked = 0;
|
|
|
|
|
pthread_mutexattr_t attr;
|
|
|
|
|
pthread_mutexattr_init(&attr);
|
|
|
|
|
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK_NP);
|
|
|
|
|
pthread_mutex_init(&mutex, &attr);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cMyMutex::~cMyMutex()
|
|
|
|
|
{
|
|
|
|
|
pthread_mutex_destroy(&mutex);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void cMyMutex::Lock(void)
|
|
|
|
|
{
|
|
|
|
|
pthread_mutex_lock(&mutex);
|
|
|
|
|
locked++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void cMyMutex::Unlock(void)
|
|
|
|
|
{
|
|
|
|
|
if (!--locked)
|
|
|
|
|
pthread_mutex_unlock(&mutex);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//***************************************************************************
|
|
|
|
|
// cMyTimeMs
|
2014-04-12 17:10:43 +02:00
|
|
|
|
//***************************************************************************
|
|
|
|
|
|
2014-05-09 16:53:56 +02:00
|
|
|
|
cMyTimeMs::cMyTimeMs(int Ms)
|
|
|
|
|
{
|
|
|
|
|
if (Ms >= 0)
|
|
|
|
|
Set(Ms);
|
|
|
|
|
else
|
|
|
|
|
begin = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint64_t cMyTimeMs::Now(void)
|
|
|
|
|
{
|
|
|
|
|
#define MIN_RESOLUTION 5 // ms
|
|
|
|
|
static bool initialized = false;
|
|
|
|
|
static bool monotonic = false;
|
|
|
|
|
struct timespec tp;
|
|
|
|
|
if (!initialized) {
|
|
|
|
|
// check if monotonic timer is available and provides enough accurate resolution:
|
|
|
|
|
if (clock_getres(CLOCK_MONOTONIC, &tp) == 0) {
|
|
|
|
|
// long Resolution = tp.tv_nsec;
|
|
|
|
|
// require a minimum resolution:
|
|
|
|
|
if (tp.tv_sec == 0 && tp.tv_nsec <= MIN_RESOLUTION * 1000000) {
|
|
|
|
|
if (clock_gettime(CLOCK_MONOTONIC, &tp) == 0) {
|
|
|
|
|
monotonic = true;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
tell(0, "cMyTimeMs: clock_gettime(CLOCK_MONOTONIC) failed");
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
tell(0, "cMyTimeMs: not using monotonic clock - resolution is too bad (%ld s %ld ns)", tp.tv_sec, tp.tv_nsec);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
tell(0, "cMyTimeMs: clock_getres(CLOCK_MONOTONIC) failed");
|
|
|
|
|
initialized = true;
|
|
|
|
|
}
|
|
|
|
|
if (monotonic) {
|
|
|
|
|
if (clock_gettime(CLOCK_MONOTONIC, &tp) == 0)
|
|
|
|
|
return (uint64_t(tp.tv_sec)) * 1000 + tp.tv_nsec / 1000000;
|
|
|
|
|
tell(0, "cMyTimeMs: clock_gettime(CLOCK_MONOTONIC) failed");
|
|
|
|
|
monotonic = false;
|
|
|
|
|
// fall back to gettimeofday()
|
|
|
|
|
}
|
|
|
|
|
struct timeval t;
|
|
|
|
|
if (gettimeofday(&t, NULL) == 0)
|
|
|
|
|
return (uint64_t(t.tv_sec)) * 1000 + t.tv_usec / 1000;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void cMyTimeMs::Set(int Ms)
|
|
|
|
|
{
|
|
|
|
|
begin = Now() + Ms;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool cMyTimeMs::TimedOut(void)
|
|
|
|
|
{
|
|
|
|
|
return Now() >= begin;
|
|
|
|
|
}
|
2014-04-12 17:10:43 +02:00
|
|
|
|
|
2014-05-09 16:53:56 +02:00
|
|
|
|
uint64_t cMyTimeMs::Elapsed(void)
|
|
|
|
|
{
|
|
|
|
|
return Now() - begin;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//***************************************************************************
|
|
|
|
|
// Class LogDuration
|
|
|
|
|
//***************************************************************************
|
2014-04-12 17:10:43 +02:00
|
|
|
|
|
|
|
|
|
LogDuration::LogDuration(const char* aMessage, int aLogLevel)
|
|
|
|
|
{
|
|
|
|
|
logLevel = aLogLevel;
|
|
|
|
|
strcpy(message, aMessage);
|
|
|
|
|
|
|
|
|
|
// at last !
|
|
|
|
|
|
2014-05-09 16:53:56 +02:00
|
|
|
|
durationStart = cMyTimeMs::Now();
|
2014-04-12 17:10:43 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
LogDuration::~LogDuration()
|
|
|
|
|
{
|
2014-05-09 01:05:21 +02:00
|
|
|
|
tell(logLevel, "duration '%s' was (%ldms)",
|
2014-05-09 16:53:56 +02:00
|
|
|
|
message, cMyTimeMs::Now() - durationStart);
|
2014-04-12 17:10:43 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void LogDuration::show(const char* label)
|
|
|
|
|
{
|
2014-05-09 01:05:21 +02:00
|
|
|
|
tell(logLevel, "elapsed '%s' at '%s' was (%ldms)",
|
2014-05-09 16:53:56 +02:00
|
|
|
|
message, label, cMyTimeMs::Now() - durationStart);
|
2014-04-12 17:10:43 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//***************************************************************************
|
|
|
|
|
// Get Unique ID
|
|
|
|
|
//***************************************************************************
|
|
|
|
|
|
|
|
|
|
#ifdef USEUUID
|
|
|
|
|
const char* getUniqueId()
|
|
|
|
|
{
|
|
|
|
|
static char uuid[sizeUuid+TB] = "";
|
|
|
|
|
|
|
|
|
|
uuid_t id;
|
|
|
|
|
uuid_generate(id);
|
|
|
|
|
uuid_unparse_upper(id, uuid);
|
|
|
|
|
|
|
|
|
|
return uuid;
|
|
|
|
|
}
|
|
|
|
|
#endif // USEUUID
|
|
|
|
|
|
|
|
|
|
//***************************************************************************
|
|
|
|
|
// Create MD5
|
|
|
|
|
//***************************************************************************
|
|
|
|
|
|
|
|
|
|
#ifdef USEMD5
|
|
|
|
|
|
|
|
|
|
int createMd5(const char* buf, md5* md5)
|
|
|
|
|
{
|
|
|
|
|
MD5_CTX c;
|
|
|
|
|
unsigned char out[MD5_DIGEST_LENGTH];
|
|
|
|
|
|
|
|
|
|
MD5_Init(&c);
|
|
|
|
|
MD5_Update(&c, buf, strlen(buf));
|
|
|
|
|
MD5_Final(out, &c);
|
|
|
|
|
|
|
|
|
|
for (int n = 0; n < MD5_DIGEST_LENGTH; n++)
|
|
|
|
|
sprintf(md5+2*n, "%02x", out[n]);
|
|
|
|
|
|
|
|
|
|
md5[sizeMd5] = 0;
|
|
|
|
|
|
|
|
|
|
return done;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int createMd5OfFile(const char* path, const char* name, md5* md5)
|
|
|
|
|
{
|
|
|
|
|
FILE* f;
|
|
|
|
|
char buffer[1000];
|
|
|
|
|
int nread = 0;
|
|
|
|
|
MD5_CTX c;
|
|
|
|
|
unsigned char out[MD5_DIGEST_LENGTH];
|
|
|
|
|
char* file = 0;
|
|
|
|
|
|
|
|
|
|
asprintf(&file, "%s/%s", path, name);
|
|
|
|
|
|
|
|
|
|
if (!(f = fopen(file, "r")))
|
|
|
|
|
{
|
2014-05-09 01:05:21 +02:00
|
|
|
|
tell(0, "Fatal: Can't access '%s'; %s", file, strerror(errno));
|
2014-04-12 17:10:43 +02:00
|
|
|
|
free(file);
|
|
|
|
|
return fail;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
free(file);
|
|
|
|
|
|
|
|
|
|
MD5_Init(&c);
|
|
|
|
|
|
|
|
|
|
while ((nread = fread(buffer, 1, 1000, f)) > 0)
|
|
|
|
|
MD5_Update(&c, buffer, nread);
|
|
|
|
|
|
|
|
|
|
fclose(f);
|
|
|
|
|
|
|
|
|
|
MD5_Final(out, &c);
|
|
|
|
|
|
|
|
|
|
for (int n = 0; n < MD5_DIGEST_LENGTH; n++)
|
|
|
|
|
sprintf(md5+2*n, "%02x", out[n]);
|
|
|
|
|
|
|
|
|
|
md5[sizeMd5] = 0;
|
|
|
|
|
|
|
|
|
|
return success;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endif // USEMD5
|
2014-05-09 01:05:21 +02:00
|
|
|
|
|
|
|
|
|
//***************************************************************************
|
|
|
|
|
// Url Unescape
|
|
|
|
|
//***************************************************************************
|
|
|
|
|
/*
|
|
|
|
|
* The buffer pointed to by @dst must be at least strlen(@src) bytes.
|
|
|
|
|
* Decoding stops at the first character from @src that decodes to null.
|
|
|
|
|
|
|
|
|
|
* Path normalization will remove redundant slashes and slash+dot sequences,
|
|
|
|
|
* as well as removing path components when slash+dot+dot is found. It will
|
|
|
|
|
* keep the root slash (if one was present) and will stop normalization
|
|
|
|
|
* at the first questionmark found (so query parameters won't be normalized).
|
|
|
|
|
*
|
|
|
|
|
* @param dst destination buffer
|
|
|
|
|
* @param src source buffer
|
|
|
|
|
* @param normalize perform path normalization if nonzero
|
|
|
|
|
* @return number of valid characters in @dst
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
int urlUnescape(char* dst, const char* src, int normalize)
|
|
|
|
|
{
|
|
|
|
|
// CURL* curl;
|
|
|
|
|
// int resultSize;
|
|
|
|
|
|
|
|
|
|
// if (curl_global_init(CURL_GLOBAL_ALL) != 0)
|
|
|
|
|
// {
|
|
|
|
|
// tell(0, "Error, something went wrong with curl_global_init()");
|
|
|
|
|
|
|
|
|
|
// return fail;
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// curl = curl_easy_init();
|
|
|
|
|
|
|
|
|
|
// if (!curl)
|
|
|
|
|
// {
|
|
|
|
|
// tell(0, "Error, unable to get handle from curl_easy_init()");
|
|
|
|
|
|
|
|
|
|
// return fail;
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// dst = curl_easy_unescape(curl, src, strlen(src), &resultSize);
|
|
|
|
|
|
|
|
|
|
// tell(0, " [%.40s]", src);
|
|
|
|
|
|
|
|
|
|
// tell(0, "res size %d [%.40s]", resultSize, dst);
|
|
|
|
|
// return resultSize;
|
|
|
|
|
|
|
|
|
|
char* org_dst = dst;
|
|
|
|
|
int slash_dot_dot = 0;
|
|
|
|
|
char ch, a, b;
|
|
|
|
|
|
|
|
|
|
a = 0;
|
|
|
|
|
|
|
|
|
|
do {
|
|
|
|
|
ch = *src++;
|
|
|
|
|
|
|
|
|
|
if (ch == '%' && isxdigit(a = src[0]) && isxdigit(b = src[1]))
|
|
|
|
|
{
|
|
|
|
|
if (a < 'A')
|
|
|
|
|
a -= '0';
|
|
|
|
|
else if
|
|
|
|
|
(a < 'a') a -= 'A' - 10;
|
|
|
|
|
else
|
|
|
|
|
a -= 'a' - 10;
|
|
|
|
|
|
|
|
|
|
if (b < 'A')
|
|
|
|
|
b -= '0';
|
|
|
|
|
else if (b < 'a')
|
|
|
|
|
b -= 'A' - 10;
|
|
|
|
|
else
|
|
|
|
|
b -= 'a' - 10;
|
|
|
|
|
|
|
|
|
|
ch = 16 * a + b;
|
|
|
|
|
src += 2;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (normalize)
|
|
|
|
|
{
|
|
|
|
|
switch (ch)
|
|
|
|
|
{
|
|
|
|
|
case '/': // compress consecutive slashes and remove slash-dot
|
|
|
|
|
if (slash_dot_dot < 3)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
dst -= slash_dot_dot;
|
|
|
|
|
slash_dot_dot = 1;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
// fall-through
|
|
|
|
|
|
|
|
|
|
case '?': // at start of query, stop normalizing
|
|
|
|
|
if (ch == '?')
|
|
|
|
|
normalize = 0;
|
|
|
|
|
|
|
|
|
|
// fall-through
|
|
|
|
|
|
|
|
|
|
case '\0': // remove trailing slash-dot-(dot)
|
|
|
|
|
if (slash_dot_dot > 1)
|
|
|
|
|
{
|
|
|
|
|
dst -= slash_dot_dot;
|
|
|
|
|
|
|
|
|
|
// remove parent directory if it was two dots
|
|
|
|
|
|
|
|
|
|
if (slash_dot_dot == 3)
|
|
|
|
|
while (dst > org_dst && *--dst != '/')
|
|
|
|
|
; // empty body
|
|
|
|
|
slash_dot_dot = (ch == '/') ? 1 : 0;
|
|
|
|
|
|
|
|
|
|
// keep the root slash if any
|
|
|
|
|
|
|
|
|
|
if (!slash_dot_dot && dst == org_dst && *dst == '/')
|
|
|
|
|
++dst;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case '.':
|
|
|
|
|
if (slash_dot_dot == 1 || slash_dot_dot == 2)
|
|
|
|
|
{
|
|
|
|
|
++slash_dot_dot;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
// fall-through
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
slash_dot_dot = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
*dst++ = ch;
|
|
|
|
|
} while(ch);
|
|
|
|
|
|
|
|
|
|
return (dst - org_dst) - 1;
|
|
|
|
|
}
|