SASC
DVBSoftCAM

tools.cpp

Go to the documentation of this file.
00001 /*
00002  * tools.c: Various tools
00003  *
00004  * See the main source file 'vdr.c' for copyright information and
00005  * how to reach the author.
00006  *
00007  * $Id: tools.c 1.97 2005/08/27 14:43:55 kls Exp $
00008  */
00009 
00010 #include "include/vdr/tools.h"
00011 #include <ctype.h>
00012 #include <dirent.h>
00013 #include <errno.h>
00014 #include <stdarg.h>
00015 #include <stdlib.h>
00016 #include <sys/time.h>
00017 #include <sys/vfs.h>
00018 #include <time.h>
00019 #include <unistd.h>
00020 #include "include/vdr/i18n.h"
00021 #include "include/vdr/thread.h"
00022 
00023 int SysLogLevel = 3;
00024 
00025 #define MAXSYSLOGBUF 256
00026 
00027 void syslog_with_tid(int priority, const char *format, ...)
00028 {
00029   va_list ap;
00030   char fmt[MAXSYSLOGBUF];
00031   snprintf(fmt, sizeof(fmt), "[%d] %s", cThread::ThreadId(), format);
00032   va_start(ap, format);
00033   vsyslog(priority, fmt, ap);
00034   va_end(ap);
00035 }
00036 
00037 int BCD2INT(int x)
00038 {
00039   return ((1000000 * BCDCHARTOINT((x >> 24) & 0xFF)) +
00040             (10000 * BCDCHARTOINT((x >> 16) & 0xFF)) +
00041               (100 * BCDCHARTOINT((x >>  8) & 0xFF)) +
00042                      BCDCHARTOINT( x        & 0xFF));
00043 }
00044 
00045 ssize_t safe_read(int filedes, void *buffer, size_t size)
00046 {
00047   for (;;) {
00048       ssize_t p = read(filedes, buffer, size);
00049       if (p < 0 && errno == EINTR) {
00050          dsyslog("EINTR while reading from file handle %d - retrying", filedes);
00051          continue;
00052          }
00053       return p;
00054       }
00055 }
00056 
00057 ssize_t safe_write(int filedes, const void *buffer, size_t size)
00058 {
00059   ssize_t p = 0;
00060   ssize_t written = size;
00061   const unsigned char *ptr = (const unsigned char *)buffer;
00062   while (size > 0) {
00063         p = write(filedes, ptr, size);
00064         if (p < 0) {
00065            if (errno == EINTR) {
00066               dsyslog("EINTR while writing to file handle %d - retrying", filedes);
00067               continue;
00068               }
00069            break;
00070            }
00071         ptr  += p;
00072         size -= p;
00073         }
00074   return p < 0 ? p : written;
00075 }
00076 
00077 void writechar(int filedes, char c)
00078 {
00079   safe_write(filedes, &c, sizeof(c));
00080 }
00081 
00082 int WriteAllOrNothing(int fd, const uchar *Data, int Length, int TimeoutMs, int RetryMs)
00083 {
00084   int written = 0;
00085   while (Length > 0) {
00086         int w = write(fd, Data + written, Length);
00087         if (w > 0) {
00088            Length -= w;
00089            written += w;
00090            }
00091         else if (written > 0 && !FATALERRNO) {
00092            // we've started writing, so we must finish it!
00093            cTimeMs t;
00094            cPoller Poller(fd, true);
00095            Poller.Poll(RetryMs);
00096            if (TimeoutMs > 0 && (TimeoutMs -= t.Elapsed()) <= 0)
00097               break;
00098            }
00099         else
00100            // nothing written yet (or fatal error), so we can just return the error code:
00101            return w;
00102         }
00103   return written;
00104 }
00105 
00106 char *strcpyrealloc(char *dest, const char *src)
00107 {
00108   if (src) {
00109      int l = max(dest ? strlen(dest) : 0, strlen(src)) + 1; // don't let the block get smaller!
00110      dest = (char *)realloc(dest, l);
00111      if (dest)
00112         strcpy(dest, src);
00113      else
00114         esyslog("ERROR: out of memory");
00115      }
00116   else {
00117      free(dest);
00118      dest = NULL;
00119      }
00120   return dest;
00121 }
00122 
00123 char *strn0cpy(char *dest, const char *src, size_t n)
00124 {
00125   char *s = dest;
00126   for ( ; --n && (*dest = *src) != 0; dest++, src++) ;
00127   *dest = 0;
00128   return s;
00129 }
00130 
00131 char *strreplace(char *s, char c1, char c2)
00132 {
00133   char *p = s;
00134 
00135   while (p && *p) {
00136         if (*p == c1)
00137            *p = c2;
00138         p++;
00139         }
00140   return s;
00141 }
00142 
00143 char *strreplace(char *s, const char *s1, const char *s2)
00144 {
00145   char *p = strstr(s, s1);
00146   if (p) {
00147      int of = p - s;
00148      int l  = strlen(s);
00149      int l1 = strlen(s1);
00150      int l2 = strlen(s2);
00151      if (l2 > l1)
00152         s = (char *)realloc(s, strlen(s) + l2 - l1 + 1);
00153      if (l2 != l1)
00154         memmove(s + of + l2, s + of + l1, l - of - l1 + 1);
00155      strncpy(s + of, s2, l2);
00156      }
00157   return s;
00158 }
00159 
00160 char *skipspace(const char *s)
00161 {
00162   while (*s && isspace(*s))
00163         s++;
00164   return (char *)s;
00165 }
00166 
00167 char *stripspace(char *s)
00168 {
00169   if (s && *s) {
00170      for (char *p = s + strlen(s) - 1; p >= s; p--) {
00171          if (!isspace(*p))
00172             break;
00173          *p = 0;
00174          }
00175      }
00176   return s;
00177 }
00178 
00179 char *compactspace(char *s)
00180 {
00181   if (s && *s) {
00182      char *t = stripspace(skipspace(s));
00183      char *p = t;
00184      while (p && *p) {
00185            char *q = skipspace(p);
00186            if (q - p > 1)
00187               memmove(p + 1, q, strlen(q) + 1);
00188            p++;
00189            }
00190      if (t != s)
00191         memmove(s, t, strlen(t) + 1);
00192      }
00193   return s;
00194 }
00195 
00196 cString strescape(const char *s, const char *chars)
00197 {
00198   char *buffer;
00199   const char *p = s;
00200   char *t = NULL;
00201   while (*p) {
00202         if (strchr(chars, *p)) {
00203            if (!t) {
00204               buffer = MALLOC(char, 2 * strlen(s) + 1);
00205               t = buffer + (p - s);
00206               s = strcpy(buffer, s);
00207               }
00208            *t++ = '\\';
00209            }
00210         if (t)
00211            *t++ = *p;
00212         p++;
00213         }
00214   if (t)
00215      *t = 0;
00216   return cString(s, t != NULL);
00217 }
00218 
00219 bool startswith(const char *s, const char *p)
00220 {
00221   while (*p) {
00222         if (*p++ != *s++)
00223            return false;
00224         }
00225   return true;
00226 }
00227 
00228 bool endswith(const char *s, const char *p)
00229 {
00230   const char *se = s + strlen(s) - 1;
00231   const char *pe = p + strlen(p) - 1;
00232   while (pe >= p) {
00233         if (*pe-- != *se-- || (se < s && pe >= p))
00234            return false;
00235         }
00236   return true;
00237 }
00238 
00239 bool isempty(const char *s)
00240 {
00241   return !(s && *skipspace(s));
00242 }
00243 
00244 int numdigits(int n)
00245 {
00246   char buf[16];
00247   snprintf(buf, sizeof(buf), "%d", n);
00248   return strlen(buf);
00249 }
00250 
00251 bool isnumber(const char *s)
00252 {
00253   if (!*s)
00254      return false;
00255   while (*s) {
00256         if (!isdigit(*s))
00257            return false;
00258         s++;
00259         }
00260   return true;
00261 }
00262 
00263 cString AddDirectory(const char *DirName, const char *FileName)
00264 {
00265   char *buf;
00266   asprintf(&buf, "%s/%s", DirName && *DirName ? DirName : ".", FileName);
00267   return cString(buf, true);
00268 }
00269 
00270 cString itoa(int n)
00271 {
00272   char buf[16];
00273   snprintf(buf, sizeof(buf), "%d", n);
00274   return buf;
00275 }
00276 
00277 int FreeDiskSpaceMB(const char *Directory, int *UsedMB)
00278 {
00279   if (UsedMB)
00280      *UsedMB = 0;
00281   int Free = 0;
00282   struct statfs statFs;
00283   if (statfs(Directory, &statFs) == 0) {
00284      double blocksPerMeg = 1024.0 * 1024.0 / statFs.f_bsize;
00285      if (UsedMB)
00286         *UsedMB = int((statFs.f_blocks - statFs.f_bfree) / blocksPerMeg);
00287      Free = int(statFs.f_bavail / blocksPerMeg);
00288      }
00289   else
00290      LOG_ERROR_STR(Directory);
00291   return Free;
00292 }
00293 
00294 bool DirectoryOk(const char *DirName, bool LogErrors)
00295 {
00296   struct stat ds;
00297   if (stat(DirName, &ds) == 0) {
00298      if (S_ISDIR(ds.st_mode)) {
00299         if (access(DirName, R_OK | W_OK | X_OK) == 0)
00300            return true;
00301         else if (LogErrors)
00302            esyslog("ERROR: can't access %s", DirName);
00303         }
00304      else if (LogErrors)
00305         esyslog("ERROR: %s is not a directory", DirName);
00306      }
00307   else if (LogErrors)
00308      LOG_ERROR_STR(DirName);
00309   return false;
00310 }
00311 
00312 bool MakeDirs(const char *FileName, bool IsDirectory)
00313 {
00314   bool result = true;
00315   char *s = strdup(FileName);
00316   char *p = s;
00317   if (*p == '/')
00318      p++;
00319   while ((p = strchr(p, '/')) != NULL || IsDirectory) {
00320         if (p)
00321            *p = 0;
00322         struct stat fs;
00323         if (stat(s, &fs) != 0 || !S_ISDIR(fs.st_mode)) {
00324            dsyslog("creating directory %s", s);
00325            if (mkdir(s, ACCESSPERMS) == -1) {
00326               LOG_ERROR_STR(s);
00327               result = false;
00328               break;
00329               }
00330            }
00331         if (p)
00332            *p++ = '/';
00333         else
00334            break;
00335         }
00336   free(s);
00337   return result;
00338 }
00339 
00340 bool RemoveFileOrDir(const char *FileName, bool FollowSymlinks)
00341 {
00342   struct stat st;
00343   if (stat(FileName, &st) == 0) {
00344      if (S_ISDIR(st.st_mode)) {
00345         cReadDir d(FileName);
00346         if (d.Ok()) {
00347            struct dirent *e;
00348            while ((e = d.Next()) != NULL) {
00349                  if (strcmp(e->d_name, ".") && strcmp(e->d_name, "..")) {
00350                     char *buffer;
00351                     asprintf(&buffer, "%s/%s", FileName, e->d_name);
00352                     if (FollowSymlinks) {
00353                        int size = strlen(buffer) * 2; // should be large enough
00354                        char *l = MALLOC(char, size);
00355                        int n = readlink(buffer, l, size);
00356                        if (n < 0) {
00357                           if (errno != EINVAL)
00358                              LOG_ERROR_STR(buffer);
00359                           }
00360                        else if (n < size) {
00361                           l[n] = 0;
00362                           dsyslog("removing %s", l);
00363                           if (remove(l) < 0)
00364                              LOG_ERROR_STR(l);
00365                           }
00366                        else
00367                           esyslog("ERROR: symlink name length (%d) exceeded anticipated buffer size (%d)", n, size);
00368                        free(l);
00369                        }
00370                     dsyslog("removing %s", buffer);
00371                     if (remove(buffer) < 0)
00372                        LOG_ERROR_STR(buffer);
00373                     free(buffer);
00374                     }
00375                  }
00376            }
00377         else {
00378            LOG_ERROR_STR(FileName);
00379            return false;
00380            }
00381         }
00382      dsyslog("removing %s", FileName);
00383      if (remove(FileName) < 0) {
00384         LOG_ERROR_STR(FileName);
00385         return false;
00386         }
00387      }
00388   else if (errno != ENOENT) {
00389      LOG_ERROR_STR(FileName);
00390      return false;
00391      }
00392   return true;
00393 }
00394 
00395 bool RemoveEmptyDirectories(const char *DirName, bool RemoveThis)
00396 {
00397   cReadDir d(DirName);
00398   if (d.Ok()) {
00399      bool empty = true;
00400      struct dirent *e;
00401      while ((e = d.Next()) != NULL) {
00402            if (strcmp(e->d_name, ".") && strcmp(e->d_name, "..") && strcmp(e->d_name, "lost+found")) {
00403               char *buffer;
00404               asprintf(&buffer, "%s/%s", DirName, e->d_name);
00405               struct stat st;
00406               if (stat(buffer, &st) == 0) {
00407                  if (S_ISDIR(st.st_mode)) {
00408                     if (!RemoveEmptyDirectories(buffer, true))
00409                        empty = false;
00410                     }
00411                  else
00412                     empty = false;
00413                  }
00414               else {
00415                  LOG_ERROR_STR(buffer);
00416                  free(buffer);
00417                  return false;
00418                  }
00419               free(buffer);
00420               }
00421            }
00422      if (RemoveThis && empty) {
00423         dsyslog("removing %s", DirName);
00424         if (remove(DirName) < 0) {
00425            LOG_ERROR_STR(DirName);
00426            return false;
00427            }
00428         }
00429      return empty;
00430      }
00431   else
00432      LOG_ERROR_STR(DirName);
00433   return false;
00434 }
00435 
00436 char *ReadLink(const char *FileName)
00437 {
00438   char RealName[PATH_MAX];
00439   const char *TargetName = NULL;
00440   int n = readlink(FileName, RealName, sizeof(RealName) - 1);
00441   if (n < 0) {
00442      if (errno == ENOENT || errno == EINVAL) // file doesn't exist or is not a symlink
00443         TargetName = FileName;
00444      else // some other error occurred
00445         LOG_ERROR_STR(FileName);
00446      }
00447   else if (n < int(sizeof(RealName))) { // got it!
00448      RealName[n] = 0;
00449      TargetName = RealName;
00450      }
00451   else
00452      esyslog("ERROR: symlink's target name too long: %s", FileName);
00453   return TargetName ? strdup(TargetName) : NULL;
00454 }
00455 
00456 bool SpinUpDisk(const char *FileName)
00457 {
00458   char *buf = NULL;
00459   for (int n = 0; n < 10; n++) {
00460       free(buf);
00461       if (DirectoryOk(FileName))
00462          asprintf(&buf, "%s/vdr-%06d", *FileName ? FileName : ".", n);
00463       else
00464          asprintf(&buf, "%s.vdr-%06d", FileName, n);
00465       if (access(buf, F_OK) != 0) { // the file does not exist
00466          timeval tp1, tp2;
00467          gettimeofday(&tp1, NULL);
00468          int f = open(buf, O_WRONLY | O_CREAT, DEFFILEMODE);
00469          // O_SYNC doesn't work on all file systems
00470          if (f >= 0) {
00471             if (fdatasync(f) < 0)
00472                LOG_ERROR_STR(buf);
00473             close(f);
00474             remove(buf);
00475             gettimeofday(&tp2, NULL);
00476             double seconds = (((long long)tp2.tv_sec * 1000000 + tp2.tv_usec) - ((long long)tp1.tv_sec * 1000000 + tp1.tv_usec)) / 1000000.0;
00477             if (seconds > 0.5)
00478                dsyslog("SpinUpDisk took %.2f seconds\n", seconds);
00479             free(buf);
00480             return true;
00481             }
00482          else
00483             LOG_ERROR_STR(buf);
00484          }
00485       }
00486   free(buf);
00487   esyslog("ERROR: SpinUpDisk failed");
00488   return false;
00489 }
00490 
00491 time_t LastModifiedTime(const char *FileName)
00492 {
00493   struct stat fs;
00494   if (stat(FileName, &fs) == 0)
00495      return fs.st_mtime;
00496   return 0;
00497 }
00498 
00499 // --- cTimeMs ---------------------------------------------------------------
00500 
00501 cTimeMs::cTimeMs(int Ms)
00502 {
00503   Set(Ms);
00504 }
00505 
00506 uint64_t cTimeMs::Now(void)
00507 {
00508   struct timeval t;
00509   if (gettimeofday(&t, NULL) == 0)
00510      return (uint64_t(t.tv_sec)) * 1000 + t.tv_usec / 1000;
00511   return 0;
00512 }
00513 
00514 void cTimeMs::Set(int Ms)
00515 {
00516   begin = Now() + Ms;
00517 }
00518 
00519 bool cTimeMs::TimedOut(void)
00520 {
00521   return Now() >= begin;
00522 }
00523 
00524 uint64_t cTimeMs::Elapsed(void)
00525 {
00526   return Now() - begin;
00527 }
00528 
00529 // --- cString ---------------------------------------------------------------
00530 
00531 cString::cString(const char *S, bool TakePointer)
00532 {
00533   s = TakePointer ? (char *)S : S ? strdup(S) : NULL;
00534 }
00535 
00536 cString::~cString()
00537 {
00538   free(s);
00539 }
00540 
00541 cString &cString::operator=(const cString &String)
00542 {
00543   s = String.s ? strdup(String.s) : NULL;
00544   return *this;
00545 }
00546 
00547 cString cString::sprintf(const char *fmt, ...)
00548 {
00549   va_list ap;
00550   va_start(ap, fmt);
00551   char *buffer;
00552   vasprintf(&buffer, fmt, ap);
00553   return cString(buffer, true);
00554 }
00555 
00556 cString WeekDayName(int WeekDay)
00557 {
00558   char buffer[4];
00559   WeekDay = WeekDay == 0 ? 6 : WeekDay - 1; // we start with monday==0!
00560   if (0 <= WeekDay && WeekDay <= 6) {
00561      const char *day = "MonTueWedThuFriSatSun";
00562      day += WeekDay * 3;
00563      strn0cpy(buffer, day, sizeof(buffer));
00564      return buffer;
00565      }
00566   else
00567      return "???";
00568 }
00569 
00570 cString WeekDayName(time_t t)
00571 {
00572   struct tm tm_r;
00573   return WeekDayName(localtime_r(&t, &tm_r)->tm_wday);
00574 }
00575 
00576 cString DayDateTime(time_t t)
00577 {
00578   char buffer[32];
00579   if (t == 0)
00580      time(&t);
00581   struct tm tm_r;
00582   tm *tm = localtime_r(&t, &tm_r);
00583   snprintf(buffer, sizeof(buffer), "%s %2d.%02d %02d:%02d", *WeekDayName(tm->tm_wday), tm->tm_mday, tm->tm_mon + 1, tm->tm_hour, tm->tm_min);
00584   return buffer;
00585 }
00586 
00587 cString TimeToString(time_t t)
00588 {
00589   char buffer[32];
00590   if (ctime_r(&t, buffer)) {
00591      buffer[strlen(buffer) - 1] = 0; // strip trailing newline
00592      return buffer;
00593      }
00594   return "???";
00595 }
00596 
00597 cString DateString(time_t t)
00598 {
00599   char buf[32];
00600   struct tm tm_r;
00601   tm *tm = localtime_r(&t, &tm_r);
00602   char *p = stpcpy(buf, WeekDayName(tm->tm_wday));
00603   *p++ = ' ';
00604   strftime(p, sizeof(buf) - (p - buf), "%d.%m.%Y", tm);
00605   return buf;
00606 }
00607 
00608 cString TimeString(time_t t)
00609 {
00610   char buf[25];
00611   struct tm tm_r;
00612   strftime(buf, sizeof(buf), "%R", localtime_r(&t, &tm_r));
00613   return buf;
00614 }
00615 
00616 // --- cReadLine -------------------------------------------------------------
00617 
00618 char *cReadLine::Read(FILE *f)
00619 {
00620   if (fgets(buffer, sizeof(buffer), f) > 0) {
00621      int l = strlen(buffer) - 1;
00622      if (l >= 0 && buffer[l] == '\n')
00623         buffer[l] = 0;
00624      return buffer;
00625      }
00626   return NULL;
00627 }
00628 
00629 // --- cPoller ---------------------------------------------------------------
00630 
00631 cPoller::cPoller(int FileHandle, bool Out)
00632 {
00633   numFileHandles = 0;
00634   Add(FileHandle, Out);
00635 }
00636 
00637 bool cPoller::Add(int FileHandle, bool Out)
00638 {
00639   if (FileHandle >= 0) {
00640      for (int i = 0; i < numFileHandles; i++) {
00641          if (pfd[i].fd == FileHandle && pfd[i].events == (Out ? POLLOUT : POLLIN))
00642             return true;
00643          }
00644      if (numFileHandles < MaxPollFiles) {
00645         pfd[numFileHandles].fd = FileHandle;
00646         pfd[numFileHandles].events = Out ? POLLOUT : POLLIN;
00647         pfd[numFileHandles].revents = 0;
00648         numFileHandles++;
00649         return true;
00650         }
00651      esyslog("ERROR: too many file handles in cPoller");
00652      }
00653   return false;
00654 }
00655 
00656 bool cPoller::Poll(int TimeoutMs)
00657 {
00658   if (numFileHandles) {
00659      if (poll(pfd, numFileHandles, TimeoutMs) != 0)
00660         return true; // returns true even in case of an error, to let the caller
00661                      // access the file and thus see the error code
00662      }
00663   return false;
00664 }
00665 
00666 // --- cReadDir --------------------------------------------------------------
00667 
00668 cReadDir::cReadDir(const char *Directory)
00669 {
00670   directory = opendir(Directory);
00671 }
00672 
00673 cReadDir::~cReadDir()
00674 {
00675   if (directory)
00676      closedir(directory);
00677 }
00678 
00679 struct dirent *cReadDir::Next(void)
00680 {
00681   return directory && readdir_r(directory, &u.d, &result) == 0 ? result : NULL;
00682 }
00683 
00684 // --- cFile -----------------------------------------------------------------
00685 
00686 bool cFile::files[FD_SETSIZE] = { false };
00687 int cFile::maxFiles = 0;
00688 
00689 cFile::cFile(void)
00690 {
00691   f = -1;
00692 }
00693 
00694 cFile::~cFile()
00695 {
00696   Close();
00697 }
00698 
00699 bool cFile::Open(const char *FileName, int Flags, mode_t Mode)
00700 {
00701   if (!IsOpen())
00702      return Open(open(FileName, Flags, Mode));
00703   esyslog("ERROR: attempt to re-open %s", FileName);
00704   return false;
00705 }
00706 
00707 bool cFile::Open(int FileDes)
00708 {
00709   if (FileDes >= 0) {
00710      if (!IsOpen()) {
00711         f = FileDes;
00712         if (f >= 0) {
00713            if (f < FD_SETSIZE) {
00714               if (f >= maxFiles)
00715                  maxFiles = f + 1;
00716               if (!files[f])
00717                  files[f] = true;
00718               else
00719                  esyslog("ERROR: file descriptor %d already in files[]", f);
00720               return true;
00721               }
00722            else
00723               esyslog("ERROR: file descriptor %d is larger than FD_SETSIZE (%d)", f, FD_SETSIZE);
00724            }
00725         }
00726      else
00727         esyslog("ERROR: attempt to re-open file descriptor %d", FileDes);
00728      }
00729   return false;
00730 }
00731 
00732 void cFile::Close(void)
00733 {
00734   if (f >= 0) {
00735      close(f);
00736      files[f] = false;
00737      f = -1;
00738      }
00739 }
00740 
00741 bool cFile::Ready(bool Wait)
00742 {
00743   return f >= 0 && AnyFileReady(f, Wait ? 1000 : 0);
00744 }
00745 
00746 bool cFile::AnyFileReady(int FileDes, int TimeoutMs)
00747 {
00748   fd_set set;
00749   FD_ZERO(&set);
00750   for (int i = 0; i < maxFiles; i++) {
00751       if (files[i])
00752          FD_SET(i, &set);
00753       }
00754   if (0 <= FileDes && FileDes < FD_SETSIZE && !files[FileDes])
00755      FD_SET(FileDes, &set); // in case we come in with an arbitrary descriptor
00756   if (TimeoutMs == 0)
00757      TimeoutMs = 10; // load gets too heavy with 0
00758   struct timeval timeout;
00759   timeout.tv_sec  = TimeoutMs / 1000;
00760   timeout.tv_usec = (TimeoutMs % 1000) * 1000;
00761   return select(FD_SETSIZE, &set, NULL, NULL, &timeout) > 0 && (FileDes < 0 || FD_ISSET(FileDes, &set));
00762 }
00763 
00764 bool cFile::FileReady(int FileDes, int TimeoutMs)
00765 {
00766   fd_set set;
00767   struct timeval timeout;
00768   FD_ZERO(&set);
00769   FD_SET(FileDes, &set);
00770   if (TimeoutMs >= 0) {
00771      if (TimeoutMs < 100)
00772         TimeoutMs = 100;
00773      timeout.tv_sec  = TimeoutMs / 1000;
00774      timeout.tv_usec = (TimeoutMs % 1000) * 1000;
00775      }
00776   return select(FD_SETSIZE, &set, NULL, NULL, (TimeoutMs >= 0) ? &timeout : NULL) > 0 && FD_ISSET(FileDes, &set);
00777 }
00778 
00779 bool cFile::FileReadyForWriting(int FileDes, int TimeoutMs)
00780 {
00781   fd_set set;
00782   struct timeval timeout;
00783   FD_ZERO(&set);
00784   FD_SET(FileDes, &set);
00785   if (TimeoutMs < 100)
00786      TimeoutMs = 100;
00787   timeout.tv_sec  = 0;
00788   timeout.tv_usec = TimeoutMs * 1000;
00789   return select(FD_SETSIZE, NULL, &set, NULL, &timeout) > 0 && FD_ISSET(FileDes, &set);
00790 }
00791 
00792 // --- cSafeFile -------------------------------------------------------------
00793 
00794 cSafeFile::cSafeFile(const char *FileName)
00795 {
00796   f = NULL;
00797   fileName = ReadLink(FileName);
00798   tempName = fileName ? MALLOC(char, strlen(fileName) + 5) : NULL;
00799   if (tempName)
00800      strcat(strcpy(tempName, fileName), ".$$$");
00801 }
00802 
00803 cSafeFile::~cSafeFile()
00804 {
00805   if (f)
00806      fclose(f);
00807   unlink(tempName);
00808   free(fileName);
00809   free(tempName);
00810 }
00811 
00812 bool cSafeFile::Open(void)
00813 {
00814   if (!f && fileName && tempName) {
00815      f = fopen(tempName, "w");
00816      if (!f)
00817         LOG_ERROR_STR(tempName);
00818      }
00819   return f != NULL;
00820 }
00821 
00822 bool cSafeFile::Close(void)
00823 {
00824   bool result = true;
00825   if (f) {
00826      if (ferror(f) != 0) {
00827         LOG_ERROR_STR(tempName);
00828         result = false;
00829         }
00830      if (fclose(f) < 0) {
00831         LOG_ERROR_STR(tempName);
00832         result = false;
00833         }
00834      f = NULL;
00835      if (result && rename(tempName, fileName) < 0) {
00836         LOG_ERROR_STR(fileName);
00837         result = false;
00838         }
00839      }
00840   else
00841      result = false;
00842   return result;
00843 }
00844 
00845 // --- cLockFile -------------------------------------------------------------
00846 
00847 #define LOCKFILENAME      ".lock-vdr"
00848 #define LOCKFILESTALETIME 600 // seconds before considering a lock file "stale"
00849 
00850 cLockFile::cLockFile(const char *Directory)
00851 {
00852   fileName = NULL;
00853   f = -1;
00854   if (DirectoryOk(Directory))
00855      asprintf(&fileName, "%s/%s", Directory, LOCKFILENAME);
00856 }
00857 
00858 cLockFile::~cLockFile()
00859 {
00860   Unlock();
00861   free(fileName);
00862 }
00863 
00864 bool cLockFile::Lock(int WaitSeconds)
00865 {
00866   if (f < 0 && fileName) {
00867      time_t Timeout = time(NULL) + WaitSeconds;
00868      do {
00869         f = open(fileName, O_WRONLY | O_CREAT | O_EXCL, DEFFILEMODE);
00870         if (f < 0) {
00871            if (errno == EEXIST) {
00872               struct stat fs;
00873               if (stat(fileName, &fs) == 0) {
00874                  if (abs(time(NULL) - fs.st_mtime) > LOCKFILESTALETIME) {
00875                     esyslog("ERROR: removing stale lock file '%s'", fileName);
00876                     if (remove(fileName) < 0) {
00877                        LOG_ERROR_STR(fileName);
00878                        break;
00879                        }
00880                     continue;
00881                     }
00882                  }
00883               else if (errno != ENOENT) {
00884                  LOG_ERROR_STR(fileName);
00885                  break;
00886                  }
00887               }
00888            else {
00889               LOG_ERROR_STR(fileName);
00890               break;
00891               }
00892            if (WaitSeconds)
00893               sleep(1);
00894            }
00895         } while (f < 0 && time(NULL) < Timeout);
00896      }
00897   return f >= 0;
00898 }
00899 
00900 void cLockFile::Unlock(void)
00901 {
00902   if (f >= 0) {
00903      close(f);
00904      remove(fileName);
00905      f = -1;
00906      }
00907 }
00908 
00909 // --- cListObject -----------------------------------------------------------
00910 
00911 cListObject::cListObject(void)
00912 {
00913   prev = next = NULL;
00914 }
00915 
00916 cListObject::~cListObject()
00917 {
00918 }
00919 
00920 void cListObject::Append(cListObject *Object)
00921 {
00922   next = Object;
00923   Object->prev = this;
00924 }
00925 
00926 void cListObject::Insert(cListObject *Object)
00927 {
00928   prev = Object;
00929   Object->next = this;
00930 }
00931 
00932 void cListObject::Unlink(void)
00933 {
00934   if (next)
00935      next->prev = prev;
00936   if (prev)
00937      prev->next = next;
00938   next = prev = NULL;
00939 }
00940 
00941 int cListObject::Index(void) const
00942 {
00943   cListObject *p = prev;
00944   int i = 0;
00945 
00946   while (p) {
00947         i++;
00948         p = p->prev;
00949         }
00950   return i;
00951 }
00952 
00953 // --- cListBase -------------------------------------------------------------
00954 
00955 cListBase::cListBase(void)
00956 { 
00957   objects = lastObject = NULL;
00958   count = 0;
00959 }
00960 
00961 cListBase::~cListBase()
00962 {
00963   Clear();
00964 }
00965 
00966 void cListBase::Add(cListObject *Object, cListObject *After)
00967 { 
00968   if (After && After != lastObject) {
00969      After->Next()->Insert(Object);
00970      After->Append(Object);
00971      }
00972   else {
00973      if (lastObject)
00974         lastObject->Append(Object);
00975      else
00976         objects = Object;
00977      lastObject = Object;
00978      }
00979   count++;
00980 }
00981 
00982 void cListBase::Ins(cListObject *Object, cListObject *Before)
00983 { 
00984   if (Before && Before != objects) {
00985      Before->Prev()->Append(Object);
00986      Before->Insert(Object);
00987      }
00988   else {
00989      if (objects)
00990         objects->Insert(Object);
00991      else
00992         lastObject = Object;
00993      objects = Object;
00994      }
00995   count++;
00996 }
00997 
00998 void cListBase::Del(cListObject *Object, bool DeleteObject)
00999 {
01000   if (Object == objects)
01001      objects = Object->Next();
01002   if (Object == lastObject)
01003      lastObject = Object->Prev();
01004   Object->Unlink();
01005   if (DeleteObject)
01006      delete Object;
01007   count--;
01008 }
01009 
01010 void cListBase::Move(int From, int To)
01011 {
01012   Move(Get(From), Get(To));
01013 }
01014 
01015 void cListBase::Move(cListObject *From, cListObject *To)
01016 {
01017   if (From && To) {
01018      if (From->Index() < To->Index())
01019         To = To->Next();
01020      if (From == objects)
01021         objects = From->Next();
01022      if (From == lastObject)
01023         lastObject = From->Prev();
01024      From->Unlink();
01025      if (To) {
01026         if (To->Prev())
01027            To->Prev()->Append(From);
01028         From->Append(To);
01029         }
01030      else {
01031         lastObject->Append(From);
01032         lastObject = From;
01033         }
01034      if (!From->Prev())
01035         objects = From;
01036      }
01037 }
01038 
01039 void cListBase::Clear(void)
01040 {
01041   while (objects) {
01042         cListObject *object = objects->Next();
01043         delete objects;
01044         objects = object;
01045         }
01046   objects = lastObject = NULL;
01047   count = 0;
01048 }
01049 
01050 cListObject *cListBase::Get(int Index) const
01051 {
01052   if (Index < 0)
01053      return NULL;
01054   cListObject *object = objects;
01055   while (object && Index-- > 0)
01056         object = object->Next();
01057   return object;
01058 }
01059 
01060 static int CompareListObjects(const void *a, const void *b)
01061 {
01062   const cListObject *la = *(const cListObject **)a;
01063   const cListObject *lb = *(const cListObject **)b;
01064   return la->Compare(*lb);
01065 }
01066 
01067 void cListBase::Sort(void)
01068 {
01069   int n = Count();
01070   cListObject *a[n];
01071   cListObject *object = objects;
01072   int i = 0;
01073   while (object && i < n) {
01074         a[i++] = object;
01075         object = object->Next();
01076         }
01077   qsort(a, n, sizeof(cListObject *), CompareListObjects);
01078   objects = lastObject = NULL;
01079   for (i = 0; i < n; i++) {
01080       a[i]->Unlink();
01081       count--;
01082       Add(a[i]);
01083       }
01084 }
01085 
01086 // --- cHashBase -------------------------------------------------------------
01087 
01088 cHashBase::cHashBase(int Size)
01089 {
01090   size = Size;
01091   hashTable = (cList<cHashObject>**)calloc(size, sizeof(cList<cHashObject>*));
01092 }
01093 
01094 cHashBase::~cHashBase(void)
01095 {
01096   for (int i = 0; i < size; i++)
01097       delete hashTable[i];
01098   free(hashTable);
01099 }
01100 
01101 void cHashBase::Add(cListObject *Object, unsigned int Id)
01102 {
01103   unsigned int hash = hashfn(Id);
01104   if (!hashTable[hash])
01105      hashTable[hash] = new cList<cHashObject>;
01106   hashTable[hash]->Add(new cHashObject(Object, Id));
01107 }
01108 
01109 void cHashBase::Del(cListObject *Object, unsigned int Id)
01110 {
01111   cList<cHashObject> *list = hashTable[hashfn(Id)];
01112   if (list) {
01113      for (cHashObject *hob = list->First(); hob; hob = list->Next(hob)) {
01114          if (hob->object == Object) {
01115             list->Del(hob);
01116             break;
01117             }
01118          }
01119      }
01120 }
01121 
01122 cListObject *cHashBase::Get(unsigned int Id) const
01123 {
01124   cList<cHashObject> *list = hashTable[hashfn(Id)];
01125   if (list) {
01126      for (cHashObject *hob = list->First(); hob; hob = list->Next(hob)) {
01127          if (hob->id == Id)
01128             return hob->object;
01129          }
01130      }
01131   return NULL;
01132 }
01133 
01134 cList<cHashObject> *cHashBase::GetList(unsigned int Id) const
01135 {
01136   return hashTable[hashfn(Id)];
01137 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines