1
0
mirror of https://github.com/VDR4Arch/vdr.git synced 2023-10-10 13:36:52 +02:00

Fixed a crash when moving a recording to a folder on a different volume

This commit is contained in:
Klaus Schmidinger 2016-12-13 13:54:00 +01:00
parent a9bd3ca0dc
commit 08066065e3
6 changed files with 46 additions and 44 deletions

View File

@ -8828,7 +8828,7 @@ Video Disk Recorder Revision History
- Empty adaptation field TS packets are now skipped when recording (thanks to - Empty adaptation field TS packets are now skipped when recording (thanks to
Christopher Reimer, based on the "AFFcleaner" by Stefan Pöschel). Christopher Reimer, based on the "AFFcleaner" by Stefan Pöschel).
2016-12-11: Version 2.3.2 2016-12-13: Version 2.3.2
- Fixed a crash when deleting a recording (reported by Oliver Endriss). - Fixed a crash when deleting a recording (reported by Oliver Endriss).
- Fixed an overflow of PIDs in a receiver (thanks to Robert Hannebauer). - Fixed an overflow of PIDs in a receiver (thanks to Robert Hannebauer).
@ -8847,3 +8847,7 @@ Video Disk Recorder Revision History
- Fixed setting the current item and counter values in the Recordings menu after - Fixed setting the current item and counter values in the Recordings menu after
deleting the last recording in a subfolder. deleting the last recording in a subfolder.
- Fixed a crash when deleting a recording that is currently being replayed. - Fixed a crash when deleting a recording that is currently being replayed.
- Fixed a crash when moving a recording to a folder on a different volume.
The cRecordingsHandler now performs its actual operations in a separate thread,
thus avoiding locking problems and reducing the time between subsequent
operations.

12
menu.c
View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: menu.c 4.17 2016/12/11 12:43:55 kls Exp $ * $Id: menu.c 4.18 2016/12/13 12:49:10 kls Exp $
*/ */
#include "menu.h" #include "menu.h"
@ -2687,14 +2687,15 @@ eOSState cMenuRecordingEdit::ApplyChanges(void)
cRecordings *Recordings = cRecordings::GetRecordingsWrite(StateKey); cRecordings *Recordings = cRecordings::GetRecordingsWrite(StateKey);
cRecording *Recording = Recordings->GetByName(recording->FileName()); cRecording *Recording = Recordings->GetByName(recording->FileName());
if (!Recording) { if (!Recording) {
StateKey.Remove(false);
Skins.Message(mtWarning, tr("Recording vanished!")); Skins.Message(mtWarning, tr("Recording vanished!"));
return osBack; return osBack;
} }
bool Modified = false; bool Modified = false;
if (priority != recording->Priority() || lifetime != recording->Lifetime()) { if (priority != recording->Priority() || lifetime != recording->Lifetime()) {
if (!Recording->ChangePriorityLifetime(priority, lifetime)) { if (!Recording->ChangePriorityLifetime(priority, lifetime)) {
Skins.Message(mtError, tr("Error while changing priority/lifetime!"));
StateKey.Remove(Modified); StateKey.Remove(Modified);
Skins.Message(mtError, tr("Error while changing priority/lifetime!"));
return osContinue; return osContinue;
} }
Modified = true; Modified = true;
@ -2707,8 +2708,8 @@ eOSState cMenuRecordingEdit::ApplyChanges(void)
NewName.CompactChars(FOLDERDELIMCHAR); NewName.CompactChars(FOLDERDELIMCHAR);
if (strcmp(NewName, Recording->Name())) { if (strcmp(NewName, Recording->Name())) {
if (!Recording->ChangeName(NewName)) { if (!Recording->ChangeName(NewName)) {
Skins.Message(mtError, tr("Error while changing folder/name!"));
StateKey.Remove(Modified); StateKey.Remove(Modified);
Skins.Message(mtError, tr("Error while changing folder/name!"));
return osContinue; return osContinue;
} }
Modified = true; Modified = true;
@ -3095,13 +3096,12 @@ eOSState cMenuRecordings::Delete(void)
if (const cRecording *Recording = Recordings->GetByName(ri->Recording()->FileName())) { if (const cRecording *Recording = Recordings->GetByName(ri->Recording()->FileName())) {
FileName = Recording->FileName(); FileName = Recording->FileName();
if (RecordingsHandler.GetUsage(FileName)) { if (RecordingsHandler.GetUsage(FileName)) {
if (Interface->Confirm(tr("Recording is being edited - really delete?"))) if (!Interface->Confirm(tr("Recording is being edited - really delete?")))
RecordingsHandler.Del(FileName);
else
return osContinue; return osContinue;
} }
} }
} }
RecordingsHandler.Del(FileName); // must do this w/o holding a lock, because the cleanup section in cDirCopier::Action() might request one!
if (cReplayControl::NowReplaying() && strcmp(cReplayControl::NowReplaying(), FileName) == 0) if (cReplayControl::NowReplaying() && strcmp(cReplayControl::NowReplaying(), FileName) == 0)
cControl::Shutdown(); cControl::Shutdown();
cRecordings *Recordings = cRecordings::GetRecordingsWrite(recordingsStateKey); cRecordings *Recordings = cRecordings::GetRecordingsWrite(recordingsStateKey);

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: recording.c 4.4 2015/09/09 10:21:58 kls Exp $ * $Id: recording.c 4.5 2016/12/13 13:39:09 kls Exp $
*/ */
#include "recording.h" #include "recording.h"
@ -1701,7 +1701,7 @@ void cDirCopier::Action(void)
int To = -1; int To = -1;
size_t BufferSize = BUFSIZ; size_t BufferSize = BUFSIZ;
while (Running()) { while (Running()) {
// Suspend cutting if we have severe throughput problems: // Suspend copying if we have severe throughput problems:
if (Throttled()) { if (Throttled()) {
cCondWait::SleepMs(100); cCondWait::SleepMs(100);
continue; continue;
@ -1900,6 +1900,7 @@ bool cRecordingsHandlerEntry::Active(bool &Error)
cRecordingsHandler RecordingsHandler; cRecordingsHandler RecordingsHandler;
cRecordingsHandler::cRecordingsHandler(void) cRecordingsHandler::cRecordingsHandler(void)
:cThread("recordings handler")
{ {
finished = true; finished = true;
error = false; error = false;
@ -1907,6 +1908,23 @@ cRecordingsHandler::cRecordingsHandler(void)
cRecordingsHandler::~cRecordingsHandler() cRecordingsHandler::~cRecordingsHandler()
{ {
Cancel(3);
}
void cRecordingsHandler::Action(void)
{
while (Running()) {
{
cMutexLock MutexLock(&mutex);
while (cRecordingsHandlerEntry *r = operations.First()) {
if (!r->Active(error))
operations.Del(r);
}
if (!operations.Count())
break;
}
cCondWait::SleepMs(100);
}
} }
cRecordingsHandlerEntry *cRecordingsHandler::Get(const char *FileName) cRecordingsHandlerEntry *cRecordingsHandler::Get(const char *FileName)
@ -1934,8 +1952,7 @@ bool cRecordingsHandler::Add(int Usage, const char *FileNameSrc, const char *Fil
Usage |= ruPending; Usage |= ruPending;
operations.Add(new cRecordingsHandlerEntry(Usage, FileNameSrc, FileNameDst)); operations.Add(new cRecordingsHandlerEntry(Usage, FileNameSrc, FileNameDst));
finished = false; finished = false;
Active(); // start it right away if possible Start();
LOCK_RECORDINGS_WRITE; // to trigger a state change
return true; return true;
} }
else else
@ -1955,17 +1972,17 @@ bool cRecordingsHandler::Add(int Usage, const char *FileNameSrc, const char *Fil
void cRecordingsHandler::Del(const char *FileName) void cRecordingsHandler::Del(const char *FileName)
{ {
cMutexLock MutexLock(&mutex); cMutexLock MutexLock(&mutex);
if (cRecordingsHandlerEntry *r = Get(FileName)) { if (cRecordingsHandlerEntry *r = Get(FileName))
operations.Del(r); operations.Del(r);
LOCK_RECORDINGS_WRITE; // to trigger a state change
}
} }
void cRecordingsHandler::DelAll(void) void cRecordingsHandler::DelAll(void)
{ {
cMutexLock MutexLock(&mutex); {
operations.Clear(); cMutexLock MutexLock(&mutex);
LOCK_RECORDINGS_WRITE; // to trigger a state change operations.Clear();
}
Cancel(3);
} }
int cRecordingsHandler::GetUsage(const char *FileName) int cRecordingsHandler::GetUsage(const char *FileName)
@ -1976,18 +1993,6 @@ int cRecordingsHandler::GetUsage(const char *FileName)
return ruNone; return ruNone;
} }
bool cRecordingsHandler::Active(void)
{
cMutexLock MutexLock(&mutex);
while (cRecordingsHandlerEntry *r = operations.First()) {
if (r->Active(error))
return true;
else
operations.Del(r);
}
return false;
}
bool cRecordingsHandler::Finished(bool &Error) bool cRecordingsHandler::Finished(bool &Error)
{ {
cMutexLock MutexLock(&mutex); cMutexLock MutexLock(&mutex);

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: recording.h 4.3 2015/08/29 14:12:14 kls Exp $ * $Id: recording.h 4.4 2016/12/13 13:12:12 kls Exp $
*/ */
#ifndef __RECORDING_H #ifndef __RECORDING_H
@ -302,16 +302,18 @@ DEF_LIST_LOCK2(Recordings, DeletedRecordings);
class cRecordingsHandlerEntry; class cRecordingsHandlerEntry;
class cRecordingsHandler { class cRecordingsHandler : public cThread {
private: private:
cMutex mutex; cMutex mutex;
cList<cRecordingsHandlerEntry> operations; cList<cRecordingsHandlerEntry> operations;
bool finished; bool finished;
bool error; bool error;
cRecordingsHandlerEntry *Get(const char *FileName); cRecordingsHandlerEntry *Get(const char *FileName);
protected:
virtual void Action(void);
public: public:
cRecordingsHandler(void); cRecordingsHandler(void);
~cRecordingsHandler(); virtual ~cRecordingsHandler();
bool Add(int Usage, const char *FileNameSrc, const char *FileNameDst = NULL); bool Add(int Usage, const char *FileNameSrc, const char *FileNameDst = NULL);
///< Adds the given FileNameSrc to the recordings handler for (later) ///< Adds the given FileNameSrc to the recordings handler for (later)
///< processing. Usage can be either ruCut, ruMove or ruCopy. FileNameDst ///< processing. Usage can be either ruCut, ruMove or ruCopy. FileNameDst
@ -329,12 +331,6 @@ public:
///< Deletes/terminates all operations. ///< Deletes/terminates all operations.
int GetUsage(const char *FileName); int GetUsage(const char *FileName);
///< Returns the usage type for the given FileName. ///< Returns the usage type for the given FileName.
bool Active(void);
///< Checks whether there is currently any operation running and starts
///> the next one form the list if the previous one has finished.
///< This function must be called regularly to trigger switching to the
///< next operation in the list.
///< Returns true if there are any operations in the list.
bool Finished(bool &Error); bool Finished(bool &Error);
///< Returns true if all operations in the list have been finished. ///< Returns true if all operations in the list have been finished.
///< If there have been any errors, Errors will be set to true. ///< If there have been any errors, Errors will be set to true.

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: tools.h 4.3 2015/09/06 10:45:54 kls Exp $ * $Id: tools.h 4.4 2016/12/13 12:13:46 kls Exp $
*/ */
#ifndef __TOOLS_H #ifndef __TOOLS_H
@ -609,7 +609,7 @@ public: \
else \ else \
list = c##Class::Get##Name##Read(stateKey); \ list = c##Class::Get##Name##Read(stateKey); \
} \ } \
~c##Name##Lock() { stateKey.Remove(); } \ ~c##Name##Lock() { if (list) stateKey.Remove(); } \
const c##Class *Name(void) const { return list; } \ const c##Class *Name(void) const { return list; } \
c##Class *Name(void) { return const_cast<c##Class *>(list); } \ c##Class *Name(void) { return const_cast<c##Class *>(list); } \
} }

5
vdr.c
View File

@ -22,7 +22,7 @@
* *
* The project's page is at http://www.tvdr.de * The project's page is at http://www.tvdr.de
* *
* $Id: vdr.c 4.7 2015/09/11 08:02:50 kls Exp $ * $Id: vdr.c 4.8 2016/12/13 13:13:10 kls Exp $
*/ */
#include <getopt.h> #include <getopt.h>
@ -1480,9 +1480,6 @@ int main(int argc, char *argv[])
ShutdownHandler.countdown.Cancel(); ShutdownHandler.countdown.Cancel();
} }
// Keep the recordings handler alive:
RecordingsHandler.Active();
if ((Now - LastInteract) > ACTIVITYTIMEOUT && !cRecordControls::Active() && !RecordingsHandler.Active() && (Now - cRemote::LastActivity()) > ACTIVITYTIMEOUT) { if ((Now - LastInteract) > ACTIVITYTIMEOUT && !cRecordControls::Active() && !RecordingsHandler.Active() && (Now - cRemote::LastActivity()) > ACTIVITYTIMEOUT) {
// Handle housekeeping tasks // Handle housekeeping tasks