From 2bf640209911dd8ba26b432340fbd21888fdb015 Mon Sep 17 00:00:00 2001 From: Alexander Zhylin Date: Wed, 5 Nov 2025 15:20:05 +0200 Subject: [PATCH] get files in FS by their hash number --- TODO.md | 6 ++-- src/db.c | 98 +++++++++++++++++++++++++++++++++++++++++----------- src/db.h | 13 +++---- src/file_p.c | 84 +++++++++++++++++++++++++------------------- src/main.h | 7 ++-- 5 files changed, 140 insertions(+), 68 deletions(-) diff --git a/TODO.md b/TODO.md index 0b539ce..8f040ce 100644 --- a/TODO.md +++ b/TODO.md @@ -2,12 +2,12 @@ ## Features -- [ ] Database integration +- [x] Database integration - [ ] Paging in the file list -- [ ] Get files in FS by their hash +- [x] Get files in FS by their hash - [ ] Registration - [ ] Message to admin -- [ ] Advanced folder structure for the storage +- [x] Advanced folder structure in the storage - [ ] File encryption - [ ] Connection encryption diff --git a/src/db.c b/src/db.c index a31bdbe..b5dc93e 100644 --- a/src/db.c +++ b/src/db.c @@ -54,6 +54,15 @@ static int exit_query_2(int code) { return code; } +static void *exit_query_3(void *ptr) { + fprintf(stderr, "%s\n", PQerrorMessage(conn)); + + if (res != NULL) + PQclear(res); + + return ptr; +} + static void processNotice(void *arg, const char *message) { UNUSED(arg); UNUSED(message); @@ -104,20 +113,18 @@ int db_user_auth(i_auth_t *credentials, o_auth_t *response) { return exit_query(2); } -int db_save_collision(uint32_t hash); - #define BIN 1 #define TEXT 0 -int db_save_file(session *s) { +int32_t db_save_file(session *s) { const char *paramValues[6]; int paramFormats[6]; int paramLengths[6]; int collision_id = 0; - session_file *sf = s->file; + s_file_t *sf = s->file; int32_t uid_n = htonl(s->uid); - int64_t size_n = htonl(sf->size); + uint64_t size_n = htobe64(sf->size); int32_t hash_n = htonl(sf->hash); int32_t perm_n = htonl(sf->permissions); @@ -130,7 +137,7 @@ int db_save_file(session *s) { paramLengths[0] = sizeof(int32_t); paramLengths[1] = strlen(sf->name); - paramLengths[2] = sizeof(int64_t); + paramLengths[2] = sizeof(uint64_t); paramLengths[3] = sizeof(int32_t); paramLengths[4] = strlen(sf->description); paramLengths[5] = sizeof(int32_t); @@ -158,9 +165,57 @@ int db_save_file(session *s) { } // TODO: get file -// int db_get_file(i_get_file_db *arg) { +s_file_t *db_get_file(i_get_file_db *arg) { + s_file_t *sf; + char s_field[24]; + char value[64] = ""; + const char *paramValues[1]; + char query[512]; + uint32_t q_len = 0; -// } + if (arg->id) { + strcpy(s_field, "id"); + sprintf(value, "%u", arg->id); + } else if (strlen(arg->name)) { + strcpy(s_field, "name"); + strcpy(value, arg->name); + } else if (arg->user_id) { + strcpy(s_field, "user_id"); + sprintf(value, "%u", arg->user_id); + } else { + fprintf(stderr, "db_get_file: none of the args is specified!\n"); + return NULL; + } + + paramValues[0] = value; + + sprintf(query, + "SELECT files.id, user_id, name, size, description, permissions, hash " + "FROM files JOIN users ON user_id = users.id WHERE files.%s = $1%n", + s_field, &q_len); + + res = PQexecParams(conn, query, 1, NULL, paramValues, NULL, NULL, TEXT); + + if (PQresultStatus(res) != PGRES_TUPLES_OK && !PQntuples(res)) + return exit_query_3(NULL); + + sf = malloc(sizeof(s_file_t)); + sf->id = atoi(PQgetvalue(res, 0, 0)); + sf->owner_id = atoi(PQgetvalue(res, 0, 1)); + char *name = PQgetvalue(res, 0, 2); + sf->name = malloc(strlen(name) + 1); + strcpy(sf->name, name); + sf->size = atoll(PQgetvalue(res, 0, 3)); + char *description = PQgetvalue(res, 0, 4); + sf->description = malloc(strlen(description) + 1); + strcpy(sf->description, description); + sf->permissions = atoi(PQgetvalue(res, 0, 5)); + sf->hash = atoi(PQgetvalue(res, 0, 6)); + + clearRes(); + + return sf; +} uint64_t db_get_files_data(i_get_files_db *arg, fl_t **fl_start, uint64_t *full_count) { @@ -204,12 +259,12 @@ uint64_t db_get_files_data(i_get_files_db *arg, fl_t **fl_start, paramFormats[0] = BIN; paramFormats[1] = BIN; - sprintf( - query, - "SELECT user_id, name, size, description, permissions, hash, username " - "FROM files JOIN users ON user_id = users.id " - "ORDER BY files.%s %s LIMIT $1 OFFSET $2", - sort_by, sort_dir); + sprintf(query, + "SELECT files.id, user_id, name, size, description, permissions, " + "hash, username " + "FROM files JOIN users ON user_id = users.id " + "ORDER BY files.%s %s LIMIT $1 OFFSET $2", + sort_by, sort_dir); res = PQexecParams(conn, query, 2, NULL, paramValues, paramLengths, paramFormats, TEXT); @@ -220,17 +275,18 @@ uint64_t db_get_files_data(i_get_files_db *arg, fl_t **fl_start, for (i = 0; i < PQntuples(res); i++) { fl_t *l_item = malloc(sizeof(fl_t)); l_item->next = NULL; - l_item->owner_id = atoi(PQgetvalue(res, i, 0)); - char *name = PQgetvalue(res, i, 1); + l_item->id = atoi(PQgetvalue(res, i, 0)); + l_item->owner_id = atoi(PQgetvalue(res, i, 1)); + char *name = PQgetvalue(res, i, 2); l_item->name = malloc(strlen(name) + 1); strcpy(l_item->name, name); - l_item->size = atoll(PQgetvalue(res, i, 2)); - char *description = PQgetvalue(res, i, 3); + l_item->size = atoll(PQgetvalue(res, i, 3)); + char *description = PQgetvalue(res, i, 4); l_item->description = malloc(strlen(description) + 1); strcpy(l_item->description, description); - l_item->permissions = atoi(PQgetvalue(res, i, 4)); - l_item->hash = atoi(PQgetvalue(res, i, 5)); - char *owner = PQgetvalue(res, i, 6); + l_item->permissions = atoi(PQgetvalue(res, i, 5)); + l_item->hash = atoi(PQgetvalue(res, i, 6)); + char *owner = PQgetvalue(res, i, 7); l_item->owner = malloc(strlen(owner) + 1); strcpy(l_item->owner, owner); diff --git a/src/db.h b/src/db.h index 319592d..19ba890 100644 --- a/src/db.h +++ b/src/db.h @@ -18,9 +18,9 @@ typedef struct { /* Get file */ typedef struct { - int id; - char *name; - int user_id; + uint32_t id; + uint32_t user_id; + char name[64]; } i_get_file_db; enum sort_direction { ASC, DESC }; @@ -35,9 +35,10 @@ typedef struct { enum sort_direction sort_direction; } i_get_files_db; -int init_db_connection(); -int db_user_auth(i_auth_t *credentials, o_auth_t *response); -int db_save_file(session *s); +int32_t init_db_connection(); +int32_t db_save_file(session *s); +int32_t db_user_auth(i_auth_t *credentials, o_auth_t *response); +s_file_t *db_get_file(i_get_file_db *arg); uint64_t db_get_files_data(i_get_files_db *arg, fl_t **fl_start, uint64_t *full_count); #endif \ No newline at end of file diff --git a/src/file_p.c b/src/file_p.c index 4737772..dc70344 100644 --- a/src/file_p.c +++ b/src/file_p.c @@ -100,43 +100,10 @@ void file_list(session *sess, server_data_t *s_d) { } while ((fl_current = fl_current->next) != NULL); sess->fl_start = fl_start; - write(sess->sd, list_end, sizeof(list_end)); + write(sess->sd, list_end, sizeof(list_end)-1); write(sess->sd, page_info, strlen(page_info)); } -int file_send_prepare(session *sess, char *line, server_data_t *s_d) { - sess->file = malloc(sizeof(session_file)); - int sd = sess->sd; - char fname[50]; - sscanf(line, "%*s %*s %s", fname); - char filepath[256]; - sprintf(filepath, "%s/%s", STORAGE_FOLDER, fname); - char st_message[256]; - size_t fsize; - - int file_d = open(filepath, O_RDONLY); - - if (file_d == -1) { - fprintf(stdout, "ERROR: %d\n", errno); - char err_mes[256]; - int mlen; - mlen = sprintf(err_mes, "Can't open file named \"%s\"\n", fname); - write(sd, err_mes, mlen); - return -1; - } - - fsize = lseek(file_d, 0, SEEK_END); - lseek(file_d, 0, SEEK_SET); - - sess->file->size = fsize; - sess->file->rest = fsize; - sess->file->name = malloc(strlen(fname)); - int fname_len = strlen(fname) - 1; - strncpy(sess->file->name, fname, fname_len); - sess->file->name[fname_len] = 0; - return 0; -} - int directory_exists(const char *path) { struct stat info; @@ -156,13 +123,58 @@ void extract_names_from_hash(uint32_t file_hash, char *dirname, char *fname) { fname[6] = 0; } +int32_t file_send_prepare(session *sess, char *line, server_data_t *s_d) { + int32_t sd = sess->sd; + i_get_file_db args = {.id = 0, .user_id = 0, .name = ""}; + char st_message[256]; + int32_t file_d; + size_t fsize; + char hashed_dir_name[3]; + char hashed_name[7]; + char err_mes[256]; + uint32_t mlen; + + sscanf(line, "%*s %*s %s", args.name); + sess->file = db_get_file(&args); + + if (sess->file == NULL) + return -1; + + extract_names_from_hash(sess->file->hash, hashed_dir_name, hashed_name); + sess->file->path = malloc(sizeof(STORAGE_FOLDER) + 2 + 9); + sprintf(sess->file->path, "%s/%s/%s", STORAGE_FOLDER, hashed_dir_name, + hashed_name); + + file_d = open(sess->file->path, O_RDONLY); + + if (file_d == -1) { + fprintf(stdout, "ERROR: %d\n", errno); + mlen = sprintf(err_mes, "Can't open file with id = %u\n", sess->file->id); + write(sd, err_mes, mlen); + return -2; + } + + fsize = lseek(file_d, 0, SEEK_END); + lseek(file_d, 0, SEEK_SET); + + if (sess->file->size != fsize) { + mlen = sprintf(err_mes, "File with id = %u exists, but seems to be damaged\n", sess->file->id); + write(sd, err_mes, mlen); + return -3; + } + + sess->file->rest = fsize; + sess->fd = file_d; + return 0; +} + int file_receive_prepare(session *sess, char *line, server_data_t *s_d) { int sd = sess->sd; char fname[64]; size_t fsize; int perm; sscanf(line, "file upload \"%s %zd %d", fname, &fsize, &perm); - sess->file = malloc(sizeof(session_file)); + sess->file = malloc(sizeof(s_file_t)); sess->file->name = malloc(sizeof(char) * strlen(fname)); sess->file->path = malloc(sizeof(STORAGE_FOLDER) + 2 + 9); sess->file->permissions = (char)perm; @@ -235,7 +247,7 @@ int file_receive_prepare(session *sess, char *line, server_data_t *s_d) { } void clear_file_from_sess(session *s) { - session_file *sf = s->file; + s_file_t *sf = s->file; if (sf->name != NULL) { free(sf->name); sf->name = NULL; diff --git a/src/main.h b/src/main.h index 81c9d3d..fef7452 100644 --- a/src/main.h +++ b/src/main.h @@ -49,7 +49,9 @@ typedef struct { size_t size; size_t rest; uint32_t hash; -} session_file; + uint32_t id; + uint32_t owner_id; +} s_file_t; typedef struct fl_t { char *name; @@ -59,6 +61,7 @@ typedef struct fl_t { uint32_t owner_id; uint32_t hash; size_t size; + uint32_t id; struct fl_t *next; } fl_t; @@ -74,7 +77,7 @@ typedef struct session { uint32_t uid; int fd; int sd; /* session descriptor */ - session_file *file; + s_file_t *file; fl_t *fl_start; fl_t *fl_current; } session;