file db saving (not complete)

This commit is contained in:
2025-10-30 17:51:26 +02:00
parent 76dff7dafb
commit 7c4c9e6694
10 changed files with 310 additions and 155 deletions
+151 -6
View File
@@ -1,5 +1,10 @@
#include "db.h"
#include "main.h"
#include <libpq-fe.h>
#include <netinet/in.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define UNUSED(x) (void)(x)
@@ -38,6 +43,16 @@ static int exit_query(int code) {
return code;
}
static int exit_query_2(int code) {
if (code == 0)
fprintf(stderr, "%s\n", PQerrorMessage(conn));
if (res != NULL)
PQclear(res);
return code;
}
static void processNotice(void *arg, const char *message) {
UNUSED(arg);
UNUSED(message);
@@ -56,6 +71,11 @@ int init_db_connection() {
char *user = PQuser(conn);
char *db_name = PQdb(conn);
// res = PQexec(conn, "SELECT pg_catalog.set_config('search_path', '',
// false)"); if (PQresultStatus(res) != PGRES_TUPLES_OK) {
// return terminate(2);
// }
printf("Connection established! server version: %d, user: %s, db: %s\n",
server_ver, user, db_name);
return exit_query(0);
@@ -66,19 +86,144 @@ int db_user_auth(i_auth_t *credentials, o_auth_t *response) {
paramValues[0] = credentials->name;
res = PQexecParams(conn,
"SELECT username, password, privileges "
"SELECT id, username, password, privileges "
"FROM users "
"WHERE username= $1", 1,
NULL, paramValues, NULL, NULL, 0);
"WHERE username= $1",
1, NULL, paramValues, NULL, NULL, 0);
if (PQresultStatus(res) != PGRES_TUPLES_OK && !PQntuples(res))
return exit_query(1);
const char *pass = PQgetvalue(res, 0, 1);
const char *pass = PQgetvalue(res, 0, 2);
if (!strcmp(pass, credentials->pass)) {
response->is_logged = 1;
response->privileges = PQgetvalue(res, 0, 2)[0];
response->privileges = PQgetvalue(res, 0, 3)[0];
response->uid = atoi(PQgetvalue(res, 0, 0));
return exit_query(0);
}
return exit_query(2);
}
int db_save_collision(uint32_t hash);
#define BIN 1
#define TEXT 0
int db_save_file(session *s) {
const char *paramValues[6];
int paramFormats[6];
int paramLengths[6];
int collision_id = 0;
session_file *sf = s->file;
if (sf->seed != FILE_HASH_SEED) {
// TODO: сиды обрабатываются неправильно
collision_id = db_save_collision(sf->hash);
}
int32_t uid_n = htonl(s->uid);
int64_t size_n = htonl(sf->size);
int32_t coll_n = htonl(collision_id);
int32_t perm_n = htonl(sf->permissions);
paramValues[0] = (char *)&uid_n;
paramValues[1] = sf->name;
paramValues[2] = (char *)&size_n;
paramValues[3] = (char *)&coll_n;
paramValues[4] = sf->description;
paramValues[5] = (char *)&perm_n;
paramLengths[0] = sizeof(int32_t);
paramLengths[1] = strlen(sf->name);
paramLengths[2] = sizeof(int64_t);
paramLengths[3] = sizeof(int32_t);
paramLengths[4] = strlen(sf->description);
paramLengths[5] = sizeof(int32_t);
paramFormats[0] = BIN;
paramFormats[1] = TEXT;
paramFormats[2] = BIN;
paramFormats[3] = BIN;
paramFormats[4] = TEXT;
paramFormats[5] = BIN;
res = PQexecParams(conn,
"INSERT INTO files(user_id, name, size, created_at, "
"collision_id, description, permissions) "
"VALUES ($1, $2, $3, NOW(), NULLIF($4, 0), $5, $6) "
"RETURNING id",
6, NULL, paramValues, paramLengths, paramFormats, TEXT);
if (PQresultStatus(res) != PGRES_TUPLES_OK && !PQntuples(res))
return exit_query_2(0);
int id = atoi(PQgetvalue(res, 0, 0));
clearRes();
return id;
}
int db_save_collision(uint32_t hash) {
const char *paramValues[1];
int paramLengths[1];
int paramFormats[1];
uint32_t hash_n = htonl(hash);
paramValues[0] = (char *)&hash_n;
paramLengths[0] = sizeof(uint32_t);
paramFormats[0] = BIN;
res = PQexecParams(conn,
"INSERT INTO file_collisions(hash) "
"VALUES ($1) "
"RETURNING id",
1, NULL, paramValues, paramLengths, paramFormats, TEXT);
if (PQresultStatus(res) != PGRES_TUPLES_OK && !PQntuples(res))
return exit_query_2(0);
int id = atoi(PQgetvalue(res, 0, 0));
clearRes();
return id;
}
// TODO: get file
// int db_get_file(i_get_file_db *arg) {
// }
int db_get_files(i_get_files_db *arg) {
const char *paramValues[3];
int paramLengths[3];
int paramFormats[3];
int i, j, nFields;
paramValues[0] = arg->sort_by;
paramValues[1] = (char *)&arg->limit;
paramValues[2] = (char *)&arg->offset;
paramLengths[0] = strlen(arg->sort_by);
paramLengths[1] = sizeof(arg->limit);
paramLengths[2] = sizeof(arg->offset);
paramFormats[0] = TEXT;
paramFormats[1] = BIN;
paramFormats[2] = BIN;
res = PQexecParams(conn, "SELECT * FROM files ORDER BY $1 LIMIT $2 OFFSET $3",
3, NULL, paramValues, paramLengths, paramFormats, TEXT);
nFields = PQnfields(res);
for (i = 0; i < nFields; i++)
printf("%-15s", PQfname(res, i));
printf("\n\n");
for (i = 0; i < PQntuples(res); i++) {
for (j = 0; j < nFields; j++)
printf("%-15s", PQgetvalue(res, i, j));
printf("\n");
}
clearRes();
return 0;
}
+27 -4
View File
@@ -1,12 +1,35 @@
#include "main.h"
#include <stdint.h>
/* Auth */
typedef struct {
char *name;
char *pass;
char *name;
char *pass;
} i_auth_t;
typedef struct {
char privileges;
int is_logged;
char privileges;
uint32_t uid;
} o_auth_t;
/* Get file */
typedef struct {
int id;
char *name;
int user_id;
} i_get_file_db;
typedef struct {
int user_id; // TODO: implement
char *name; // TODO: implement
int limit;
int offset;
char sort_by[12];
} 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);
+8
View File
@@ -0,0 +1,8 @@
client.o: src/client.c src/client.h src/main.h src/file_p.h src/session.h
db.o: src/db.c src/db.h src/main.h
file_p.o: src/file_p.c src/file_p.h src/main.h src/libs/murmur3/murmur3.h
main.o: src/main.c src/main.h src/file_p.h src/server.h src/db.h
server.o: src/server.c src/main.h src/session.h src/user.h
session.o: src/session.c src/session.h src/main.h src/client.h \
src/file_p.h src/user.h src/db.h
user.o: src/user.c src/main.h src/session.h src/db.h
+85 -75
View File
@@ -1,7 +1,6 @@
#include "file_p.h"
#include "libs/murmur3/murmur3.h"
#include "main.h"
#include "session.h"
#include <arpa/inet.h>
#include <errno.h>
#include <fcntl.h>
@@ -53,14 +52,14 @@ void file_list(session *sess, server_data_t *s_d) {
}
int file_send_prepare(session *sess, char *line, server_data_t *s_d) {
// TODO: рефактор в C++
sess->file = malloc(sizeof(session_file));
int sd = sess->sd;
char fname[32];
char fname[50];
sscanf(line, "%*s %*s %s", fname);
char filepath[256];
sprintf(filepath, "%s/%s", STORAGE_FOLDER, fname);
size_t fsize;
char st_message[256];
size_t fsize;
int file_d = open(filepath, O_RDONLY);
@@ -76,13 +75,13 @@ int file_send_prepare(session *sess, char *line, server_data_t *s_d) {
fsize = lseek(file_d, 0, SEEK_END);
lseek(file_d, 0, SEEK_SET);
sess->fd = file_d;
sess->fsize = fsize;
sess->f_rest = fsize;
sess->fname = malloc(strlen(fname));
sess->file->fd = file_d;
sess->file->size = fsize;
sess->file->rest = fsize;
sess->file->name = malloc(strlen(fname));
int fname_len = strlen(fname) - 1;
strncpy(sess->fname, fname, fname_len);
sess->fname[fname_len] = 0;
strncpy(sess->file->name, fname, fname_len);
sess->file->name[fname_len] = 0;
return 0;
}
@@ -111,16 +110,19 @@ int file_receive_prepare(session *sess, char *line, server_data_t *s_d) {
size_t fsize;
int perm;
sscanf(line, "file upload \"%s %zd %d", fname, &fsize, &perm);
sess->fname = malloc(sizeof(char) * strlen(fname));
sess->f_perm = (char)perm;
strncpy(sess->fname, fname, strlen(fname) - 1); // remove the last \"
sess->file = malloc(sizeof(session_file));
sess->file->name = malloc(sizeof(char) * strlen(fname));
// TODO: в конце гуляет \n и \"
sess->file->permissions = (char)perm;
sess->file->description = NULL;
strncpy(sess->file->name, fname, strlen(fname) - 1); // remove the last \"
char mes[256];
char mes_len = 0;
struct statvfs st_str;
statvfs(".", &st_str);
size_t available_space = st_str.f_bavail * st_str.f_bsize;
if (strlen(sess->fname) > st_str.f_namemax) {
if (strlen(sess->file->name) > st_str.f_namemax) {
mes_len = sprintf(mes, "file name is tool long\n");
write(sd, mes, mes_len);
sess->state = OP_WAIT;
@@ -136,81 +138,85 @@ int file_receive_prepare(session *sess, char *line, server_data_t *s_d) {
char hashed_dir_name[3];
char hashed_name[7];
int seed = FILE_HASH_SEED;
sess->file->seed = FILE_HASH_SEED;
int file_d;
for (;;) {
MurmurHash3_x86_32(sess->fname, strlen(sess->fname), FILE_HASH_SEED,
&(sess->hash));
MurmurHash3_x86_32(sess->file->name, strlen(sess->file->name), sess->file->seed,
&sess->file->hash);
extract_names_from_hash(sess->hash, hashed_dir_name, hashed_name);
extract_names_from_hash(sess->file->hash, hashed_dir_name, hashed_name);
sess->fpath = malloc(sizeof(STORAGE_FOLDER) + 2 + 9);
sprintf(sess->fpath, "%s/%s/%s", STORAGE_FOLDER, hashed_dir_name,
sess->file->path = malloc(sizeof(STORAGE_FOLDER) + 2 + 9);
sprintf(sess->file->path, "%s/%s/%s", STORAGE_FOLDER, hashed_dir_name,
hashed_name);
chdir(STORAGE_FOLDER);
if (!directory_exists(hashed_dir_name)) {
mkdir(hashed_dir_name, 0700);
}
chdir(hashed_dir_name);
chdir("../");
file_d = open(sess->fpath, O_WRONLY | O_CREAT | O_EXCL, 0666);
file_d = open(sess->file->path, O_WRONLY | O_CREAT | O_EXCL, 0666);
if (file_d == -1) {
if (errno == EEXIST) {
seed++;
free(sess->fpath);
sess->fpath = NULL;
sess->file->seed++;
free(sess->file->path);
sess->file->path = NULL;
continue;
}
mes_len = sprintf(mes, "Can't create file with such name: \"%s\"\n",
sess->fname);
sess->file->name);
write(sd, mes, mes_len);
clear_file_from_sess(sess);
sess->file = NULL;
return -1;
}
break;
}
mes_len = sprintf(mes, "accept");
sess->fd = file_d;
sess->fsize = fsize;
sess->f_rest = fsize;
sess->file->fd = file_d;
sess->file->size = fsize;
sess->file->rest = fsize;
write(sd, mes, mes_len);
return 0;
}
void clear_file_from_sess(session *sess) {
if (sess->fname != NULL) {
free(sess->fname);
sess->fname = NULL;
void clear_file_from_sess(session *s) {
session_file * sf = s->file;
if (sf->name != NULL) {
free(sf->name);
sf->name = NULL;
}
if (sess->fpath != NULL) {
free(sess->fpath);
sess->fpath = NULL;
if (sf->path != NULL) {
free(sf->path);
sf->path = NULL;
}
if (sess->fdesc != NULL) {
free(sess->fdesc);
sess->fdesc = NULL;
if (sf->description != NULL) {
free(sf->description);
sf->description = NULL;
}
if (sess->fd > -1) {
close(sess->fd);
if (sf->fd > -1) {
close(sf->fd);
}
sess->fd = -1;
sess->fsize = 0;
sess->f_rest = 0;
free(sf);
s->file = NULL;
}
void file_download_upload(session *sess, enum f_actions f_action) {
int source_d = f_action == F_DOWNLOAD ? sess->fd : sess->sd;
int dest_d = f_action == F_DOWNLOAD ? sess->sd : sess->fd;
int source_d = f_action == F_DOWNLOAD ? sess->file->fd : sess->sd;
int dest_d = f_action == F_DOWNLOAD ? sess->sd : sess->file->fd;
char buf[INBUFSIZE];
int rlen = read(source_d, buf, INBUFSIZE);
if (rlen == 0) {
if (sess->f_rest) {
if (sess->file->rest) {
if (f_action == F_DOWNLOAD) {
fprintf(stderr, "Error downloading file %s!\n", sess->fname);
fprintf(stderr, "Error downloading file %s!\n", sess->file->name);
} else {
fprintf(stderr, "Error uploading file %s!\n", sess->fname);
unlink(sess->fpath); /* remove file */
fprintf(stderr, "Error uploading file %s!\n", sess->file->name);
unlink(sess->file->path); /* remove file */
}
clear_file_from_sess(sess);
}
@@ -218,13 +224,13 @@ void file_download_upload(session *sess, enum f_actions f_action) {
return;
}
write(dest_d, buf, rlen);
sess->f_rest -= rlen;
if (!sess->f_rest) {
sess->file->rest -= rlen;
if (!sess->file->rest) {
if (f_action == F_DOWNLOAD) {
printf("File %s is downloaded from the server\n", sess->fname);
printf("File %s is downloaded from the server\n", sess->file->name);
clear_file_from_sess(sess);
} else {
printf("File %s is uploaded to the server\n", sess->fname);
printf("File %s is uploaded to the server\n", sess->file->name);
}
if (f_action == F_UPLOAD) {
sess->state = OP_UPLOAD_DESCRIPTION;
@@ -256,27 +262,31 @@ size_t get_file_size(char *dir_n, char *file_n) {
/* returns 1 if there is :END: ; 0 if opposite */
int file_upload_description(session *sess, char *line, server_data_t *s_d) {
for (;;) {
if (line != NULL && sess->fdesc == NULL) { /* first query */
sess->fdesc = malloc(strlen(line) + 1);
strcpy(sess->fdesc, line);
} else { /* subsequent queries */
if (line == NULL) {
if (sess->buf_used > 0) {
query_extract_from_buf(sess, &line);
} else {
return 0;
}
}
sess->fdesc =
realloc(sess->fdesc, strlen(sess->fdesc) + strlen(line) + 1);
strcat(sess->fdesc, line);
}
char *desc_end = strstr(line, ":END:");
if (desc_end != NULL) {
return 1;
}
}
// for (;;) {
// if (line != NULL && sess->file->description == NULL) { /* first query */
// sess->file->description = malloc(strlen(line) + 1);
// strcpy(sess->file->description, line);
// } else { /* subsequent queries */
// if (line == NULL) {
// if (sess->buf_used > 0) {
// query_extract_from_buf(sess, &line);
// } else {
// return 0;
// }
// }
// sess->file->description =
// realloc(sess->file->description, strlen(sess->file->description) + strlen(line) + 1);
// strcat(sess->file->description, line);
// }
// char *desc_end = strstr(line, ":END:");
// if (desc_end != NULL) {
// return 1;
// }
// }
char _msg[] = "This is a test \n Description!\n";
sess->file->description = malloc(sizeof(_msg) + 1);
strcpy(sess->file->description, _msg);
return 1;
}
// TODO: синхронизовать c C++
+1 -1
View File
@@ -12,5 +12,5 @@ void file_download_upload(session *sess, enum f_actions);
int file_receive_prepare(session *sess, char *line, server_data_t *s_d);
int file_upload_description(session *sess, char *line, server_data_t *s_d);
int file_save_db(session *sess, server_data_t *s_d);
void clear_file_from_sess(session *sess);
void clear_file_from_sess(session *);
#endif
+14 -9
View File
@@ -42,6 +42,18 @@ enum error_reason {
EXIT,
};
typedef struct {
char *name;
char *path;
char *description;
char permissions;
size_t size;
size_t rest;
uint32_t hash;
int seed;
int fd;
} session_file;
typedef struct session {
unsigned long from_ip;
unsigned short from_port;
@@ -51,16 +63,9 @@ typedef struct session {
enum error_reason reason;
char privileges;
char *uname;
uint32_t uid;
int sd; /* session descriptor */
int fd; /* file descriptor */
char *fname;
char *fpath;
char f_perm;
char *fdesc;
uint32_t hash;
size_t fsize;
size_t f_rest;
long int userpos; /* hint to the position in user list */
session_file *file;
} session;
typedef struct fl_t {
+5 -5
View File
@@ -4,11 +4,11 @@
#include <arpa/inet.h>
#include <errno.h>
#include <fcntl.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/select.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <unistd.h>
@@ -35,8 +35,8 @@ void server_main_loop(server_data_t *s_d) {
if (i > maxfd)
maxfd = i;
/* active uploads/downloads */
int fd = connections[i]->fd;
if (fd > -1) {
if (connections[i]->file && connections[i]->file->fd > -1) {
int fd = connections[i]->file->fd;
FD_SET(fd, &readfds);
if (fd > maxfd)
maxfd = fd;
@@ -61,8 +61,8 @@ void server_main_loop(server_data_t *s_d) {
/* download/upload file */
if (connections[i] != NULL && (connections[i]->state == OP_UPLOAD ||
connections[i]->state == OP_DOWNLOAD)) {
if (connections[i] != NULL && connections[i]->fd > -1 &&
FD_ISSET(connections[i]->fd, &readfds)) {
if (connections[i]->file && connections[i]->file->fd > -1 &&
FD_ISSET(connections[i]->file->fd, &readfds)) {
perform_session_action(connections[i], NULL, s_d);
}
} else if (connections[i] != NULL && FD_ISSET(i, &readfds)) {
+11 -54
View File
@@ -3,10 +3,12 @@
#include "file_p.h"
#include "main.h"
#include "user.h"
#include "db.h"
#include <arpa/inet.h>
#include <fcntl.h>
#include <netinet/in.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -39,14 +41,8 @@ session *make_new_session(int fd, struct sockaddr_in *from, char *wm) {
sess->state = OP_LOGIN_USR;
sess->reason = NO_REASON;
sess->uname = NULL;
sess->f_perm = 0;
sess->fdesc = NULL;
sess->sd = fd;
sess->fd = -1;
sess->fsize = 0;
sess->f_rest = 0;
sess->fname = NULL;
sess->fpath = NULL;
sess->file = NULL;
session_send_string(sess, wm);
session_send_string(sess, "login> ");
return sess;
@@ -150,61 +146,22 @@ void perform_session_action(session *sess, char *line, server_data_t *s_d) {
case OP_UPLOAD_DESCRIPTION:
res = file_upload_description(sess, line, s_d);
if (res) {
file_save_db(sess, s_d);
session_send_string(sess, "File is saved!\n");
sess->state = OP_WAIT;
if (db_save_file(sess)) {
clear_file_from_sess(sess);
session_send_string(sess, "File is saved!\n");
sess->state = OP_WAIT;
} else {
// TODO: error case
}
}
break;
}
/* } */
}
int file_save_db(session *sess, server_data_t *s_d) {
/* crate and fill the new item */
fl_t *nitem = malloc(sizeof(fl_t));
nitem->description = sess->fdesc;
nitem->name = sess->fname;
nitem->size = sess->fsize;
nitem->owner = malloc(strlen(sess->uname));
strcpy(nitem->owner, sess->uname);
nitem->permissions = sess->f_perm;
nitem->next = NULL;
/* set to NULL and clear */
sess->fname = NULL;
free(sess->fpath);
sess->fpath = NULL;
sess->fdesc = NULL;
if (sess->fd > -1) {
close(sess->fd);
}
sess->fd = -1;
sess->fsize = 0;
sess->f_rest = 0;
/* add new item to list */
s_d->fl_current->next = nitem;
s_d->fl_current = nitem;
/* save to the db file */
int fd = open(FILE_DESCRIPTIONS_NAME, O_WRONLY);
lseek(fd, 0, SEEK_END);
char permissions[4];
snprintf(permissions, 3, "%d", nitem->permissions);
unsigned int res_len = strlen(nitem->name) + 1 + strlen(nitem->owner) + 1 +
strlen(permissions) + 1 + strlen(nitem->description) +
1;
char *res_str = malloc(res_len);
res_len = sprintf(res_str, "%s\n%s\n%s\n%s", nitem->name, nitem->owner,
permissions, nitem->description);
nitem->description[strlen(nitem->description) - 6] = 0;
write(fd, res_str, res_len);
close(fd);
return 0;
}
void close_session(session *connections[], int sd) {
if (connections[sd] != NULL) {
if (connections[sd]->file) clear_file_from_sess(connections[sd]);
close(sd);
connections[sd]->sd = -1;
free(connections[sd]->uname);
+3 -1
View File
@@ -40,10 +40,12 @@ int login(session *sess, char *pass) {
o_auth_t response;
cred.name = sess->uname;
cred.pass = pass;
response.uid = 0;
db_user_auth(&cred, &response);
if (response.is_logged) {
if (response.uid) {
sess->state = OP_WAIT;
sess->privileges = (char)atoi(&response.privileges);
sess->uid = response.uid;
sprintf(tmp_string, "Welcome, %s\n", sess->uname);
session_send_string(sess, tmp_string);
return 0;