summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/cc4group.c517
1 files changed, 441 insertions, 76 deletions
diff --git a/src/cc4group.c b/src/cc4group.c
index 3a78073..ce4dbb1 100644
--- a/src/cc4group.c
+++ b/src/cc4group.c
@@ -20,6 +20,7 @@
#include <sys/time.h>
#include <time.h>
#include <utime.h>
+#include <dirent.h>
#include <assert.h>
#include <stdio.h>
@@ -64,6 +65,7 @@ typedef struct C4GroupEntryData_t {
struct C4GroupEntryData_t* parent;
size_t absolutePosition;
+ const char* path;
} C4GroupEntryData;
LIST_AUTO(C4GroupEntryData, GroupEntryList)
@@ -143,13 +145,15 @@ static void cc4group_applyMemoryManagementEnd(CC4Group_MemoryManagement const ma
management->end((void*)data, management->arg);
}
-static const uint8_t* cc4group_getOnlyEntryData(CC4Group* const this, const C4GroupEntryData* entry);
-static const C4GroupEntryData* cc4group_getEntryByPath(CC4Group* const this, const char* const entryPath, bool allowRoot, bool* error);
-static const C4GroupEntryData* cc4group_getDirectoryByPath(CC4Group* const this, const char* const entryPath, bool allowRoot);
-static const C4GroupEntryData* cc4group_getFileByPath(CC4Group* const this, const char* const entryPath);
-static const C4GroupEntryData* cc4group_getFileOrDirectoryByPath(CC4Group* const this, const char* const entryPath, bool allowRoot);
-static GroupEntryList* cc4group_getChildren(CC4Group* const this, const C4GroupEntryData* entry);
-static C4GroupHeader* cc4group_getHeader(CC4Group* const this, const C4GroupEntryData* entry);
+static const uint8_t* cc4group_getOnlyEntryData(CC4Group* const this, const C4GroupEntryData* const entry);
+static const C4GroupEntryData* cc4group_getEntryByPath(CC4Group* const this, const char* const entryPath, bool const allowRoot, bool* const error, const C4GroupEntryData* const inParent);
+static const C4GroupEntryData* cc4group_getDirectoryByPath(CC4Group* const this, const char* const entryPath, bool const allowRoot, const C4GroupEntryData* const inParent);
+static const C4GroupEntryData* cc4group_getFileByPath(CC4Group* const this, const char* const entryPath, const C4GroupEntryData* const inParent);
+static const C4GroupEntryData* cc4group_getFileOrDirectoryByPath(CC4Group* const this, const char* const entryPath, bool const allowRoot, const C4GroupEntryData* const inParent);
+static GroupEntryList* cc4group_getChildren(CC4Group* const this, const C4GroupEntryData* const entry);
+static C4GroupHeader* cc4group_getHeader(CC4Group* const this, const C4GroupEntryData* const entry);
+static C4GroupEntryData* cc4group_createEntry(CC4Group* const this, const char* const path, C4GroupEntryData* const parent);
+static C4GroupEntryData* cc4group_createDirectory(CC4Group* const this, const char* const path, C4GroupEntryData* const parent);
static char* cc4group_strerrorFormatter(int32_t const code, const char* const method, const char* const causer, void* const data)
{
@@ -313,7 +317,7 @@ static bool buildChildren(CC4Group* const this, C4GroupEntryData* const entry, s
return false;
}
- C4GroupEntryData* childEntry = &GroupEntryListAppend(entry->children, (C4GroupEntryData){.core = *core, .data = childData + core->Offset, .memoryManagement = cc4group.MemoryManagement.Reference, .children = NULL, .parent = entry, .absolutePosition = entry->absolutePosition + childDataOffset + core->Offset})->value;
+ C4GroupEntryData* childEntry = &GroupEntryListAppend(entry->children, (C4GroupEntryData){.core = *core, .data = childData + core->Offset, .memoryManagement = cc4group.MemoryManagement.Reference, .children = NULL, .parent = entry, .absolutePosition = entry->absolutePosition + childDataOffset + core->Offset, .path = NULL})->value;
if(this->readState.position < childEntry->absolutePosition)
{
@@ -340,6 +344,10 @@ static void deleteChildren(GroupEntryList* const entries)
{
cc4group_applyMemoryManagementEnd(entry->value.memoryManagement, entry->value.data);
}
+ if(entry->value.path != NULL)
+ {
+ free((void*)entry->value.path);
+ }
// if they are not loaded yet, there is no need to delete them
if(entry->value.core.Directory && entry->value.children != NULL)
@@ -1025,7 +1033,7 @@ static bool cc4group_setSubRoot(CC4Group* const this, const char* const subPath)
{
if(subPath != NULL && *subPath != '\0')
{
- const C4GroupEntryData* subRoot = cc4group_getDirectoryByPath(this, subPath, false);
+ const C4GroupEntryData* subRoot = cc4group_getDirectoryByPath(this, subPath, false, NULL);
if(subRoot == NULL || cc4group_getChildren(this, subRoot) == NULL)
{
@@ -1223,7 +1231,7 @@ static bool cc4group_setMaker(CC4Group* const this, const char* const maker, con
assert(this);
assert(maker);
- const C4GroupEntryData* entry = cc4group_getDirectoryByPath(this, path, true);
+ const C4GroupEntryData* entry = cc4group_getDirectoryByPath(this, path, true, NULL);
if(entry == NULL)
{
@@ -1277,7 +1285,7 @@ static bool cc4group_setOfficial(CC4Group* const this, bool const official, cons
{
assert(this);
- const C4GroupEntryData* entry = cc4group_getDirectoryByPath(this, path, true);
+ const C4GroupEntryData* entry = cc4group_getDirectoryByPath(this, path, true, NULL);
if(entry == NULL)
{
@@ -1332,7 +1340,7 @@ static bool cc4group_setCreation(CC4Group* const this, int32_t const creation, c
{
assert(this);
- C4GroupEntryData* entry = (C4GroupEntryData*)cc4group_getFileOrDirectoryByPath(this, path, true);
+ C4GroupEntryData* entry = (C4GroupEntryData*)cc4group_getFileOrDirectoryByPath(this, path, true, NULL);
if(entry == NULL)
{
@@ -1433,6 +1441,235 @@ static bool cc4group_openFilePointer(CC4Group* const this, FILE* const file)
return cc4group_uncompressGroup(this, cc4group_readFilePointerReadCallback, arg, cc4group.MemoryManagement.Reference, cc4group_initChunkBufferCallback, cc4group_deinitChunkBufferCallback);
}
+static bool cc4group_isDirectory(const char* const path)
+{
+ struct stat st;
+ return stat(path, &st) != -1 && S_ISDIR(st.st_mode);
+}
+
+static char* cc4group_pathCombine(const char* const firstPart, const char* secondPart)
+{
+ if(firstPart == NULL)
+ {
+ assert(secondPart);
+ return strdup(secondPart);
+ }
+ if(secondPart == NULL)
+ {
+ assert(firstPart);
+ return strdup(firstPart);
+ }
+
+ if(*secondPart == '/')
+ {
+ ++secondPart;
+ }
+
+ size_t firstLen = strlen(firstPart);
+ if(firstLen && firstPart[firstLen - 1] == '/')
+ {
+ --firstLen;
+ }
+
+ char* const result = malloc(firstLen + 1 + strlen(secondPart) + 1); // '/' and '\0'
+ if(result != NULL)
+ {
+ strncpy(result, firstPart, firstLen);
+ result[firstLen] = '/';
+ strcpy(result + firstLen + 1, secondPart);
+ }
+ return result;
+}
+
+// takes over memory management of filePath
+static C4GroupEntryData* cc4group_addFileFromDisk(CC4Group* const this, const char* const filePath, const char* const targetPath, C4GroupEntryData* const parent)
+{
+ assert(this);
+ assert(filePath);
+ assert(targetPath);
+
+ C4GroupEntryData* result = NULL;
+
+ struct stat st;
+ if(stat(filePath, &st) == -1)
+ {
+ SET_ERRNO_ERROR("stat: getting information of a contained file");
+ goto ret;
+ }
+
+ result = cc4group_createEntry(this, targetPath, parent);
+ if(result == NULL)
+ {
+ goto ret;
+ }
+
+ if(!S_ISREG(st.st_mode))
+ {
+ SET_MESSAGE_ERROR("Unsupported directory entry type found. Only regular files and directories are supported.");
+ goto ret;
+ }
+
+ result->core.Executable = (st.st_mode & S_IXUSR) ? 1 : 0;
+ result->core.Modified = st.st_mtime;
+ result->core.Size = st.st_size;
+ result->path = filePath;
+
+ret:
+ if(result == NULL || result->path == NULL)
+ {
+ free((void*)filePath);
+ }
+
+ return result;
+}
+
+// takes over memory management of directoryPath
+static bool cc4group_addDirectoryFromDisk(CC4Group* const this, const char* directoryPath, const char* const targetPath, C4GroupEntryData* const parent)
+{
+ assert(this);
+ assert(directoryPath);
+
+ bool success = false;
+
+ if(!cc4group_isDirectory(directoryPath))
+ {
+ SET_MESSAGE_ERROR("The specified path is not a directory");
+ goto ret;
+ }
+
+ C4GroupEntryData* existingDirectory = targetPath == NULL ? &this->root : (C4GroupEntryData*)cc4group_getDirectoryByPath(this, targetPath, false, parent);
+ if(existingDirectory == NULL)
+ {
+ existingDirectory = cc4group_createDirectory(this, targetPath, parent);
+ if(existingDirectory == NULL)
+ {
+ goto ret;
+ }
+ }
+
+ struct stat st;
+ if(stat(directoryPath, &st) == -1)
+ {
+ SET_ERRNO_ERROR("stat: getting information of a directory");
+ goto ret;
+ }
+ existingDirectory->core.Modified = st.st_mtime;
+
+ existingDirectory->path = directoryPath;
+ directoryPath = NULL;
+
+ success = true;
+ret:
+ if(directoryPath != NULL)
+ {
+ free((void*)directoryPath);
+ }
+
+ return success;
+}
+static bool cc4group_populateDirectoryFromDisk(CC4Group* const this, C4GroupEntryData* const entry)
+{
+ assert(this);
+ assert(entry);
+ assert(entry->core.Directory);
+ assert(entry->path);
+ assert(!entry->children);
+
+ entry->children = GroupEntryListNew();
+
+ DIR* dir = opendir(entry->path);
+ if(dir == NULL)
+ {
+ SET_ERRNO_ERROR("opendir: Opening the directoryPath");
+ return false;
+ }
+
+ bool success = false;
+ for(;;)
+ {
+ errno = 0;
+ struct dirent* dirEntry = readdir(dir);
+ if(dirEntry == NULL)
+ {
+ success = errno == 0;
+ if(!success)
+ {
+ SET_ERRNO_ERROR("readdir: reading the next entry");
+ }
+ break;
+ }
+
+ if(strcmp(dirEntry->d_name, ".") == 0 || strcmp(dirEntry->d_name, "..") == 0)
+ {
+ continue;
+ }
+
+ char* directoryEntryPath = cc4group_pathCombine(entry->path, dirEntry->d_name);
+ if(directoryEntryPath == NULL)
+ {
+ SET_ERRNO_ERROR("malloc: allocating memory for the temporary path of an entry in the directory");
+ break;
+ }
+
+ if(cc4group_isDirectory(directoryEntryPath))
+ {
+ if(!cc4group_addDirectoryFromDisk(this, directoryEntryPath, dirEntry->d_name, entry))
+ {
+ success = false;
+ break;
+ }
+ }
+ else
+ {
+ if(!cc4group_addFileFromDisk(this, directoryEntryPath, dirEntry->d_name, entry))
+ {
+ success = false;
+ break;
+ }
+ }
+ }
+
+ entry->header->Entries = GroupEntryListSize(entry->children);
+
+ if(closedir(dir) == -1)
+ {
+ cc4group_warn(this, "closedir: Closing the directory stream \"%s\" failed: %s", entry->path, strerror(errno));
+ }
+
+ return success;
+}
+
+static bool cc4group_openDirectory(CC4Group* const this, const char* const path)
+{
+ assert(this);
+ assert(path);
+
+ if(!cc4group_isDirectory(path))
+ {
+ SET_MESSAGE_ERROR("The specified path is not a directory");
+ return false;
+ }
+
+ this->root.core.Directory = 1;
+ this->root.core.FileName[0] = '\0';
+ this->lazy = false;
+
+ if(!cc4group_initNewHeader(this))
+ {
+ return false;
+ }
+
+ if(cc4group_addDirectoryFromDisk(this, strdup(path), NULL, NULL) && cc4group_populateDirectoryFromDisk(this, &this->root))
+ {
+ AddCleanUpJob(deleteChildren, this->root.children);
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
static bool cc4group_openExisting(CC4Group* const this, const char* const path)
{
assert(this);
@@ -1443,6 +1680,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))
+ {
+ return cc4group_openDirectory(this, path);
+ }
return cc4group_uncompressGroupFromFile(this, path);
}
@@ -1598,16 +1839,17 @@ static bool cc4group_extractAll(CC4Group* const this, const char* const targetPa
// sets *error to true if any error is set
-static const C4GroupEntryData* cc4group_getEntryByPath(CC4Group* const this, const char* const entryPath, bool allowRoot, bool* error)
+static const C4GroupEntryData* cc4group_getEntryByPath(CC4Group* const this, const char* const entryPath, bool const allowRoot, bool* const error, const C4GroupEntryData* const inParent)
{
assert(this);
assert(this->root.children);
+ const C4GroupEntryData* currentParent = inParent ? inParent : &this->root;
if(entryPath == NULL || *entryPath == '\0')
{
if(allowRoot)
{
- return &this->root;
+ return currentParent;
}
else
{
@@ -1617,7 +1859,6 @@ static const C4GroupEntryData* cc4group_getEntryByPath(CC4Group* const this, con
}
}
- const C4GroupEntryData* currentParent = &this->root;
char* path = strdup(entryPath);
if(path == NULL)
@@ -1674,11 +1915,11 @@ ret:
}
// sets error
-static const C4GroupEntryData* cc4group_getDirectoryByPath(CC4Group* const this, const char* const entryPath, bool allowRoot)
+static const C4GroupEntryData* cc4group_getDirectoryByPath(CC4Group* const this, const char* const entryPath, bool const allowRoot, const C4GroupEntryData* const inParent)
{
// asserts are in cc4group_getEntryByPath
bool error = false;
- const C4GroupEntryData* entry = cc4group_getEntryByPath(this, entryPath, allowRoot, &error);
+ const C4GroupEntryData* entry = cc4group_getEntryByPath(this, entryPath, allowRoot, &error, inParent);
if(error)
{
return NULL;
@@ -1686,7 +1927,7 @@ static const C4GroupEntryData* cc4group_getDirectoryByPath(CC4Group* const this,
if(entry == NULL)
{
- SET_MESSAGE_ERROR("The dirctory was not found in the group file");
+ SET_MESSAGE_ERROR("The directory was not found in the group file");
return NULL;
}
@@ -1700,11 +1941,11 @@ static const C4GroupEntryData* cc4group_getDirectoryByPath(CC4Group* const this,
}
// sets error
-static const C4GroupEntryData* cc4group_getFileByPath(CC4Group* const this, const char* const entryPath)
+static const C4GroupEntryData* cc4group_getFileByPath(CC4Group* const this, const char* const entryPath, const C4GroupEntryData* const inParent)
{
// asserts are in cc4group_getEntryByPath
bool error = false;
- const C4GroupEntryData* entry = cc4group_getEntryByPath(this, entryPath, true, &error);
+ const C4GroupEntryData* entry = cc4group_getEntryByPath(this, entryPath, true, &error, inParent);
if(error)
{
return NULL;
@@ -1726,11 +1967,11 @@ static const C4GroupEntryData* cc4group_getFileByPath(CC4Group* const this, cons
}
// sets error
-static const C4GroupEntryData* cc4group_getFileOrDirectoryByPath(CC4Group* const this, const char* const entryPath, bool allowRoot)
+static const C4GroupEntryData* cc4group_getFileOrDirectoryByPath(CC4Group* const this, const char* const entryPath, bool const allowRoot, const C4GroupEntryData* const inParent)
{
// asserts are in cc4group_getEntryByPath
bool error = false;
- const C4GroupEntryData* entry = cc4group_getEntryByPath(this, entryPath, allowRoot, &error);
+ const C4GroupEntryData* entry = cc4group_getEntryByPath(this, entryPath, allowRoot, &error, inParent);
if(error)
{
return false;
@@ -1750,7 +1991,7 @@ static bool cc4group_extractSingle(CC4Group* const this, const char* const entry
assert(this);
assert(targetPath);
- const C4GroupEntryData* entry = cc4group_getFileOrDirectoryByPath(this, entryPath, true);
+ const C4GroupEntryData* entry = cc4group_getFileOrDirectoryByPath(this, entryPath, true, NULL);
if(entry == NULL)
{
return false;
@@ -1759,16 +2000,97 @@ static bool cc4group_extractSingle(CC4Group* const this, const char* const entry
return cc4group_extractChildren(this, entry, targetPath);
}
-static const uint8_t* cc4group_getOnlyEntryData(CC4Group* const this, const C4GroupEntryData* const entry)
+static void* cc4group_mmappedFileManagementStart(void* const data, size_t const size, void* const arg)
+{
+ (void)size;
+ (void)arg;
+ return data;
+}
+
+typedef struct {
+ CC4Group_MemoryManagement_t management;
+ size_t size;
+ int fd;
+ const CC4Group* group;
+} CC4GroupMMappedFileManagement;
+
+static void cc4group_mmappedFileManagementEnd(void* const data, void* const arg)
+{
+ (void)data;
+ CC4GroupMMappedFileManagement* argData = arg;
+ if(cc4group_munmap(data, argData->size) == -1)
+ {
+ cc4group_warn(argData->group, "munmap: unmapping a mmapped file failed: %s", strerror(errno));
+ }
+ if(argData->fd != -1)
+ {
+ if(close(argData->fd) == -1)
+ {
+ cc4group_warn(argData->group, "close: closing a file after unmapping (and also directly after mapping) it failed: %s", strerror(errno));
+ }
+ }
+ free(argData);
+}
+
+static const uint8_t* cc4group_getOnlyEntryData(CC4Group* const this, const C4GroupEntryData* entry)
{
if(entry->data == NULL)
{
- if(!cc4group_uncompressUntilPosition(this, entry->absolutePosition + entry->core.Size))
+ if(entry->path != NULL)
{
- return NULL;
+ int file = open(entry->path, O_RDONLY | O_BINARY);
+ if(file == -1)
+ {
+ SET_ERRNO_ERROR("open: Opening the needed file");
+ return NULL;
+ }
+
+ void* mapped = cc4group_mmap(NULL, entry->core.Size, PROT_READ, MAP_PRIVATE, file, 0);
+ if(mapped == MAP_FAILED)
+ {
+ SET_ERRNO_ERROR("mmap: Mapping the file to add/load from disk");
+ if(close(file) == -1)
+ {
+ cc4group_warn(this, "close: after mmapping the file \"%s\" failed, closing it failed too: %s", entry->path, strerror(errno));
+ }
+ return NULL;
+ }
+
+ CC4GroupMMappedFileManagement* management = malloc(sizeof(*management));
+ if(management == NULL)
+ {
+ SET_ERRNO_ERROR("malloc: allocating memory for temporary memory management");
+ return NULL;
+ }
+
+ *management = (CC4GroupMMappedFileManagement){
+ .management = {
+ .start = cc4group_mmappedFileManagementStart,
+ .end = cc4group_mmappedFileManagementEnd,
+ .arg = management
+ },
+ .size = entry->core.Size,
+ .fd = -1,
+ .group = this
+ };
+
+ if(close(file) == -1)
+ {
+ management->fd = file;
+ }
+
+ ((C4GroupEntryData*)entry)->data = mapped;
+ ((C4GroupEntryData*)entry)->memoryManagement = &management->management;
}
+ else
+ {
+ if(!cc4group_uncompressUntilPosition(this, entry->absolutePosition + entry->core.Size))
+ {
+ return NULL;
+ }
- ((C4GroupEntryData*)entry)->data = this->uncompressedData + entry->absolutePosition;
+ ((C4GroupEntryData*)entry)->data = this->uncompressedData + entry->absolutePosition;
+ }
}
return entry->data;
@@ -1776,13 +2098,23 @@ static const uint8_t* cc4group_getOnlyEntryData(CC4Group* const this, const C4Gr
static C4GroupHeader* cc4group_getHeader(CC4Group* const this, const C4GroupEntryData* const entry)
{
+ assert(this);
+ assert(entry);
assert(entry->core.Directory);
- if(entry->header == NULL)
+ if(entry->header == NULL || (entry->path != NULL && entry->children == NULL))
{
- if(!cc4group_uncompressUntilPosition(this, entry->absolutePosition + sizeof(C4GroupHeader)))
+ if(entry->path != NULL)
{
- return NULL;
+ cc4group_populateDirectoryFromDisk(this, (C4GroupEntryData*)entry);
+ return entry->header;
+ }
+ else
+ {
+ if(!cc4group_uncompressUntilPosition(this, entry->absolutePosition + sizeof(C4GroupHeader)))
+ {
+ return NULL;
+ }
}
((C4GroupEntryData*)entry)->data = this->uncompressedData + entry->absolutePosition;
@@ -1806,14 +2138,22 @@ static GroupEntryList* cc4group_getChildren(CC4Group* const this, const C4GroupE
return NULL;
}
- if(!cc4group_uncompressUntilPosition(this, entry->absolutePosition + sizeof(C4GroupHeader) + entry->header->Entries * sizeof(C4GroupEntryCore)))
+ if(entry->path != NULL)
{
- return NULL;
+ // should have been handled by getHeader if possible
+ return entry->children;
}
-
- if(!buildChildren(this, (C4GroupEntryData*)entry, entry->core.Size))
+ else
{
- return NULL;
+ if(!cc4group_uncompressUntilPosition(this, entry->absolutePosition + sizeof(C4GroupHeader) + entry->header->Entries * sizeof(C4GroupEntryCore)))
+ {
+ return NULL;
+ }
+
+ if(!buildChildren(this, (C4GroupEntryData*)entry, entry->core.Size))
+ {
+ return NULL;
+ }
}
}
@@ -1826,7 +2166,7 @@ static bool cc4group_getEntryData(CC4Group* const this, const char* const entryP
assert(data);
assert(size);
- const C4GroupEntryData* entry = cc4group_getFileByPath(this, entryPath);
+ const C4GroupEntryData* entry = cc4group_getFileByPath(this, entryPath, NULL);
if(entry == NULL)
{
return false;
@@ -2289,7 +2629,7 @@ static bool cc4group_saveOverwrite(CC4Group* const this, const char* const path)
static bool cc4group_getEntryInfoForEntry(CC4Group* const this, const C4GroupEntryData* const entry, CC4Group_EntryInfo* const info, bool const lazy)
{
C4GroupHeader* header = NULL;
- if(entry->core.Directory && !(this->lazy && lazy))
+ if(entry->core.Directory && !((this->lazy || entry->path != NULL) && lazy))
{
header = cc4group_getHeader(this, entry);
if(header == NULL)
@@ -2317,7 +2657,7 @@ static bool cc4group_getEntryInfo(CC4Group* const this, const char* const path,
assert(this);
assert(info);
- const C4GroupEntryData* entry = cc4group_getFileOrDirectoryByPath(this, path, true);
+ const C4GroupEntryData* entry = cc4group_getFileOrDirectoryByPath(this, path, true, NULL);
if(entry == NULL)
{
return false;
@@ -2336,7 +2676,7 @@ static bool cc4group_getEntryInfos(CC4Group* const this, const char* const path,
if(path != NULL && *path != '\0')
{
- const C4GroupEntryData* entry = cc4group_getDirectoryByPath(this, path, true);
+ const C4GroupEntryData* entry = cc4group_getDirectoryByPath(this, path, true, NULL);
if(entry == NULL)
{
return false;
@@ -2418,7 +2758,7 @@ static bool cc4group_getParentAndChildEntries(CC4Group* const this, const char*
const char* parentPath;
char* entryName = cc4group_splitParentAndChildPaths(myPath, &parentPath);
- parent = cc4group_getDirectoryByPath(this, parentPath, true);
+ parent = cc4group_getDirectoryByPath(this, parentPath, true, NULL);
if(parent == NULL)
{
@@ -2488,6 +2828,10 @@ static bool cc4group_deleteEntry(CC4Group* const this, const char* const path, b
{
cc4group_applyMemoryManagementEnd(deleteEntry->value.memoryManagement, deleteEntry->value.data);
}
+ if(deleteEntry->value.path)
+ {
+ free((void*)deleteEntry->value.path);
+ }
GroupEntryList* parentChildren = cc4group_getChildren(this, parent);
assert(parentChildren); // if there was an error, it should have really been catched already in cc4group_getParentAndChildEntries
@@ -2522,7 +2866,7 @@ static bool cc4group_renameEntry(CC4Group* const this, const char* const oldPath
assert(newPath);
bool error = false;
- if(cc4group_getEntryByPath(this, newPath, false, &error) != NULL)
+ if(cc4group_getEntryByPath(this, newPath, false, &error, NULL) != NULL)
{
SET_MESSAGE_ERROR("The desired target path already exists");
return false;
@@ -2552,7 +2896,7 @@ static bool cc4group_renameEntry(CC4Group* const this, const char* const oldPath
const char* targetDirectory;
char* targetName = cc4group_splitParentAndChildPaths(targetPath, &targetDirectory);
- C4GroupEntryData* newParent = (C4GroupEntryData*)cc4group_getDirectoryByPath(this, targetDirectory, true);
+ C4GroupEntryData* newParent = (C4GroupEntryData*)cc4group_getDirectoryByPath(this, targetDirectory, true, NULL);
if(newParent == NULL)
{
free(targetPath);
@@ -2573,10 +2917,10 @@ static bool cc4group_renameEntry(CC4Group* const this, const char* const oldPath
return true;
}
-static C4GroupEntryData* cc4group_createEntry(CC4Group* const this, const char* const path)
+static C4GroupEntryData* cc4group_createEntry(CC4Group* const this, const char* const path, C4GroupEntryData* inParent)
{
bool error = false;
- if(cc4group_getEntryByPath(this, path, false, &error) != NULL)
+ if(cc4group_getEntryByPath(this, path, false, &error, inParent) != NULL)
{
SET_MESSAGE_ERROR("The desired target path already exists");
return NULL;
@@ -2587,50 +2931,62 @@ static C4GroupEntryData* cc4group_createEntry(CC4Group* const this, const char*
return NULL;
}
- char* targetPath = strdup(path);
-
- if(targetPath == NULL)
+ const char* targetName;
+ C4GroupEntryData* parent;
+ char* targetPath;
+ if(inParent == NULL)
{
- SET_ERRNO_ERROR("strdup: duplicating the path");
- return NULL;
- }
-
- const char* targetDirectory;
- char* targetName = cc4group_splitParentAndChildPaths(targetPath, &targetDirectory);
+ targetPath = strdup(path);
+ if(targetPath == NULL)
+ {
+ SET_ERRNO_ERROR("strdup: duplicating the path");
+ return NULL;
+ }
+ const char* targetDirectory;
+ targetName = cc4group_splitParentAndChildPaths(targetPath, &targetDirectory);
- C4GroupEntryData* parent = (C4GroupEntryData*)cc4group_getDirectoryByPath(this, targetDirectory, true);
- if(parent == NULL)
+ parent = (C4GroupEntryData*)cc4group_getDirectoryByPath(this, targetDirectory, true, NULL);
+ if(parent == NULL)
+ {
+ free(targetPath);
+ return NULL;
+ }
+ }
+ else
{
- free(targetPath);
- return NULL;
+ parent = inParent;
+ targetName = path;
}
C4GroupEntryData entry;
entry.data = NULL;
+ entry.path = NULL;
entry.memoryManagement = cc4group.MemoryManagement.Reference;
C4GroupEntryCore_init(&entry.core);
C4GroupEntryCore_setFileName(&entry.core, targetName);
- free(targetPath);
+ if(inParent == NULL)
+ {
+ free(targetPath);
+ }
return cc4group_addEntryToDirectory(this, parent, &entry);
}
-static bool cc4group_createDirectory(CC4Group* const this, const char* const path)
+static C4GroupEntryData* cc4group_createDirectory(CC4Group* const this, const char* const path, C4GroupEntryData* const parent)
{
assert(this);
assert(path);
- C4GroupEntryData* entry = cc4group_createEntry(this, path);
+ C4GroupEntryData* entry = cc4group_createEntry(this, path, parent);
if(entry == NULL)
{
- return false;
+ return NULL;
}
-
C4GroupHeader* header = malloc(sizeof(C4GroupHeader));
if(header == NULL)
@@ -2639,7 +2995,7 @@ static bool cc4group_createDirectory(CC4Group* const this, const char* const pat
return NULL;
}
- entry->children = GroupEntryListNew();
+ entry->children = NULL;
C4GroupHeader_init(header);
C4GroupHeader_setOfficial(header, C4GroupHeader_isOfficial(entry->parent->header));
@@ -2649,7 +3005,17 @@ static bool cc4group_createDirectory(CC4Group* const this, const char* const pat
entry->core.Directory = 1;
entry->memoryManagement = cc4group.MemoryManagement.Take;
- return true;
+ return entry;
+}
+
+static bool cc4group_createEmptyDirectory(CC4Group* const this, const char* const path)
+{
+ C4GroupEntryData* entry = cc4group_createDirectory(this, path, NULL);
+ if(entry != NULL)
+ {
+ entry->children = GroupEntryListNew();
+ }
+ return entry != NULL;
}
static bool cc4group_createFile(CC4Group* const this, const char* const path)
@@ -2657,14 +3023,7 @@ static bool cc4group_createFile(CC4Group* const this, const char* const path)
assert(this);
assert(path);
- C4GroupEntryData* entry = cc4group_createEntry(this, path);
-
- if(entry == NULL)
- {
- return false;
- }
-
- return true;
+ return cc4group_createEntry(this, path, NULL) != NULL;
}
static bool cc4group_setEntryData(CC4Group* const this, const char* const entryPath, const void* const data, size_t const size, CC4Group_MemoryManagement const memoryManagement)
@@ -2672,7 +3031,7 @@ static bool cc4group_setEntryData(CC4Group* const this, const char* const entryP
assert(this);
assert(entryPath);
- C4GroupEntryData* entry = (C4GroupEntryData*)cc4group_getFileByPath(this, entryPath);
+ C4GroupEntryData* entry = (C4GroupEntryData*)cc4group_getFileByPath(this, entryPath, NULL);
if(entry == NULL)
{
return false;
@@ -2687,6 +3046,12 @@ static bool cc4group_setEntryData(CC4Group* const this, const char* const entryP
entry->memoryManagement = cc4group.MemoryManagement.Reference;
}
+ if(entry->path != NULL)
+ {
+ free((void*)entry->path);
+ entry->path = NULL;
+ }
+
if(data != NULL && size != 0)
{
const uint8_t* ownData = data;
@@ -2712,7 +3077,7 @@ static bool cc4group_setExecutable(CC4Group* const this, bool const executable,
{
assert(this);
- C4GroupEntryData* entry = (C4GroupEntryData*)cc4group_getFileByPath(this, path);
+ C4GroupEntryData* entry = (C4GroupEntryData*)cc4group_getFileByPath(this, path, NULL);
if(entry == NULL)
{
@@ -2727,7 +3092,7 @@ static CC4Group* cc4group_openAsChild(CC4Group* const this, const char* const pa
{
assert(this);
- const C4GroupEntryData* entry = cc4group_getDirectoryByPath(this, path, false);
+ const C4GroupEntryData* entry = cc4group_getDirectoryByPath(this, path, false, NULL);
if(entry == NULL)
{
@@ -2888,7 +3253,7 @@ CC4Group_API cc4group = {
.setExecutable = cc4group_setExecutable,
- .createDirectory = cc4group_createDirectory,
+ .createDirectory = cc4group_createEmptyDirectory,
.createFile = cc4group_createFile,
.renameEntry = cc4group_renameEntry,
.deleteEntry = cc4group_deleteEntry,