summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarkus Mittendrein <git@maxmitti.tk>2020-04-20 21:51:58 +0200
committerMarkus Mittendrein <git@maxmitti.tk>2020-04-20 21:52:07 +0200
commit4ded6e352ee0fb5d96d2e1b9f051aac1f07b4886 (patch)
tree8d29721809a690acbbaa2efb56402f55eb6436c1
parentd42414b65cdb0156a5a2064a08c894c19370d7a7 (diff)
downloadcc4group-4ded6e352ee0fb5d96d2e1b9f051aac1f07b4886.tar.gz
cc4group-4ded6e352ee0fb5d96d2e1b9f051aac1f07b4886.zip
Rework group saving
save / saveParent write back to the original group saveParent saves changes in child groups (openAsChild) by saving the top-most parent saveAs / saveAsOverwrite resembles the old save / saveOverwrite For all other saving methods, groups opend with openAsChild are saved as if there was no parent
-rw-r--r--examples/c4add.c2
-rw-r--r--examples/c4copy.c2
-rw-r--r--examples/c4mkdir.c2
-rw-r--r--examples/c4rm.c2
-rw-r--r--examples/c4touch.c9
-rw-r--r--src/cc4group.c86
-rw-r--r--src/cc4group.h19
-rw-r--r--src/cppc4group.cpp9
-rw-r--r--src/cppc4group.hpp6
-rw-r--r--src/platform/platform.h7
-rw-r--r--src/platform/unix.c5
-rw-r--r--src/platform/windows.c6
12 files changed, 130 insertions, 25 deletions
diff --git a/examples/c4add.c b/examples/c4add.c
index 8eb056a..df53846 100644
--- a/examples/c4add.c
+++ b/examples/c4add.c
@@ -28,7 +28,7 @@ int main(int argc, char* argv[])
}
else
{
- success = cc4group.saveOverwrite(group, argv[1]);
+ success = cc4group.saveParent(group);
if(!success)
{
diff --git a/examples/c4copy.c b/examples/c4copy.c
index 30cf95c..619b658 100644
--- a/examples/c4copy.c
+++ b/examples/c4copy.c
@@ -33,7 +33,7 @@ int main(int argc, char* argv[])
}
- success = cc4group.save(group, argv[2]);
+ success = cc4group.saveAs(group, argv[2]);
if(!success)
{
diff --git a/examples/c4mkdir.c b/examples/c4mkdir.c
index 110149e..d925654 100644
--- a/examples/c4mkdir.c
+++ b/examples/c4mkdir.c
@@ -28,7 +28,7 @@ int main(int argc, char* argv[])
}
else
{
- success = cc4group.saveOverwrite(group, argv[1]);
+ success = cc4group.saveParent(group);
if(!success)
{
diff --git a/examples/c4rm.c b/examples/c4rm.c
index 46ef55d..902ab30 100644
--- a/examples/c4rm.c
+++ b/examples/c4rm.c
@@ -35,7 +35,7 @@ int main(int argc, char* argv[])
}
else
{
- success = cc4group.saveOverwrite(group, argv[1]);
+ success = cc4group.saveParent(group);
if(!success)
{
diff --git a/examples/c4touch.c b/examples/c4touch.c
index 40312c6..a8bfb16 100644
--- a/examples/c4touch.c
+++ b/examples/c4touch.c
@@ -49,7 +49,14 @@ int main(int argc, char* argv[])
cc4group.setMaker(group, argv[2], NULL, true);
}
- success = (exists ? cc4group.saveOverwrite : cc4group.save)(group, argv[1]);
+ if(exists)
+ {
+ success = cc4group.saveParent(group);
+ }
+ else
+ {
+ success = cc4group.saveAs(group, argv[1]);
+ }
if(!success)
{
diff --git a/src/cc4group.c b/src/cc4group.c
index 0483eea..5cbce53 100644
--- a/src/cc4group.c
+++ b/src/cc4group.c
@@ -124,6 +124,8 @@ struct CC4Group_t {
} readState;
bool lazy;
+ const char* path;
+ bool subRooted;
};
typedef struct {
@@ -1062,6 +1064,7 @@ static bool cc4group_setSubRoot(CC4Group* const this, const char* const subPath)
this->realRoot = this->root;
this->root = *subRoot;
+ this->subRooted = true;
}
return true;
@@ -1179,6 +1182,14 @@ ret:
if(success)
{
success = cc4group_setSubRoot(this, subPath);
+ if(success && subPath != NULL && *subPath != '\0')
+ {
+ if(this->path != NULL)
+ {
+ free((void*)this->path);
+ }
+ this->path = cc4group_absolutePath(tmpPath);
+ }
}
free(tmpPath);
@@ -1193,6 +1204,8 @@ static void cc4group_init(CC4Group* const this)
this->referenceCounter = 1;
this->parent = NULL;
this->lazy = true;
+ this->path = NULL;
+ this->subRooted = false;
this->uncompressedData = NULL;
this->uncompressedSize = 0;
@@ -1700,7 +1713,10 @@ static bool cc4group_openExisting(CC4Group* const this, const char* const path)
SET_BINARY(STDIN_FILENO);
return cc4group_openFd(this, STDIN_FILENO);
}
- else if(cc4group_isDirectory(path))
+
+ this->path = cc4group_absolutePath(path);
+
+ if(cc4group_isDirectory(path))
{
return cc4group_openDirectory(this, path);
}
@@ -1739,6 +1755,11 @@ static void cc4group_delete(CC4Group* const this)
free(this->error.lastFormattedMessage);
}
+ if(this->path != NULL)
+ {
+ free((void*)this->path);
+ }
+
free(this);
}
@@ -2501,12 +2522,6 @@ static bool cc4group_saveWithWriteCallback(CC4Group* const this, CC4Group_WriteC
maxBlockSize = 1024 * 1024;
}
- if(this->parent != NULL)
- {
- SET_MESSAGE_ERROR("Saving is currently not implemented for groups opened with openAsChild");
- return false;
- }
-
WriteCallback callback = {
.callback = writeCallback,
.arg = arg,
@@ -2617,7 +2632,7 @@ static bool cc4group_saveToFd(CC4Group* const this, int fd)
return cc4group_saveWithWriteCallback(this, cc4group_writeToFdCallback, &fd, 0);
}
-static bool cc4group_save(CC4Group* const this, const char* const path)
+static bool cc4group_saveAs(CC4Group* const this, const char* const path)
{
assert(this);
assert(path);
@@ -2658,11 +2673,11 @@ static bool cc4group_save(CC4Group* const this, const char* const path)
return success;
}
-static bool cc4group_saveOverwrite(CC4Group* const this, const char* const path)
+static bool cc4group_saveAsOverwrite(CC4Group* const this, const char* const path)
{
if(strcmp(path, "-") == 0)
{
- return cc4group_save(this, path);
+ return cc4group_saveAs(this, path);
}
char tmpFileName[tmpFileNameLength];
@@ -2704,6 +2719,52 @@ ret:
return success;
}
+static bool cc4group_save(CC4Group* const this)
+{
+ assert(this);
+ if(this->path == NULL)
+ {
+ SET_MESSAGE_ERROR("This group was not opened from an existing on disk group. cc4group.save can not be used.");
+ return false;
+ }
+
+ if(this->parent != NULL)
+ {
+ SET_MESSAGE_ERROR("Refusing to save a group opened with openAsChild. cc4group.saveParent might be used.");
+ return false;
+ }
+
+ if(this->subRooted)
+ {
+ SET_MESSAGE_ERROR("Refusing to save a group opened with a path inside the actual group. cc4group.saveParent might be used.");
+ return false;
+ }
+
+ return cc4group_saveAsOverwrite(this, this->path);
+}
+
+static bool cc4group_saveParent(CC4Group* const this)
+{
+ CC4Group* root = this;
+ while(root->parent)
+ {
+ root = root->parent;
+ }
+
+ if(root->subRooted)
+ {
+ C4GroupEntryData tmp = root->root;
+ root->root = root->realRoot;
+ root->subRooted = false;
+ bool success = cc4group_save(root);
+ root->root = tmp;
+ root->subRooted = true;
+ return success;
+ }
+
+ return cc4group_save(root);
+}
+
static bool cc4group_getEntryInfoForEntry(CC4Group* const this, const C4GroupEntryData* const entry, CC4Group_EntryInfo* const info, bool const lazy)
{
C4GroupHeader* header = NULL;
@@ -3334,9 +3395,10 @@ CC4Group_API cc4group = {
.openFilePointer = cc4group_openFilePointer,
.openWithReadCallback = cc4group_uncompressGroup,
-
.save = cc4group_save,
- .saveOverwrite = cc4group_saveOverwrite,
+ .saveParent = cc4group_saveParent,
+ .saveAs = cc4group_saveAs,
+ .saveAsOverwrite = cc4group_saveAsOverwrite,
.saveToFd = cc4group_saveToFd,
.saveToFilePointer = cc4group_saveToFilePointer,
.saveWithWriteCallback = cc4group_saveWithWriteCallback,
diff --git a/src/cc4group.h b/src/cc4group.h
index c08bad8..8de4616 100644
--- a/src/cc4group.h
+++ b/src/cc4group.h
@@ -247,6 +247,7 @@ typedef struct {
bool (*create)(CC4Group* const this);
// opens a group or a normal folder on the filesystem; path may point to a directory inside a group; path "-" can be used to read the group from stdin
+ // if path points to a directory inside a group, saving behaves the same as for cc4group.openAsChild
bool (*openExisting)(CC4Group* const this, const char* const path);
// opens a group that is stored entirely in memory
@@ -273,12 +274,21 @@ typedef struct {
// saves the current in-memory state of the group as a compressed c4group to disk
+ // overwrites the group from which this instance was opened
+ // works only for groups opened using cc4group.openExisting (and not from stdin via "-")
+ bool (*save)(CC4Group* const this);
+
+ // same as cc4group.save, but in case of a group created using cc4group.openAsChild, saves the top-most parent instead
+ // also applies to groups which have been opened using a path which is a subgroup of the actual group
+ bool (*saveParent)(CC4Group* const this);
+
+ // saves the current in-memory state of the group as a compressed c4group to disk
// fails if the given path already exists; path "-" can be used to write the group to stdout
- bool (*save)(CC4Group* const this, const char* const path);
+ bool (*saveAs)(CC4Group* const this, const char* const path);
// same as save, except that an already existing group will be overwritten
// be careful, any existing file will be overwritten in-place. if any error occurs after opening the target file (e.g. out of memory, a program or system crash), the previous contents will be lost
- bool (*saveOverwrite)(CC4Group* const this, const char* const path);
+ bool (*saveAsOverwrite)(CC4Group* const this, const char* const path);
// saves the compressed group file by writing it to the file descriptor
// the file descriptor must have been opened with write access and must be in blocking mode (should be default if O_NONBLOCK is not specified)
@@ -415,7 +425,10 @@ typedef struct {
// the returned group will share most resources with its parent (the one passed as this)
// the parent may be deleted anytime, but it will stay in memory until the child is deleted as well (using reference counting)
// because both share most of their data, modifications of the child will affect the parent and the opposite direction is also possible if the modifications involve the subgroup
- // saving through child groups is not implemented yet, it will result in an error
+ // all save methods except cc4group.save and cc4group.saveParent save the child groups contents as if it didn't have a parent at all
+ // cc4group.save refuses to save groups from cc4group.openAsChild
+ // cc4group.saveParent saves the top-most parent with cc4group.save in order to save the changes in the child to disk. this will also save modifications made inside the parent group...
+ // ...outside of this children
CC4Group* (*openAsChild)(CC4Group* const this, const char* const path);
} const CC4Group_API;
diff --git a/src/cppc4group.cpp b/src/cppc4group.cpp
index ea24f3b..4db6153 100644
--- a/src/cppc4group.cpp
+++ b/src/cppc4group.cpp
@@ -239,9 +239,14 @@ bool CppC4Group::openWithReadCallback(const ReadCallback callback, void* const c
return cc4group.openWithReadCallback(p->g, callback, callbackArg, convertMemoryManagement(management), initCallback, deinitCallback);
}
-bool CppC4Group::save(const std::string& path, const bool overwrite)
+bool CppC4Group::save(const bool parent)
{
- return (overwrite ? cc4group.saveOverwrite : cc4group.save)(p->g, path.c_str());
+ return (parent ? cc4group.saveParent : cc4group.save)(p->g);
+}
+
+bool CppC4Group::saveAs(const std::string& path, const bool overwrite)
+{
+ return (overwrite ? cc4group.saveAsOverwrite : cc4group.saveAs)(p->g, path.c_str());
}
bool CppC4Group::saveToFd(const int fd)
diff --git a/src/cppc4group.hpp b/src/cppc4group.hpp
index 0ca9eb1..33cf2cc 100644
--- a/src/cppc4group.hpp
+++ b/src/cppc4group.hpp
@@ -153,8 +153,10 @@ public:
bool openMemory(const void* const data, const size_t size, const MemoryManagement& management = MemoryManagement::Reference);
bool openWithReadCallback(const ReadCallback callback, void* const callbackArg, const MemoryManagement& management = MemoryManagement::Take, SetupCallback initCallback = nullptr, SetupCallback deinitCallback = nullptr);
- // save actually maps to both cc4group.save and cc4group.saveOverwrite, thanks to default arguments (yes, thats the reason why they are separate in the C-API)
- bool save(const std::string& path, const bool overwrite = false);
+ // save actually maps to both cc4group.save and cc4group.saveParent, thanks to default arguments (yes, thats the reason why they are separate in the C-API)
+ bool save(const bool parent = false);
+ // saveAs actually maps to both cc4group.saveAs and cc4group.saveAsOverwrite, as above
+ bool saveAs(const std::string& path, const bool overwrite = false);
bool saveToFd(const int fd);
bool saveToFilePointer(FILE* file);
bool saveWithWriteCallback(const WriteCallback callback, void* const arg = nullptr, size_t bufferSize = 0);
diff --git a/src/platform/platform.h b/src/platform/platform.h
index 688d851..55ed242 100644
--- a/src/platform/platform.h
+++ b/src/platform/platform.h
@@ -24,7 +24,11 @@
#define cc4group_mkdir(path, mode) mkdir((path))
#define SET_BINARY(fd) setmode(fd, O_BINARY)
#else
+ #ifndef _XOPEN_SOURCE
+ #define _XOPEN_SOURCE 700
+ #endif
#include <sys/mman.h>
+ #include <stdlib.h>
#define cc4group_mkdir(path, mode) mkdir((path), (mode))
#define O_BINARY 0
@@ -32,4 +36,5 @@
#endif
void *cc4group_mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset);
-int cc4group_munmap(void *addr, size_t length); \ No newline at end of file
+int cc4group_munmap(void *addr, size_t length);
+char* cc4group_absolutePath(const char* path); \ No newline at end of file
diff --git a/src/platform/unix.c b/src/platform/unix.c
index 9bd8f57..01161fc 100644
--- a/src/platform/unix.c
+++ b/src/platform/unix.c
@@ -9,3 +9,8 @@ int cc4group_munmap(void *addr, size_t length)
{
return munmap(addr, length);
}
+
+char* cc4group_absolutePath(const char* path)
+{
+ return realpath(path, NULL);
+}
diff --git a/src/platform/windows.c b/src/platform/windows.c
index 53d5038..96678ab 100644
--- a/src/platform/windows.c
+++ b/src/platform/windows.c
@@ -97,5 +97,11 @@ int cc4group_munmap(void *addr, size_t length)
return 0;
}
+char* cc4group_absolutePath(const char* path)
+{
+ return _fullpath(NULL, path, 0);
+}
+
+
#undef DWORD_HI
#undef DWORD_LO