diff options
author | Klaus Schmidinger <vdr@tvdr.de> | 2001-01-13 15:36:31 +0100 |
---|---|---|
committer | Klaus Schmidinger <vdr@tvdr.de> | 2001-01-13 15:36:31 +0100 |
commit | 297e727a59b2e08f8c414739325f8df390b567c4 (patch) | |
tree | 0eb697cc5be0968b3fbcc7151f87e2fc5b8ac647 | |
parent | ba2c25d1835dae0030b12e35b814c2b0ab9406fb (diff) | |
download | vdr-297e727a59b2e08f8c414739325f8df390b567c4.tar.gz vdr-297e727a59b2e08f8c414739325f8df390b567c4.tar.bz2 |
Implemented safe writing of config files
-rw-r--r-- | HISTORY | 2 | ||||
-rw-r--r-- | config.c | 15 | ||||
-rw-r--r-- | config.h | 13 | ||||
-rw-r--r-- | tools.c | 62 | ||||
-rw-r--r-- | tools.h | 16 |
5 files changed, 90 insertions, 18 deletions
@@ -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). @@ -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; } @@ -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; } }; @@ -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) @@ -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; |