diff options
Diffstat (limited to 'videodir.c')
-rw-r--r-- | videodir.c | 182 |
1 files changed, 182 insertions, 0 deletions
diff --git a/videodir.c b/videodir.c new file mode 100644 index 00000000..7bd6299a --- /dev/null +++ b/videodir.c @@ -0,0 +1,182 @@ +/* + * videodir.c: Functions to maintain a distributed video directory + * + * See the main source file 'vdr.c' for copyright information and + * how to reach the author. + * + * $Id: videodir.c 1.1 2000/07/29 15:21:42 kls Exp $ + */ + +#include "videodir.h" +#include <ctype.h> +#include <errno.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/stat.h> +#include <unistd.h> +#include "tools.h" + +const char *VideoDirectory = "/video"; + +class cVideoDirectory { +private: + char *name, *stored, *adjusted; + int length, number, digits; +public: + cVideoDirectory(void); + ~cVideoDirectory(); + uint FreeMB(void); + const char *Name(void) { return name; } + const char *Stored(void) { return stored; } + int Length(void) { return length; } + bool IsDistributed(void) { return name != NULL; } + bool Next(void); + void Store(void); + const char *Adjust(const char *FileName); + }; + +cVideoDirectory::cVideoDirectory(void) +{ + length = strlen(VideoDirectory); + name = (VideoDirectory[length - 1] == '0') ? strdup(VideoDirectory) : NULL; + stored = adjusted = NULL; + number = -1; + digits = 0; +} + +cVideoDirectory::~cVideoDirectory() +{ + delete name; + delete stored; + delete adjusted; +} + +uint cVideoDirectory::FreeMB(void) +{ + return FreeDiskSpaceMB(name ? name : VideoDirectory); +} + +bool cVideoDirectory::Next(void) +{ + if (name) { + if (number < 0) { + int l = length; + while (l-- > 0 && isdigit(name[l])) + ; + l++; + digits = length - l; + int n = atoi(&name[l]); + if (n == 0) + number = n; + else + return false; // base video directory must end with zero + } + if (++number > 0) { + char buf[16]; + if (sprintf(buf, "%0*d", digits, number) == digits) { + strcpy(&name[length - digits], buf); + return DirectoryOk(name); + } + } + } + return false; +} + +void cVideoDirectory::Store(void) +{ + if (name) { + delete stored; + stored = strdup(name); + } +} + +const char *cVideoDirectory::Adjust(const char *FileName) +{ + if (stored) { + delete adjusted; + adjusted = strdup(FileName); + return strncpy(adjusted, stored, length); + } + return NULL; +} + +int OpenVideoFile(const char *FileName, int Flags) +{ + const char *ActualFileName = FileName; + + // Incoming name must be in base video directory: + if (strstr(FileName, VideoDirectory) != FileName) { + esyslog(LOG_ERR, "ERROR: %s not in %s", FileName, VideoDirectory); + errno = ENOENT; // must set 'errno' - any ideas for a better value? + return -1; + } + // Are we going to create a new file? + if ((Flags & O_CREAT) != 0) { + cVideoDirectory Dir; + if (Dir.IsDistributed()) { + // Find the directory with the most free space: + uint MaxFree = Dir.FreeMB(); + while (Dir.Next()) { + uint Free = FreeDiskSpaceMB(Dir.Name()); + if (Free > MaxFree) { + Dir.Store(); + MaxFree = Free; + } + } + if (Dir.Stored()) { + ActualFileName = Dir.Adjust(FileName); + if (!MakeDirs(ActualFileName, false)) + return -1; // errno has been set by MakeDirs() + if (symlink(ActualFileName, FileName) < 0) { + LOG_ERROR_STR(FileName); + return -1; + } + ActualFileName = strdup(ActualFileName); // must survive Dir! + } + } + } + int Result = open(ActualFileName, Flags, S_IRUSR | S_IWUSR); + if (ActualFileName != FileName) + delete ActualFileName; + return Result; +} + +int CloseVideoFile(int FileHandle) +{ + // just in case we ever decide to do something special when closing the file! + return close(FileHandle); +} + +bool RenameVideoFile(const char *OldName, const char *NewName) +{ + // Only the base video directory entry will be renamed, leaving the + // possible symlinks untouched. Going through all the symlinks and disks + // would be unnecessary work - maybe later... + if (rename(OldName, NewName) == -1) { + LOG_ERROR_STR(OldName); + return false; + } + return true; +} + +bool RemoveVideoFile(const char *FileName) +{ + return RemoveFileOrDir(FileName, true); +} + +bool VideoFileSpaceAvailable(unsigned int SizeMB) +{ + cVideoDirectory Dir; + if (Dir.IsDistributed()) { + if (Dir.FreeMB() >= SizeMB * 2) // base directory needs additional space + return true; + while (Dir.Next()) { + if (Dir.FreeMB() >= SizeMB) + return true; + } + return false; + } + return Dir.FreeMB() >= SizeMB; +} |