update: better package database
This commit is contained in:
@ -4,238 +4,316 @@
|
||||
#include "../../include/util.h"
|
||||
|
||||
#include <sqlite3.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <strings.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
|
||||
ssize_t lm_database_files_count(lm_database_t *db, lm_entry_t *entry){
|
||||
ssize_t count = 0;
|
||||
#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;
|
||||
}
|
||||
|
||||
if(sqlite3_prepare(db->files_db, queries[QUERY_SELECT_FILE_ALL], strlen(queries[QUERY_SELECT_FILE_ALL]), &db->files_st, NULL) != SQLITE_OK){
|
||||
pdebug(__func__, "failed to prepare statement for selecting all: %s", sqlite3_errmsg(db->files_db));
|
||||
lm_error_set(LM_ERR_DbSqlPrepareFail);
|
||||
return false;
|
||||
}
|
||||
|
||||
sqlite3_bind_text(db->files_st, 1, entry->name, strlen(entry->name), SQLITE_STATIC);
|
||||
while(NULL != (ent = readdir(ddir))){
|
||||
size_t entlen = strlen(ent->d_name);
|
||||
char entpath[entlen+dirlen+10];
|
||||
|
||||
while(sqlite3_step(db->files_st) == SQLITE_ROW)
|
||||
count++;
|
||||
end:
|
||||
if(NULL != db->files_st){
|
||||
sqlite3_finalize(db->files_st);
|
||||
db->files_st = NULL;
|
||||
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){
|
||||
char *package = NULL;
|
||||
bool ret = false;
|
||||
|
||||
if(NULL == db || NULL == path){
|
||||
if(NULL == db || NULL == entry || NULL == path){
|
||||
lm_error_set(LM_ERR_ArgNULL);
|
||||
goto end;
|
||||
}
|
||||
|
||||
if(sqlite3_prepare(db->files_db, queries[QUERY_SELECT_FILE_SINGLE], strlen(queries[QUERY_SELECT_FILE_SINGLE]), &db->files_st, NULL) != SQLITE_OK){
|
||||
pdebug(__func__, "failed to prepare statement for selecting %s: %s", path, sqlite3_errmsg(db->files_db));
|
||||
lm_error_set(LM_ERR_DbSqlPrepareFail);
|
||||
goto end;
|
||||
return false;
|
||||
}
|
||||
|
||||
sqlite3_bind_text(db->files_st, FILES_COLUMN_PATH, path, strlen(path), SQLITE_STATIC);
|
||||
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);
|
||||
|
||||
if(sqlite3_step(db->files_st) != SQLITE_ROW){
|
||||
pdebug(__func__, "failed to execute select statement for selecting %s: %s", path, sqlite3_errmsg(db->files_db));
|
||||
lm_error_set(LM_ERR_DbSqlSelectFail);
|
||||
goto end;
|
||||
}
|
||||
|
||||
package = (char*)sqlite3_column_text(db->files_st, FILES_COLUMN_ENTRY-1);
|
||||
ret = eq(package, entry->name);
|
||||
end:
|
||||
if(NULL != db->files_st){
|
||||
sqlite3_finalize(db->files_st);
|
||||
db->files_st = NULL;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool lm_database_files_matches(lm_database_t *db, char *path, char *hash){
|
||||
char *hashdb = NULL;
|
||||
bool ret = false;
|
||||
|
||||
if(NULL == db || NULL == path || NULL == hash){
|
||||
lm_error_set(LM_ERR_ArgNULL);
|
||||
goto end;
|
||||
}
|
||||
|
||||
if(sqlite3_prepare(db->files_db, queries[QUERY_SELECT_FILE_SINGLE], strlen(queries[QUERY_SELECT_FILE_SINGLE]), &db->files_st, NULL) != SQLITE_OK){
|
||||
pdebug(__func__, "failed to prepare statement for selecting %s: %s", path, sqlite3_errmsg(db->files_db));
|
||||
lm_error_set(LM_ERR_DbSqlPrepareFail);
|
||||
goto end;
|
||||
return false;
|
||||
}
|
||||
|
||||
sqlite3_bind_text(db->files_st, 1, path, strlen(path), SQLITE_STATIC);
|
||||
char *line = NULL, *line_hash = NULL;
|
||||
bool ret = false;
|
||||
|
||||
if(sqlite3_step(db->files_st) != SQLITE_ROW){
|
||||
pdebug(__func__, "failed to execute select statement for selecting %s: %s", path, sqlite3_errmsg(db->files_db));
|
||||
lm_error_set(LM_ERR_DbSqlSelectFail);
|
||||
goto end;
|
||||
}
|
||||
if(NULL == (line = __lm_database_files_line_all(db, path)))
|
||||
return false;
|
||||
|
||||
hashdb = (char*)sqlite3_column_text(db->files_st, FILES_COLUMN_HASH-1);
|
||||
ret = eq(hashdb, hash);
|
||||
line_hash = line+2;
|
||||
line[35] = 0;
|
||||
|
||||
end:
|
||||
if(NULL != db->files_st){
|
||||
sqlite3_finalize(db->files_st);
|
||||
db->files_st = NULL;
|
||||
}
|
||||
if(eq(line_hash, hash))
|
||||
ret = true;
|
||||
|
||||
free(line);
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool lm_database_files_iskeep(lm_database_t *db, char *path){
|
||||
bool ret = false;
|
||||
int iskeep = 0;
|
||||
|
||||
if(NULL == db || NULL == path){
|
||||
lm_error_set(LM_ERR_ArgNULL);
|
||||
goto end;
|
||||
return false;
|
||||
}
|
||||
|
||||
if(sqlite3_prepare(db->files_db, queries[QUERY_SELECT_FILE_SINGLE], strlen(queries[QUERY_SELECT_FILE_SINGLE]), &db->files_st, NULL) != SQLITE_OK){
|
||||
pdebug(__func__, "failed to prepare statement for selecting %s: %s", path, sqlite3_errmsg(db->files_db));
|
||||
lm_error_set(LM_ERR_DbSqlPrepareFail);
|
||||
goto end;
|
||||
}
|
||||
|
||||
sqlite3_bind_text(db->files_st, 1, path, strlen(path), SQLITE_STATIC);
|
||||
|
||||
if(!lm_database_step_all(db->files_st)){
|
||||
pdebug(__func__, "failed to execute select statement for selecting %s: %s", path, sqlite3_errmsg(db->files_db));
|
||||
lm_error_set(LM_ERR_DbSqlSelectFail);
|
||||
goto end;
|
||||
}
|
||||
|
||||
iskeep = sqlite3_column_int64(db->files_st, FILES_COLUMN_KEEP-1);
|
||||
ret = iskeep == 1;
|
||||
|
||||
end:
|
||||
if(NULL != db->files_st){
|
||||
sqlite3_finalize(db->files_st);
|
||||
db->files_st = NULL;
|
||||
}
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
bool lm_database_files_add(lm_database_t *db, lm_entry_t *entry, char *path, char *hash){
|
||||
char *line = NULL;
|
||||
bool ret = false;
|
||||
|
||||
if(NULL == db || NULL == entry || NULL == path || NULL == hash){
|
||||
lm_error_set(LM_ERR_ArgNULL);
|
||||
goto end;
|
||||
}
|
||||
if(NULL == (line = __lm_database_files_line_all(db, path)))
|
||||
return false;
|
||||
|
||||
if(sqlite3_prepare(db->files_db, queries[QUERY_INSERT_FILE_SINGLE], strlen(queries[QUERY_INSERT_FILE_SINGLE]), &db->files_st, NULL) != SQLITE_OK){
|
||||
pdebug(__func__, "failed to prepare statement for inserting %s: %s", path, sqlite3_errmsg(db->files_db));
|
||||
lm_error_set(LM_ERR_DbSqlPrepareFail);
|
||||
goto end;
|
||||
}
|
||||
if(line[0] == '1')
|
||||
ret = true;
|
||||
|
||||
sqlite3_bind_text(db->files_st, FILES_COLUMN_PATH, path, strlen(path), SQLITE_STATIC);
|
||||
sqlite3_bind_text(db->files_st, FILES_COLUMN_HASH, hash, strlen(hash), SQLITE_STATIC);
|
||||
if(lm_package_data_keep_contains(entry, path))
|
||||
sqlite3_bind_int(db->files_st, FILES_COLUMN_KEEP, 1);
|
||||
else
|
||||
sqlite3_bind_int(db->files_st, FILES_COLUMN_KEEP, 0);
|
||||
sqlite3_bind_text(db->files_st, FILES_COLUMN_ENTRY, entry->name, strlen(entry->name), SQLITE_STATIC);
|
||||
|
||||
if(!lm_database_step_all(db->files_st)){
|
||||
pdebug(__func__, "failed to execute insert statement for inserting %s: %s", entry->name, sqlite3_errmsg(db->files_db));
|
||||
lm_error_set(LM_ERR_DbSqlInsertFail);
|
||||
goto end;
|
||||
}
|
||||
|
||||
ret = true;
|
||||
end:
|
||||
if(NULL != db->files_st){
|
||||
sqlite3_finalize(db->files_st);
|
||||
db->files_st = NULL;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
bool ret = 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;
|
||||
|
||||
if(sqlite3_prepare(db->files_db, queries[QUERY_DELETE_FILE_ALL], strlen(queries[QUERY_DELETE_FILE_ALL]), &db->files_st, NULL) != SQLITE_OK){
|
||||
pdebug(__func__, "failed to prepare statement for deleting %s: %s", entry->name, sqlite3_errmsg(db->files_db));
|
||||
lm_error_set(LM_ERR_DbSqlPrepareFail);
|
||||
__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);
|
||||
goto end;
|
||||
}
|
||||
|
||||
if(NULL == (temp = fopen(temp_path, "a"))){
|
||||
lm_error_set(LM_ERR_DbFilesOpenFail);
|
||||
goto end;
|
||||
}
|
||||
|
||||
sqlite3_bind_text(db->files_st, 1, entry->name, strlen(entry->name), SQLITE_STATIC);
|
||||
while ((line_len = getline(&line, (size_t*)&line_len, original)) >= LINE_MIN){
|
||||
if(line[0] == '1'){
|
||||
fwrite(line, 1, line_len, temp);
|
||||
empty = false;
|
||||
}
|
||||
|
||||
if(!lm_database_step_all(db->files_st)){
|
||||
pdebug(__func__, "failed to execute delete statement for deleting %s: %s", entry->name, sqlite3_errmsg(db->files_db));
|
||||
lm_error_set(LM_ERR_DbSqlDeleteFail);
|
||||
goto end;
|
||||
free(line);
|
||||
line = NULL;
|
||||
line_len = 0;
|
||||
}
|
||||
|
||||
ret = true;
|
||||
end:
|
||||
if(NULL != db->files_st){
|
||||
sqlite3_finalize(db->files_st);
|
||||
db->files_st = NULL;
|
||||
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_single(lm_database_t *db, char *path){
|
||||
if(NULL == db || NULL == path){
|
||||
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);
|
||||
|
||||
bool ret = false;
|
||||
|
||||
if(sqlite3_prepare(db->files_db, queries[QUERY_DELETE_FILE_SINGLE], strlen(queries[QUERY_DELETE_FILE_SINGLE]), &db->files_st, NULL) != SQLITE_OK){
|
||||
pdebug(__func__, "failed to prepare statement for deleting %s: %s", path, sqlite3_errmsg(db->files_db));
|
||||
lm_error_set(LM_ERR_DbSqlPrepareFail);
|
||||
goto end;
|
||||
if(exists(files_path, NULL) && unlink(files_path) != 0){
|
||||
lm_error_set(LM_ERR_DbFilesUnlinkFail, files_path);
|
||||
return false;
|
||||
}
|
||||
|
||||
sqlite3_bind_text(db->files_st, 1, path, strlen(path), SQLITE_STATIC);
|
||||
|
||||
if(!lm_database_step_all(db->files_st)){
|
||||
pdebug(__func__, "failed to execute delete statement for deleting %s: %s", path, sqlite3_errmsg(db->files_db));
|
||||
lm_error_set(LM_ERR_DbSqlDeleteFail);
|
||||
goto end;
|
||||
}
|
||||
|
||||
ret = true;
|
||||
end:
|
||||
if(NULL != db->files_st){
|
||||
sqlite3_finalize(db->files_st);
|
||||
db->files_st = NULL;
|
||||
}
|
||||
return ret;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool lm_database_files_next(lm_database_t *db, lm_entry_t *entry, char **path, char **hash, bool *keep){
|
||||
@ -244,33 +322,38 @@ bool lm_database_files_next(lm_database_t *db, lm_entry_t *entry, char **path, c
|
||||
return false;
|
||||
}
|
||||
|
||||
if(NULL == db->files_st){
|
||||
if(sqlite3_prepare(db->files_db, queries[QUERY_SELECT_FILE_ALL], strlen(queries[QUERY_SELECT_FILE_ALL]), &db->files_st, NULL) != SQLITE_OK){
|
||||
pdebug(__func__, "failed to prepare statement for selecting all: %s", sqlite3_errmsg(db->files_db));
|
||||
lm_error_set(LM_ERR_DbSqlPrepareFail);
|
||||
return false;
|
||||
}
|
||||
sqlite3_bind_text(db->files_st, 1, entry->name, strlen(entry->name), SQLITE_STATIC);
|
||||
}
|
||||
if(NULL == db->filesp && NULL == (db->filesp = __lm_database_files_open(db, entry, "r")))
|
||||
return false; // error set by function
|
||||
|
||||
else if(NULL != db->files_st){
|
||||
free(*path);
|
||||
free(*hash);
|
||||
*path = NULL;
|
||||
*hash = NULL;
|
||||
*keep = false;
|
||||
}
|
||||
ssize_t line_len = 0;
|
||||
char *line = NULL;
|
||||
|
||||
if(sqlite3_step(db->files_st) != SQLITE_ROW){
|
||||
sqlite3_finalize(db->files_st);
|
||||
db->files_st = NULL;
|
||||
return false;
|
||||
}
|
||||
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;
|
||||
|
||||
*path = strdup((char*)sqlite3_column_text(db->files_st, FILES_COLUMN_PATH-1));
|
||||
*hash = strdup((char*)sqlite3_column_text(db->files_st, FILES_COLUMN_HASH-1));
|
||||
*keep = sqlite3_column_int(db->files_st, FILES_COLUMN_KEEP-1) == 1;
|
||||
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){
|
||||
@ -279,16 +362,14 @@ void lm_database_files_next_free(lm_database_t *db, lm_entry_t *entry, char **pa
|
||||
return;
|
||||
}
|
||||
|
||||
if(NULL != db->files_st){
|
||||
sqlite3_finalize(db->files_st);
|
||||
db->files_st = NULL;
|
||||
}
|
||||
|
||||
if(NULL != path)
|
||||
free(*path);
|
||||
if(NULL != db->filesp)
|
||||
fclose(db->filesp);
|
||||
|
||||
if(NULL != hash)
|
||||
free(*hash);
|
||||
if(NULL != *hash)
|
||||
free(*hash-HASH_INDEX);
|
||||
|
||||
db->filesp = NULL;
|
||||
*keep = false;
|
||||
*path = NULL;
|
||||
*hash = NULL;
|
||||
}
|
||||
|
Reference in New Issue
Block a user