Removed the code for distributing recordings over several video directories; added the cVideoDirectory plugin API

This commit is contained in:
Klaus Schmidinger 2013-09-11 12:20:37 +02:00
parent 209b850067
commit 3971cc6e88
9 changed files with 266 additions and 254 deletions

23
HISTORY
View File

@ -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().

View File

@ -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>

View File

@ -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);
}
}

6
menu.c
View File

@ -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() : "");

View File

@ -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;
}
}

View File

@ -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

5
vdr.c
View File

@ -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);

View File

@ -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;
}
cVideoDirectory *cVideoDirectory::Current(void)
{
if (!current)
current = new cVideoDirectory;
return current;
}
void cVideoDirectory::Destroy(void)
{
delete current;
}
int cVideoDirectory::FreeMB(int *UsedMB)
{
return FreeDiskSpaceMB(
#ifdef DEPRECATED_DISTRIBUTED_VIDEODIR
name ? name :
return FreeDiskSpaceMB(Name(), UsedMB);
}
const char *cVideoDirectory::Name(void)
{
return name;
}
void cVideoDirectory::SetName(const char *Name)
{
name = Name;
#ifdef DEPRECATED_VIDEODIR
VideoDirectory = Name;
#endif
VideoDirectory, UsedMB);
}
#ifdef DEPRECATED_DISTRIBUTED_VIDEODIR
bool cVideoDirectory::Next(void)
bool cVideoDirectory::Register(const char *FileName)
{
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) {
free(stored);
stored = strdup(name);
}
}
const char *cVideoDirectory::Adjust(const char *FileName)
{
if (stored) {
free(adjusted);
adjusted = strdup(FileName);
return strncpy(adjusted, stored, length);
}
return NULL;
}
#endif
cUnbufferedFile *OpenVideoFile(const char *FileName, int Flags)
{
const char *ActualFileName = 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!
}
}
}
#endif
cUnbufferedFile *File = cUnbufferedFile::Create(ActualFileName, Flags, DEFFILEMODE);
if (ActualFileName != FileName)
free((char *)ActualFileName);
return File;
}
int CloseVideoFile(cUnbufferedFile *File)
{
int Result = File->Close();
delete File;
return Result;
}
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)
bool cVideoDirectory::Rename(const char *OldName, const char *NewName)
{
return RemoveFileOrDir(FileName, true);
}
bool VideoFileSpaceAvailable(int SizeMB)
{
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;
}
if (rename(OldName, NewName) == -1) {
LOG_ERROR_STR(NewName);
return false;
}
#endif
return Dir.FreeMB() >= SizeMB;
return true;
}
int VideoDiskSpace(int *FreeMB, int *UsedMB)
bool cVideoDirectory::Move(const char *FromName, const char *ToName)
{
int free = 0, used = 0;
if (rename(FromName, ToName) == -1) {
LOG_ERROR_STR(ToName);
return false;
}
return true;
}
bool cVideoDirectory::Remove(const char *Name)
{
return RemoveFileOrDir(Name);
}
void cVideoDirectory::Cleanup(const char *IgnoreFiles[])
{
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);
}
bool cVideoDirectory::MoveVideoFile(const char *FromName, const char *ToName)
{
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;

View File

@ -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: