summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKlaus Schmidinger <vdr@tvdr.de>2000-07-29 15:21:42 +0200
committerKlaus Schmidinger <vdr@tvdr.de>2000-07-29 15:21:42 +0200
commit0f2099b4f2528f1aa9846d889e0ccde47f5eb1aa (patch)
tree8ba3132387c2eda4bb1fb6ac4b8f5354c61fed25
parent92096e097a5cb6b90fb982d90b16012682d67ccf (diff)
downloadvdr-0f2099b4f2528f1aa9846d889e0ccde47f5eb1aa.tar.gz
vdr-0f2099b4f2528f1aa9846d889e0ccde47f5eb1aa.tar.bz2
Support for more than one video directory
-rw-r--r--CONTRIBUTORS1
-rw-r--r--HISTORY5
-rw-r--r--INSTALL34
-rw-r--r--Makefile11
-rw-r--r--dvbapi.c48
-rw-r--r--recording.c42
-rw-r--r--recording.h4
-rw-r--r--tools.c67
-rw-r--r--tools.h7
-rw-r--r--vdr.c5
-rw-r--r--videodir.c182
-rw-r--r--videodir.h21
12 files changed, 352 insertions, 75 deletions
diff --git a/CONTRIBUTORS b/CONTRIBUTORS
index 0201f80c..c24496f1 100644
--- a/CONTRIBUTORS
+++ b/CONTRIBUTORS
@@ -5,6 +5,7 @@ Carsten Koch <Carsten.Koch@icem.de>
for making the 'Recordings' menu be listed alphabetically
for implementing the 'Summary' feature
for adding the 'epg2timers' tool (see Tools/epg2timers)
+ for his idea of using multiple disks (and for testing this feature)
Plamen Ganev <pganev@com-it.net>
for fixing the frequency offset for Hotbird channels
diff --git a/HISTORY b/HISTORY
index f95ac51f..36bc8d71 100644
--- a/HISTORY
+++ b/HISTORY
@@ -100,9 +100,12 @@ Video Disk Recorder Revision History
the 'timers.conf' file with a text editor, or by defining/modifying the timer
via the SVDRP interface.
-2000-07-28:
+2000-07-29:
- When scrolling through a list it now moves a full page up or down when the
cursor reaches the top or bottom of the menu (thanks to Heino Goldenstein!).
- Added missing '#include <sys/stat.h>' to recording.c.
- The video directory can now be defined with the command line option -v.
+- There can now be more than one video directory (in case you have several
+ disks).
+- Fixed learning key codes for PC keyboard.
diff --git a/INSTALL b/INSTALL
index 3261ef00..6bf3a9fd 100644
--- a/INSTALL
+++ b/INSTALL
@@ -49,6 +49,9 @@ If the program shall run as a daemon, use the --daemon option. This
will completely detach it from the terminal and will continue as a
background process.
+Command line options:
+---------------------
+
Use "vdr --help" for a list of available command line options.
The video data directory:
@@ -57,14 +60,41 @@ The video data directory:
All recordings are written into directories below "/video". Please
make sure this directory exists, and that the user who runs the 'vdr'
program has read and write access to that directory.
-If you prefer a different location for your video files, you can change
-the value of 'BaseDir' in recording.c.
+If you prefer a different location for your video files, you can use
+the '-v' option to change that.
Note that the file system need not be 64-bit proof, since the 'vdr'
program splits video files into chunks of about 1GB. You should use
a disk with several gigabytes of free space. One GB can store roughly
half an hour of video data.
+If you have more than one disk and don't want to combine them to form
+one large logical volume, you can set up several video directories as
+mount points for these disks. All of these directories must have the
+same basic name and must end with a numeric part, which starts at 0 for
+the main directory and has increasing values for the rest of the
+directories. For example
+
+ /video0
+ /video1
+ /video2
+
+would be a setup with three directories. You can use more than one
+numeric digit, and the directories need not be directly under '/':
+
+ /mnt/MyVideos/vdr.00
+ /mnt/MyVideos/vdr.01
+ /mnt/MyVideos/vdr.02
+ ...
+ /mnt/MyVideos/vdr.11
+
+would set up twelve disks (wow, what a machine that would be!).
+
+To use such a multi directory setup, you need to add the '-v' option
+with the name of the basic directory when running 'vdr':
+
+ vdr -v /video0
+
Configuration files:
--------------------
diff --git a/Makefile b/Makefile
index 8fb678bc..f71236b7 100644
--- a/Makefile
+++ b/Makefile
@@ -4,9 +4,9 @@
# See the main source file 'vdr.c' for copyright information and
# how to reach the author.
#
-# $Id: Makefile 1.5 2000/07/23 11:57:14 kls Exp $
+# $Id: Makefile 1.6 2000/07/28 14:37:44 kls Exp $
-OBJS = config.o dvbapi.o interface.o menu.o osd.o recording.o remote.o svdrp.o tools.o vdr.o
+OBJS = config.o dvbapi.o interface.o menu.o osd.o recording.o remote.o svdrp.o tools.o vdr.o videodir.o
ifndef REMOTE
REMOTE = KBD
@@ -24,15 +24,16 @@ endif
all: vdr
config.o : config.c config.h dvbapi.h interface.h tools.h
-dvbapi.o : dvbapi.c config.h dvbapi.h interface.h tools.h
+dvbapi.o : dvbapi.c config.h dvbapi.h interface.h tools.h videodir.h
interface.o: interface.c config.h dvbapi.h interface.h remote.h tools.h
menu.o : menu.c config.h dvbapi.h interface.h menu.h osd.h recording.h tools.h
osd.o : osd.c config.h dvbapi.h interface.h osd.h tools.h
-vdr.o : vdr.c config.h dvbapi.h interface.h menu.h osd.h recording.h svdrp.h tools.h
-recording.o: recording.c config.h dvbapi.h interface.h recording.h tools.h
+vdr.o : vdr.c config.h dvbapi.h interface.h menu.h osd.h recording.h svdrp.h tools.h videodir.h
+recording.o: recording.c config.h dvbapi.h interface.h recording.h tools.h videodir.h
remote.o : remote.c remote.h tools.h
svdrp.o : svdrp.c svdrp.h config.h interface.h tools.h
tools.o : tools.c tools.h
+videodir.o : videodir.c tools.h videodir.h
vdr: $(OBJS)
g++ -g -O2 $(OBJS) -lncurses -o vdr
diff --git a/dvbapi.c b/dvbapi.c
index a9673a7a..2f726ed5 100644
--- a/dvbapi.c
+++ b/dvbapi.c
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: dvbapi.c 1.15 2000/07/21 13:18:02 kls Exp $
+ * $Id: dvbapi.c 1.16 2000/07/29 14:49:46 kls Exp $
*/
#include "dvbapi.h"
@@ -17,6 +17,7 @@
#include <unistd.h>
#include "interface.h"
#include "tools.h"
+#include "videodir.h"
#define VIDEODEVICE "/dev/video"
@@ -50,9 +51,12 @@
// 'signed'), so let's use 1GB for absolute safety (the actual file size
// may be slightly higher because we stop recording only before the next
// 'I' frame, to have a complete Group Of Pictures):
-#define MAXVIDEOFILESIZE (1024*1024*1024)
+#define MAXVIDEOFILESIZE (1024*1024*1024) // Byte
#define MAXFILESPERRECORDING 255
+#define MINFREEDISKSPACE (512) // MB
+#define DISKCHECKINTERVAL 100 // seconds
+
#define INDEXFILESUFFIX "/index.vdr"
#define RESUMEFILESUFFIX "/resume.vdr"
#define RECORDFILESUFFIX "/%03d.vdr"
@@ -598,6 +602,8 @@ private:
int recordFile;
uchar tagAudio, tagVideo;
bool ok, synced;
+ time_t lastDiskSpaceCheck;
+ bool RunningLowOnDiskSpace(void);
int Synchronize(void);
bool NextFile(void);
virtual int Write(int Max = -1);
@@ -615,6 +621,7 @@ cRecordBuffer::cRecordBuffer(int *InFile, const char *FileName)
recordFile = -1;
tagAudio = tagVideo = 0;
ok = synced = false;
+ lastDiskSpaceCheck = time(NULL);
if (!fileName)
return;//XXX find a better way???
// Find the highest existing file suffix:
@@ -636,7 +643,20 @@ cRecordBuffer::cRecordBuffer(int *InFile, const char *FileName)
cRecordBuffer::~cRecordBuffer()
{
if (recordFile >= 0)
- close(recordFile);
+ CloseVideoFile(recordFile);
+}
+
+bool cRecordBuffer::RunningLowOnDiskSpace(void)
+{
+ if (time(NULL) > lastDiskSpaceCheck + DISKCHECKINTERVAL) {
+ uint Free = FreeDiskSpaceMB(fileName);
+ lastDiskSpaceCheck = time(NULL);
+ if (Free < MINFREEDISKSPACE) {
+ dsyslog(LOG_INFO, "low disk space (%d MB, limit is %d MB)", Free, MINFREEDISKSPACE);
+ return true;
+ }
+ }
+ return false;
}
int cRecordBuffer::Synchronize(void)
@@ -714,20 +734,22 @@ int cRecordBuffer::Synchronize(void)
bool cRecordBuffer::NextFile(void)
{
- if (recordFile >= 0 && fileSize > MAXVIDEOFILESIZE && pictureType == I_FRAME) {
- if (close(recordFile) < 0)
- LOG_ERROR;
- // don't return 'false', maybe we can still record into the next file
- recordFile = -1;
- fileNumber++;
- if (fileNumber == 0)
- esyslog(LOG_ERR, "ERROR: max number of files (%d) exceeded", MAXFILESPERRECORDING);
- fileSize = 0;
+ if (recordFile >= 0 && pictureType == I_FRAME) { // every file shall start with an I_FRAME
+ if (fileSize > MAXVIDEOFILESIZE || RunningLowOnDiskSpace()) {
+ if (CloseVideoFile(recordFile) < 0)
+ LOG_ERROR;
+ // don't return 'false', maybe we can still record into the next file
+ recordFile = -1;
+ fileNumber++;
+ if (fileNumber == 0)
+ esyslog(LOG_ERR, "ERROR: max number of files (%d) exceeded", MAXFILESPERRECORDING);
+ fileSize = 0;
+ }
}
if (recordFile < 0) {
sprintf(pFileNumber, RECORDFILESUFFIX, fileNumber);
dsyslog(LOG_INFO, "recording to '%s'", fileName);
- recordFile = open(fileName, O_RDWR | O_CREAT | O_NONBLOCK, S_IRUSR | S_IWUSR);
+ recordFile = OpenVideoFile(fileName, O_RDWR | O_CREAT | O_NONBLOCK);
if (recordFile < 0) {
LOG_ERROR;
return false;
diff --git a/recording.c b/recording.c
index 277b9114..9f3b3885 100644
--- a/recording.c
+++ b/recording.c
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: recording.c 1.14 2000/07/28 12:47:54 kls Exp $
+ * $Id: recording.c 1.15 2000/07/29 14:08:17 kls Exp $
*/
#define _GNU_SOURCE
@@ -17,6 +17,7 @@
#include <unistd.h>
#include "interface.h"
#include "tools.h"
+#include "videodir.h"
#define RECEXT ".rec"
#define DELEXT ".del"
@@ -25,40 +26,12 @@
#define SUMMARYFILESUFFIX "/summary.vdr"
-#define FINDCMD "find %s -type d -name '%s' | sort -df"
+#define FINDCMD "find %s -follow -type d -name '%s' 2> /dev/null | sort -df"
-#define DFCMD "df -m %s"
#define MINDISKSPACE 1024 // MB
#define DISKCHECKDELTA 300 // seconds between checks for free disk space
-const char *VideoDirectory = "/video";
-
-static bool LowDiskSpace(void)
-{
- //TODO Find a simpler way to determine the amount of free disk space!
- bool result = true;
- char *cmd = NULL;
- asprintf(&cmd, DFCMD, VideoDirectory);
- FILE *p = popen(cmd, "r");
- if (p) {
- char *s;
- while ((s = readline(p)) != NULL) {
- if (*s == '/') {
- int available;
- sscanf(s, "%*s %*d %*d %d", &available);
- result = available < MINDISKSPACE;
- break;
- }
- }
- pclose(p);
- }
- else
- esyslog(LOG_ERR, "ERROR: can't open pipe for cmd '%s'", cmd);
- delete cmd;
- return result;
-}
-
void AssertFreeDiskSpace(void)
{
// With every call to this function we try to actually remove
@@ -66,7 +39,7 @@ void AssertFreeDiskSpace(void)
// it will get removed during the next call.
static time_t LastFreeDiskCheck = 0;
if (time(NULL) - LastFreeDiskCheck > DISKCHECKDELTA) {
- if (LowDiskSpace()) {
+ if (!VideoFileSpaceAvailable(MINDISKSPACE)) {
// Remove the oldest file that has been "deleted":
cRecordings Recordings;
if (Recordings.Load(true)) {
@@ -240,10 +213,7 @@ bool cRecording::Delete(void)
if (strcmp(ext, RECEXT) == 0) {
strncpy(ext, DELEXT, strlen(ext));
isyslog(LOG_INFO, "deleting recording %s", FileName());
- if (rename(FileName(), NewName) == -1) {
- esyslog(LOG_ERR, "ERROR: %s: %s", FileName(), strerror(errno));
- result = false;
- }
+ result = RenameVideoFile(FileName(), NewName);
}
delete NewName;
return result;
@@ -252,7 +222,7 @@ bool cRecording::Delete(void)
bool cRecording::Remove(void)
{
isyslog(LOG_INFO, "removing recording %s", FileName());
- return RemoveFileOrDir(FileName());
+ return RemoveVideoFile(FileName());
}
// --- cRecordings -----------------------------------------------------------
diff --git a/recording.h b/recording.h
index ae17cd3c..dc3b3d74 100644
--- a/recording.h
+++ b/recording.h
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: recording.h 1.8 2000/07/28 12:48:06 kls Exp $
+ * $Id: recording.h 1.9 2000/07/28 13:53:54 kls Exp $
*/
#ifndef __RECORDING_H
@@ -14,8 +14,6 @@
#include "config.h"
#include "tools.h"
-extern const char *VideoDirectory;
-
void AssertFreeDiskSpace(void);
class cRecording : public cListObject {
diff --git a/tools.c b/tools.c
index 88acd333..83cb51ef 100644
--- a/tools.c
+++ b/tools.c
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: tools.c 1.11 2000/07/28 13:22:10 kls Exp $
+ * $Id: tools.c 1.12 2000/07/29 14:02:41 kls Exp $
*/
#define _GNU_SOURCE
@@ -145,20 +145,47 @@ bool isnumber(const char *s)
return true;
}
-bool DirectoryOk(const char *DirName)
+#define DFCMD "df -m %s"
+
+uint FreeDiskSpaceMB(const char *Directory)
+{
+ //TODO Find a simpler way to determine the amount of free disk space!
+ uint Free = 0;
+ char *cmd = NULL;
+ asprintf(&cmd, DFCMD, Directory);
+ FILE *p = popen(cmd, "r");
+ if (p) {
+ char *s;
+ while ((s = readline(p)) != NULL) {
+ if (*s == '/') {
+ uint available;
+ sscanf(s, "%*s %*d %*d %u", &available);
+ Free = available;
+ break;
+ }
+ }
+ pclose(p);
+ }
+ else
+ esyslog(LOG_ERR, "ERROR: can't open pipe for cmd '%s'", cmd);
+ delete cmd;
+ return Free;
+}
+
+bool DirectoryOk(const char *DirName, bool LogErrors)
{
struct stat ds;
if (stat(DirName, &ds) == 0) {
if (S_ISDIR(ds.st_mode)) {
if (access(DirName, R_OK | W_OK | X_OK) == 0)
return true;
- else
+ else if (LogErrors)
esyslog(LOG_ERR, "ERROR: can't access %s", DirName);
}
- else
+ else if (LogErrors)
esyslog(LOG_ERR, "ERROR: %s is not a directory", DirName);
}
- else
+ else if (LogErrors)
LOG_ERROR_STR(DirName);
return false;
}
@@ -175,7 +202,7 @@ bool MakeDirs(const char *FileName, bool IsDirectory)
*p = 0;
struct stat fs;
if (stat(s, &fs) != 0 || !S_ISDIR(fs.st_mode)) {
- isyslog(LOG_INFO, "creating directory %s", s);
+ dsyslog(LOG_INFO, "creating directory %s", s);
if (mkdir(s, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) == -1) {
esyslog(LOG_ERR, "ERROR: %s: %s", s, strerror(errno));
result = false;
@@ -191,7 +218,7 @@ bool MakeDirs(const char *FileName, bool IsDirectory)
return result;
}
-bool RemoveFileOrDir(const char *FileName)
+bool RemoveFileOrDir(const char *FileName, bool FollowSymlinks)
{
struct stat st;
if (stat(FileName, &st) == 0) {
@@ -203,23 +230,43 @@ bool RemoveFileOrDir(const char *FileName)
if (strcmp(e->d_name, ".") && strcmp(e->d_name, "..")) {
char *buffer;
asprintf(&buffer, "%s/%s", FileName, e->d_name);
+ if (FollowSymlinks) {
+ int size = strlen(buffer) * 2; // should be large enough
+ char *l = new char[size];
+ int n = readlink(buffer, l, size);
+ if (n < 0) {
+ if (errno != EINVAL)
+ LOG_ERROR_STR(buffer);
+ }
+ else if (n < size) {
+ l[n] = 0;
+ dsyslog(LOG_INFO, "removing %s", l);
+ if (remove(l) < 0)
+ LOG_ERROR_STR(l);
+ }
+ else
+ esyslog(LOG_ERR, "symlink name length (%d) exceeded anticipated buffer size (%d)", n, size);
+ delete l;
+ }
+ dsyslog(LOG_INFO, "removing %s", buffer);
if (remove(buffer) < 0)
- esyslog(LOG_ERR, "ERROR: %s: %s", buffer, strerror(errno));
+ LOG_ERROR_STR(buffer);
delete buffer;
}
}
closedir(d);
}
else {
- esyslog(LOG_ERR, "ERROR: %s: %s", FileName, strerror(errno));
+ LOG_ERROR_STR(FileName);
return false;
}
}
+ dsyslog(LOG_INFO, "removing %s", FileName);
if (remove(FileName) == 0)
return true;
}
else
- esyslog(LOG_ERR, "ERROR: %s: %s", FileName, strerror(errno));
+ LOG_ERROR_STR(FileName);
return false;
}
diff --git a/tools.h b/tools.h
index dc22033d..563f3d06 100644
--- a/tools.h
+++ b/tools.h
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: tools.h 1.11 2000/07/28 13:02:05 kls Exp $
+ * $Id: tools.h 1.12 2000/07/29 10:56:00 kls Exp $
*/
#ifndef __TOOLS_H
@@ -43,9 +43,10 @@ char *skipspace(char *s);
int time_ms(void);
void delay_ms(int ms);
bool isnumber(const char *s);
-bool DirectoryOk(const char *DirName);
+uint FreeDiskSpaceMB(const char *Directory);
+bool DirectoryOk(const char *DirName, bool LogErrors = false);
bool MakeDirs(const char *FileName, bool IsDirectory = false);
-bool RemoveFileOrDir(const char *FileName);
+bool RemoveFileOrDir(const char *FileName, bool FollowSymlinks = false);
bool CheckProcess(pid_t pid);
void KillProcess(pid_t pid, int Timeout = MAXPROCESSTIMEOUT);
diff --git a/vdr.c b/vdr.c
index 36ddcb42..51422234 100644
--- a/vdr.c
+++ b/vdr.c
@@ -22,7 +22,7 @@
*
* The project's page is at http://www.cadsoft.de/people/kls/vdr
*
- * $Id: vdr.c 1.24 2000/07/28 13:14:19 kls Exp $
+ * $Id: vdr.c 1.25 2000/07/28 15:55:31 kls Exp $
*/
#include <getopt.h>
@@ -36,6 +36,7 @@
#include "recording.h"
#include "svdrp.h"
#include "tools.h"
+#include "videodir.h"
#ifdef REMOTE_KBD
#define KEYS_CONF "keys-pc.conf"
@@ -105,7 +106,7 @@ int main(int argc, char *argv[])
// Check the video directory:
- if (!DirectoryOk(VideoDirectory)) {
+ if (!DirectoryOk(VideoDirectory, true)) {
fprintf(stderr, "vdr: can't access video directory %s\n", VideoDirectory);
abort();
}
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;
+}
diff --git a/videodir.h b/videodir.h
new file mode 100644
index 00000000..7ce15314
--- /dev/null
+++ b/videodir.h
@@ -0,0 +1,21 @@
+/*
+ * videodir.h: 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.h 1.1 2000/07/29 14:08:27 kls Exp $
+ */
+
+#ifndef __VIDEODIR_H
+#define __VIDEODIR_H
+
+extern const char *VideoDirectory;
+
+int OpenVideoFile(const char *FileName, int Flags);
+int CloseVideoFile(int FileHandle);
+bool RenameVideoFile(const char *OldName, const char *NewName);
+bool RemoveVideoFile(const char *FileName);
+bool VideoFileSpaceAvailable(unsigned int SizeMB);
+
+#endif //__VIDEODIR_H