331 lines
No EOL
8.1 KiB
C
331 lines
No EOL
8.1 KiB
C
#include "file.h"
|
|
|
|
File* new_empty_file() {
|
|
File* file = calloc(1, sizeof(File));
|
|
file->content = NULL;
|
|
file->lines = 0;
|
|
|
|
return file;
|
|
}
|
|
|
|
File* new_file(const char* path) {
|
|
if (!path) return NULL;
|
|
FILE* f = fopen(path, "rb");
|
|
if (!f) return NULL;
|
|
|
|
if (fseek(f, 0, SEEK_END) != 0) { fclose(f); return NULL; }
|
|
long sz = ftell(f);
|
|
if (sz < 0) { fclose(f); return NULL; }
|
|
if (fseek(f, 0, SEEK_SET) != 0) { fclose(f); return NULL; }
|
|
|
|
size_t n = (size_t)sz;
|
|
char* buf = (char *)calloc(n + 1, 1);
|
|
if (!buf) { fclose(f); return NULL; }
|
|
|
|
size_t got = fread(buf, 1, n, f);
|
|
fclose(f);
|
|
|
|
buf[got] = '\0';
|
|
|
|
size_t count = 1;
|
|
for (size_t i = 0; i < got; ++i) if (buf[i] == '\n') count++;
|
|
if (buf[got-1] == '\n') count--;
|
|
|
|
char** lines = count ? (char**)malloc(count * sizeof *lines) : NULL;
|
|
if (count && !lines) return NULL;
|
|
|
|
size_t idx = 0;
|
|
lines[idx++] = buf;
|
|
|
|
for (size_t i = 0; i < got; ++i) {
|
|
if (buf[i] == '\n') {
|
|
if (i > 0 && buf[i-1] == '\r') buf[i-1] = '\0';
|
|
buf[i] = '\0';
|
|
if (i+1 < got) lines[idx++] = &buf[i+1];
|
|
}
|
|
}
|
|
|
|
if (got > 0 && buf[got-1] == '\r') buf[got-1] = '\0';
|
|
|
|
File* file = calloc(1, sizeof(File));
|
|
file->content = lines;
|
|
file->lines = idx;
|
|
|
|
return file;
|
|
}
|
|
|
|
File* from_string(char* string) {
|
|
if (!string) return NULL;
|
|
|
|
size_t len = strlen(string);
|
|
if (len == 0) return new_empty_file();
|
|
|
|
char* buf = malloc(len + 1);
|
|
if (!buf) return NULL;
|
|
strcpy(buf, string);
|
|
|
|
size_t count = 1;
|
|
for (size_t i = 0; i < len; ++i) {
|
|
if (buf[i] == '\n') count++;
|
|
}
|
|
if (buf[len-1] == '\n') count--;
|
|
|
|
char** lines = count ? (char**)malloc(count * sizeof *lines) : NULL;
|
|
if (count && !lines) {
|
|
free(buf);
|
|
return NULL;
|
|
}
|
|
|
|
size_t idx = 0;
|
|
lines[idx++] = buf;
|
|
for (size_t i = 0; i < len; ++i) {
|
|
if (buf[i] == '\n') {
|
|
if (i > 0 && buf[i-1] == '\r') buf[i-1] = '\0';
|
|
buf[i] = '\0';
|
|
if (i+1 < len) lines[idx++] = &buf[i+1];
|
|
}
|
|
}
|
|
if (len > 0 && buf[len-1] == '\r') buf[len-1] = '\0';
|
|
|
|
File* file = calloc(1, sizeof(File));
|
|
if (!file) {
|
|
free(lines);
|
|
free(buf);
|
|
return NULL;
|
|
}
|
|
file->content = lines;
|
|
file->lines = idx;
|
|
return file;
|
|
}
|
|
|
|
File* slice_file(File* original, uint64_t start, uint64_t end) {
|
|
if (!original || (end < start) || (end > original->lines)) return NULL;
|
|
|
|
File* slice = calloc(1, sizeof(File));
|
|
if (!slice) return NULL;
|
|
|
|
uint64_t lines = end-start;
|
|
if (!original->content || lines == 0) return NULL;
|
|
|
|
slice->content = original->content + start;
|
|
slice->lines = lines;
|
|
return slice;
|
|
}
|
|
|
|
File* copy_file(File* original) {
|
|
if (!original) return NULL;
|
|
|
|
File* copy = calloc(1, sizeof(File));
|
|
if (!copy) return NULL;
|
|
|
|
copy->lines = original->lines;
|
|
if (original->lines == 0) {
|
|
copy->content = NULL;
|
|
return copy;
|
|
}
|
|
|
|
copy->content = malloc(original->lines * sizeof(char*));
|
|
if (!copy->content) {
|
|
free(copy);
|
|
return NULL;
|
|
}
|
|
|
|
for (size_t i = 0; i < original->lines; i++) {
|
|
copy->content[i] = strdup(original->content[i]);
|
|
if (!copy->content[i]) {
|
|
for (size_t j = 0; j < i; j++) {
|
|
free(copy->content[j]);
|
|
}
|
|
free(copy->content);
|
|
free(copy);
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
return copy;
|
|
}
|
|
|
|
int insert_line(File* file, char* line, size_t idx) {
|
|
if (!file || !line || idx > file->lines) return 0;
|
|
|
|
char** new_content = realloc(file->content, (file->lines + 1) * sizeof(char*));
|
|
if (!new_content) return 0;
|
|
|
|
file->content = new_content;
|
|
|
|
for (size_t i = file->lines; i > idx; i--) {
|
|
file->content[i] = file->content[i - 1];
|
|
}
|
|
|
|
file->content[idx] = strdup(line);
|
|
file->lines++;
|
|
|
|
return 1;
|
|
}
|
|
|
|
int delete_line(File* file, size_t idx) {
|
|
if (!file || idx >= file->lines) return 0;
|
|
|
|
free(file->content[idx]);
|
|
|
|
for (size_t i = idx; i < file->lines - 1; i++) {
|
|
file->content[i] = file->content[i + 1];
|
|
}
|
|
|
|
char** new_content = realloc(file->content, (file->lines - 1) * sizeof(char*));
|
|
if (file->lines - 1 > 0 && !new_content) return 0;
|
|
|
|
file->content = new_content;
|
|
file->lines--;
|
|
|
|
return 1;
|
|
}
|
|
|
|
int snapshot_file(char* path, char* root, size_t basefile_id, char* hash) {
|
|
File* file = new_file(path);
|
|
if (!file) return 1;
|
|
|
|
char** content = file->content;
|
|
size_t lines = file->lines;
|
|
size_t total_len = 0;
|
|
for (size_t i = 0; i < lines; i++) {
|
|
total_len += strlen(content[i]);
|
|
if (i < lines - 1) {
|
|
total_len++;
|
|
}
|
|
}
|
|
total_len += 1;
|
|
|
|
char* concat_file = calloc(total_len, sizeof(char));
|
|
if (!concat_file) {
|
|
free_file(file);
|
|
return 1;
|
|
}
|
|
|
|
strcpy(concat_file, content[0]);
|
|
for (size_t i = 1; i < lines; i++) {
|
|
strcat(concat_file, "\n");
|
|
strcat(concat_file, content[i]);
|
|
}
|
|
|
|
const char* basefile_prefix = "basefile ";
|
|
size_t prefix_len = strlen(basefile_prefix);
|
|
size_t content_len = prefix_len + total_len;
|
|
|
|
char* final_content = calloc(content_len, sizeof(char));
|
|
if (!final_content) {
|
|
free(concat_file);
|
|
concat_file = NULL;
|
|
free_file(file);
|
|
return 1;
|
|
}
|
|
|
|
strcat(final_content, basefile_prefix);
|
|
strcat(final_content, concat_file);
|
|
|
|
free(concat_file);
|
|
concat_file = NULL;
|
|
|
|
char id[2 + snprintf(NULL, 0, "%d", basefile_id) + strlen(path)];
|
|
snprintf(id, sizeof(id), "%s %d", path, basefile_id);
|
|
object_hash(BaseFileObject, id, hash);
|
|
|
|
char dir_path[PATH_MAX];
|
|
char file_path[PATH_MAX];
|
|
snprintf(dir_path, sizeof(dir_path), "%s/.merk/objects/%.2s", root, hash);
|
|
mkdir(dir_path, 0755);
|
|
snprintf(file_path, sizeof(file_path), "%s/%s", dir_path, hash + 2);
|
|
|
|
FILE* fp = fopen(file_path, "wb");
|
|
if (!fp) {
|
|
perror("ERROR: cannot open path in snapshot_file!\n");
|
|
free(final_content);
|
|
final_content = NULL;
|
|
free_file(file);
|
|
return 0;
|
|
}
|
|
|
|
uLong originalLen = strlen(final_content) + 1;
|
|
uLong compressedLen = compressBound(originalLen);
|
|
Bytef* compressed = malloc(compressedLen);
|
|
if (!compressed) {
|
|
fclose(fp);
|
|
free(final_content);
|
|
final_content = NULL;
|
|
free_file(file);
|
|
return 0;
|
|
}
|
|
|
|
if (compress(compressed, &compressedLen, (const Bytef*)final_content, originalLen) != Z_OK) {
|
|
perror("ERROR: compression failed in snapshot_file!");
|
|
free(compressed);
|
|
fclose(fp);
|
|
free(final_content);
|
|
final_content = NULL;
|
|
free_file(file);
|
|
return 0;
|
|
}
|
|
|
|
fprintf(fp, "%lu ", (unsigned long)originalLen);
|
|
fwrite(compressed, 1, compressedLen, fp);
|
|
|
|
fclose(fp);
|
|
|
|
chmod(file_path, S_IRUSR | S_IRGRP | S_IROTH);
|
|
|
|
free(compressed);
|
|
free(final_content);
|
|
final_content = NULL;
|
|
free_file(file);
|
|
|
|
return 1;
|
|
}
|
|
|
|
void free_file(File* file) {
|
|
if (!file) return;
|
|
|
|
if (file->content) {
|
|
free(file->content[0]);
|
|
free(file->content);
|
|
}
|
|
|
|
free(file);
|
|
}
|
|
|
|
FileInfoBuffer* file_info_buffer_new() {
|
|
return list_new(sizeof(FileInfo));
|
|
}
|
|
|
|
int file_info_buffer_push(FileInfoBuffer* buffer, FileInfo info) {
|
|
return list_push(buffer, &info);
|
|
}
|
|
|
|
void file_info_buffer_free(List* buffer) {
|
|
if (buffer) {
|
|
free(buffer->items);
|
|
free(buffer);
|
|
}
|
|
}
|
|
|
|
int compare_file_info(const void* a, const void* b) {
|
|
const FileInfo* info1 = (const FileInfo*)a;
|
|
const FileInfo* info2 = (const FileInfo*)b;
|
|
|
|
return strcmp(info1->name, info2->name);
|
|
}
|
|
|
|
void file_info_buffer_sort(FileInfoBuffer* buffer) {
|
|
if (!buffer || buffer->len <= 1) {
|
|
return;
|
|
}
|
|
|
|
qsort(buffer->items, buffer->len, sizeof(FileInfo), compare_file_info);
|
|
}
|
|
|
|
FileInfo* file_info_buffer_search(FileInfoBuffer* buffer, const char* filename) {
|
|
if (!buffer || !filename) return NULL;
|
|
|
|
FileInfo search_key = {.mode = 0, .name = (char*)filename};
|
|
|
|
return (FileInfo*)list_binary_search(buffer, &search_key, compare_file_info);
|
|
} |