vdr  2.0.6
tools.c
Go to the documentation of this file.
1 /*
2  * tools.c: Various tools
3  *
4  * See the main source file 'vdr.c' for copyright information and
5  * how to reach the author.
6  *
7  * $Id: tools.c 2.29 2012/12/08 11:16:30 kls Exp $
8  */
9 
10 #include "tools.h"
11 #include <ctype.h>
12 #include <dirent.h>
13 #include <errno.h>
14 extern "C" {
15 #ifdef boolean
16 #define HAVE_BOOLEAN
17 #endif
18 #include <jpeglib.h>
19 #undef boolean
20 }
21 #include <locale.h>
22 #include <stdlib.h>
23 #include <sys/time.h>
24 #include <sys/vfs.h>
25 #include <time.h>
26 #include <unistd.h>
27 #include <utime.h>
28 #include "i18n.h"
29 #include "thread.h"
30 
31 int SysLogLevel = 3;
32 
33 #define MAXSYSLOGBUF 256
34 
35 void syslog_with_tid(int priority, const char *format, ...)
36 {
37  va_list ap;
38  char fmt[MAXSYSLOGBUF];
39  snprintf(fmt, sizeof(fmt), "[%d] %s", cThread::ThreadId(), format);
40  va_start(ap, format);
41  vsyslog(priority, fmt, ap);
42  va_end(ap);
43 }
44 
45 int BCD2INT(int x)
46 {
47  return ((1000000 * BCDCHARTOINT((x >> 24) & 0xFF)) +
48  (10000 * BCDCHARTOINT((x >> 16) & 0xFF)) +
49  (100 * BCDCHARTOINT((x >> 8) & 0xFF)) +
50  BCDCHARTOINT( x & 0xFF));
51 }
52 
53 ssize_t safe_read(int filedes, void *buffer, size_t size)
54 {
55  for (;;) {
56  ssize_t p = read(filedes, buffer, size);
57  if (p < 0 && errno == EINTR) {
58  dsyslog("EINTR while reading from file handle %d - retrying", filedes);
59  continue;
60  }
61  return p;
62  }
63 }
64 
65 ssize_t safe_write(int filedes, const void *buffer, size_t size)
66 {
67  ssize_t p = 0;
68  ssize_t written = size;
69  const unsigned char *ptr = (const unsigned char *)buffer;
70  while (size > 0) {
71  p = write(filedes, ptr, size);
72  if (p < 0) {
73  if (errno == EINTR) {
74  dsyslog("EINTR while writing to file handle %d - retrying", filedes);
75  continue;
76  }
77  break;
78  }
79  ptr += p;
80  size -= p;
81  }
82  return p < 0 ? p : written;
83 }
84 
85 void writechar(int filedes, char c)
86 {
87  safe_write(filedes, &c, sizeof(c));
88 }
89 
90 int WriteAllOrNothing(int fd, const uchar *Data, int Length, int TimeoutMs, int RetryMs)
91 {
92  int written = 0;
93  while (Length > 0) {
94  int w = write(fd, Data + written, Length);
95  if (w > 0) {
96  Length -= w;
97  written += w;
98  }
99  else if (written > 0 && !FATALERRNO) {
100  // we've started writing, so we must finish it!
101  cTimeMs t;
102  cPoller Poller(fd, true);
103  Poller.Poll(RetryMs);
104  if (TimeoutMs > 0 && (TimeoutMs -= t.Elapsed()) <= 0)
105  break;
106  }
107  else
108  // nothing written yet (or fatal error), so we can just return the error code:
109  return w;
110  }
111  return written;
112 }
113 
114 char *strcpyrealloc(char *dest, const char *src)
115 {
116  if (src) {
117  int l = max(dest ? strlen(dest) : 0, strlen(src)) + 1; // don't let the block get smaller!
118  dest = (char *)realloc(dest, l);
119  if (dest)
120  strcpy(dest, src);
121  else
122  esyslog("ERROR: out of memory");
123  }
124  else {
125  free(dest);
126  dest = NULL;
127  }
128  return dest;
129 }
130 
131 char *strn0cpy(char *dest, const char *src, size_t n)
132 {
133  char *s = dest;
134  for ( ; --n && (*dest = *src) != 0; dest++, src++) ;
135  *dest = 0;
136  return s;
137 }
138 
139 char *strreplace(char *s, char c1, char c2)
140 {
141  if (s) {
142  char *p = s;
143  while (*p) {
144  if (*p == c1)
145  *p = c2;
146  p++;
147  }
148  }
149  return s;
150 }
151 
152 char *strreplace(char *s, const char *s1, const char *s2)
153 {
154  char *p = strstr(s, s1);
155  if (p) {
156  int of = p - s;
157  int l = strlen(s);
158  int l1 = strlen(s1);
159  int l2 = strlen(s2);
160  if (l2 > l1) {
161  if (char *NewBuffer = (char *)realloc(s, l + l2 - l1 + 1))
162  s = NewBuffer;
163  else {
164  esyslog("ERROR: out of memory");
165  return s;
166  }
167  }
168  char *sof = s + of;
169  if (l2 != l1)
170  memmove(sof + l2, sof + l1, l - of - l1 + 1);
171  strncpy(sof, s2, l2);
172  }
173  return s;
174 }
175 
176 char *stripspace(char *s)
177 {
178  if (s && *s) {
179  for (char *p = s + strlen(s) - 1; p >= s; p--) {
180  if (!isspace(*p))
181  break;
182  *p = 0;
183  }
184  }
185  return s;
186 }
187 
188 char *compactspace(char *s)
189 {
190  if (s && *s) {
191  char *t = stripspace(skipspace(s));
192  char *p = t;
193  while (p && *p) {
194  char *q = skipspace(p);
195  if (q - p > 1)
196  memmove(p + 1, q, strlen(q) + 1);
197  p++;
198  }
199  if (t != s)
200  memmove(s, t, strlen(t) + 1);
201  }
202  return s;
203 }
204 
205 cString strescape(const char *s, const char *chars)
206 {
207  char *buffer;
208  const char *p = s;
209  char *t = NULL;
210  while (*p) {
211  if (strchr(chars, *p)) {
212  if (!t) {
213  buffer = MALLOC(char, 2 * strlen(s) + 1);
214  t = buffer + (p - s);
215  s = strcpy(buffer, s);
216  }
217  *t++ = '\\';
218  }
219  if (t)
220  *t++ = *p;
221  p++;
222  }
223  if (t)
224  *t = 0;
225  return cString(s, t != NULL);
226 }
227 
228 bool startswith(const char *s, const char *p)
229 {
230  while (*p) {
231  if (*p++ != *s++)
232  return false;
233  }
234  return true;
235 }
236 
237 bool endswith(const char *s, const char *p)
238 {
239  const char *se = s + strlen(s) - 1;
240  const char *pe = p + strlen(p) - 1;
241  while (pe >= p) {
242  if (*pe-- != *se-- || (se < s && pe >= p))
243  return false;
244  }
245  return true;
246 }
247 
248 bool isempty(const char *s)
249 {
250  return !(s && *skipspace(s));
251 }
252 
253 int numdigits(int n)
254 {
255  int res = 1;
256  while (n >= 10) {
257  n /= 10;
258  res++;
259  }
260  return res;
261 }
262 
263 bool isnumber(const char *s)
264 {
265  if (!s || !*s)
266  return false;
267  do {
268  if (!isdigit(*s))
269  return false;
270  } while (*++s);
271  return true;
272 }
273 
274 int64_t StrToNum(const char *s)
275 {
276  char *t = NULL;
277  int64_t n = strtoll(s, &t, 10);
278  if (t) {
279  switch (*t) {
280  case 'T': n *= 1024;
281  case 'G': n *= 1024;
282  case 'M': n *= 1024;
283  case 'K': n *= 1024;
284  }
285  }
286  return n;
287 }
288 
289 bool StrInArray(const char *a[], const char *s)
290 {
291  if (a) {
292  while (*a) {
293  if (strcmp(*a, s) == 0)
294  return true;
295  a++;
296  }
297  }
298  return false;
299 }
300 
301 cString AddDirectory(const char *DirName, const char *FileName)
302 {
303  return cString::sprintf("%s/%s", DirName && *DirName ? DirName : ".", FileName);
304 }
305 
306 #define DECIMAL_POINT_C '.'
307 
308 double atod(const char *s)
309 {
310  static lconv *loc = localeconv();
311  if (*loc->decimal_point != DECIMAL_POINT_C) {
312  char buf[strlen(s) + 1];
313  char *p = buf;
314  while (*s) {
315  if (*s == DECIMAL_POINT_C)
316  *p = *loc->decimal_point;
317  else
318  *p = *s;
319  p++;
320  s++;
321  }
322  *p = 0;
323  return atof(buf);
324  }
325  else
326  return atof(s);
327 }
328 
329 cString dtoa(double d, const char *Format)
330 {
331  static lconv *loc = localeconv();
332  char buf[16];
333  snprintf(buf, sizeof(buf), Format, d);
334  if (*loc->decimal_point != DECIMAL_POINT_C)
335  strreplace(buf, *loc->decimal_point, DECIMAL_POINT_C);
336  return buf;
337 }
338 
339 cString itoa(int n)
340 {
341  char buf[16];
342  snprintf(buf, sizeof(buf), "%d", n);
343  return buf;
344 }
345 
346 bool EntriesOnSameFileSystem(const char *File1, const char *File2)
347 {
348  struct stat st;
349  if (stat(File1, &st) == 0) {
350  dev_t dev1 = st.st_dev;
351  if (stat(File2, &st) == 0)
352  return st.st_dev == dev1;
353  else
354  LOG_ERROR_STR(File2);
355  }
356  else
357  LOG_ERROR_STR(File1);
358  return false;
359 }
360 
361 int FreeDiskSpaceMB(const char *Directory, int *UsedMB)
362 {
363  if (UsedMB)
364  *UsedMB = 0;
365  int Free = 0;
366  struct statfs statFs;
367  if (statfs(Directory, &statFs) == 0) {
368  double blocksPerMeg = 1024.0 * 1024.0 / statFs.f_bsize;
369  if (UsedMB)
370  *UsedMB = int((statFs.f_blocks - statFs.f_bfree) / blocksPerMeg);
371  Free = int(statFs.f_bavail / blocksPerMeg);
372  }
373  else
374  LOG_ERROR_STR(Directory);
375  return Free;
376 }
377 
378 bool DirectoryOk(const char *DirName, bool LogErrors)
379 {
380  struct stat ds;
381  if (stat(DirName, &ds) == 0) {
382  if (S_ISDIR(ds.st_mode)) {
383  if (access(DirName, R_OK | W_OK | X_OK) == 0)
384  return true;
385  else if (LogErrors)
386  esyslog("ERROR: can't access %s", DirName);
387  }
388  else if (LogErrors)
389  esyslog("ERROR: %s is not a directory", DirName);
390  }
391  else if (LogErrors)
392  LOG_ERROR_STR(DirName);
393  return false;
394 }
395 
396 bool MakeDirs(const char *FileName, bool IsDirectory)
397 {
398  bool result = true;
399  char *s = strdup(FileName);
400  char *p = s;
401  if (*p == '/')
402  p++;
403  while ((p = strchr(p, '/')) != NULL || IsDirectory) {
404  if (p)
405  *p = 0;
406  struct stat fs;
407  if (stat(s, &fs) != 0 || !S_ISDIR(fs.st_mode)) {
408  dsyslog("creating directory %s", s);
409  if (mkdir(s, ACCESSPERMS) == -1) {
410  LOG_ERROR_STR(s);
411  result = false;
412  break;
413  }
414  }
415  if (p)
416  *p++ = '/';
417  else
418  break;
419  }
420  free(s);
421  return result;
422 }
423 
424 bool RemoveFileOrDir(const char *FileName, bool FollowSymlinks)
425 {
426  struct stat st;
427  if (stat(FileName, &st) == 0) {
428  if (S_ISDIR(st.st_mode)) {
429  cReadDir d(FileName);
430  if (d.Ok()) {
431  struct dirent *e;
432  while ((e = d.Next()) != NULL) {
433  cString buffer = AddDirectory(FileName, e->d_name);
434  if (FollowSymlinks) {
435  struct stat st2;
436  if (lstat(buffer, &st2) == 0) {
437  if (S_ISLNK(st2.st_mode)) {
438  int size = st2.st_size + 1;
439  char *l = MALLOC(char, size);
440  int n = readlink(buffer, l, size - 1);
441  if (n < 0) {
442  if (errno != EINVAL)
443  LOG_ERROR_STR(*buffer);
444  }
445  else {
446  l[n] = 0;
447  dsyslog("removing %s", l);
448  if (remove(l) < 0)
449  LOG_ERROR_STR(l);
450  }
451  free(l);
452  }
453  }
454  else if (errno != ENOENT) {
455  LOG_ERROR_STR(FileName);
456  return false;
457  }
458  }
459  dsyslog("removing %s", *buffer);
460  if (remove(buffer) < 0)
461  LOG_ERROR_STR(*buffer);
462  }
463  }
464  else {
465  LOG_ERROR_STR(FileName);
466  return false;
467  }
468  }
469  dsyslog("removing %s", FileName);
470  if (remove(FileName) < 0) {
471  LOG_ERROR_STR(FileName);
472  return false;
473  }
474  }
475  else if (errno != ENOENT) {
476  LOG_ERROR_STR(FileName);
477  return false;
478  }
479  return true;
480 }
481 
482 bool RemoveEmptyDirectories(const char *DirName, bool RemoveThis, const char *IgnoreFiles[])
483 {
484  bool HasIgnoredFiles = false;
485  cReadDir d(DirName);
486  if (d.Ok()) {
487  bool empty = true;
488  struct dirent *e;
489  while ((e = d.Next()) != NULL) {
490  if (strcmp(e->d_name, "lost+found")) {
491  cString buffer = AddDirectory(DirName, e->d_name);
492  struct stat st;
493  if (stat(buffer, &st) == 0) {
494  if (S_ISDIR(st.st_mode)) {
495  if (!RemoveEmptyDirectories(buffer, true, IgnoreFiles))
496  empty = false;
497  }
498  else if (RemoveThis && IgnoreFiles && StrInArray(IgnoreFiles, e->d_name))
499  HasIgnoredFiles = true;
500  else
501  empty = false;
502  }
503  else {
504  LOG_ERROR_STR(*buffer);
505  empty = false;
506  }
507  }
508  }
509  if (RemoveThis && empty) {
510  if (HasIgnoredFiles) {
511  while (*IgnoreFiles) {
512  cString buffer = AddDirectory(DirName, *IgnoreFiles);
513  if (access(buffer, F_OK) == 0) {
514  dsyslog("removing %s", *buffer);
515  if (remove(buffer) < 0) {
516  LOG_ERROR_STR(*buffer);
517  return false;
518  }
519  }
520  IgnoreFiles++;
521  }
522  }
523  dsyslog("removing %s", DirName);
524  if (remove(DirName) < 0) {
525  LOG_ERROR_STR(DirName);
526  return false;
527  }
528  }
529  return empty;
530  }
531  else
532  LOG_ERROR_STR(DirName);
533  return false;
534 }
535 
536 int DirSizeMB(const char *DirName)
537 {
538  cReadDir d(DirName);
539  if (d.Ok()) {
540  int size = 0;
541  struct dirent *e;
542  while (size >= 0 && (e = d.Next()) != NULL) {
543  cString buffer = AddDirectory(DirName, e->d_name);
544  struct stat st;
545  if (stat(buffer, &st) == 0) {
546  if (S_ISDIR(st.st_mode)) {
547  int n = DirSizeMB(buffer);
548  if (n >= 0)
549  size += n;
550  else
551  size = -1;
552  }
553  else
554  size += st.st_size / MEGABYTE(1);
555  }
556  else {
557  LOG_ERROR_STR(*buffer);
558  size = -1;
559  }
560  }
561  return size;
562  }
563  else
564  LOG_ERROR_STR(DirName);
565  return -1;
566 }
567 
568 char *ReadLink(const char *FileName)
569 {
570  if (!FileName)
571  return NULL;
572  char *TargetName = canonicalize_file_name(FileName);
573  if (!TargetName) {
574  if (errno == ENOENT) // file doesn't exist
575  TargetName = strdup(FileName);
576  else // some other error occurred
577  LOG_ERROR_STR(FileName);
578  }
579  return TargetName;
580 }
581 
582 bool SpinUpDisk(const char *FileName)
583 {
584  for (int n = 0; n < 10; n++) {
585  cString buf;
586  if (DirectoryOk(FileName))
587  buf = cString::sprintf("%s/vdr-%06d", *FileName ? FileName : ".", n);
588  else
589  buf = cString::sprintf("%s.vdr-%06d", FileName, n);
590  if (access(buf, F_OK) != 0) { // the file does not exist
591  timeval tp1, tp2;
592  gettimeofday(&tp1, NULL);
593  int f = open(buf, O_WRONLY | O_CREAT, DEFFILEMODE);
594  // O_SYNC doesn't work on all file systems
595  if (f >= 0) {
596  if (fdatasync(f) < 0)
597  LOG_ERROR_STR(*buf);
598  close(f);
599  remove(buf);
600  gettimeofday(&tp2, NULL);
601  double seconds = (((long long)tp2.tv_sec * 1000000 + tp2.tv_usec) - ((long long)tp1.tv_sec * 1000000 + tp1.tv_usec)) / 1000000.0;
602  if (seconds > 0.5)
603  dsyslog("SpinUpDisk took %.2f seconds", seconds);
604  return true;
605  }
606  else
607  LOG_ERROR_STR(*buf);
608  }
609  }
610  esyslog("ERROR: SpinUpDisk failed");
611  return false;
612 }
613 
614 void TouchFile(const char *FileName)
615 {
616  if (utime(FileName, NULL) == -1 && errno != ENOENT)
617  LOG_ERROR_STR(FileName);
618 }
619 
620 time_t LastModifiedTime(const char *FileName)
621 {
622  struct stat fs;
623  if (stat(FileName, &fs) == 0)
624  return fs.st_mtime;
625  return 0;
626 }
627 
628 off_t FileSize(const char *FileName)
629 {
630  struct stat fs;
631  if (stat(FileName, &fs) == 0)
632  return fs.st_size;
633  return -1;
634 }
635 
636 // --- cTimeMs ---------------------------------------------------------------
637 
639 {
640  if (Ms >= 0)
641  Set(Ms);
642  else
643  begin = 0;
644 }
645 
646 uint64_t cTimeMs::Now(void)
647 {
648 #if _POSIX_TIMERS > 0 && defined(_POSIX_MONOTONIC_CLOCK)
649 #define MIN_RESOLUTION 5 // ms
650  static bool initialized = false;
651  static bool monotonic = false;
652  struct timespec tp;
653  if (!initialized) {
654  // check if monotonic timer is available and provides enough accurate resolution:
655  if (clock_getres(CLOCK_MONOTONIC, &tp) == 0) {
656  long Resolution = tp.tv_nsec;
657  // require a minimum resolution:
658  if (tp.tv_sec == 0 && tp.tv_nsec <= MIN_RESOLUTION * 1000000) {
659  if (clock_gettime(CLOCK_MONOTONIC, &tp) == 0) {
660  dsyslog("cTimeMs: using monotonic clock (resolution is %ld ns)", Resolution);
661  monotonic = true;
662  }
663  else
664  esyslog("cTimeMs: clock_gettime(CLOCK_MONOTONIC) failed");
665  }
666  else
667  dsyslog("cTimeMs: not using monotonic clock - resolution is too bad (%ld s %ld ns)", tp.tv_sec, tp.tv_nsec);
668  }
669  else
670  esyslog("cTimeMs: clock_getres(CLOCK_MONOTONIC) failed");
671  initialized = true;
672  }
673  if (monotonic) {
674  if (clock_gettime(CLOCK_MONOTONIC, &tp) == 0)
675  return (uint64_t(tp.tv_sec)) * 1000 + tp.tv_nsec / 1000000;
676  esyslog("cTimeMs: clock_gettime(CLOCK_MONOTONIC) failed");
677  monotonic = false;
678  // fall back to gettimeofday()
679  }
680 #else
681 # warning Posix monotonic clock not available
682 #endif
683  struct timeval t;
684  if (gettimeofday(&t, NULL) == 0)
685  return (uint64_t(t.tv_sec)) * 1000 + t.tv_usec / 1000;
686  return 0;
687 }
688 
689 void cTimeMs::Set(int Ms)
690 {
691  begin = Now() + Ms;
692 }
693 
695 {
696  return Now() >= begin;
697 }
698 
699 uint64_t cTimeMs::Elapsed(void)
700 {
701  return Now() - begin;
702 }
703 
704 // --- UTF-8 support ---------------------------------------------------------
705 
706 static uint SystemToUtf8[128] = { 0 };
707 
708 int Utf8CharLen(const char *s)
709 {
711  return 1;
712 #define MT(s, m, v) ((*(s) & (m)) == (v)) // Mask Test
713  if (MT(s, 0xE0, 0xC0) && MT(s + 1, 0xC0, 0x80))
714  return 2;
715  if (MT(s, 0xF0, 0xE0) && MT(s + 1, 0xC0, 0x80) && MT(s + 2, 0xC0, 0x80))
716  return 3;
717  if (MT(s, 0xF8, 0xF0) && MT(s + 1, 0xC0, 0x80) && MT(s + 2, 0xC0, 0x80) && MT(s + 3, 0xC0, 0x80))
718  return 4;
719  return 1;
720 }
721 
722 uint Utf8CharGet(const char *s, int Length)
723 {
725  return (uchar)*s < 128 ? *s : SystemToUtf8[(uchar)*s - 128];
726  if (!Length)
727  Length = Utf8CharLen(s);
728  switch (Length) {
729  case 2: return ((*s & 0x1F) << 6) | (*(s + 1) & 0x3F);
730  case 3: return ((*s & 0x0F) << 12) | ((*(s + 1) & 0x3F) << 6) | (*(s + 2) & 0x3F);
731  case 4: return ((*s & 0x07) << 18) | ((*(s + 1) & 0x3F) << 12) | ((*(s + 2) & 0x3F) << 6) | (*(s + 3) & 0x3F);
732  default: ;
733  }
734  return *s;
735 }
736 
737 int Utf8CharSet(uint c, char *s)
738 {
739  if (c < 0x80 || cCharSetConv::SystemCharacterTable()) {
740  if (s)
741  *s = c;
742  return 1;
743  }
744  if (c < 0x800) {
745  if (s) {
746  *s++ = ((c >> 6) & 0x1F) | 0xC0;
747  *s = (c & 0x3F) | 0x80;
748  }
749  return 2;
750  }
751  if (c < 0x10000) {
752  if (s) {
753  *s++ = ((c >> 12) & 0x0F) | 0xE0;
754  *s++ = ((c >> 6) & 0x3F) | 0x80;
755  *s = (c & 0x3F) | 0x80;
756  }
757  return 3;
758  }
759  if (c < 0x110000) {
760  if (s) {
761  *s++ = ((c >> 18) & 0x07) | 0xF0;
762  *s++ = ((c >> 12) & 0x3F) | 0x80;
763  *s++ = ((c >> 6) & 0x3F) | 0x80;
764  *s = (c & 0x3F) | 0x80;
765  }
766  return 4;
767  }
768  return 0; // can't convert to UTF-8
769 }
770 
771 int Utf8SymChars(const char *s, int Symbols)
772 {
774  return Symbols;
775  int n = 0;
776  while (*s && Symbols--) {
777  int sl = Utf8CharLen(s);
778  s += sl;
779  n += sl;
780  }
781  return n;
782 }
783 
784 int Utf8StrLen(const char *s)
785 {
787  return strlen(s);
788  int n = 0;
789  while (*s) {
790  s += Utf8CharLen(s);
791  n++;
792  }
793  return n;
794 }
795 
796 char *Utf8Strn0Cpy(char *Dest, const char *Src, int n)
797 {
799  return strn0cpy(Dest, Src, n);
800  char *d = Dest;
801  while (*Src) {
802  int sl = Utf8CharLen(Src);
803  n -= sl;
804  if (n > 0) {
805  while (sl--)
806  *d++ = *Src++;
807  }
808  else
809  break;
810  }
811  *d = 0;
812  return Dest;
813 }
814 
815 int Utf8ToArray(const char *s, uint *a, int Size)
816 {
817  int n = 0;
818  while (*s && --Size > 0) {
820  *a++ = (uchar)(*s++);
821  else {
822  int sl = Utf8CharLen(s);
823  *a++ = Utf8CharGet(s, sl);
824  s += sl;
825  }
826  n++;
827  }
828  if (Size > 0)
829  *a = 0;
830  return n;
831 }
832 
833 int Utf8FromArray(const uint *a, char *s, int Size, int Max)
834 {
835  int NumChars = 0;
836  int NumSyms = 0;
837  while (*a && NumChars < Size) {
838  if (Max >= 0 && NumSyms++ >= Max)
839  break;
841  *s++ = *a++;
842  NumChars++;
843  }
844  else {
845  int sl = Utf8CharSet(*a);
846  if (NumChars + sl <= Size) {
847  Utf8CharSet(*a, s);
848  a++;
849  s += sl;
850  NumChars += sl;
851  }
852  else
853  break;
854  }
855  }
856  if (NumChars < Size)
857  *s = 0;
858  return NumChars;
859 }
860 
861 // --- cCharSetConv ----------------------------------------------------------
862 
864 
865 cCharSetConv::cCharSetConv(const char *FromCode, const char *ToCode)
866 {
867  if (!FromCode)
868  FromCode = systemCharacterTable ? systemCharacterTable : "UTF-8";
869  if (!ToCode)
870  ToCode = "UTF-8";
871  cd = iconv_open(ToCode, FromCode);
872  result = NULL;
873  length = 0;
874 }
875 
877 {
878  free(result);
879  if (cd != (iconv_t)-1)
880  iconv_close(cd);
881 }
882 
883 void cCharSetConv::SetSystemCharacterTable(const char *CharacterTable)
884 {
885  free(systemCharacterTable);
886  systemCharacterTable = NULL;
887  if (!strcasestr(CharacterTable, "UTF-8")) {
888  // Set up a map for the character values 128...255:
889  char buf[129];
890  for (int i = 0; i < 128; i++)
891  buf[i] = i + 128;
892  buf[128] = 0;
893  cCharSetConv csc(CharacterTable);
894  const char *s = csc.Convert(buf);
895  int i = 0;
896  while (*s) {
897  int sl = Utf8CharLen(s);
898  SystemToUtf8[i] = Utf8CharGet(s, sl);
899  s += sl;
900  i++;
901  }
902  systemCharacterTable = strdup(CharacterTable);
903  }
904 }
905 
906 const char *cCharSetConv::Convert(const char *From, char *To, size_t ToLength)
907 {
908  if (cd != (iconv_t)-1 && From && *From) {
909  char *FromPtr = (char *)From;
910  size_t FromLength = strlen(From);
911  char *ToPtr = To;
912  if (!ToPtr) {
913  int NewLength = max(length, FromLength * 2); // some reserve to avoid later reallocations
914  if (char *NewBuffer = (char *)realloc(result, NewLength)) {
915  length = NewLength;
916  result = NewBuffer;
917  }
918  else {
919  esyslog("ERROR: out of memory");
920  return From;
921  }
922  ToPtr = result;
923  ToLength = length;
924  }
925  else if (!ToLength)
926  return From; // can't convert into a zero sized buffer
927  ToLength--; // save space for terminating 0
928  char *Converted = ToPtr;
929  while (FromLength > 0) {
930  if (iconv(cd, &FromPtr, &FromLength, &ToPtr, &ToLength) == size_t(-1)) {
931  if (errno == E2BIG || errno == EILSEQ && ToLength < 1) {
932  if (To)
933  break; // caller provided a fixed size buffer, but it was too small
934  // The result buffer is too small, so increase it:
935  size_t d = ToPtr - result;
936  size_t r = length / 2;
937  int NewLength = length + r;
938  if (char *NewBuffer = (char *)realloc(result, NewLength)) {
939  length = NewLength;
940  Converted = result = NewBuffer;
941  }
942  else {
943  esyslog("ERROR: out of memory");
944  return From;
945  }
946  ToLength += r;
947  ToPtr = result + d;
948  }
949  if (errno == EILSEQ) {
950  // A character can't be converted, so mark it with '?' and proceed:
951  FromPtr++;
952  FromLength--;
953  *ToPtr++ = '?';
954  ToLength--;
955  }
956  else if (errno != E2BIG)
957  return From; // unknown error, return original string
958  }
959  }
960  *ToPtr = 0;
961  return Converted;
962  }
963  return From;
964 }
965 
966 // --- cString ---------------------------------------------------------------
967 
968 cString::cString(const char *S, bool TakePointer)
969 {
970  s = TakePointer ? (char *)S : S ? strdup(S) : NULL;
971 }
972 
973 cString::cString(const cString &String)
974 {
975  s = String.s ? strdup(String.s) : NULL;
976 }
977 
979 {
980  free(s);
981 }
982 
984 {
985  if (this == &String)
986  return *this;
987  free(s);
988  s = String.s ? strdup(String.s) : NULL;
989  return *this;
990 }
991 
992 cString &cString::operator=(const char *String)
993 {
994  if (s == String)
995  return *this;
996  free(s);
997  s = String ? strdup(String) : NULL;
998  return *this;
999 }
1000 
1002 {
1003  int l = strlen(s);
1004  if (Index < 0)
1005  Index = l + Index;
1006  if (Index >= 0 && Index < l)
1007  s[Index] = 0;
1008  return *this;
1009 }
1010 
1011 cString cString::sprintf(const char *fmt, ...)
1012 {
1013  va_list ap;
1014  va_start(ap, fmt);
1015  char *buffer;
1016  if (!fmt || vasprintf(&buffer, fmt, ap) < 0) {
1017  esyslog("error in vasprintf('%s', ...)", fmt);
1018  buffer = strdup("???");
1019  }
1020  va_end(ap);
1021  return cString(buffer, true);
1022 }
1023 
1024 cString cString::vsprintf(const char *fmt, va_list &ap)
1025 {
1026  char *buffer;
1027  if (!fmt || vasprintf(&buffer, fmt, ap) < 0) {
1028  esyslog("error in vasprintf('%s', ...)", fmt);
1029  buffer = strdup("???");
1030  }
1031  return cString(buffer, true);
1032 }
1033 
1034 cString WeekDayName(int WeekDay)
1035 {
1036  char buffer[16];
1037  WeekDay = WeekDay == 0 ? 6 : WeekDay - 1; // we start with Monday==0!
1038  if (0 <= WeekDay && WeekDay <= 6) {
1039  // TRANSLATORS: abbreviated weekdays, beginning with monday (must all be 3 letters!)
1040  const char *day = tr("MonTueWedThuFriSatSun");
1041  day += Utf8SymChars(day, WeekDay * 3);
1042  strn0cpy(buffer, day, min(Utf8SymChars(day, 3) + 1, int(sizeof(buffer))));
1043  return buffer;
1044  }
1045  else
1046  return "???";
1047 }
1048 
1050 {
1051  struct tm tm_r;
1052  return WeekDayName(localtime_r(&t, &tm_r)->tm_wday);
1053 }
1054 
1056 {
1057  WeekDay = WeekDay == 0 ? 6 : WeekDay - 1; // we start with Monday==0!
1058  switch (WeekDay) {
1059  case 0: return tr("Monday");
1060  case 1: return tr("Tuesday");
1061  case 2: return tr("Wednesday");
1062  case 3: return tr("Thursday");
1063  case 4: return tr("Friday");
1064  case 5: return tr("Saturday");
1065  case 6: return tr("Sunday");
1066  default: return "???";
1067  }
1068 }
1069 
1071 {
1072  struct tm tm_r;
1073  return WeekDayNameFull(localtime_r(&t, &tm_r)->tm_wday);
1074 }
1075 
1077 {
1078  char buffer[32];
1079  if (t == 0)
1080  time(&t);
1081  struct tm tm_r;
1082  tm *tm = localtime_r(&t, &tm_r);
1083  snprintf(buffer, sizeof(buffer), "%s %02d.%02d. %02d:%02d", *WeekDayName(tm->tm_wday), tm->tm_mday, tm->tm_mon + 1, tm->tm_hour, tm->tm_min);
1084  return buffer;
1085 }
1086 
1088 {
1089  char buffer[32];
1090  if (ctime_r(&t, buffer)) {
1091  buffer[strlen(buffer) - 1] = 0; // strip trailing newline
1092  return buffer;
1093  }
1094  return "???";
1095 }
1096 
1098 {
1099  char buf[32];
1100  struct tm tm_r;
1101  tm *tm = localtime_r(&t, &tm_r);
1102  char *p = stpcpy(buf, WeekDayName(tm->tm_wday));
1103  *p++ = ' ';
1104  strftime(p, sizeof(buf) - (p - buf), "%d.%m.%Y", tm);
1105  return buf;
1106 }
1107 
1109 {
1110  char buf[32];
1111  struct tm tm_r;
1112  tm *tm = localtime_r(&t, &tm_r);
1113  strftime(buf, sizeof(buf), "%d.%m.%y", tm);
1114  return buf;
1115 }
1116 
1118 {
1119  char buf[25];
1120  struct tm tm_r;
1121  strftime(buf, sizeof(buf), "%R", localtime_r(&t, &tm_r));
1122  return buf;
1123 }
1124 
1125 // --- RgbToJpeg -------------------------------------------------------------
1126 
1127 #define JPEGCOMPRESSMEM 500000
1128 
1129 struct tJpegCompressData {
1130  int size;
1131  uchar *mem;
1132  };
1133 
1134 static void JpegCompressInitDestination(j_compress_ptr cinfo)
1135 {
1136  tJpegCompressData *jcd = (tJpegCompressData *)cinfo->client_data;
1137  if (jcd) {
1138  cinfo->dest->free_in_buffer = jcd->size = JPEGCOMPRESSMEM;
1139  cinfo->dest->next_output_byte = jcd->mem = MALLOC(uchar, jcd->size);
1140  }
1141 }
1142 
1143 static boolean JpegCompressEmptyOutputBuffer(j_compress_ptr cinfo)
1144 {
1145  tJpegCompressData *jcd = (tJpegCompressData *)cinfo->client_data;
1146  if (jcd) {
1147  int Used = jcd->size;
1148  int NewSize = jcd->size + JPEGCOMPRESSMEM;
1149  if (uchar *NewBuffer = (uchar *)realloc(jcd->mem, NewSize)) {
1150  jcd->size = NewSize;
1151  jcd->mem = NewBuffer;
1152  }
1153  else {
1154  esyslog("ERROR: out of memory");
1155  return false;
1156  }
1157  if (jcd->mem) {
1158  cinfo->dest->next_output_byte = jcd->mem + Used;
1159  cinfo->dest->free_in_buffer = jcd->size - Used;
1160  return true;
1161  }
1162  }
1163  return false;
1164 }
1165 
1166 static void JpegCompressTermDestination(j_compress_ptr cinfo)
1167 {
1168  tJpegCompressData *jcd = (tJpegCompressData *)cinfo->client_data;
1169  if (jcd) {
1170  int Used = cinfo->dest->next_output_byte - jcd->mem;
1171  if (Used < jcd->size) {
1172  if (uchar *NewBuffer = (uchar *)realloc(jcd->mem, Used)) {
1173  jcd->size = Used;
1174  jcd->mem = NewBuffer;
1175  }
1176  else
1177  esyslog("ERROR: out of memory");
1178  }
1179  }
1180 }
1181 
1182 uchar *RgbToJpeg(uchar *Mem, int Width, int Height, int &Size, int Quality)
1183 {
1184  if (Quality < 0)
1185  Quality = 0;
1186  else if (Quality > 100)
1187  Quality = 100;
1188 
1189  jpeg_destination_mgr jdm;
1190 
1191  jdm.init_destination = JpegCompressInitDestination;
1192  jdm.empty_output_buffer = JpegCompressEmptyOutputBuffer;
1193  jdm.term_destination = JpegCompressTermDestination;
1194 
1195  struct jpeg_compress_struct cinfo;
1196  struct jpeg_error_mgr jerr;
1197  cinfo.err = jpeg_std_error(&jerr);
1198  jpeg_create_compress(&cinfo);
1199  cinfo.dest = &jdm;
1200  tJpegCompressData jcd;
1201  cinfo.client_data = &jcd;
1202  cinfo.image_width = Width;
1203  cinfo.image_height = Height;
1204  cinfo.input_components = 3;
1205  cinfo.in_color_space = JCS_RGB;
1206 
1207  jpeg_set_defaults(&cinfo);
1208  jpeg_set_quality(&cinfo, Quality, true);
1209  jpeg_start_compress(&cinfo, true);
1210 
1211  int rs = Width * 3;
1212  JSAMPROW rp[Height];
1213  for (int k = 0; k < Height; k++)
1214  rp[k] = &Mem[rs * k];
1215  jpeg_write_scanlines(&cinfo, rp, Height);
1216  jpeg_finish_compress(&cinfo);
1217  jpeg_destroy_compress(&cinfo);
1218 
1219  Size = jcd.size;
1220  return jcd.mem;
1221 }
1222 
1223 // --- cBase64Encoder --------------------------------------------------------
1224 
1225 const char *cBase64Encoder::b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
1226 
1227 cBase64Encoder::cBase64Encoder(const uchar *Data, int Length, int MaxResult)
1228 {
1229  data = Data;
1230  length = Length;
1231  maxResult = MaxResult;
1232  i = 0;
1233  result = MALLOC(char, maxResult + 1);
1234 }
1235 
1237 {
1238  free(result);
1239 }
1240 
1241 const char *cBase64Encoder::NextLine(void)
1242 {
1243  int r = 0;
1244  while (i < length && r < maxResult - 3) {
1245  result[r++] = b64[(data[i] >> 2) & 0x3F];
1246  uchar c = (data[i] << 4) & 0x3F;
1247  if (++i < length)
1248  c |= (data[i] >> 4) & 0x0F;
1249  result[r++] = b64[c];
1250  if (i < length) {
1251  c = (data[i] << 2) & 0x3F;
1252  if (++i < length)
1253  c |= (data[i] >> 6) & 0x03;
1254  result[r++] = b64[c];
1255  }
1256  else {
1257  i++;
1258  result[r++] = '=';
1259  }
1260  if (i < length) {
1261  c = data[i] & 0x3F;
1262  result[r++] = b64[c];
1263  }
1264  else
1265  result[r++] = '=';
1266  i++;
1267  }
1268  if (r > 0) {
1269  result[r] = 0;
1270  return result;
1271  }
1272  return NULL;
1273 }
1274 
1275 // --- cBitStream ------------------------------------------------------------
1276 
1278 {
1279  if (index >= length)
1280  return 1;
1281  int r = (data[index >> 3] >> (7 - (index & 7))) & 1;
1282  ++index;
1283  return r;
1284 }
1285 
1286 uint32_t cBitStream::GetBits(int n)
1287 {
1288  uint32_t r = 0;
1289  while (n--)
1290  r |= GetBit() << n;
1291  return r;
1292 }
1293 
1295 {
1296  int n = index % 8;
1297  if (n > 0)
1298  SkipBits(8 - n);
1299 }
1300 
1302 {
1303  int n = index % 16;
1304  if (n > 0)
1305  SkipBits(16 - n);
1306 }
1307 
1308 bool cBitStream::SetLength(int Length)
1309 {
1310  if (Length > length)
1311  return false;
1312  length = Length;
1313  return true;
1314 }
1315 
1316 // --- cReadLine -------------------------------------------------------------
1317 
1319 {
1320  size = 0;
1321  buffer = NULL;
1322 }
1323 
1325 {
1326  free(buffer);
1327 }
1328 
1329 char *cReadLine::Read(FILE *f)
1330 {
1331  int n = getline(&buffer, &size, f);
1332  if (n > 0) {
1333  n--;
1334  if (buffer[n] == '\n') {
1335  buffer[n] = 0;
1336  if (n > 0) {
1337  n--;
1338  if (buffer[n] == '\r')
1339  buffer[n] = 0;
1340  }
1341  }
1342  return buffer;
1343  }
1344  return NULL;
1345 }
1346 
1347 // --- cPoller ---------------------------------------------------------------
1348 
1349 cPoller::cPoller(int FileHandle, bool Out)
1350 {
1351  numFileHandles = 0;
1352  Add(FileHandle, Out);
1353 }
1354 
1355 bool cPoller::Add(int FileHandle, bool Out)
1356 {
1357  if (FileHandle >= 0) {
1358  for (int i = 0; i < numFileHandles; i++) {
1359  if (pfd[i].fd == FileHandle && pfd[i].events == (Out ? POLLOUT : POLLIN))
1360  return true;
1361  }
1362  if (numFileHandles < MaxPollFiles) {
1363  pfd[numFileHandles].fd = FileHandle;
1364  pfd[numFileHandles].events = Out ? POLLOUT : POLLIN;
1365  pfd[numFileHandles].revents = 0;
1366  numFileHandles++;
1367  return true;
1368  }
1369  esyslog("ERROR: too many file handles in cPoller");
1370  }
1371  return false;
1372 }
1373 
1374 bool cPoller::Poll(int TimeoutMs)
1375 {
1376  if (numFileHandles) {
1377  if (poll(pfd, numFileHandles, TimeoutMs) != 0)
1378  return true; // returns true even in case of an error, to let the caller
1379  // access the file and thus see the error code
1380  }
1381  return false;
1382 }
1383 
1384 // --- cReadDir --------------------------------------------------------------
1385 
1386 cReadDir::cReadDir(const char *Directory)
1387 {
1388  directory = opendir(Directory);
1389 }
1390 
1392 {
1393  if (directory)
1394  closedir(directory);
1395 }
1396 
1397 struct dirent *cReadDir::Next(void)
1398 {
1399  if (directory) {
1400  while (readdir_r(directory, &u.d, &result) == 0 && result) {
1401  if (strcmp(result->d_name, ".") && strcmp(result->d_name, ".."))
1402  return result;
1403  }
1404  }
1405  return NULL;
1406 }
1407 
1408 // --- cStringList -----------------------------------------------------------
1409 
1411 {
1412  Clear();
1413 }
1414 
1415 int cStringList::Find(const char *s) const
1416 {
1417  for (int i = 0; i < Size(); i++) {
1418  if (!strcmp(s, At(i)))
1419  return i;
1420  }
1421  return -1;
1422 }
1423 
1425 {
1426  for (int i = 0; i < Size(); i++)
1427  free(At(i));
1429 }
1430 
1431 // --- cFileNameList ---------------------------------------------------------
1432 
1433 // TODO better GetFileNames(const char *Directory, cStringList *List)?
1434 cFileNameList::cFileNameList(const char *Directory, bool DirsOnly)
1435 {
1436  Load(Directory, DirsOnly);
1437 }
1438 
1439 bool cFileNameList::Load(const char *Directory, bool DirsOnly)
1440 {
1441  Clear();
1442  if (Directory) {
1443  cReadDir d(Directory);
1444  struct dirent *e;
1445  if (d.Ok()) {
1446  while ((e = d.Next()) != NULL) {
1447  if (DirsOnly) {
1448  struct stat ds;
1449  if (stat(AddDirectory(Directory, e->d_name), &ds) == 0) {
1450  if (!S_ISDIR(ds.st_mode))
1451  continue;
1452  }
1453  }
1454  Append(strdup(e->d_name));
1455  }
1456  Sort();
1457  return true;
1458  }
1459  else
1460  LOG_ERROR_STR(Directory);
1461  }
1462  return false;
1463 }
1464 
1465 // --- cFile -----------------------------------------------------------------
1466 
1467 bool cFile::files[FD_SETSIZE] = { false };
1468 int cFile::maxFiles = 0;
1469 
1471 {
1472  f = -1;
1473 }
1474 
1476 {
1477  Close();
1478 }
1479 
1480 bool cFile::Open(const char *FileName, int Flags, mode_t Mode)
1481 {
1482  if (!IsOpen())
1483  return Open(open(FileName, Flags, Mode));
1484  esyslog("ERROR: attempt to re-open %s", FileName);
1485  return false;
1486 }
1487 
1488 bool cFile::Open(int FileDes)
1489 {
1490  if (FileDes >= 0) {
1491  if (!IsOpen()) {
1492  f = FileDes;
1493  if (f >= 0) {
1494  if (f < FD_SETSIZE) {
1495  if (f >= maxFiles)
1496  maxFiles = f + 1;
1497  if (!files[f])
1498  files[f] = true;
1499  else
1500  esyslog("ERROR: file descriptor %d already in files[]", f);
1501  return true;
1502  }
1503  else
1504  esyslog("ERROR: file descriptor %d is larger than FD_SETSIZE (%d)", f, FD_SETSIZE);
1505  }
1506  }
1507  else
1508  esyslog("ERROR: attempt to re-open file descriptor %d", FileDes);
1509  }
1510  return false;
1511 }
1512 
1513 void cFile::Close(void)
1514 {
1515  if (f >= 0) {
1516  close(f);
1517  files[f] = false;
1518  f = -1;
1519  }
1520 }
1521 
1522 bool cFile::Ready(bool Wait)
1523 {
1524  return f >= 0 && AnyFileReady(f, Wait ? 1000 : 0);
1525 }
1526 
1527 bool cFile::AnyFileReady(int FileDes, int TimeoutMs)
1528 {
1529  fd_set set;
1530  FD_ZERO(&set);
1531  for (int i = 0; i < maxFiles; i++) {
1532  if (files[i])
1533  FD_SET(i, &set);
1534  }
1535  if (0 <= FileDes && FileDes < FD_SETSIZE && !files[FileDes])
1536  FD_SET(FileDes, &set); // in case we come in with an arbitrary descriptor
1537  if (TimeoutMs == 0)
1538  TimeoutMs = 10; // load gets too heavy with 0
1539  struct timeval timeout;
1540  timeout.tv_sec = TimeoutMs / 1000;
1541  timeout.tv_usec = (TimeoutMs % 1000) * 1000;
1542  return select(FD_SETSIZE, &set, NULL, NULL, &timeout) > 0 && (FileDes < 0 || FD_ISSET(FileDes, &set));
1543 }
1544 
1545 bool cFile::FileReady(int FileDes, int TimeoutMs)
1546 {
1547  fd_set set;
1548  struct timeval timeout;
1549  FD_ZERO(&set);
1550  FD_SET(FileDes, &set);
1551  if (TimeoutMs >= 0) {
1552  if (TimeoutMs < 100)
1553  TimeoutMs = 100;
1554  timeout.tv_sec = TimeoutMs / 1000;
1555  timeout.tv_usec = (TimeoutMs % 1000) * 1000;
1556  }
1557  return select(FD_SETSIZE, &set, NULL, NULL, (TimeoutMs >= 0) ? &timeout : NULL) > 0 && FD_ISSET(FileDes, &set);
1558 }
1559 
1560 bool cFile::FileReadyForWriting(int FileDes, int TimeoutMs)
1561 {
1562  fd_set set;
1563  struct timeval timeout;
1564  FD_ZERO(&set);
1565  FD_SET(FileDes, &set);
1566  if (TimeoutMs < 100)
1567  TimeoutMs = 100;
1568  timeout.tv_sec = 0;
1569  timeout.tv_usec = TimeoutMs * 1000;
1570  return select(FD_SETSIZE, NULL, &set, NULL, &timeout) > 0 && FD_ISSET(FileDes, &set);
1571 }
1572 
1573 // --- cSafeFile -------------------------------------------------------------
1574 
1575 cSafeFile::cSafeFile(const char *FileName)
1576 {
1577  f = NULL;
1578  fileName = ReadLink(FileName);
1579  tempName = fileName ? MALLOC(char, strlen(fileName) + 5) : NULL;
1580  if (tempName)
1581  strcat(strcpy(tempName, fileName), ".$$$");
1582 }
1583 
1585 {
1586  if (f)
1587  fclose(f);
1588  unlink(tempName);
1589  free(fileName);
1590  free(tempName);
1591 }
1592 
1594 {
1595  if (!f && fileName && tempName) {
1596  f = fopen(tempName, "w");
1597  if (!f)
1599  }
1600  return f != NULL;
1601 }
1602 
1604 {
1605  bool result = true;
1606  if (f) {
1607  if (ferror(f) != 0) {
1609  result = false;
1610  }
1611  fflush(f);
1612  fsync(fileno(f));
1613  if (fclose(f) < 0) {
1615  result = false;
1616  }
1617  f = NULL;
1618  if (result && rename(tempName, fileName) < 0) {
1620  result = false;
1621  }
1622  }
1623  else
1624  result = false;
1625  return result;
1626 }
1627 
1628 // --- cUnbufferedFile -------------------------------------------------------
1629 
1630 #define USE_FADVISE
1631 
1632 #define WRITE_BUFFER KILOBYTE(800)
1633 
1635 {
1636  fd = -1;
1637 }
1638 
1640 {
1641  Close();
1642 }
1643 
1644 int cUnbufferedFile::Open(const char *FileName, int Flags, mode_t Mode)
1645 {
1646  Close();
1647  fd = open(FileName, Flags, Mode);
1648  curpos = 0;
1649 #ifdef USE_FADVISE
1650  begin = lastpos = ahead = 0;
1651  cachedstart = 0;
1652  cachedend = 0;
1653  readahead = KILOBYTE(128);
1654  written = 0;
1655  totwritten = 0;
1656  if (fd >= 0)
1657  posix_fadvise(fd, 0, 0, POSIX_FADV_RANDOM); // we could use POSIX_FADV_SEQUENTIAL, but we do our own readahead, disabling the kernel one.
1658 #endif
1659  return fd;
1660 }
1661 
1663 {
1664  if (fd >= 0) {
1665 #ifdef USE_FADVISE
1666  if (totwritten) // if we wrote anything make sure the data has hit the disk before
1667  fdatasync(fd); // calling fadvise, as this is our last chance to un-cache it.
1668  posix_fadvise(fd, 0, 0, POSIX_FADV_DONTNEED);
1669 #endif
1670  int OldFd = fd;
1671  fd = -1;
1672  return close(OldFd);
1673  }
1674  errno = EBADF;
1675  return -1;
1676 }
1677 
1678 // When replaying and going e.g. FF->PLAY the position jumps back 2..8M
1679 // hence we do not want to drop recently accessed data at once.
1680 // We try to handle the common cases such as PLAY->FF->PLAY, small
1681 // jumps, moving editing marks etc.
1682 
1683 #define FADVGRAN KILOBYTE(4) // AKA fadvise-chunk-size; PAGE_SIZE or getpagesize(2) would also work.
1684 #define READCHUNK MEGABYTE(8)
1685 
1687 {
1688  readahead = ra;
1689 }
1690 
1691 int cUnbufferedFile::FadviseDrop(off_t Offset, off_t Len)
1692 {
1693  // rounding up the window to make sure that not PAGE_SIZE-aligned data gets freed.
1694  return posix_fadvise(fd, Offset - (FADVGRAN - 1), Len + (FADVGRAN - 1) * 2, POSIX_FADV_DONTNEED);
1695 }
1696 
1697 off_t cUnbufferedFile::Seek(off_t Offset, int Whence)
1698 {
1699  if (Whence == SEEK_SET && Offset == curpos)
1700  return curpos;
1701  curpos = lseek(fd, Offset, Whence);
1702  return curpos;
1703 }
1704 
1705 ssize_t cUnbufferedFile::Read(void *Data, size_t Size)
1706 {
1707  if (fd >= 0) {
1708 #ifdef USE_FADVISE
1709  off_t jumped = curpos-lastpos; // nonzero means we're not at the last offset
1710  if ((cachedstart < cachedend) && (curpos < cachedstart || curpos > cachedend)) {
1711  // current position is outside the cached window -- invalidate it.
1712  FadviseDrop(cachedstart, cachedend-cachedstart);
1713  cachedstart = curpos;
1714  cachedend = curpos;
1715  }
1717 #endif
1718  ssize_t bytesRead = safe_read(fd, Data, Size);
1719  if (bytesRead > 0) {
1720  curpos += bytesRead;
1721 #ifdef USE_FADVISE
1722  cachedend = max(cachedend, curpos);
1723 
1724  // Read ahead:
1725  // no jump? (allow small forward jump still inside readahead window).
1726  if (jumped >= 0 && jumped <= (off_t)readahead) {
1727  // Trigger the readahead IO, but only if we've used at least
1728  // 1/2 of the previously requested area. This avoids calling
1729  // fadvise() after every read() call.
1730  if (ahead - curpos < (off_t)(readahead / 2)) {
1731  posix_fadvise(fd, curpos, readahead, POSIX_FADV_WILLNEED);
1732  ahead = curpos + readahead;
1733  cachedend = max(cachedend, ahead);
1734  }
1735  if (readahead < Size * 32) { // automagically tune readahead size.
1736  readahead = Size * 32;
1737  }
1738  }
1739  else
1740  ahead = curpos; // jumped -> we really don't want any readahead, otherwise e.g. fast-rewind gets in trouble.
1741 #endif
1742  }
1743 #ifdef USE_FADVISE
1744  if (cachedstart < cachedend) {
1745  if (curpos - cachedstart > READCHUNK * 2) {
1746  // current position has moved forward enough, shrink tail window.
1749  }
1750  else if (cachedend > ahead && cachedend - curpos > READCHUNK * 2) {
1751  // current position has moved back enough, shrink head window.
1752  FadviseDrop(curpos + READCHUNK, cachedend - (curpos + READCHUNK));
1753  cachedend = curpos + READCHUNK;
1754  }
1755  }
1756  lastpos = curpos;
1757 #endif
1758  return bytesRead;
1759  }
1760  return -1;
1761 }
1762 
1763 ssize_t cUnbufferedFile::Write(const void *Data, size_t Size)
1764 {
1765  if (fd >=0) {
1766  ssize_t bytesWritten = safe_write(fd, Data, Size);
1767 #ifdef USE_FADVISE
1768  if (bytesWritten > 0) {
1769  begin = min(begin, curpos);
1770  curpos += bytesWritten;
1771  written += bytesWritten;
1772  lastpos = max(lastpos, curpos);
1773  if (written > WRITE_BUFFER) {
1774  if (lastpos > begin) {
1775  // Now do three things:
1776  // 1) Start writeback of begin..lastpos range
1777  // 2) Drop the already written range (by the previous fadvise call)
1778  // 3) Handle nonpagealigned data.
1779  // This is why we double the WRITE_BUFFER; the first time around the
1780  // last (partial) page might be skipped, writeback will start only after
1781  // second call; the third call will still include this page and finally
1782  // drop it from cache.
1783  off_t headdrop = min(begin, off_t(WRITE_BUFFER * 2));
1784  posix_fadvise(fd, begin - headdrop, lastpos - begin + headdrop, POSIX_FADV_DONTNEED);
1785  }
1786  begin = lastpos = curpos;
1787  totwritten += written;
1788  written = 0;
1789  // The above fadvise() works when writing slowly (recording), but could
1790  // leave cached data around when writing at a high rate, e.g. when cutting,
1791  // because by the time we try to flush the cached pages (above) the data
1792  // can still be dirty - we are faster than the disk I/O.
1793  // So we do another round of flushing, just like above, but at larger
1794  // intervals -- this should catch any pages that couldn't be released
1795  // earlier.
1796  if (totwritten > MEGABYTE(32)) {
1797  // It seems in some setups, fadvise() does not trigger any I/O and
1798  // a fdatasync() call would be required do all the work (reiserfs with some
1799  // kind of write gathering enabled), but the syncs cause (io) load..
1800  // Uncomment the next line if you think you need them.
1801  //fdatasync(fd);
1802  off_t headdrop = min(off_t(curpos - totwritten), off_t(totwritten * 2));
1803  posix_fadvise(fd, curpos - totwritten - headdrop, totwritten + headdrop, POSIX_FADV_DONTNEED);
1804  totwritten = 0;
1805  }
1806  }
1807  }
1808 #endif
1809  return bytesWritten;
1810  }
1811  return -1;
1812 }
1813 
1814 cUnbufferedFile *cUnbufferedFile::Create(const char *FileName, int Flags, mode_t Mode)
1815 {
1816  cUnbufferedFile *File = new cUnbufferedFile;
1817  if (File->Open(FileName, Flags, Mode) < 0) {
1818  delete File;
1819  File = NULL;
1820  }
1821  return File;
1822 }
1823 
1824 // --- cLockFile -------------------------------------------------------------
1825 
1826 #define LOCKFILENAME ".lock-vdr"
1827 #define LOCKFILESTALETIME 600 // seconds before considering a lock file "stale"
1828 
1829 cLockFile::cLockFile(const char *Directory)
1830 {
1831  fileName = NULL;
1832  f = -1;
1833  if (DirectoryOk(Directory))
1834  fileName = strdup(AddDirectory(Directory, LOCKFILENAME));
1835 }
1836 
1838 {
1839  Unlock();
1840  free(fileName);
1841 }
1842 
1843 bool cLockFile::Lock(int WaitSeconds)
1844 {
1845  if (f < 0 && fileName) {
1846  time_t Timeout = time(NULL) + WaitSeconds;
1847  do {
1848  f = open(fileName, O_WRONLY | O_CREAT | O_EXCL, DEFFILEMODE);
1849  if (f < 0) {
1850  if (errno == EEXIST) {
1851  struct stat fs;
1852  if (stat(fileName, &fs) == 0) {
1853  if (abs(time(NULL) - fs.st_mtime) > LOCKFILESTALETIME) {
1854  esyslog("ERROR: removing stale lock file '%s'", fileName);
1855  if (remove(fileName) < 0) {
1857  break;
1858  }
1859  continue;
1860  }
1861  }
1862  else if (errno != ENOENT) {
1864  break;
1865  }
1866  }
1867  else {
1869  break;
1870  }
1871  if (WaitSeconds)
1872  cCondWait::SleepMs(1000);
1873  }
1874  } while (f < 0 && time(NULL) < Timeout);
1875  }
1876  return f >= 0;
1877 }
1878 
1880 {
1881  if (f >= 0) {
1882  close(f);
1883  remove(fileName);
1884  f = -1;
1885  }
1886 }
1887 
1888 // --- cListObject -----------------------------------------------------------
1889 
1891 {
1892  prev = next = NULL;
1893 }
1894 
1896 {
1897 }
1898 
1900 {
1901  next = Object;
1902  Object->prev = this;
1903 }
1904 
1906 {
1907  prev = Object;
1908  Object->next = this;
1909 }
1910 
1912 {
1913  if (next)
1914  next->prev = prev;
1915  if (prev)
1916  prev->next = next;
1917  next = prev = NULL;
1918 }
1919 
1920 int cListObject::Index(void) const
1921 {
1922  cListObject *p = prev;
1923  int i = 0;
1924 
1925  while (p) {
1926  i++;
1927  p = p->prev;
1928  }
1929  return i;
1930 }
1931 
1932 // --- cListBase -------------------------------------------------------------
1933 
1935 {
1936  objects = lastObject = NULL;
1937  count = 0;
1938 }
1939 
1941 {
1942  Clear();
1943 }
1944 
1946 {
1947  if (After && After != lastObject) {
1948  After->Next()->Insert(Object);
1949  After->Append(Object);
1950  }
1951  else {
1952  if (lastObject)
1953  lastObject->Append(Object);
1954  else
1955  objects = Object;
1956  lastObject = Object;
1957  }
1958  count++;
1959 }
1960 
1962 {
1963  if (Before && Before != objects) {
1964  Before->Prev()->Append(Object);
1965  Before->Insert(Object);
1966  }
1967  else {
1968  if (objects)
1969  objects->Insert(Object);
1970  else
1971  lastObject = Object;
1972  objects = Object;
1973  }
1974  count++;
1975 }
1976 
1977 void cListBase::Del(cListObject *Object, bool DeleteObject)
1978 {
1979  if (Object == objects)
1980  objects = Object->Next();
1981  if (Object == lastObject)
1982  lastObject = Object->Prev();
1983  Object->Unlink();
1984  if (DeleteObject)
1985  delete Object;
1986  count--;
1987 }
1988 
1989 void cListBase::Move(int From, int To)
1990 {
1991  Move(Get(From), Get(To));
1992 }
1993 
1995 {
1996  if (From && To && From != To) {
1997  if (From->Index() < To->Index())
1998  To = To->Next();
1999  if (From == objects)
2000  objects = From->Next();
2001  if (From == lastObject)
2002  lastObject = From->Prev();
2003  From->Unlink();
2004  if (To) {
2005  if (To->Prev())
2006  To->Prev()->Append(From);
2007  From->Append(To);
2008  }
2009  else {
2010  lastObject->Append(From);
2011  lastObject = From;
2012  }
2013  if (!From->Prev())
2014  objects = From;
2015  }
2016 }
2017 
2019 {
2020  while (objects) {
2021  cListObject *object = objects->Next();
2022  delete objects;
2023  objects = object;
2024  }
2025  objects = lastObject = NULL;
2026  count = 0;
2027 }
2028 
2029 cListObject *cListBase::Get(int Index) const
2030 {
2031  if (Index < 0)
2032  return NULL;
2033  cListObject *object = objects;
2034  while (object && Index-- > 0)
2035  object = object->Next();
2036  return object;
2037 }
2038 
2039 static int CompareListObjects(const void *a, const void *b)
2040 {
2041  const cListObject *la = *(const cListObject **)a;
2042  const cListObject *lb = *(const cListObject **)b;
2043  return la->Compare(*lb);
2044 }
2045 
2047 {
2048  int n = Count();
2049  cListObject *a[n];
2050  cListObject *object = objects;
2051  int i = 0;
2052  while (object && i < n) {
2053  a[i++] = object;
2054  object = object->Next();
2055  }
2056  qsort(a, n, sizeof(cListObject *), CompareListObjects);
2057  objects = lastObject = NULL;
2058  for (i = 0; i < n; i++) {
2059  a[i]->Unlink();
2060  count--;
2061  Add(a[i]);
2062  }
2063 }
2064 
2065 // --- cHashBase -------------------------------------------------------------
2066 
2068 {
2069  size = Size;
2070  hashTable = (cList<cHashObject>**)calloc(size, sizeof(cList<cHashObject>*));
2071 }
2072 
2074 {
2075  Clear();
2076  free(hashTable);
2077 }
2078 
2079 void cHashBase::Add(cListObject *Object, unsigned int Id)
2080 {
2081  unsigned int hash = hashfn(Id);
2082  if (!hashTable[hash])
2083  hashTable[hash] = new cList<cHashObject>;
2084  hashTable[hash]->Add(new cHashObject(Object, Id));
2085 }
2086 
2087 void cHashBase::Del(cListObject *Object, unsigned int Id)
2088 {
2089  cList<cHashObject> *list = hashTable[hashfn(Id)];
2090  if (list) {
2091  for (cHashObject *hob = list->First(); hob; hob = list->Next(hob)) {
2092  if (hob->object == Object) {
2093  list->Del(hob);
2094  break;
2095  }
2096  }
2097  }
2098 }
2099 
2101 {
2102  for (int i = 0; i < size; i++) {
2103  delete hashTable[i];
2104  hashTable[i] = NULL;
2105  }
2106 }
2107 
2108 cListObject *cHashBase::Get(unsigned int Id) const
2109 {
2110  cList<cHashObject> *list = hashTable[hashfn(Id)];
2111  if (list) {
2112  for (cHashObject *hob = list->First(); hob; hob = list->Next(hob)) {
2113  if (hob->id == Id)
2114  return hob->object;
2115  }
2116  }
2117  return NULL;
2118 }
2119 
2121 {
2122  return hashTable[hashfn(Id)];
2123 }
int Find(const char *s) const
Definition: tools.c:1415
cString dtoa(double d, const char *Format)
Converts the given double value to a string, making sure it uses a '.
Definition: tools.c:329
struct dirent * Next(void)
Definition: tools.c:1397
cListObject * next
Definition: tools.h:446
iconv_t cd
Definition: tools.h:141
cString itoa(int n)
Definition: tools.c:339
void Append(cListObject *Object)
Definition: tools.c:1899
unsigned char uchar
Definition: tools.h:30
int f
Definition: tools.h:436
static unsigned char buf(long p)
Definition: vdr-genindex.c:63
#define LOCKFILESTALETIME
Definition: tools.c:1827
~cFile()
Definition: tools.c:1475
ssize_t Write(const void *Data, size_t Size)
Definition: tools.c:1763
cListObject * prev
Definition: tools.h:446
virtual void Clear(void)
Definition: tools.c:1424
bool isempty(const char *s)
Definition: tools.c:248
#define dsyslog(a...)
Definition: tools.h:36
off_t curpos
Definition: tools.h:411
cString AddDirectory(const char *DirName, const char *FileName)
Definition: tools.c:301
int Index(void) const
Definition: tools.c:1920
int Utf8StrLen(const char *s)
Returns the number of UTF-8 symbols formed by the given string of character bytes.
Definition: tools.c:784
bool isnumber(const char *s)
Definition: tools.c:263
void Set(int Ms=0)
Definition: tools.c:689
bool Close(void)
Definition: tools.c:1603
cString(const char *S=NULL, bool TakePointer=false)
Definition: tools.c:968
bool Ready(bool Wait=true)
Definition: tools.c:1522
cListObject * Get(unsigned int Id) const
Definition: tools.c:2108
cList< cHashObject > * GetList(unsigned int Id) const
Definition: tools.c:2120
virtual ~cStringList()
Definition: tools.c:1410
uint32_t GetBits(int n)
Definition: tools.c:1286
void Clear(void)
Definition: tools.c:2100
void Add(cListObject *Object, cListObject *After=NULL)
Definition: tools.c:1945
cTimeMs(int Ms=0)
Creates a timer with ms resolution and an initial timeout of Ms.
Definition: tools.c:638
size_t totwritten
Definition: tools.h:419
~cReadDir()
Definition: tools.c:1391
static char * systemCharacterTable
Definition: tools.h:144
char * stripspace(char *s)
Definition: tools.c:176
bool DirectoryOk(const char *DirName, bool LogErrors)
Definition: tools.c:378
bool Open(void)
Definition: tools.c:1593
ssize_t Read(void *Data, size_t Size)
Definition: tools.c:1705
static const char * SystemCharacterTable(void)
Definition: tools.h:162
bool MakeDirs(const char *FileName, bool IsDirectory)
Definition: tools.c:396
bool endswith(const char *s, const char *p)
Definition: tools.c:237
static cString sprintf(const char *fmt,...) __attribute__((format(printf
Definition: tools.c:1011
off_t Seek(off_t Offset, int Whence)
Definition: tools.c:1697
static bool FileReady(int FileDes, int TimeoutMs=1000)
Definition: tools.c:1545
virtual void Append(char *Data)
Definition: tools.h:545
void Del(cListObject *Object, unsigned int Id)
Definition: tools.c:2087
void Unlink(void)
Definition: tools.c:1911
bool Add(int FileHandle, bool Out)
Definition: tools.c:1355
#define esyslog(a...)
Definition: tools.h:34
cString & Truncate(int Index)
Truncate the string at the given Index (if Index is < 0 it is counted from the end of the string)...
Definition: tools.c:1001
char * strn0cpy(char *dest, const char *src, size_t n)
Definition: tools.c:131
cUnbufferedFile(void)
Definition: tools.c:1634
char * tempName
Definition: tools.h:396
bool TimedOut(void)
Definition: tools.c:694
int BCD2INT(int x)
Definition: tools.c:45
void Unlock(void)
Definition: tools.c:1879
#define LOG_ERROR_STR(s)
Definition: tools.h:39
T max(T a, T b)
Definition: tools.h:55
cReadDir(const char *Directory)
Definition: tools.c:1386
pollfd pfd[MaxPollFiles]
Definition: tools.h:350
DIR * directory
Definition: tools.h:360
void syslog_with_tid(int priority, const char *format,...)
Definition: tools.c:35
off_t lastpos
Definition: tools.h:415
double atod(const char *s)
Converts the given string, which is a floating point number using a '.
Definition: tools.c:308
int DirSizeMB(const char *DirName)
returns the total size of the files in the given directory, or -1 in case of an error ...
Definition: tools.c:536
int Count(void) const
Definition: tools.h:475
char * ReadLink(const char *FileName)
returns a new string allocated on the heap, which the caller must delete (or NULL in case of an error...
Definition: tools.c:568
T min(T a, T b)
Definition: tools.h:54
void WordAlign(void)
Definition: tools.c:1301
cUnbufferedFile is used for large files that are mainly written or read in a streaming manner...
Definition: tools.h:408
const char * Convert(const char *From, char *To=NULL, size_t ToLength=0)
Converts the given Text from FromCode to ToCode (as set in the constructor).
Definition: tools.c:906
cCharSetConv(const char *FromCode=NULL, const char *ToCode=NULL)
Sets up a character set converter to convert from FromCode to ToCode.
Definition: tools.c:865
bool Poll(int TimeoutMs=0)
Definition: tools.c:1374
uint64_t Elapsed(void)
Definition: tools.c:699
int Open(const char *FileName, int Flags, mode_t Mode=DEFFILEMODE)
Definition: tools.c:1644
int SysLogLevel
Definition: tools.c:31
char * Read(FILE *f)
Definition: tools.c:1329
int Length(void) const
Definition: tools.h:318
#define MALLOC(type, size)
Definition: tools.h:46
virtual void Clear(void)
Definition: tools.c:2018
#define JPEGCOMPRESSMEM
Definition: tools.c:1127
#define MT(s, m, v)
char * buffer
Definition: tools.h:340
~cSafeFile()
Definition: tools.c:1584
uint64_t begin
Definition: tools.h:325
#define MAXSYSLOGBUF
Definition: tools.c:33
int Utf8CharSet(uint c, char *s)
Converts the given UTF-8 symbol to a sequence of character bytes and copies them to the given string...
Definition: tools.c:737
bool IsOpen(void)
Definition: tools.h:385
cList< cHashObject > ** hashTable
Definition: tools.h:612
virtual ~cListBase()
Definition: tools.c:1940
#define DECIMAL_POINT_C
Definition: tools.c:306
cString TimeToString(time_t t)
Converts the given time to a string of the form "www mmm dd hh:mm:ss yyyy".
Definition: tools.c:1087
static cString static cString vsprintf(const char *fmt, va_list &ap)
Definition: tools.c:1024
cBase64Encoder(const uchar *Data, int Length, int MaxResult=64)
Sets up a new base 64 encoder for the given Data, with the given Length.
Definition: tools.c:1227
int f
Definition: tools.h:377
off_t begin
Definition: tools.h:414
virtual int Compare(const cListObject &ListObject) const
Must return 0 if this object is equal to ListObject, a positive value if it is "greater", and a negative value if it is "smaller".
Definition: tools.h:450
T * Next(const T *object) const
Definition: tools.h:485
ssize_t safe_write(int filedes, const void *buffer, size_t size)
Definition: tools.c:65
cString WeekDayName(int WeekDay)
Converts the given WeekDay (0=Sunday, 1=Monday, ...) to a three letter day name.
Definition: tools.c:1034
static void JpegCompressInitDestination(j_compress_ptr cinfo)
Definition: tools.c:1134
static int maxFiles
Definition: tools.h:376
cListObject * Next(void) const
Definition: tools.h:458
int Utf8CharLen(const char *s)
Returns the number of character bytes at the beginning of the given string that form a UTF-8 symbol...
Definition: tools.c:708
const uchar * data
Definition: tools.h:279
~cCharSetConv()
Definition: tools.c:876
static boolean JpegCompressEmptyOutputBuffer(j_compress_ptr cinfo)
Definition: tools.c:1143
#define LOCKFILENAME
Definition: tools.c:1826
virtual ~cString()
Definition: tools.c:978
cListObject(void)
Definition: tools.c:1890
static void SleepMs(int TimeoutMs)
Creates a cCondWait object and uses it to sleep for TimeoutMs milliseconds, immediately giving up the...
Definition: thread.c:57
int length
Definition: tools.h:280
cReadLine(void)
Definition: tools.c:1318
void Sort(void)
Definition: tools.c:2046
void Ins(cListObject *Object, cListObject *Before=NULL)
Definition: tools.c:1961
~cReadLine()
Definition: tools.c:1324
#define WRITE_BUFFER
Definition: tools.c:1632
bool Ok(void)
Definition: tools.h:369
cFileNameList(const char *Directory=NULL, bool DirsOnly=false)
Definition: tools.c:1434
int FreeDiskSpaceMB(const char *Directory, int *UsedMB)
Definition: tools.c:361
bool Open(const char *FileName, int Flags, mode_t Mode=DEFFILEMODE)
Definition: tools.c:1480
const char * NextLine(void)
Returns the next line of encoded data (terminated by '\0'), or NULL if there is no more encoded data...
Definition: tools.c:1241
union cReadDir::@24 u
cString DayDateTime(time_t t)
Converts the given time to a string of the form "www dd.mm. hh:mm".
Definition: tools.c:1076
static void SetSystemCharacterTable(const char *CharacterTable)
Definition: tools.c:883
int numdigits(int n)
Definition: tools.c:253
static tThreadId ThreadId(void)
Definition: thread.c:341
int Size(void) const
Definition: tools.h:533
off_t ahead
Definition: tools.h:416
cFile(void)
Definition: tools.c:1470
void SkipBits(int n)
Definition: tools.h:314
size_t readahead
Definition: tools.h:417
cListBase(void)
Definition: tools.c:1934
static uint SystemToUtf8[128]
Definition: tools.c:706
cPoller(int FileHandle=-1, bool Out=false)
Definition: tools.c:1349
unsigned int hashfn(unsigned int Id) const
Definition: tools.h:614
virtual ~cListObject()
Definition: tools.c:1895
cListObject * objects
Definition: tools.h:463
#define FADVGRAN
Definition: tools.c:1683
cListObject * lastObject
Definition: tools.h:463
char * fileName
Definition: tools.h:395
bool Lock(int WaitSeconds=0)
Definition: tools.c:1843
#define BCDCHARTOINT(x)
Definition: tools.h:64
cString WeekDayNameFull(int WeekDay)
Converts the given WeekDay (0=Sunday, 1=Monday, ...) to a full day name.
Definition: tools.c:1055
FILE * f
Definition: tools.h:394
uchar * RgbToJpeg(uchar *Mem, int Width, int Height, int &Size, int Quality)
Converts the given Memory to a JPEG image and returns a pointer to the resulting image.
Definition: tools.c:1182
bool Load(const char *Directory, bool DirsOnly=false)
Definition: tools.c:1439
int64_t StrToNum(const char *s)
Converts the given string to a number.
Definition: tools.c:274
bool SpinUpDisk(const char *FileName)
Definition: tools.c:582
int WriteAllOrNothing(int fd, const uchar *Data, int Length, int TimeoutMs, int RetryMs)
Writes either all Data to the given file descriptor, or nothing at all.
Definition: tools.c:90
bool startswith(const char *s, const char *p)
Definition: tools.c:228
#define MEGABYTE(n)
Definition: tools.h:44
void SetReadAhead(size_t ra)
Definition: tools.c:1686
cListObject * Prev(void) const
Definition: tools.h:457
T * First(void) const
Definition: tools.h:482
void Del(cListObject *Object, bool DeleteObject=true)
Definition: tools.c:1977
const uint8_t * data
Definition: tools.h:303
cListObject * Get(int Index) const
Definition: tools.c:2029
cLockFile(const char *Directory)
Definition: tools.c:1829
#define FATALERRNO
Definition: tools.h:51
int maxResult
Definition: tools.h:281
int Utf8ToArray(const char *s, uint *a, int Size)
Converts the given character bytes (including the terminating 0) into an array of UTF-8 symbols of th...
Definition: tools.c:815
struct dirent * result
Definition: tools.h:361
static bool FileReadyForWriting(int FileDes, int TimeoutMs=1000)
Definition: tools.c:1560
off_t FileSize(const char *FileName)
returns the size of the given file, or -1 in case of an error (e.g. if the file doesn't exist) ...
Definition: tools.c:628
#define KILOBYTE(n)
Definition: tools.h:43
static void JpegCompressTermDestination(j_compress_ptr cinfo)
Definition: tools.c:1166
#define tr(s)
Definition: i18n.h:85
int numFileHandles
Definition: tools.h:351
size_t written
Definition: tools.h:418
virtual void Move(int From, int To)
Definition: tools.c:1989
char * s
Definition: tools.h:168
virtual ~cHashBase()
Definition: tools.c:2073
char * skipspace(const char *s)
Definition: tools.h:194
bool EntriesOnSameFileSystem(const char *File1, const char *File2)
Definition: tools.c:346
off_t cachedstart
Definition: tools.h:412
uint Utf8CharGet(const char *s, int Length)
Returns the UTF-8 symbol at the beginning of the given string.
Definition: tools.c:722
int Utf8FromArray(const uint *a, char *s, int Size, int Max)
Converts the given array of UTF-8 symbols (including the terminating 0) into a sequence of character ...
Definition: tools.c:833
int GetBit(void)
Definition: tools.c:1277
int count
Definition: tools.h:465
cSafeFile(const char *FileName)
Definition: tools.c:1575
cString TimeString(time_t t)
Converts the given time to a string of the form "hh:mm".
Definition: tools.c:1117
char * strcpyrealloc(char *dest, const char *src)
Definition: tools.c:114
static bool files[]
Definition: tools.h:375
bool StrInArray(const char *a[], const char *s)
Returns true if the string s is equal to one of the strings pointed to by the (NULL terminated) array...
Definition: tools.c:289
void Sort(bool IgnoreCase=false)
Definition: tools.h:584
ssize_t safe_read(int filedes, void *buffer, size_t size)
Definition: tools.c:53
bool RemoveEmptyDirectories(const char *DirName, bool RemoveThis, const char *IgnoreFiles[])
Removes all empty directories under the given directory DirName.
Definition: tools.c:482
int size
Definition: tools.h:613
void Add(cListObject *Object, unsigned int Id)
Definition: tools.c:2079
Definition: tools.h:323
cString ShortDateString(time_t t)
Converts the given time to a string of the form "dd.mm.yy".
Definition: tools.c:1108
static uint64_t Now(void)
Definition: tools.c:646
bool SetLength(int Length)
Definition: tools.c:1308
char * result
Definition: tools.h:283
static int CompareListObjects(const void *a, const void *b)
Definition: tools.c:2039
static cUnbufferedFile * Create(const char *FileName, int Flags, mode_t Mode=DEFFILEMODE)
Definition: tools.c:1814
cHashBase(int Size)
Definition: tools.c:2067
bool RemoveFileOrDir(const char *FileName, bool FollowSymlinks)
Definition: tools.c:424
void TouchFile(const char *FileName)
Definition: tools.c:614
char * result
Definition: tools.h:142
cString & operator=(const cString &String)
Definition: tools.c:983
#define READCHUNK
Definition: tools.c:1684
~cLockFile()
Definition: tools.c:1837
char * compactspace(char *s)
Definition: tools.c:188
cString strescape(const char *s, const char *chars)
Definition: tools.c:205
char * Utf8Strn0Cpy(char *Dest, const char *Src, int n)
Copies at most n character bytes from Src to Dest, making sure that the resulting copy ends with a co...
Definition: tools.c:796
int index
Definition: tools.h:305
void Close(void)
Definition: tools.c:1513
char *& At(int Index) const
Definition: tools.h:518
virtual void Clear(void)
Definition: tools.h:557
Definition: tools.h:347
int length
Definition: tools.h:304
size_t size
Definition: tools.h:339
static bool AnyFileReady(int FileDes=-1, int TimeoutMs=1000)
Definition: tools.c:1527
off_t cachedend
Definition: tools.h:413
~cUnbufferedFile()
Definition: tools.c:1639
int Utf8SymChars(const char *s, int Symbols)
Returns the number of character bytes at the beginning of the given string that form at most the give...
Definition: tools.c:771
int FadviseDrop(off_t Offset, off_t Len)
Definition: tools.c:1691
char * fileName
Definition: tools.h:435
time_t LastModifiedTime(const char *FileName)
Definition: tools.c:620
char * strreplace(char *s, char c1, char c2)
Definition: tools.c:139
~cBase64Encoder()
Definition: tools.c:1236
void ByteAlign(void)
Definition: tools.c:1294
void Insert(cListObject *Object)
Definition: tools.c:1905
void writechar(int filedes, char c)
Definition: tools.c:85
Definition: tools.h:166
int Close(void)
Definition: tools.c:1662
static const char * b64
Definition: tools.h:284
cString DateString(time_t t)
Converts the given time to a string of the form "www dd.mm.yyyy".
Definition: tools.c:1097
size_t length
Definition: tools.h:143