fix(tree): now does properly generate the snapshot with the given FileInfoBuffer instead of the debug walk through the repo

This commit is contained in:
lisk77 2025-09-16 15:32:32 +02:00
parent 8cbf82a535
commit 550b47d568

View file

@ -1,27 +1,20 @@
#include "tree.h" #include "tree.h"
void snapshot_tree(FileInfoBuffer* tree, char* hash) { void snapshot_tree(FileInfoBuffer* tree, char* hash) {
FileInfoBuffer* files = file_info_buffer_new();
if (!files) {
perror("ERROR: failed to create file info buffer!");
return;
}
char relative[PATH_MAX] = ""; char relative[PATH_MAX] = "";
char* root = find_root(relative); char* root = find_root(relative);
if (!root) { if (!root) {
perror("ERROR: unable to find root directory of the repository!"); perror("ERROR: unable to find root directory of the repository!");
file_info_buffer_free(files); file_info_buffer_free(tree);
return; return;
} }
walk(root, relative, relative, files, 1, root); file_info_buffer_sort(tree);
file_info_buffer_sort(files);
size_t buffer_size = 0; size_t buffer_size = 0;
for (size_t idx = 0; idx < files->len; idx++) { for (size_t idx = 0; idx < tree->len; idx++) {
FileInfo* file_info = (FileInfo*)files->items + idx; FileInfo* file_info = (FileInfo*)tree->items + idx;
buffer_size += snprintf(NULL, 0, "%o %s %s\n", file_info->mode, file_info->name, file_info->hash); buffer_size += snprintf(NULL, 0, "%o %s %s\n", file_info->mode, file_info->name, file_info->hash);
} }
@ -30,15 +23,15 @@ void snapshot_tree(FileInfoBuffer* tree, char* hash) {
char* tmp = calloc(buffer_size, sizeof(char)); char* tmp = calloc(buffer_size, sizeof(char));
if (!tmp) { if (!tmp) {
perror("ERROR: memory allocation failed in snapshot_tree!"); perror("ERROR: memory allocation failed in snapshot_tree!");
file_info_buffer_free(files); file_info_buffer_free(tree);
free(root); free(root);
return; return;
} }
size_t offset = 0; size_t offset = 0;
for (size_t idx = 0; idx < files->len; idx++) { for (size_t idx = 0; idx < tree->len; idx++) {
FileInfo* file_info = (FileInfo*)files->items + idx; FileInfo* file_info = (FileInfo*)tree->items + idx;
size_t remaining = buffer_size - offset; size_t remaining = buffer_size - offset;
int written = snprintf(tmp + offset, remaining, "%o %s %s\n", int written = snprintf(tmp + offset, remaining, "%o %s %s\n",
@ -47,7 +40,7 @@ void snapshot_tree(FileInfoBuffer* tree, char* hash) {
if (written < 0 || (size_t)written >= remaining) { if (written < 0 || (size_t)written >= remaining) {
perror("ERROR: buffer overflow in snapshot_tree!"); perror("ERROR: buffer overflow in snapshot_tree!");
free(tmp); free(tmp);
file_info_buffer_free(files); file_info_buffer_free(tree);
free(root); free(root);
return; return;
} }
@ -64,7 +57,7 @@ void snapshot_tree(FileInfoBuffer* tree, char* hash) {
if (access(file_path, F_OK) == 0) { if (access(file_path, F_OK) == 0) {
free(tmp); free(tmp);
file_info_buffer_free(files); file_info_buffer_free(tree);
free(root); free(root);
return; return;
} }
@ -73,7 +66,7 @@ void snapshot_tree(FileInfoBuffer* tree, char* hash) {
if (!fp) { if (!fp) {
perror("ERROR: cannot open path in snapshot_tree!"); perror("ERROR: cannot open path in snapshot_tree!");
free(tmp); free(tmp);
file_info_buffer_free(files); file_info_buffer_free(tree);
free(root); free(root);
return; return;
} }
@ -84,7 +77,7 @@ void snapshot_tree(FileInfoBuffer* tree, char* hash) {
if (!compressed) { if (!compressed) {
fclose(fp); fclose(fp);
free(tmp); free(tmp);
file_info_buffer_free(files); file_info_buffer_free(tree);
free(root); free(root);
return; return;
} }
@ -94,7 +87,7 @@ void snapshot_tree(FileInfoBuffer* tree, char* hash) {
free(compressed); free(compressed);
free(tmp); free(tmp);
fclose(fp); fclose(fp);
file_info_buffer_free(files); file_info_buffer_free(tree);
free(root); free(root);
return; return;
} }
@ -108,7 +101,7 @@ void snapshot_tree(FileInfoBuffer* tree, char* hash) {
free(compressed); free(compressed);
free(tmp); free(tmp);
file_info_buffer_free(files); file_info_buffer_free(tree);
free(root); free(root);
} }
@ -117,7 +110,6 @@ int save_tree_diff(FileInfoBuffer* current_tree, char* root, char* branch_name,
return 0; return 0;
} }
// Step 1: Read the base tree file and convert to File*
char base_tree_location[PATH_MAX]; char base_tree_location[PATH_MAX];
snprintf(base_tree_location, sizeof(base_tree_location), "%s/.merk/objects/%.2s/%s", root, base_tree_hash, base_tree_hash+2); snprintf(base_tree_location, sizeof(base_tree_location), "%s/.merk/objects/%.2s/%s", root, base_tree_hash, base_tree_hash+2);
@ -127,7 +119,6 @@ int save_tree_diff(FileInfoBuffer* current_tree, char* root, char* branch_name,
return 0; return 0;
} }
// Parse length from compressed data
size_t idx = 0; size_t idx = 0;
while (idx < compressed_size && IS_DIGIT(compressed_data[idx])) { while (idx < compressed_size && IS_DIGIT(compressed_data[idx])) {
idx++; idx++;
@ -157,10 +148,9 @@ int save_tree_diff(FileInfoBuffer* current_tree, char* root, char* branch_name,
return 0; return 0;
} }
size_t offset = strlen(size_str) + 1; // +1 for space after length size_t offset = strlen(size_str) + 1;
free(size_str); free(size_str);
// Decompress base tree content
char* base_tree_content = calloc(size + 1, sizeof(char)); char* base_tree_content = calloc(size + 1, sizeof(char));
if (!base_tree_content) { if (!base_tree_content) {
free(compressed_data); free(compressed_data);
@ -179,20 +169,18 @@ int save_tree_diff(FileInfoBuffer* current_tree, char* root, char* branch_name,
base_tree_content[dest_len] = '\0'; base_tree_content[dest_len] = '\0';
// Convert base tree content to File*
File* base_tree_file = from_string(base_tree_content); File* base_tree_file = from_string(base_tree_content);
if (!base_tree_file) { if (!base_tree_file) {
free(base_tree_content); free(base_tree_content);
return 0; return 0;
} }
// Step 2: Convert FileInfoBuffer to string (same as snapshot_tree logic)
size_t buffer_size = 0; size_t buffer_size = 0;
for (size_t i = 0; i < current_tree->len; i++) { for (size_t i = 0; i < current_tree->len; i++) {
FileInfo* file_info = (FileInfo*)current_tree->items + i; FileInfo* file_info = (FileInfo*)current_tree->items + i;
buffer_size += snprintf(NULL, 0, "%o %s %s\n", file_info->mode, file_info->name, file_info->hash); buffer_size += snprintf(NULL, 0, "%o %s %s\n", file_info->mode, file_info->name, file_info->hash);
} }
buffer_size += 1; // null terminator buffer_size += 1;
char* current_tree_content = malloc(buffer_size); char* current_tree_content = malloc(buffer_size);
if (!current_tree_content) { if (!current_tree_content) {
@ -222,7 +210,6 @@ int save_tree_diff(FileInfoBuffer* current_tree, char* root, char* branch_name,
} }
current_tree_content[content_offset] = '\0'; current_tree_content[content_offset] = '\0';
// Convert current tree content to File*
File* current_tree_file = from_string(current_tree_content); File* current_tree_file = from_string(current_tree_content);
if (!current_tree_file) { if (!current_tree_file) {
free(current_tree_content); free(current_tree_content);
@ -233,14 +220,11 @@ int save_tree_diff(FileInfoBuffer* current_tree, char* root, char* branch_name,
return 0; return 0;
} }
// Step 3: Generate diff using Myers algorithm
ActionList* diff = myers_diff(base_tree_file, current_tree_file, 0, 0); ActionList* diff = myers_diff(base_tree_file, current_tree_file, 0, 0);
// Handle case where trees are identical
if (!diff || diff->len == 0) { if (!diff || diff->len == 0) {
strcpy(hash, base_tree_hash); strcpy(hash, base_tree_hash);
// Cleanup
free(current_tree_content); free(current_tree_content);
free(base_tree_content); free(base_tree_content);
free(base_tree_file->content[0]); free(base_tree_file->content[0]);
@ -256,23 +240,20 @@ int save_tree_diff(FileInfoBuffer* current_tree, char* root, char* branch_name,
return 1; return 1;
} }
// Step 4: Save the diff size_t diff_buffer_size = strlen(base_tree_hash) + 1;
// Calculate size for diff content string diff_buffer_size += snprintf(NULL, 0, "%zu ", diff->len);
size_t diff_buffer_size = strlen(base_tree_hash) + 1; // base hash + space
diff_buffer_size += snprintf(NULL, 0, "%zu ", diff->len); // action count + space
for (size_t i = 0; i < diff->len; i++) { for (size_t i = 0; i < diff->len; i++) {
Action action = diff->actions[i]; Action action = diff->actions[i];
if (action.type == DELETE) { if (action.type == DELETE) {
diff_buffer_size += snprintf(NULL, 0, "0 %zu %zu ", action.line_original, action.line_changed); diff_buffer_size += snprintf(NULL, 0, "0 %zu %zu ", action.line_original, action.line_changed);
} else { // INSERT } else {
diff_buffer_size += snprintf(NULL, 0, "1 %zu %zu %s ", diff_buffer_size += snprintf(NULL, 0, "1 %zu %zu %s ",
action.line_original, action.line_changed, current_tree_file->content[action.line_changed]); action.line_original, action.line_changed, current_tree_file->content[action.line_changed]);
} }
} }
diff_buffer_size += 1; // null terminator diff_buffer_size += 1;
// Build diff content string
char* diff_content = malloc(diff_buffer_size); char* diff_content = malloc(diff_buffer_size);
if (!diff_content) { if (!diff_content) {
perror("ERROR: memory allocation failed for diff content!"); perror("ERROR: memory allocation failed for diff content!");
@ -315,7 +296,7 @@ int save_tree_diff(FileInfoBuffer* current_tree, char* root, char* branch_name,
return 0; return 0;
} }
diff_offset += (size_t)written; diff_offset += (size_t)written;
} else { // INSERT } else {
int written = snprintf(diff_content + diff_offset, remaining, "1 %zu %zu %s ", int written = snprintf(diff_content + diff_offset, remaining, "1 %zu %zu %s ",
action.line_original, action.line_changed, current_tree_file->content[action.line_changed]); action.line_original, action.line_changed, current_tree_file->content[action.line_changed]);
if (written < 0 || (size_t)written >= remaining) { if (written < 0 || (size_t)written >= remaining) {
@ -337,10 +318,8 @@ int save_tree_diff(FileInfoBuffer* current_tree, char* root, char* branch_name,
} }
} }
// Generate hash from the actual diff content
object_hash(TreeDiffObject, diff_content, hash); object_hash(TreeDiffObject, diff_content, hash);
// Create directory structure
char dir_path[PATH_MAX]; char dir_path[PATH_MAX];
char file_path[PATH_MAX]; char file_path[PATH_MAX];
snprintf(dir_path, sizeof(dir_path), "%s/.merk/objects/%.2s", root, hash); snprintf(dir_path, sizeof(dir_path), "%s/.merk/objects/%.2s", root, hash);
@ -361,7 +340,6 @@ int save_tree_diff(FileInfoBuffer* current_tree, char* root, char* branch_name,
} }
snprintf(file_path, sizeof(file_path), "%s/%s", dir_path, hash+2); snprintf(file_path, sizeof(file_path), "%s/%s", dir_path, hash+2);
// Open file for writing
FILE* fp = fopen(file_path, "wb"); FILE* fp = fopen(file_path, "wb");
if (!fp) { if (!fp) {
perror("ERROR: cannot open file for writing!"); perror("ERROR: cannot open file for writing!");
@ -379,7 +357,6 @@ int save_tree_diff(FileInfoBuffer* current_tree, char* root, char* branch_name,
return 0; return 0;
} }
// Compress the diff content
uLong originalLen = strlen(diff_content) + 1; uLong originalLen = strlen(diff_content) + 1;
uLong compressedLen = compressBound(originalLen); uLong compressedLen = compressBound(originalLen);
Bytef* compressed = malloc(compressedLen); Bytef* compressed = malloc(compressedLen);
@ -418,15 +395,12 @@ int save_tree_diff(FileInfoBuffer* current_tree, char* root, char* branch_name,
return 0; return 0;
} }
// Write length prefix and compressed data
fprintf(fp, "%lu ", (unsigned long)originalLen); fprintf(fp, "%lu ", (unsigned long)originalLen);
fwrite(compressed, 1, compressedLen, fp); fwrite(compressed, 1, compressedLen, fp);
fclose(fp); fclose(fp);
// Set file permissions
chmod(file_path, S_IRUSR | S_IRGRP | S_IROTH); chmod(file_path, S_IRUSR | S_IRGRP | S_IROTH);
// Cleanup
free(compressed); free(compressed);
free(diff_content); free(diff_content);
free(current_tree_content); free(current_tree_content);