From 7a2d3d993c932a12d17236f34a03f542c8943221 Mon Sep 17 00:00:00 2001 From: Klaus Schmidinger Date: Tue, 24 Dec 2013 14:41:09 +0100 Subject: [PATCH] Fixed a possible crash if the recordings list is updated externally while the Recordings menu is open --- CONTRIBUTORS | 2 ++ HISTORY | 4 ++- recording.c | 69 +++++++++++++++++++++++++++++++++++++--------------- recording.h | 8 ++++-- vdr.c | 3 ++- 5 files changed, 63 insertions(+), 23 deletions(-) diff --git a/CONTRIBUTORS b/CONTRIBUTORS index 712cc136..2c37d415 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -2864,6 +2864,8 @@ Lars Hanisch used for making the LIRC remote control connect to the socket even if it doesn't yet exist when VDR is started + for reporting a possible crash if the recordings list is updated externally while the + Recordings menu is open Alex Lasnier for adding tuning support for ATSC devices diff --git a/HISTORY b/HISTORY index 92fe649a..36ad3751 100644 --- a/HISTORY +++ b/HISTORY @@ -8032,7 +8032,7 @@ Video Disk Recorder Revision History the last replayed recording (if any) by pressing Ok repeatedly in the Recordings menu. -2013-11-15: Version 2.1.3 +2013-12-24: Version 2.1.3 - Changed the return value of cPositioner::HorizonLongitude() to 0 in case the latitude of the antenna location is beyond +/-81 degrees. @@ -8065,3 +8065,5 @@ Video Disk Recorder Revision History by Marko Mäkelä). - Fixed uninitialized item area coordinates in cSkinLCARSDisplayMenu (reported by Marko Mäkelä). +- Fixed a possible crash if the recordings list is updated externally while the + Recordings menu is open (reported by Lars Hanisch). diff --git a/recording.c b/recording.c index d6ffb41e..f2577ab9 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.8 2013/10/20 09:51:23 kls Exp $ + * $Id: recording.c 3.9 2013/12/24 14:32:29 kls Exp $ */ #include "recording.h" @@ -76,6 +76,7 @@ bool DirectoryEncoding = false; int InstanceId = 0; cRecordings DeletedRecordings(true); +static cRecordings VanishedRecordings; // --- cRemoveDeletedRecordingsThread ---------------------------------------- @@ -220,6 +221,14 @@ void AssertFreeDiskSpace(int Priority, bool Force) } } +// --- Clear vanished recordings --------------------------------------------- + +void ClearVanishedRecordings(void) +{ + cThreadLock RecordingsLock(&Recordings); // yes, it *is* Recordings! + VanishedRecordings.Clear(); +} + // --- cResumeFile ----------------------------------------------------------- cResumeFile::cResumeFile(const char *FileName, bool IsPesRecording) @@ -1346,6 +1355,7 @@ cRecordings::cRecordings(bool Deleted) :cThread("video directory scanner") { deleted = Deleted; + initial = true; lastUpdate = 0; state = 0; } @@ -1370,15 +1380,19 @@ const char *cRecordings::UpdateFileName(void) void cRecordings::Refresh(bool Foreground) { lastUpdate = time(NULL); // doing this first to make sure we don't miss anything - Lock(); - Clear(); - ChangeState(); - Unlock(); + initial = Count() == 0; // no name checking if the list is initially empty + if (deleted) { + Lock(); + Clear(); + ChangeState(); + Unlock(); + } ScanVideoDir(cVideoDirectory::Name(), Foreground); } -void cRecordings::ScanVideoDir(const char *DirName, bool Foreground, int LinkLevel) +void cRecordings::ScanVideoDir(const char *DirName, bool Foreground, int LinkLevel, int DirLevel) { + // Find any new recordings: cReadDir d(DirName); struct dirent *e; while ((Foreground || Running()) && (e = d.Next()) != NULL) { @@ -1397,25 +1411,41 @@ void cRecordings::ScanVideoDir(const char *DirName, bool Foreground, int LinkLev } if (S_ISDIR(st.st_mode)) { if (endswith(buffer, deleted ? DELEXT : RECEXT)) { - cRecording *r = new cRecording(buffer); - if (r->Name()) { - r->NumFrames(); // initializes the numFrames member - r->FileSizeMB(); // initializes the fileSizeMB member - if (deleted) - r->deleted = time(NULL); - Lock(); - Add(r); - ChangeState(); - Unlock(); + if (deleted || initial || !GetByName(buffer)) { + cRecording *r = new cRecording(buffer); + if (r->Name()) { + r->NumFrames(); // initializes the numFrames member + r->FileSizeMB(); // initializes the fileSizeMB member + if (deleted) + r->deleted = time(NULL); + Lock(); + Add(r); + ChangeState(); + Unlock(); + } + else + delete r; } - else - delete r; } else - ScanVideoDir(buffer, Foreground, LinkLevel + Link); + ScanVideoDir(buffer, Foreground, LinkLevel + Link, DirLevel + 1); } } } + // Handle any vanished recordings: + if (!deleted && !initial && DirLevel == 0) { + for (cRecording *recording = First(); recording; ) { + cRecording *r = recording; + recording = Next(recording); + if (access(r->FileName(), F_OK) != 0) { + Lock(); + Del(r, false); + VanishedRecordings.Add(r); + ChangeState(); + Unlock(); + } + } + } } bool cRecordings::StateChanged(int &State) @@ -1456,6 +1486,7 @@ bool cRecordings::Update(bool Wait) cRecording *cRecordings::GetByName(const char *FileName) { if (FileName) { + LOCK_THREAD; for (cRecording *recording = First(); recording; recording = Next(recording)) { if (strcmp(recording->FileName(), FileName) == 0) return recording; diff --git a/recording.h b/recording.h index 3b00c71b..9baed31d 100644 --- a/recording.h +++ b/recording.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: recording.h 3.1 2013/10/10 12:08:15 kls Exp $ + * $Id: recording.h 3.2 2013/12/24 13:32:18 kls Exp $ */ #ifndef __RECORDING_H @@ -41,6 +41,7 @@ enum eRecordingUsage { }; void RemoveDeletedRecordings(void); +void ClearVanishedRecordings(void); void AssertFreeDiskSpace(int Priority = 0, bool Force = false); ///< The special Priority value -1 means that we shall get rid of any ///< deleted recordings faster than normal (because we're cutting). @@ -217,11 +218,12 @@ class cRecordings : public cList, public cThread { private: static char *updateFileName; bool deleted; + bool initial; time_t lastUpdate; int state; const char *UpdateFileName(void); void Refresh(bool Foreground = false); - void ScanVideoDir(const char *DirName, bool Foreground = false, int LinkLevel = 0); + void ScanVideoDir(const char *DirName, bool Foreground = false, int LinkLevel = 0, int DirLevel = 0); protected: void Action(void); public: @@ -277,6 +279,8 @@ public: ///< if all recordings have been successfully added to the RecordingsHandler. }; +/// Any access to Recordings that loops through the list of recordings +/// needs to hold a thread lock on this object! extern cRecordings Recordings; extern cRecordings DeletedRecordings; diff --git a/vdr.c b/vdr.c index 083d838c..72f3c3b9 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.4 2013/10/16 09:33:58 kls Exp $ + * $Id: vdr.c 3.5 2013/12/24 13:19:55 kls Exp $ */ #include @@ -1369,6 +1369,7 @@ int main(int argc, char *argv[]) // Disk housekeeping: RemoveDeletedRecordings(); + ClearVanishedRecordings(); cSchedules::Cleanup(); // Plugins housekeeping: PluginManager.Housekeeping();