summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKlaus Schmidinger <vdr@tvdr.de>2001-01-13 15:36:31 +0100
committerKlaus Schmidinger <vdr@tvdr.de>2001-01-13 15:36:31 +0100
commit297e727a59b2e08f8c414739325f8df390b567c4 (patch)
tree0eb697cc5be0968b3fbcc7151f87e2fc5b8ac647
parentba2c25d1835dae0030b12e35b814c2b0ab9406fb (diff)
downloadvdr-297e727a59b2e08f8c414739325f8df390b567c4.tar.gz
vdr-297e727a59b2e08f8c414739325f8df390b567c4.tar.bz2
Implemented safe writing of config files
-rw-r--r--HISTORY2
-rw-r--r--config.c15
-rw-r--r--config.h13
-rw-r--r--tools.c62
-rw-r--r--tools.h16
5 files changed, 90 insertions, 18 deletions
diff --git a/HISTORY b/HISTORY
index a85bc43a..50550cc4 100644
--- a/HISTORY
+++ b/HISTORY
@@ -340,3 +340,5 @@ Video Disk Recorder Revision History
- Changed the value for Diseqc to '0' in the default 'channels.conf'.
- Fixed displaying channels and recording status in the RCU's LED display when
a recording is interrupted due to higher priority.
+- Implemented safe writing of config files (first writes into a temporary file
+ and then renames it).
diff --git a/config.c b/config.c
index 781900d7..a20c801b 100644
--- a/config.c
+++ b/config.c
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: config.c 1.37 2001/01/13 12:36:32 kls Exp $
+ * $Id: config.c 1.38 2001/01/13 15:36:31 kls Exp $
*/
#include "config.h"
@@ -119,10 +119,9 @@ bool cKeys::Load(const char *FileName)
bool cKeys::Save(void)
{
- //TODO make backup copies???
bool result = true;
- FILE *f = fopen(fileName, "w");
- if (f) {
+ cSafeFile f(fileName);
+ if (f.Open()) {
if (fprintf(f, "Code\t%c\nAddress\t%04X\n", code, address) > 0) {
for (tKey *k = keys; k->type != kNone; k++) {
if (fprintf(f, "%s\t%08X\n", k->name, k->code) <= 0) {
@@ -133,7 +132,7 @@ bool cKeys::Save(void)
}
else
result = false;
- fclose(f);
+ f.Close();
}
else
result = false;
@@ -782,8 +781,8 @@ bool cSetup::Save(const char *FileName)
if (!FileName)
FileName = fileName;
if (FileName) {
- FILE *f = fopen(FileName, "w");
- if (f) {
+ cSafeFile f(FileName);
+ if (f.Open()) {
fprintf(f, "# VDR Setup\n");
fprintf(f, "OSDLanguage = %d\n", OSDLanguage);
fprintf(f, "PrimaryDVB = %d\n", PrimaryDVB);
@@ -796,7 +795,7 @@ bool cSetup::Save(const char *FileName)
fprintf(f, "MarginStart = %d\n", MarginStart);
fprintf(f, "MarginStop = %d\n", MarginStop);
fprintf(f, "EPGScanTimeout = %d\n", EPGScanTimeout);
- fclose(f);
+ f.Close();
isyslog(LOG_INFO, "saved setup to %s", FileName);
return true;
}
diff --git a/config.h b/config.h
index 34e20182..8f3cc77a 100644
--- a/config.h
+++ b/config.h
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: config.h 1.36 2000/12/25 14:20:09 kls Exp $
+ * $Id: config.h 1.37 2001/01/13 14:56:29 kls Exp $
*/
#ifndef __CONFIG_H
@@ -202,11 +202,10 @@ public:
}
bool Save(void)
{
- //TODO make backup copies???
bool result = true;
T *l = (T *)First();
- FILE *f = fopen(fileName, "w");
- if (f) {
+ cSafeFile f(fileName);
+ if (f.Open()) {
while (l) {
if (!l->Save(f)) {
result = false;
@@ -214,12 +213,10 @@ public:
}
l = (T *)l->Next();
}
- fclose(f);
+ f.Close();
}
- else {
- LOG_ERROR_STR(fileName);
+ else
result = false;
- }
return result;
}
};
diff --git a/tools.c b/tools.c
index 1caaa9fd..cd2c60f8 100644
--- a/tools.c
+++ b/tools.c
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: tools.c 1.26 2001/01/13 12:17:30 kls Exp $
+ * $Id: tools.c 1.27 2001/01/13 15:35:02 kls Exp $
*/
#define _GNU_SOURCE
@@ -247,6 +247,27 @@ bool RemoveFileOrDir(const char *FileName, bool FollowSymlinks)
return true;
}
+char *ReadLink(const char *FileName)
+{
+ char RealName[_POSIX_PATH_MAX];
+ const char *TargetName = NULL;
+ int n = readlink(FileName, RealName, sizeof(RealName) - 1);
+ if (n < 0) {
+ if (errno == ENOENT || errno == EINVAL) // file doesn't exist or is not a symlink
+ TargetName = FileName;
+ else { // some other error occurred
+ LOG_ERROR_STR(FileName);
+ }
+ }
+ else if (n < int(sizeof(RealName))) { // got it!
+ RealName[n] = 0;
+ TargetName = RealName;
+ }
+ else
+ esyslog(LOG_ERR, "ERROR: symlink's target name too long: %s", FileName);
+ return TargetName ? strdup(TargetName) : NULL;
+}
+
// --- cFile -----------------------------------------------------------------
bool cFile::files[FD_SETSIZE] = { false };
@@ -367,6 +388,45 @@ bool cFile::FileReady(int FileDes, int TimeoutMs)
return select(FD_SETSIZE, &set, NULL, NULL, &timeout) > 0 && FD_ISSET(FileDes, &set);
}
+// --- cSafeFile -------------------------------------------------------------
+
+cSafeFile::cSafeFile(const char *FileName)
+{
+ f = NULL;
+ fileName = ReadLink(FileName);
+ tempName = fileName ? new char[strlen(fileName) + 5] : NULL;
+ if (tempName)
+ strcat(strcpy(tempName, fileName), ".$$$");
+}
+
+cSafeFile::~cSafeFile()
+{
+ if (f)
+ fclose(f);
+ unlink(tempName);
+ delete fileName;
+ delete tempName;
+}
+
+bool cSafeFile::Open(void)
+{
+ if (!f && fileName && tempName) {
+ f = fopen(tempName, "w");
+ if (!f)
+ LOG_ERROR_STR(tempName);
+ }
+ return f != NULL;
+}
+
+void cSafeFile::Close(void)
+{
+ if (f) {
+ fclose(f);
+ f = NULL;
+ rename(tempName, fileName);
+ }
+}
+
// --- cListObject -----------------------------------------------------------
cListObject::cListObject(void)
diff --git a/tools.h b/tools.h
index 83f3fa0c..539dba01 100644
--- a/tools.h
+++ b/tools.h
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: tools.h 1.22 2000/12/10 11:49:42 kls Exp $
+ * $Id: tools.h 1.23 2001/01/13 15:36:00 kls Exp $
*/
#ifndef __TOOLS_H
@@ -48,6 +48,7 @@ uint FreeDiskSpaceMB(const char *Directory);
bool DirectoryOk(const char *DirName, bool LogErrors = false);
bool MakeDirs(const char *FileName, bool IsDirectory = false);
bool RemoveFileOrDir(const char *FileName, bool FollowSymlinks = false);
+char *ReadLink(const char *FileName);
class cFile {
private:
@@ -68,6 +69,19 @@ public:
static bool FileReady(int FileDes, int TimeoutMs = 1000);
};
+class cSafeFile {
+private:
+ FILE *f;
+ char *fileName;
+ char *tempName;
+public:
+ cSafeFile(const char *FileName);
+ ~cSafeFile();
+ operator FILE* () { return f; }
+ bool Open(void);
+ void Close(void);
+ };
+
class cListObject {
private:
cListObject *prev, *next;