mirror of
https://github.com/vdr-projects/vdr.git
synced 2025-03-01 10:50:46 +00:00
- Added a sleep in cDvbPlayer::Action() in case there is no data to send to the device, which avoids a busy loop on very fast machines (thanks to Martin Wache). - Modified the description of cDevice::Poll() to avoid misunderstandings. - Updated Croatian language texts (thanks to Drazen Dupor). - cDvbPlayer::Goto() now appends a Sequence End Code to get the image shown immediately with softdevices (thanks to Reinhard Nissl). - Reactivated cVideoRepacker in remux.c after some fixes (thanks to Reinhard Nissl). - Removed the fix for handling VPS timers, so that they only record if the event they are assigned to actually has the given VPS time. This has caused repeating VPS timers to stop recording prematurely. - Avoiding duplicate components in EPG events when reading epg.data or in the PUTE SVDRP command (thanks to Olaf Titz for reporting this one). - Added the command line options '--lirc', '--rcu' and '--no-kbd' to allow setting the remote control at runtime (based on a patch by Darren Salt). - Now checking whether timers or channels are currently being edited via the menu before making changes through SVDRP (thanks to Andreas Brugger for reporting a problem with this). - Files and directories are now created with rights according to the shell's umask settings (thanks to Andreas Brachold). - Fixed the cChannel copy constructor (thanks to Marcel Wiesweg for pointing out a problem with it). - Fixed an out-of-bounds memory access with audio language ids (thanks to Matthias Lenk for reporting, and Udo Richter for suggesting a fix). - Updated the Finnish OSD texts (thanks to Rolf Ahrenberg). - Added missing storing of the MenuScrollPage parameter (thanks to Frank Krömmelbein). - Added cRemux::SetTimeouts() for better use of cRemux in a single thread (thanks to Udo Richter for reporting a problem with this). - Modified cEITScanner::Process() so that it uses the primary device if it is replaying and is the only device that provides the given transponder, and that a forced EPG scan works even if EPG scan timeout is set to 0 (thanks to Bernhard Stegmaier for reporting a problem with this). - Fixed cDvbSpuBitmap::putPixel() (thanks to Reinhard Nissl). - Fixed setting system time to avoid time jumps in case of faulty data (thanks to Andreas Böttger). - Fixed a memory leak in the SVDRP command LSTE (thanks to Stefan Huelswitt).
228 lines
5.5 KiB
C
228 lines
5.5 KiB
C
/*
|
|
* 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.12 2005/08/06 09:53:21 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 = VIDEODIR;
|
|
|
|
class cVideoDirectory {
|
|
private:
|
|
char *name, *stored, *adjusted;
|
|
int length, number, digits;
|
|
public:
|
|
cVideoDirectory(void);
|
|
~cVideoDirectory();
|
|
int FreeMB(int *UsedMB = NULL);
|
|
const char *Name(void) { return name ? name : VideoDirectory; }
|
|
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()
|
|
{
|
|
free(name);
|
|
free(stored);
|
|
free(adjusted);
|
|
}
|
|
|
|
int cVideoDirectory::FreeMB(int *UsedMB)
|
|
{
|
|
return FreeDiskSpaceMB(name ? name : VideoDirectory, UsedMB);
|
|
}
|
|
|
|
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) {
|
|
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;
|
|
}
|
|
|
|
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("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:
|
|
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 -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, DEFFILEMODE);
|
|
if (ActualFileName != FileName)
|
|
free((char *)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(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;
|
|
}
|
|
|
|
int VideoDiskSpace(int *FreeMB, int *UsedMB)
|
|
{
|
|
int free = 0, used = 0;
|
|
cVideoDirectory Dir;
|
|
do {
|
|
int u;
|
|
free += Dir.FreeMB(&u);
|
|
used += u;
|
|
} while (Dir.Next());
|
|
if (FreeMB)
|
|
*FreeMB = free;
|
|
if (UsedMB)
|
|
*UsedMB = used;
|
|
return (free + used) ? used * 100 / (free + used) : 0;
|
|
}
|
|
|
|
cString PrefixVideoFileName(const char *FileName, char Prefix)
|
|
{
|
|
char PrefixedName[strlen(FileName) + 2];
|
|
|
|
const char *p = FileName + strlen(FileName); // p points at the terminating 0
|
|
int n = 2;
|
|
while (p-- > FileName && n > 0) {
|
|
if (*p == '/') {
|
|
if (--n == 0) {
|
|
int l = p - FileName + 1;
|
|
strncpy(PrefixedName, FileName, l);
|
|
PrefixedName[l] = Prefix;
|
|
strcpy(PrefixedName + l + 1, p + 1);
|
|
return PrefixedName;
|
|
}
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
void RemoveEmptyVideoDirectories(void)
|
|
{
|
|
cVideoDirectory Dir;
|
|
do {
|
|
RemoveEmptyDirectories(Dir.Name());
|
|
} while (Dir.Next());
|
|
}
|
|
|