summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKlaus Schmidinger <vdr@tvdr.de>2013-09-11 12:20:37 +0200
committerKlaus Schmidinger <vdr@tvdr.de>2013-09-11 12:20:37 +0200
commit3971cc6e8845f2a70018b20706f4a30d71edd41d (patch)
tree37a9211b2a65f972b17f3b302d16c9711146de33
parent209b8500670f0504a37232facdbed2acf68df086 (diff)
downloadvdr-3971cc6e8845f2a70018b20706f4a30d71edd41d.tar.gz
vdr-3971cc6e8845f2a70018b20706f4a30d71edd41d.tar.bz2
Removed the code for distributing recordings over several video directories; added the cVideoDirectory plugin API
-rw-r--r--HISTORY23
-rw-r--r--PLUGINS.html37
-rw-r--r--cutter.c18
-rw-r--r--menu.c6
-rw-r--r--recording.c41
-rw-r--r--svdrp.c4
-rw-r--r--vdr.c5
-rw-r--r--videodir.c268
-rw-r--r--videodir.h86
9 files changed, 250 insertions, 238 deletions
diff --git a/HISTORY b/HISTORY
index 3c3d859b..3f880fce 100644
--- a/HISTORY
+++ b/HISTORY
@@ -7943,3 +7943,26 @@ Video Disk Recorder Revision History
respectively, during replay (reported by Thomas Maass).
- The Yellow button in the main menu no longer acts as "Pause" if "Pause key handling"
is set to "do not pause live video" (suggested by Ulf Kiener).
+- The code for distributing recordings over several video directories has been
+ removed. VDR now by default assumes that the video directory is one big disk.
+ If you absolutely need to use several separate disks to store recordings, you can
+ write a plugin that uses the new cVideoDirectory API to implement the necessary
+ functionality (see PLUGINS.html, section "The video directory"). You can copy the
+ respective code from previous versions of videodir.c.
+ IMPORTANT NOTE: If you write a plugin that implements a distributed video directory,
+ =============== be sure to make cVideoDirectory::Rename() follow symbolic links!
+ This functionality was never implemented in VDR and it therefore
+ used a workaround in cutter.c. See the section marked with
+ // XXX this can be removed once RenameVideoFile() follows symlinks
+ in previous versions of cutter.c.
+ + CloseVideoFile() is obsolete and has been removed.
+ + The functions OpenVideoFile(), RenameVideoFile(), RemoveVideoFile(), VideoFileSpaceAvailable(),
+ VideoDiskSpace(), RemoveEmptyVideoDirectories(), IsOnVideoDirectoryFileSystem() and
+ PrefixVideoFileName() are now static members of cVideoDirectory and need to be called
+ with the proper prefix.
+ + The name of the video directory is now available through cVideoDirectory::Name().
+ The former global variable VideoDirectory is still there for backwards compatibility,
+ but will be removed in a future version. Comment out the line
+ #define DEPRECATED_VIDEODIR
+ in videodir.h and recompile your plugins to see whether your code will work without
+ this variable. If you get a compile error, replace it with cVideoDirectory::Name().
diff --git a/PLUGINS.html b/PLUGINS.html
index 5260c4bf..71d840ea 100644
--- a/PLUGINS.html
+++ b/PLUGINS.html
@@ -104,6 +104,7 @@ structures and allows it to hook itself into specific areas to perform special a
<li><a href="#Remote Control">Remote Control</a>
<li><a href="#Conditional Access">Conditional Access</a>
<li><a href="#Electronic Program Guide">Electronic Program Guide</a>
+<li><modified><a href="#The video directory">The video directory</a></modified>
</ul>
</ul>
@@ -2300,5 +2301,41 @@ to signal VDR that no other EPG handlers shall be queried after this one.
<p>
See <tt>VDR/epg.h</tt> for details.
+<div class="modified">
+<hr><h2><a name="The video directory">The video directory</a></h2>
+
+<div class="blurb">Bits and pieces...</div><p>
+
+By default VDR assumes that the video directory consists of one large
+volume, on which it can store its recordings. If you want to distribute your
+recordings over several physical drives, you can derive from <tt>cVideoDirectory</tt>,
+as in
+
+<p><table><tr><td class="code"><pre>
+#include &lt;vdr/videodir.h&gt;
+
+class cMyVideoDirectory : public cVideoDirectory {
+public:
+ cMyVideoDirectory(void);
+ virtual ~cMyVideoDirectory();
+ virtual int FreeMB(int *UsedMB = NULL);
+ virtual bool Register(const char *FileName);
+ virtual bool Rename(const char *OldName, const char *NewName);
+ virtual bool Move(const char *FromName, const char *ToName);
+ virtual bool Remove(const char *Name);
+ virtual void Cleanup(const char *IgnoreFiles[] = NULL);
+ virtual bool Contains(const char *Name);
+ };
+</pre></td></tr></table><p>
+
+See the description in <tt>videodir.h</tt> for details.
+<p>
+You should create your derived video directory object in the
+<a href="#Getting started"><tt>Start()</tt></a> function of your plugin.
+Note that the object has to be created on the heap (using <tt>new</tt>),
+and you shall not delete it at any point (it will be deleted automatically
+when the program ends).
+</div modified>
+
</body>
</html>
diff --git a/cutter.c b/cutter.c
index 5d007c48..ccb145a3 100644
--- a/cutter.c
+++ b/cutter.c
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: cutter.c 3.2 2013/08/21 13:15:24 kls Exp $
+ * $Id: cutter.c 3.3 2013/09/10 14:51:45 kls Exp $
*/
#include "cutter.h"
@@ -664,19 +664,7 @@ bool cCutter::Start(const char *FileName)
Recording.SetStartTime(Recording.Start() + (int(First->Position() / Recording.FramesPerSecond() + 30) / 60) * 60);
const char *evn = Recording.PrefixFileName('%');
- if (evn && RemoveVideoFile(evn) && MakeDirs(evn, true)) {
- // XXX this can be removed once RenameVideoFile() follows symlinks (see videodir.c)
- // remove a possible deleted recording with the same name to avoid symlink mixups:
- char *s = strdup(evn);
- char *e = strrchr(s, '.');
- if (e) {
- if (strcmp(e, ".rec") == 0) {
- strcpy(e, ".del");
- RemoveVideoFile(s);
- }
- }
- free(s);
- // XXX
+ if (evn && cVideoDirectory::RemoveVideoFile(evn) && MakeDirs(evn, true)) {
editedVersionName = evn;
Recording.WriteInfo();
Recordings.AddByName(editedVersionName, false);
@@ -701,7 +689,7 @@ void cCutter::Stop(void)
esyslog("ERROR: '%s' during editing process", Error);
if (cReplayControl::NowReplaying() && strcmp(cReplayControl::NowReplaying(), editedVersionName) == 0)
cControl::Shutdown();
- RemoveVideoFile(editedVersionName);
+ cVideoDirectory::RemoveVideoFile(editedVersionName);
Recordings.DelByName(editedVersionName);
}
}
diff --git a/menu.c b/menu.c
index 6224ef71..f7629092 100644
--- a/menu.c
+++ b/menu.c
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: menu.c 3.5 2013/09/07 12:43:26 kls Exp $
+ * $Id: menu.c 3.6 2013/09/10 13:16:40 kls Exp $
*/
#include "menu.h"
@@ -2316,7 +2316,7 @@ void cMenuRecordings::Set(bool Refresh)
cString cMenuRecordings::DirectoryName(void)
{
- cString d(VideoDirectory);
+ cString d(cVideoDirectory::Name());
if (base) {
char *s = ExchangeChars(strdup(base), true);
d = AddDirectory(d, s);
@@ -4342,7 +4342,7 @@ bool cRecordControls::Start(cTimer *Timer, bool Pause)
AssertFreeDiskSpace(Timer->Priority(), !Timer->Pending());
Timer->SetPending(true);
}
- VideoDiskSpace(&FreeMB);
+ cVideoDirectory::VideoDiskSpace(&FreeMB);
if (FreeMB < MINFREEDISK) {
if (!Timer || time(NULL) - LastNoDiskSpaceMessage > NODISKSPACEDELTA) {
isyslog("not enough disk space to start recording%s%s", Timer ? " timer " : "", Timer ? *Timer->ToDescr() : "");
diff --git a/recording.c b/recording.c
index f11a892e..5cbf1070 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 3.2 2013/08/21 13:56:33 kls Exp $
+ * $Id: recording.c 3.3 2013/09/11 08:28:27 kls Exp $
*/
#include "recording.h"
@@ -90,7 +90,7 @@ cRemoveDeletedRecordingsThread::cRemoveDeletedRecordingsThread(void)
void cRemoveDeletedRecordingsThread::Action(void)
{
// Make sure only one instance of VDR does this:
- cLockFile LockFile(VideoDirectory);
+ cLockFile LockFile(cVideoDirectory::Name());
if (LockFile.Lock()) {
bool deleted = false;
cThreadLock DeletedRecordingsLock(&DeletedRecordings);
@@ -109,7 +109,7 @@ void cRemoveDeletedRecordingsThread::Action(void)
}
if (deleted) {
const char *IgnoreFiles[] = { SORTMODEFILE, NULL };
- RemoveEmptyVideoDirectories(IgnoreFiles);
+ cVideoDirectory::RemoveEmptyVideoDirectories(IgnoreFiles);
}
}
}
@@ -145,9 +145,9 @@ void AssertFreeDiskSpace(int Priority, bool Force)
static time_t LastFreeDiskCheck = 0;
int Factor = (Priority == -1) ? 10 : 1;
if (Force || time(NULL) - LastFreeDiskCheck > DISKCHECKDELTA / Factor) {
- if (!VideoFileSpaceAvailable(MINDISKSPACE)) {
+ if (!cVideoDirectory::VideoFileSpaceAvailable(MINDISKSPACE)) {
// Make sure only one instance of VDR does this:
- cLockFile LockFile(VideoDirectory);
+ cLockFile LockFile(cVideoDirectory::Name());
if (!LockFile.Lock())
return;
// Remove the oldest file that has been "deleted":
@@ -800,8 +800,8 @@ cRecording::cRecording(const char *FileName)
FileName = fileName = strdup(FileName);
if (*(fileName + strlen(fileName) - 1) == '/')
*(fileName + strlen(fileName) - 1) = 0;
- if (strstr(FileName, VideoDirectory) == FileName)
- FileName += strlen(VideoDirectory) + 1;
+ if (strstr(FileName, cVideoDirectory::Name()) == FileName)
+ FileName += strlen(cVideoDirectory::Name()) + 1;
const char *p = strrchr(FileName, '/');
name = NULL;
@@ -949,7 +949,7 @@ char *cRecording::SortName(void) const
{
char **sb = (RecordingsSortMode == rsmName) ? &sortBufferName : &sortBufferTime;
if (!*sb) {
- char *s = strdup(FileName() + strlen(VideoDirectory));
+ char *s = strdup(FileName() + strlen(cVideoDirectory::Name()));
if (RecordingsSortMode != rsmName || Setup.AlwaysSortFoldersFirst)
s = StripEpisodeName(s, RecordingsSortMode != rsmName);
strreplace(s, '/', '0'); // some locales ignore '/' when sorting
@@ -990,11 +990,11 @@ const char *cRecording::FileName(void) const
const char *fmt = isPesRecording ? NAMEFORMATPES : NAMEFORMATTS;
int ch = isPesRecording ? priority : channel;
int ri = isPesRecording ? lifetime : instanceId;
- char *Name = LimitNameLengths(strdup(name), DirectoryPathMax - strlen(VideoDirectory) - 1 - 42, DirectoryNameMax); // 42 = length of an actual recording directory name (generated with DATAFORMATTS) plus some reserve
+ char *Name = LimitNameLengths(strdup(name), DirectoryPathMax - strlen(cVideoDirectory::Name()) - 1 - 42, DirectoryNameMax); // 42 = length of an actual recording directory name (generated with DATAFORMATTS) plus some reserve
if (strcmp(Name, name) != 0)
dsyslog("recording file name '%s' truncated to '%s'", name, Name);
Name = ExchangeChars(Name, true);
- fileName = strdup(cString::sprintf(fmt, VideoDirectory, Name, t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, ch, ri));
+ fileName = strdup(cString::sprintf(fmt, cVideoDirectory::Name(), Name, t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, ch, ri));
free(Name);
}
return fileName;
@@ -1063,7 +1063,7 @@ const char *cRecording::Title(char Delimiter, bool NewIndicator, int Level) cons
const char *cRecording::PrefixFileName(char Prefix)
{
- cString p = PrefixVideoFileName(FileName(), Prefix);
+ cString p = cVideoDirectory::PrefixVideoFileName(FileName(), Prefix);
if (*p) {
free(fileName);
fileName = strdup(p);
@@ -1093,7 +1093,7 @@ bool cRecording::IsEdited(void) const
bool cRecording::IsOnVideoDirectoryFileSystem(void) const
{
if (isOnVideoDirectoryFileSystem < 0)
- isOnVideoDirectoryFileSystem = ::IsOnVideoDirectoryFileSystem(FileName());
+ isOnVideoDirectoryFileSystem = cVideoDirectory::IsOnVideoDirectoryFileSystem(FileName());
return isOnVideoDirectoryFileSystem;
}
@@ -1135,11 +1135,11 @@ bool cRecording::Delete(void)
if (access(NewName, F_OK) == 0) {
// the new name already exists, so let's remove that one first:
isyslog("removing recording '%s'", NewName);
- RemoveVideoFile(NewName);
+ cVideoDirectory::RemoveVideoFile(NewName);
}
isyslog("deleting recording '%s'", FileName());
if (access(FileName(), F_OK) == 0) {
- result = RenameVideoFile(FileName(), NewName);
+ result = cVideoDirectory::RenameVideoFile(FileName(), NewName);
cRecordingUserCommand::InvokeCommand(RUC_DELETERECORDING, NewName);
}
else {
@@ -1159,7 +1159,7 @@ bool cRecording::Remove(void)
return false;
}
isyslog("removing recording %s", FileName());
- return RemoveVideoFile(FileName());
+ return cVideoDirectory::RemoveVideoFile(FileName());
}
bool cRecording::Undelete(void)
@@ -1177,7 +1177,7 @@ bool cRecording::Undelete(void)
else {
isyslog("undeleting recording '%s'", FileName());
if (access(FileName(), F_OK) == 0)
- result = RenameVideoFile(FileName(), NewName);
+ result = cVideoDirectory::RenameVideoFile(FileName(), NewName);
else {
isyslog("deleted recording '%s' vanished", FileName());
result = false;
@@ -1250,7 +1250,7 @@ void cRecordings::Action(void)
const char *cRecordings::UpdateFileName(void)
{
if (!updateFileName)
- updateFileName = strdup(AddDirectory(VideoDirectory, ".update"));
+ updateFileName = strdup(AddDirectory(cVideoDirectory::Name(), ".update"));
return updateFileName;
}
@@ -1261,7 +1261,7 @@ void cRecordings::Refresh(bool Foreground)
Clear();
ChangeState();
Unlock();
- ScanVideoDir(VideoDirectory, Foreground);
+ ScanVideoDir(cVideoDirectory::Name(), Foreground);
}
void cRecordings::ScanVideoDir(const char *DirName, bool Foreground, int LinkLevel)
@@ -2274,7 +2274,7 @@ cUnbufferedFile *cFileName::Open(void)
int BlockingFlag = blocking ? 0 : O_NONBLOCK;
if (record) {
dsyslog("recording to '%s'", fileName);
- file = OpenVideoFile(fileName, O_RDWR | O_CREAT | O_LARGEFILE | BlockingFlag);
+ file = cVideoDirectory::OpenVideoFile(fileName, O_RDWR | O_CREAT | O_LARGEFILE | BlockingFlag);
if (!file)
LOG_ERROR_STR(fileName);
}
@@ -2295,8 +2295,9 @@ cUnbufferedFile *cFileName::Open(void)
void cFileName::Close(void)
{
if (file) {
- if (CloseVideoFile(file) < 0)
+ if (file->Close() < 0)
LOG_ERROR_STR(fileName);
+ delete file;
file = NULL;
}
}
diff --git a/svdrp.c b/svdrp.c
index 8a50daeb..ef1296d9 100644
--- a/svdrp.c
+++ b/svdrp.c
@@ -10,7 +10,7 @@
* and interact with the Video Disk Recorder - or write a full featured
* graphical interface that sits on top of an SVDRP connection.
*
- * $Id: svdrp.c 2.24 2013/02/17 13:18:01 kls Exp $
+ * $Id: svdrp.c 3.1 2013/09/10 13:21:38 kls Exp $
*/
#include "svdrp.h"
@@ -1550,7 +1550,7 @@ void cSVDRP::CmdSTAT(const char *Option)
if (*Option) {
if (strcasecmp(Option, "DISK") == 0) {
int FreeMB, UsedMB;
- int Percent = VideoDiskSpace(&FreeMB, &UsedMB);
+ int Percent = cVideoDirectory::VideoDiskSpace(&FreeMB, &UsedMB);
Reply(250, "%dMB %dMB %d%%", FreeMB + UsedMB, FreeMB, Percent);
}
else
diff --git a/vdr.c b/vdr.c
index bf581a6e..3fc44d35 100644
--- a/vdr.c
+++ b/vdr.c
@@ -22,7 +22,7 @@
*
* The project's page is at http://www.tvdr.de
*
- * $Id: vdr.c 3.1 2013/06/10 14:28:43 kls Exp $
+ * $Id: vdr.c 3.2 2013/09/10 13:58:34 kls Exp $
*/
#include <getopt.h>
@@ -663,7 +663,7 @@ int main(int argc, char *argv[])
// Directories:
- SetVideoDirectory(VideoDirectory);
+ cVideoDirectory::SetName(VideoDirectory);
if (!ConfigDirectory)
ConfigDirectory = DEFAULTCONFDIR;
cPlugin::SetConfigDirectory(ConfigDirectory);
@@ -1406,6 +1406,7 @@ Exit:
}
cDevice::Shutdown();
cPositioner::DestroyPositioner();
+ cVideoDirectory::Destroy();
EpgHandlers.Clear();
PluginManager.Shutdown(true);
cSchedules::Cleanup(true);
diff --git a/videodir.c b/videodir.c
index 9ad31b6f..cd739ea1 100644
--- a/videodir.c
+++ b/videodir.c
@@ -1,10 +1,10 @@
/*
- * videodir.c: Functions to maintain a distributed video directory
+ * videodir.c: Functions to maintain the video directory
*
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: videodir.c 3.1 2013/08/23 12:28:06 kls Exp $
+ * $Id: videodir.c 3.2 2013/09/11 12:20:37 kls Exp $
*/
#include "videodir.h"
@@ -19,213 +19,129 @@
#include "recording.h"
#include "tools.h"
-//#define DEPRECATED_DISTRIBUTED_VIDEODIR // Code enclosed with this macro is deprecated and will be removed in a future version
-
+#ifdef DEPRECATED_VIDEODIR
const char *VideoDirectory = VIDEODIR;
-
-void SetVideoDirectory(const char *Directory)
-{
- VideoDirectory = strdup(Directory);
-}
-
-class cVideoDirectory {
-#ifdef DEPRECATED_DISTRIBUTED_VIDEODIR
-private:
- char *name, *stored, *adjusted;
- int length, number, digits;
#endif
-public:
- cVideoDirectory(void);
- ~cVideoDirectory();
- int FreeMB(int *UsedMB = NULL);
- const char *Name(void) { return
-#ifdef DEPRECATED_DISTRIBUTED_VIDEODIR
- name ? name :
-#endif
- VideoDirectory; }
-#ifdef DEPRECATED_DISTRIBUTED_VIDEODIR
- 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);
-#endif
- };
+cString cVideoDirectory::name;
+cVideoDirectory *cVideoDirectory::current = NULL;
cVideoDirectory::cVideoDirectory(void)
{
-#ifdef DEPRECATED_DISTRIBUTED_VIDEODIR
- length = strlen(VideoDirectory);
- name = (VideoDirectory[length - 1] == '0') ? strdup(VideoDirectory) : NULL;
- stored = adjusted = NULL;
- number = -1;
- digits = 0;
-#endif
+ delete current;
+ current = this;
}
cVideoDirectory::~cVideoDirectory()
{
-#ifdef DEPRECATED_DISTRIBUTED_VIDEODIR
- free(name);
- free(stored);
- free(adjusted);
-#endif
+ current = NULL;
}
-int cVideoDirectory::FreeMB(int *UsedMB)
+cVideoDirectory *cVideoDirectory::Current(void)
{
- return FreeDiskSpaceMB(
-#ifdef DEPRECATED_DISTRIBUTED_VIDEODIR
- name ? name :
-#endif
- VideoDirectory, UsedMB);
+ if (!current)
+ current = new cVideoDirectory;
+ return current;
}
-#ifdef DEPRECATED_DISTRIBUTED_VIDEODIR
-bool cVideoDirectory::Next(void)
+void cVideoDirectory::Destroy(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;
+ delete current;
}
-void cVideoDirectory::Store(void)
+int cVideoDirectory::FreeMB(int *UsedMB)
{
- if (name) {
- free(stored);
- stored = strdup(name);
- }
+ return FreeDiskSpaceMB(Name(), UsedMB);
}
-const char *cVideoDirectory::Adjust(const char *FileName)
+const char *cVideoDirectory::Name(void)
{
- if (stored) {
- free(adjusted);
- adjusted = strdup(FileName);
- return strncpy(adjusted, stored, length);
- }
- return NULL;
+ return name;
}
-#endif
-cUnbufferedFile *OpenVideoFile(const char *FileName, int Flags)
+void cVideoDirectory::SetName(const char *Name)
{
- const char *ActualFileName = FileName;
+ name = Name;
+#ifdef DEPRECATED_VIDEODIR
+ VideoDirectory = Name;
+#endif
+}
+bool cVideoDirectory::Register(const char *FileName)
+{
// Incoming name must be in base video directory:
- if (strstr(FileName, VideoDirectory) != FileName) {
- esyslog("ERROR: %s not in %s", FileName, VideoDirectory);
+ if (strstr(FileName, Name()) != FileName) {
+ esyslog("ERROR: %s not in %s", FileName, Name());
errno = ENOENT; // must set 'errno' - any ideas for a better value?
- return NULL;
- }
-#ifdef DEPRECATED_DISTRIBUTED_VIDEODIR
- // 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:
- int MaxFree = Dir.FreeMB();
- while (Dir.Next()) {
- int Free = FreeDiskSpaceMB(Dir.Name());
- if (Free > MaxFree) {
- Dir.Store();
- MaxFree = Free;
- }
- }
- if (Dir.Stored()) {
- ActualFileName = Dir.Adjust(FileName);
- if (!MakeDirs(ActualFileName, false))
- return NULL; // errno has been set by MakeDirs()
- if (symlink(ActualFileName, FileName) < 0) {
- LOG_ERROR_STR(FileName);
- return NULL;
- }
- ActualFileName = strdup(ActualFileName); // must survive Dir!
- }
- }
+ return false;
}
-#endif
- cUnbufferedFile *File = cUnbufferedFile::Create(ActualFileName, Flags, DEFFILEMODE);
- if (ActualFileName != FileName)
- free((char *)ActualFileName);
- return File;
+ return true;
}
-int CloseVideoFile(cUnbufferedFile *File)
+bool cVideoDirectory::Rename(const char *OldName, const char *NewName)
{
- int Result = File->Close();
- delete File;
- return Result;
+ if (rename(OldName, NewName) == -1) {
+ LOG_ERROR_STR(NewName);
+ return false;
+ }
+ return true;
}
-bool RenameVideoFile(const char *OldName, const char *NewName)
+bool cVideoDirectory::Move(const char *FromName, const char *ToName)
{
- // 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);
+ if (rename(FromName, ToName) == -1) {
+ LOG_ERROR_STR(ToName);
return false;
}
return true;
}
-bool RemoveVideoFile(const char *FileName)
+bool cVideoDirectory::Remove(const char *Name)
{
- return RemoveFileOrDir(FileName, true);
+ return RemoveFileOrDir(Name);
}
-bool VideoFileSpaceAvailable(int SizeMB)
+void cVideoDirectory::Cleanup(const char *IgnoreFiles[])
{
- cVideoDirectory Dir;
-#ifdef DEPRECATED_DISTRIBUTED_VIDEODIR
- 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;
- }
-#endif
- return Dir.FreeMB() >= SizeMB;
+ RemoveEmptyDirectories(Name(), false, IgnoreFiles);
+}
+
+bool cVideoDirectory::Contains(const char *Name)
+{
+ return EntriesOnSameFileSystem(this->Name(), Name);
+}
+
+cUnbufferedFile *cVideoDirectory::OpenVideoFile(const char *FileName, int Flags)
+{
+ if (Current()->Register(FileName))
+ return cUnbufferedFile::Create(FileName, Flags, DEFFILEMODE);
+ return NULL;
+}
+
+bool cVideoDirectory::RenameVideoFile(const char *OldName, const char *NewName)
+{
+ return Current()->Rename(OldName, NewName);
}
-int VideoDiskSpace(int *FreeMB, int *UsedMB)
+bool cVideoDirectory::MoveVideoFile(const char *FromName, const char *ToName)
{
- int free = 0, used = 0;
+ return Current()->Move(FromName, ToName);
+}
+
+bool cVideoDirectory::RemoveVideoFile(const char *FileName)
+{
+ return Current()->Remove(FileName);
+}
+
+bool cVideoDirectory::VideoFileSpaceAvailable(int SizeMB)
+{
+ return Current()->FreeMB() >= SizeMB;
+}
+
+int cVideoDirectory::VideoDiskSpace(int *FreeMB, int *UsedMB)
+{
+ int used = 0;
+ int free = Current()->FreeMB(&used);
int deleted = DeletedRecordings.TotalFileSizeMB();
- cVideoDirectory Dir;
-#ifdef DEPRECATED_DISTRIBUTED_VIDEODIR
- do {
-#endif
- int u;
- free += Dir.FreeMB(&u);
- used += u;
-#ifdef DEPRECATED_DISTRIBUTED_VIDEODIR
- } while (Dir.Next());
-#endif
if (deleted > used)
deleted = used; // let's not get beyond 100%
free += deleted;
@@ -237,7 +153,7 @@ int VideoDiskSpace(int *FreeMB, int *UsedMB)
return (free + used) ? used * 100 / (free + used) : 0;
}
-cString PrefixVideoFileName(const char *FileName, char Prefix)
+cString cVideoDirectory::PrefixVideoFileName(const char *FileName, char Prefix)
{
char PrefixedName[strlen(FileName) + 2];
@@ -257,30 +173,14 @@ cString PrefixVideoFileName(const char *FileName, char Prefix)
return NULL;
}
-void RemoveEmptyVideoDirectories(const char *IgnoreFiles[])
+void cVideoDirectory::RemoveEmptyVideoDirectories(const char *IgnoreFiles[])
{
- cVideoDirectory Dir;
-#ifdef DEPRECATED_DISTRIBUTED_VIDEODIR
- do {
-#endif
- RemoveEmptyDirectories(Dir.Name(), false, IgnoreFiles);
-#ifdef DEPRECATED_DISTRIBUTED_VIDEODIR
- } while (Dir.Next());
-#endif
+ Current()->Cleanup(IgnoreFiles);
}
-bool IsOnVideoDirectoryFileSystem(const char *FileName)
+bool cVideoDirectory::IsOnVideoDirectoryFileSystem(const char *FileName)
{
- cVideoDirectory Dir;
-#ifdef DEPRECATED_DISTRIBUTED_VIDEODIR
- do {
-#endif
- if (EntriesOnSameFileSystem(Dir.Name(), FileName))
- return true;
-#ifdef DEPRECATED_DISTRIBUTED_VIDEODIR
- } while (Dir.Next());
-#endif
- return false;
+ return Current()->Contains(FileName);
}
// --- cVideoDiskUsage -------------------------------------------------------
@@ -298,7 +198,7 @@ bool cVideoDiskUsage::HasChanged(int &State)
{
if (time(NULL) - lastChecked > DISKSPACECHEK) {
int FreeMB;
- int UsedPercent = VideoDiskSpace(&FreeMB);
+ int UsedPercent = cVideoDirectory::VideoDiskSpace(&FreeMB);
if (FreeMB != freeMB) {
usedPercent = UsedPercent;
freeMB = FreeMB;
diff --git a/videodir.h b/videodir.h
index a25ac319..c604d046 100644
--- a/videodir.h
+++ b/videodir.h
@@ -1,10 +1,10 @@
/*
- * videodir.h: Functions to maintain a distributed video directory
+ * videodir.h: Functions to maintain the video directory
*
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: videodir.h 2.3 2012/09/30 11:01:15 kls Exp $
+ * $Id: videodir.h 3.1 2013/09/11 12:19:47 kls Exp $
*/
#ifndef __VIDEODIR_H
@@ -13,18 +13,80 @@
#include <stdlib.h>
#include "tools.h"
+#define DEPRECATED_VIDEODIR
+#ifdef DEPRECATED_VIDEODIR
extern const char *VideoDirectory;
+#endif
-void SetVideoDirectory(const char *Directory);
-cUnbufferedFile *OpenVideoFile(const char *FileName, int Flags);
-int CloseVideoFile(cUnbufferedFile *File);
-bool RenameVideoFile(const char *OldName, const char *NewName);
-bool RemoveVideoFile(const char *FileName);
-bool VideoFileSpaceAvailable(int SizeMB);
-int VideoDiskSpace(int *FreeMB = NULL, int *UsedMB = NULL); // returns the used disk space in percent
-cString PrefixVideoFileName(const char *FileName, char Prefix);
-void RemoveEmptyVideoDirectories(const char *IgnoreFiles[] = NULL);
-bool IsOnVideoDirectoryFileSystem(const char *FileName);
+class cVideoDirectory {
+private:
+ static cString name;
+ static cVideoDirectory *current;
+ static cVideoDirectory *Current(void);
+public:
+ cVideoDirectory(void);
+ virtual ~cVideoDirectory();
+ virtual int FreeMB(int *UsedMB = NULL);
+ ///< Returns the total amount (in MB) of free disk space for recording.
+ ///< If UsedMB is given, it returns the amount of disk space in use by
+ ///< existing recordings (or anything else) on that disk.
+ virtual bool Register(const char *FileName);
+ ///< By default VDR assumes that the video directory consists of one large
+ ///< volume, on which it can store its recordings. A derived cVideoDirectory
+ ///< may, for instance, use several separate disks to store recordings.
+ ///< The given FileName is the full path name (including the video directory) of
+ ///< a recording file ('*.ts') that is about to be opened for writing. If the actual
+ ///< file shall be put on an other disk, the derived cVideoDirectory should
+ ///< create a symbolic link from the given FileName to the other location.
+ ///< Returns true if the operation was successful.
+ ///< The default implementation just checks whether the incoming file name really
+ ///< is under the video directory.
+ virtual bool Rename(const char *OldName, const char *NewName);
+ ///< Renames the directory OldName to NewName.
+ ///< OldName and NewName are full path names that begin with the name of the
+ ///< video directory and end with '*.rec' or '*.del'. Only the base name (the
+ ///< rightmost component) of the two names may be different.
+ ///< Returns true if the operation was successful.
+ ///< The default implementation just calls the system's rename() function.
+ virtual bool Move(const char *FromName, const char *ToName);
+ ///< Moves the directory FromName to the location ToName. FromName is the full
+ ///< path name of a recording's '*.rec' directory. ToName has the same '*.rec'
+ ///< part as FromName, but a different directory path above it.
+ ///< Returns true if the operation was successful.
+ ///< The default implementation just calls the system's rename() function.
+ virtual bool Remove(const char *Name);
+ ///< Removes the directory with the given Name and everything it contains.
+ ///< Name is a full path name that begins with the name of the video directory.
+ ///< Returns true if the operation was successful.
+ ///< The default implementation calls RemoveFileOrDir().
+ virtual void Cleanup(const char *IgnoreFiles[] = NULL);
+ ///< Recursively removes all empty directories under the video directory.
+ ///< If IgnoreFiles is given, the file names in this (NULL terminated) array
+ ///< are ignored when checking whether a directory is empty. These are
+ ///< typically "dot files", like e.g. ".sort".
+ ///< The default implementation calls RemoveEmptyDirectories().
+ virtual bool Contains(const char *Name);
+ ///< Checks whether the directory Name is on the same file system as the
+ ///< video directory. Name is the full path name of a recording's '*.rec'
+ ///< directory. This function is usually called when an ongoing recording
+ ///< is about to run out of disk space, and an existing (old) recording needs
+ ///< to be deleted. It shall make sure that deleting this old recording will
+ ///< actually free up space in the video directory, and not on some other
+ ///< device that just happens to be mounted.
+ ///< The default implementation calls EntriesOnSameFileSystem().
+ static const char *Name(void);
+ static void SetName(const char *Name);
+ static void Destroy(void);
+ static cUnbufferedFile *OpenVideoFile(const char *FileName, int Flags);
+ static bool RenameVideoFile(const char *OldName, const char *NewName);
+ static bool MoveVideoFile(const char *FromName, const char *ToName);
+ static bool RemoveVideoFile(const char *FileName);
+ static bool VideoFileSpaceAvailable(int SizeMB);
+ static int VideoDiskSpace(int *FreeMB = NULL, int *UsedMB = NULL); // returns the used disk space in percent
+ static cString PrefixVideoFileName(const char *FileName, char Prefix);
+ static void RemoveEmptyVideoDirectories(const char *IgnoreFiles[] = NULL);
+ static bool IsOnVideoDirectoryFileSystem(const char *FileName);
+ };
class cVideoDiskUsage {
private: