From d3ba5dcfd4f21e27c4ead7bde29374e66764179c Mon Sep 17 00:00:00 2001 From: Markus Mittendrein Date: Sat, 31 Aug 2019 13:51:07 +0200 Subject: use a temporary file in saveOverwrite to avoid possible data loss in error cases (fixes SIGBUS in c4touch) --- src/cc4group.c | 75 +++++++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 61 insertions(+), 14 deletions(-) diff --git a/src/cc4group.c b/src/cc4group.c index 93dbd3d..b086110 100644 --- a/src/cc4group.c +++ b/src/cc4group.c @@ -388,15 +388,30 @@ static void* cc4group_mapSizedWriteFd(CC4Group* const this, int fd, size_t size) } static const char tmpFileTemplate[] = "cc4grouptmpXXXXXX"; +#define tmpFileNameLength (sizeof(tmpFileTemplate) / sizeof(tmpFileTemplate[0])) typedef struct { void* addr; size_t size; - char fileName[sizeof(tmpFileTemplate) / sizeof(tmpFileTemplate[0])]; + char fileName[tmpFileNameLength]; bool unlinkLater; const CC4Group* group; } MunmapData; +// *fileNameTarget must be at least tmpFileNameLength long! +static int cc4group_createTmpFile(CC4Group* const this, char* const fileNameTarget) +{ + strncpy(fileNameTarget, tmpFileTemplate, tmpFileNameLength); + int tmpFile = mkstemp(fileNameTarget); + if(tmpFile == -1) + { + SET_ERRNO_ERROR("mkstemp: Creating and opening the tmp file"); + fileNameTarget[0] = '\0'; + } + + return tmpFile; +} + static void cc4group_tryWarnUnlink(const CC4Group* const this, const char* const fileName) { if(unlink(fileName) == -1) @@ -430,14 +445,10 @@ static void* cc4group_createTmpMemoryFile(CC4Group* const this, const size_t siz return NULL; } - strncpy(unmapData->fileName, tmpFileTemplate, sizeof(unmapData->fileName) / sizeof(unmapData->fileName[0])); - void* ret = NULL; - int tmpFile = mkstemp(unmapData->fileName); + int tmpFile = cc4group_createTmpFile(this, unmapData->fileName); if(tmpFile == -1) { - SET_ERRNO_ERROR("mkstemp: Creating and opening the tmp file"); - unmapData->fileName[0] = '\0'; goto ret; } @@ -2586,7 +2597,7 @@ static bool cc4group_saveToFd(CC4Group* const this, int fd) return cc4group_saveWithWriteCallback(this, cc4group_writeToFdCallback, &fd, 0); } -static bool cc4group_saveIt(CC4Group* const this, const char* const path, bool const overwrite) +static bool cc4group_save(CC4Group* const this, const char* const path) { assert(this); assert(path); @@ -2598,7 +2609,7 @@ static bool cc4group_saveIt(CC4Group* const this, const char* const path, bool c } bool success = false; - int file = open(path, O_WRONLY | O_BINARY | O_CREAT | (overwrite ? O_TRUNC : O_EXCL), 0644); + int file = open(path, O_WRONLY | O_BINARY | O_CREAT | O_EXCL, 0644); if(file == -1) { @@ -2627,14 +2638,50 @@ static bool cc4group_saveIt(CC4Group* const this, const char* const path, bool c return success; } -static bool cc4group_save(CC4Group* const this, const char* const path) -{ - return cc4group_saveIt(this, path, false); -} - static bool cc4group_saveOverwrite(CC4Group* const this, const char* const path) { - return cc4group_saveIt(this, path, true); + if(strcmp(path, "-") == 0) + { + return cc4group_save(this, path); + } + + char tmpFileName[tmpFileNameLength]; + int tmpFile = cc4group_createTmpFile(this, tmpFileName); + + if(tmpFile == -1) + { + return false; + } + + bool success = false; + if(!cc4group_saveWithWriteCallback(this, cc4group_writeToFdCallback, &tmpFile, 0)) + { + goto ret; + } + + if(rename(tmpFileName, path) == 0) + { + success = true; + } + else + { + SET_ERRNO_ERROR("rename: can't rename the temporary file to the target path"); + } + + if(close(tmpFile) == -1) + { + cc4group_warn(this, "close: Closing the target group file failed: %s", strerror(errno)); + } + +ret: + if(!success) + { + if(unlink(tmpFileName) == -1) + { + cc4group_warn(this, "unlink: Deleting the incomplete temporary group file \"%s\" failed: %s", tmpFileName, strerror(errno)); + } + } + return success; } static bool cc4group_getEntryInfoForEntry(CC4Group* const this, const C4GroupEntryData* const entry, CC4Group_EntryInfo* const info, bool const lazy) -- cgit v1.2.3-54-g00ecf