diff options
| -rw-r--r-- | src/cc4group.c | 123 |
1 files changed, 112 insertions, 11 deletions
diff --git a/src/cc4group.c b/src/cc4group.c index c8dde19..bd0ea1a 100644 --- a/src/cc4group.c +++ b/src/cc4group.c @@ -389,7 +389,7 @@ static void deleteChildren(GroupEntryList* const entries) GroupEntryListDestroy(entries); } -static void* cc4group_mapSizedWriteFd(CC4Group* const this, int fd, size_t size) +static void* cc4group_mapSizedWriteFd(CC4Group* const this, int fd, size_t size, bool allowRead) { // allocate file size // https://gist.github.com/marcetcheverry/991042 @@ -405,7 +405,12 @@ static void* cc4group_mapSizedWriteFd(CC4Group* const this, int fd, size_t size) return MAP_FAILED; } - return cc4group_mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + void* result = cc4group_mmap(NULL, size, (allowRead ? PROT_READ : 0) | PROT_WRITE, MAP_SHARED, fd, 0); + if(result == MAP_FAILED) + { + SET_ERRNO_ERROR("mmap: mapping the file failed"); + } + return result; } static const char tmpFileTemplate[] = "cc4grouptmpXXXXXX"; @@ -475,7 +480,7 @@ static void* cc4group_createTmpMemoryFile(CC4Group* const this, const size_t siz unmapData->unlinkLater = unlink(unmapData->fileName) == -1; // in case it can't be deleted now (Windows -.-), delete it when cleaning up - ret = cc4group_mapSizedWriteFd(this, tmpFile, size); + ret = cc4group_mapSizedWriteFd(this, tmpFile, size, true); if(ret == MAP_FAILED) { // error message is set in the method @@ -2897,6 +2902,109 @@ static bool cc4group_saveAs(CC4Group* const this, const char* const path) return success; } +static bool cc4group_move(CC4Group* const this, const char* src, const char* dst, bool overwrite) +{ + assert(!cc4group_isDirectory(src)); + + if(rename(src, dst) != 0) + { + if(errno == EXDEV) + { + bool success = false; + void* srcMapped = MAP_FAILED; + void* targetMapped = MAP_FAILED; + int targetFile = -1; + int sourceFile = open(src, O_RDONLY, O_BINARY); + if(sourceFile == -1) + { + SET_ERRNO_ERROR("open: Opening the source file failed"); + goto ret; + } + + struct stat st; + if(fstat(sourceFile, &st) != 0) + { + SET_ERRNO_ERROR("stat: Stating the source file failed"); + goto ret; + } + + srcMapped = cc4group_mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, sourceFile, 0); + if(srcMapped == MAP_FAILED) + { + SET_ERRNO_ERROR("mmap: Mapping the source file failed"); + goto ret; + } + + if(close(sourceFile) == 0) + { + sourceFile = -1; + } + + targetFile = open(dst, O_RDWR | O_BINARY | O_CREAT | (overwrite ? O_TRUNC : O_EXCL)); + if(targetFile == -1) + { + SET_ERRNO_ERROR("open: Opening the target file failed"); + goto ret; + } + + targetMapped = cc4group_mapSizedWriteFd(this, targetFile, st.st_size, false); + if(targetMapped == MAP_FAILED) + { + goto ret; + } + + if(close(targetFile) == 0) + { + targetFile = -1; + } + + memcpy(targetMapped, srcMapped, st.st_size); + + cc4group_tryWarnUnlink(this, src); + + success = true; + + ret: + if(sourceFile != -1) + { + if(close(sourceFile) == -1) + { + cc4group_warn(this, "cc4group_move: Closing the source file \"%s\" failed: %s", src, strerror(errno)); + } + } + if(targetFile != -1) + { + if(close(targetFile) == -1) + { + cc4group_warn(this, "cc4group_move: Closing the destination file \"%s\" failed: %s", dst, strerror(errno)); + } + } + if(srcMapped != MAP_FAILED) + { + if(cc4group_munmap(srcMapped, st.st_size) != 0) + { + cc4group_warn(this, "cc4group_move: Unmapping the source file \"%s\" failed: %s", src, strerror(errno)); + } + } + if(targetMapped != MAP_FAILED) + { + if(cc4group_munmap(targetMapped, st.st_size) != 0) + { + cc4group_warn(this, "cc4group_move: Unmapping the destination file \"%s\" failed: %s", dst, strerror(errno)); + } + } + return success; + } + else + { + SET_ERRNO_ERROR("rename: Moving the file failed"); + } + return false; + } + + return true; +} + static bool cc4group_saveAsOverwrite(CC4Group* const this, const char* const path) { if(strcmp(path, "-") == 0) @@ -2918,14 +3026,7 @@ static bool cc4group_saveAsOverwrite(CC4Group* const this, const char* const pat goto ret; } - if(rename(tmpFileName, path) == 0) - { - success = true; - } - else - { - SET_ERRNO_ERROR("rename: can't rename the temporary file to the target path"); - } + success = cc4group_move(this, tmpFileName, path, true); if(close(tmpFile) == -1) { |
