#include "../../include/database.h" #include "../../include/package.h" #include "../../include/error.h" #include "../../include/util.h" #include #include #include #include #include #include #include #include #define LINE_MIN 36 // keep (1) + colon (1) + MD5 hash (32) + colon (1) + path (min 1) #define KEEP_INDEX 0 #define HASH_INDEX 2 #define PATH_INDEX 35 size_t __lm_database_files_get(lm_database_t *db, lm_entry_t *entry, char *path){ size_t name_size = strlen(entry->name)+20; size_t full_size = name_size + strlen(db->dir); if(NULL != path){ char files_name[name_size]; snprintf(files_name, name_size, "%s_files", entry->name); join(path, db->dir, files_name); } return full_size; } #define __lm_files_size() __lm_database_files_get(db, entry, NULL) #define __lm_files_path(p) __lm_database_files_get(db, entry, p) FILE *__lm_database_files_open(lm_database_t *db, lm_entry_t *entry, char *perms){ if(NULL == db || NULL == entry){ lm_error_set(LM_ERR_ArgNULL); return false; } char files_path[__lm_files_size()]; FILE *filesp = NULL; __lm_files_path(files_path); if(!exists(files_path, NULL)){ lm_error_set(LM_ERR_DbFilesNotFound); return NULL; } if(NULL == (filesp = fopen(files_path, perms))){ lm_error_set(LM_ERR_DbFilesOpenFail, files_path); return NULL; } return filesp; } char *__lm_database_files_line_single(FILE *filesp, char *path) { ssize_t line_len = 0; char *line = NULL; while ((line_len = getline(&line, (size_t*)&line_len, filesp)) >= LINE_MIN) { // keep : hash : path // 1 : 32 : ? // ignore empty line if(line[0] == 0) goto next; // remove newline else if (line[line_len-1] == '\n') line[line_len-1] = 0; if(eq((line + PATH_INDEX), path)) return line; next: free(line); line = NULL; line_len = 0; } return line; } char *__lm_database_files_line_all(lm_database_t *db, char *path) { size_t dirlen = strlen(db->dir); struct dirent *ent = NULL; FILE* filesp = NULL; DIR *ddir = NULL; char *ret = NULL; if(NULL == (ddir = opendir(db->dir))){ lm_error_set(LM_ERR_DbFilesDirFail, db->dir); goto end; } while(NULL != (ent = readdir(ddir))){ size_t entlen = strlen(ent->d_name); char entpath[entlen+dirlen+10]; join(entpath, db->dir, ent->d_name); if(NULL == (filesp = fopen(entpath, "r"))){ lm_error_set(LM_ERR_DbFilesOpenFail, entpath); goto end; } if(NULL == (ret = __lm_database_files_line_single(filesp, path))) goto end; } end: if(NULL != ddir) closedir(ddir); if(NULL != filesp) fclose(filesp); return ret; } ssize_t lm_database_files_count(lm_database_t *db, lm_entry_t *entry){ if(NULL == db || NULL == entry){ lm_error_set(LM_ERR_ArgNULL); return 0; } FILE *filesp = NULL; ssize_t count = 0; char c = 0; if((filesp = __lm_database_files_open(db, entry, "r")) == NULL) return 0; // error set by function while((c = fgetc(filesp)) != EOF) if(c == '\n') count ++; fclose(filesp); return count; } bool lm_database_files_contains(lm_database_t *db, lm_entry_t *entry, char *path){ if(NULL == db || NULL == entry || NULL == path){ lm_error_set(LM_ERR_ArgNULL); return false; } FILE *filesp = NULL; char *line = NULL; bool ret = false; if((filesp = __lm_database_files_open(db, entry, "r")) == NULL) return false; // error set by function if((line = __lm_database_files_line_single(filesp, path)) != NULL) ret = true; free(line); if(NULL != filesp) fclose(filesp); return ret; } bool lm_database_files_matches(lm_database_t *db, char *path, char *hash){ if(NULL == db || NULL == path || NULL == hash){ lm_error_set(LM_ERR_ArgNULL); return false; } char *line = NULL, *line_hash = NULL; bool ret = false; if(NULL == (line = __lm_database_files_line_all(db, path))) return false; line_hash = line+2; line[35] = 0; if(eq(line_hash, hash)) ret = true; free(line); return ret; } bool lm_database_files_iskeep(lm_database_t *db, char *path){ if(NULL == db || NULL == path){ lm_error_set(LM_ERR_ArgNULL); return false; } char *line = NULL; bool ret = false; if(NULL == (line = __lm_database_files_line_all(db, path))) return false; if(line[0] == '1') ret = true; free(line); return ret; } bool lm_database_files_add(lm_database_t *db, lm_entry_t *entry, char *hash, char *path){ if(NULL == db || NULL == entry || NULL == hash || NULL == path){ lm_error_set(LM_ERR_ArgNULL); return false; } char files_path[__lm_files_size()]; FILE *filesp = NULL; __lm_files_path(files_path); if(NULL == (filesp = fopen(files_path, "a"))){ lm_error_set(LM_ERR_DbFilesOpenFail, files_path); return false; } fwrite(lm_package_data_keep_contains(entry, path) ? "1:" : "0:", 1, 2, filesp); fwrite(hash, 1, strlen(hash), filesp); fwrite(":", 1, 1, filesp); fwrite(path, 1, strlen(path), filesp); fwrite("\n", 1, 1, filesp); fclose(filesp); return true; } bool lm_database_files_del(lm_database_t *db, lm_entry_t *entry){ if(NULL == db || NULL == entry){ lm_error_set(LM_ERR_ArgNULL); return false; } FILE *original = NULL, *temp = NULL; char temp_name[strlen(entry->name)+15]; char temp_path[__lm_files_size()+10]; char real_path[__lm_files_size()], *line = NULL; bool ret = false, empty = true; ssize_t line_len = 0; __lm_files_path(real_path); sprintf(temp_name, "%s_files.temp", entry->name); join(temp_path, db->dir, temp_name); if(NULL == (original = fopen(real_path, "r"))){ lm_error_set(LM_ERR_DbFilesOpenFail, real_path); goto end; } if(NULL == (temp = fopen(temp_path, "a"))){ lm_error_set(LM_ERR_DbFilesOpenFail, temp_path); goto end; } while ((line_len = getline(&line, (size_t*)&line_len, original)) >= LINE_MIN){ if(line[0] == '1'){ fwrite(line, 1, line_len, temp); empty = false; } free(line); line = NULL; line_len = 0; } ret = true; end: if(NULL != original) fclose(original); if(NULL != temp) fclose(temp); free(line); if(ret && unlink(real_path) != 0){ lm_error_set(LM_ERR_DbFilesUnlinkFail, real_path); ret = false; } if(empty || !ret){ unlink(temp_path); } else if(ret && rename(temp_path, real_path) != 0){ lm_error_set(LM_ERR_DbFilesRenameFail, real_path); ret = false; } return ret; } bool lm_database_files_del_all(lm_database_t *db, lm_entry_t *entry){ if(NULL == db || NULL == entry){ lm_error_set(LM_ERR_ArgNULL); return false; } char files_path[__lm_files_size()]; __lm_files_path(files_path); if(exists(files_path, NULL) && unlink(files_path) != 0){ lm_error_set(LM_ERR_DbFilesUnlinkFail, files_path); return false; } return true; } bool lm_database_files_next(lm_database_t *db, lm_entry_t *entry, char **path, char **hash, bool *keep){ if(NULL == db || NULL == entry || NULL == path || NULL == hash || NULL == keep){ lm_error_set(LM_ERR_ArgNULL); return false; } if(NULL == db->filesp && NULL == (db->filesp = __lm_database_files_open(db, entry, "r"))) return false; // error set by function ssize_t line_len = 0; char *line = NULL; if(NULL != *hash) free(*hash-HASH_INDEX); if((line_len = getline(&line, (size_t*)&line_len, db->filesp)) <= LINE_MIN) goto eof; if(line[line_len-1] == '\n') line[line_len-1] = 0; // replace newline with null terminator line[PATH_INDEX-1] = 0; // replace colon with null terminator *keep = line[0] == '1'; *hash = line + HASH_INDEX; *path = line + PATH_INDEX; return true; eof: fclose(db->filesp); free(line); db->filesp = NULL; *keep = false; *path = NULL; *hash = NULL; return false; } void lm_database_files_next_free(lm_database_t *db, lm_entry_t *entry, char **path, char **hash, bool *keep){ if(NULL == db || NULL == entry || NULL == path || NULL == hash || NULL == keep){ lm_error_set(LM_ERR_ArgNULL); return; } if(NULL != db->filesp) fclose(db->filesp); if(NULL != *hash) free(*hash-HASH_INDEX); db->filesp = NULL; *keep = false; *path = NULL; *hash = NULL; }