mirror of
https://github.com/VDR4Arch/vdr.git
synced 2023-10-10 13:36:52 +02:00
Removed the code for distributing recordings over several video directories; added the cVideoDirectory plugin API
This commit is contained in:
parent
209b850067
commit
3971cc6e88
23
HISTORY
23
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().
|
||||
|
37
PLUGINS.html
37
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 <vdr/videodir.h>
|
||||
|
||||
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>
|
||||
|
18
cutter.c
18
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);
|
||||
}
|
||||
}
|
||||
|
6
menu.c
6
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() : "");
|
||||
|
41
recording.c
41
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;
|
||||
}
|
||||
}
|
||||
|
4
svdrp.c
4
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
|
||||
|
5
vdr.c
5
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);
|
||||
|
300
videodir.c
300
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;
|
||||
}
|
||||
|
||||
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;
|
||||
|
86
videodir.h
86
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:
|
||||
|
Loading…
Reference in New Issue
Block a user