Home

Dokumentation

Impressum

Dokumentation VDR
 

Main Page   Class Hierarchy   Alphabetical List   Data Structures   File List   Data Fields   Globals  

videodir.c

Go to the documentation of this file.
00001 /*
00002  * videodir.c: Functions to maintain a distributed video directory
00003  *
00004  * See the main source file 'vdr.c' for copyright information and
00005  * how to reach the author.
00006  *
00007  * $Id: videodir.c 1.9 2002/08/11 13:31:02 kls Exp $
00008  */
00009 
00010 #include "videodir.h"
00011 #include <ctype.h>
00012 #include <errno.h>
00013 #include <fcntl.h>
00014 #include <stdio.h>
00015 #include <stdlib.h>
00016 #include <string.h>
00017 #include <sys/stat.h>
00018 #include <unistd.h>
00019 #include "tools.h"
00020 
00021 const char *VideoDirectory = "/video";
00022 
00023 class cVideoDirectory {
00024 private:
00025   char *name, *stored, *adjusted;
00026   int length, number, digits;
00027 public:
00028   cVideoDirectory(void);
00029   ~cVideoDirectory();
00030   int FreeMB(int *UsedMB = NULL);
00031   const char *Name(void) { return name ? name : VideoDirectory; }
00032   const char *Stored(void) { return stored; }
00033   int Length(void) { return length; }
00034   bool IsDistributed(void) { return name != NULL; }
00035   bool Next(void);
00036   void Store(void);
00037   const char *Adjust(const char *FileName);
00038   };
00039 
00040 cVideoDirectory::cVideoDirectory(void)
00041 {
00042   length = strlen(VideoDirectory);
00043   name = (VideoDirectory[length - 1] == '0') ? strdup(VideoDirectory) : NULL;
00044   stored = adjusted = NULL;
00045   number = -1;
00046   digits = 0;
00047 }
00048 
00049 cVideoDirectory::~cVideoDirectory()
00050 {
00051   free(name);
00052   free(stored);
00053   free(adjusted);
00054 }
00055 
00056 int cVideoDirectory::FreeMB(int *UsedMB)
00057 {
00058   return FreeDiskSpaceMB(name ? name : VideoDirectory, UsedMB);
00059 }
00060 
00061 bool cVideoDirectory::Next(void)
00062 {
00063   if (name) {
00064      if (number < 0) {
00065         int l = length;
00066         while (l-- > 0 && isdigit(name[l]))
00067               ;
00068         l++;
00069         digits = length - l;
00070         int n = atoi(&name[l]);
00071         if (n == 0)
00072            number = n;
00073         else
00074            return false; // base video directory must end with zero
00075         }
00076      if (++number > 0) {
00077         char buf[16];
00078         if (sprintf(buf, "%0*d", digits, number) == digits) {
00079            strcpy(&name[length - digits], buf);
00080            return DirectoryOk(name);
00081            }
00082         }
00083      }
00084   return false;
00085 }
00086 
00087 void cVideoDirectory::Store(void)
00088 {
00089   if (name) {
00090      free(stored);
00091      stored = strdup(name);
00092      }
00093 }
00094 
00095 const char *cVideoDirectory::Adjust(const char *FileName)
00096 {
00097   if (stored) {
00098      free(adjusted);
00099      adjusted = strdup(FileName);
00100      return strncpy(adjusted, stored, length);
00101      }
00102   return NULL;
00103 }
00104 
00105 int OpenVideoFile(const char *FileName, int Flags)
00106 {
00107   const char *ActualFileName = FileName;
00108 
00109   // Incoming name must be in base video directory:
00110   if (strstr(FileName, VideoDirectory) != FileName) {
00111      esyslog("ERROR: %s not in %s", FileName, VideoDirectory);
00112      errno = ENOENT; // must set 'errno' - any ideas for a better value?
00113      return -1;
00114      }
00115   // Are we going to create a new file?
00116   if ((Flags & O_CREAT) != 0) {
00117      cVideoDirectory Dir;
00118      if (Dir.IsDistributed()) {
00119         // Find the directory with the most free space:
00120         int MaxFree = Dir.FreeMB();
00121         while (Dir.Next()) {
00122               int Free = FreeDiskSpaceMB(Dir.Name());
00123               if (Free > MaxFree) {
00124                  Dir.Store();
00125                  MaxFree = Free;
00126                  }
00127               }
00128         if (Dir.Stored()) {
00129            ActualFileName = Dir.Adjust(FileName);
00130            if (!MakeDirs(ActualFileName, false))
00131               return -1; // errno has been set by MakeDirs()
00132            if (symlink(ActualFileName, FileName) < 0) {
00133               LOG_ERROR_STR(FileName);
00134               return -1;
00135               }
00136            ActualFileName = strdup(ActualFileName); // must survive Dir!
00137            }
00138         }
00139      }
00140   int Result = open(ActualFileName, Flags, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
00141   if (ActualFileName != FileName)
00142      free((char *)ActualFileName);
00143   return Result;
00144 }
00145 
00146 int CloseVideoFile(int FileHandle)
00147 {
00148   // just in case we ever decide to do something special when closing the file!
00149   return close(FileHandle);
00150 }
00151 
00152 bool RenameVideoFile(const char *OldName, const char *NewName)
00153 {
00154   // Only the base video directory entry will be renamed, leaving the
00155   // possible symlinks untouched. Going through all the symlinks and disks
00156   // would be unnecessary work - maybe later...
00157   if (rename(OldName, NewName) == -1) {
00158      LOG_ERROR_STR(OldName);
00159      return false;
00160      }
00161   return true;
00162 }
00163 
00164 bool RemoveVideoFile(const char *FileName)
00165 {
00166   return RemoveFileOrDir(FileName, true);
00167 }
00168 
00169 bool VideoFileSpaceAvailable(int SizeMB)
00170 {
00171   cVideoDirectory Dir;
00172   if (Dir.IsDistributed()) {
00173      if (Dir.FreeMB() >= SizeMB * 2) // base directory needs additional space
00174         return true;
00175      while (Dir.Next()) {
00176            if (Dir.FreeMB() >= SizeMB)
00177               return true;
00178            }
00179      return false;
00180      }
00181   return Dir.FreeMB() >= SizeMB;
00182 }
00183 
00184 int VideoDiskSpace(int *FreeMB, int *UsedMB)
00185 {
00186   int free = 0, used = 0;
00187   cVideoDirectory Dir;
00188   do {
00189      int u;
00190      free += Dir.FreeMB(&u);
00191      used += u;
00192      } while (Dir.Next());
00193   if (FreeMB)
00194      *FreeMB = free;
00195   if (UsedMB)
00196      *UsedMB = used;
00197   return (free + used) ? used * 100 / (free + used) : 0;
00198 }
00199 
00200 const char *PrefixVideoFileName(const char *FileName, char Prefix)
00201 {
00202   static char *PrefixedName = NULL;
00203 
00204   if (!PrefixedName || strlen(PrefixedName) <= strlen(FileName))
00205      PrefixedName = (char *)realloc(PrefixedName, strlen(FileName) + 2);
00206   if (PrefixedName) {
00207      const char *p = FileName + strlen(FileName); // p points at the terminating 0
00208      int n = 2;
00209      while (p-- > FileName && n > 0) {
00210            if (*p == '/') {
00211               if (--n == 0) {
00212                  int l = p - FileName + 1;
00213                  strncpy(PrefixedName, FileName, l);
00214                  PrefixedName[l] = Prefix;
00215                  strcpy(PrefixedName + l + 1, p + 1);
00216                  return PrefixedName;
00217                  }
00218               }
00219            }
00220      }
00221   return NULL;
00222 }
00223 
00224 void RemoveEmptyVideoDirectories(void)
00225 {
00226   cVideoDirectory Dir;
00227   do {
00228      RemoveEmptyDirectories(Dir.Name());
00229      } while (Dir.Next());
00230 }
00231 

Generated on Wed Feb 5 23:30:12 2003 for VDR by doxygen1.3-rc2