File hashing (not finished)

This commit is contained in:
2025-10-27 17:33:39 +02:00
parent 24c4e75943
commit 76dff7dafb
9 changed files with 421 additions and 86 deletions
-2
View File
@@ -5,10 +5,8 @@ mkdir wdir
mkdir wdir/storage
touch wdir/file_descriptions
touch wdir/welcome
touch wdir/userlist
echo "Welcome to the BBS Setup!" >> wdir/welcome
echo "user 1234 15" >> wdir/userlist
# Test file
touch wdir/storage/testfile.txt
+11 -56
View File
@@ -45,7 +45,7 @@ static void processNotice(void *arg, const char *message) {
// do nothing
}
int init_connection() {
int init_db_connection() {
// TODO: get from external configs
conn = PQconnectdb("user=postgres password=dobro host=127.0.0.1 dbname=bbs");
@@ -56,20 +56,20 @@ int init_connection() {
char *user = PQuser(conn);
char *db_name = PQdb(conn);
printf("Connection established! server version: %d, user: %s, db: %s\n", server_ver,
user, db_name);
printf("Connection established! server version: %d, user: %s, db: %s\n",
server_ver, user, db_name);
return exit_query(0);
}
int db_user_auth(i_auth_t *credentials, o_auth_t *response) {
char query[Q_LEN];
response->is_logged = 0;
sprintf(query,
"SELECT username, password, privileges "
"FROM users "
"WHERE username= '%s'",
credentials->name);
res = PQexec(conn, query);
const char *paramValues[1];
paramValues[0] = credentials->name;
res = PQexecParams(conn,
"SELECT username, password, privileges "
"FROM users "
"WHERE username= $1", 1,
NULL, paramValues, NULL, NULL, 0);
if (PQresultStatus(res) != PGRES_TUPLES_OK && !PQntuples(res))
return exit_query(1);
@@ -82,48 +82,3 @@ int db_user_auth(i_auth_t *credentials, o_auth_t *response) {
}
return exit_query(2);
}
/*s
int f_main() {
int libpq_ver = PQlibVersion();
printf("Version of libpq: %d\n", libpq_ver);
conn = PQconnectdb("user=postgres password=dobro host=127.0.0.1 dbname=bbs");
if (PQstatus(conn) != CONNECTION_OK)
terminate(1);
PQsetNoticeProcessor(conn, processNotice, NULL);
int server_ver = PQserverVersion(conn);
char *user = PQuser(conn);
char *db_name = PQdb(conn);
printf("Server version: %d\n", server_ver);
printf("User: %s\n", user);
printf("Database name: %s\n", db_name);
res = PQexec(conn, "SELECT id, username, privileges, email "
"FROM users");
if (PQresultStatus(res) != PGRES_TUPLES_OK)
terminate(1);
int nrows = PQntuples(res);
for (int i = 0; i < nrows; i++) {
char *id = PQgetvalue(res, i, 0);
char *name = PQgetvalue(res, i, 1);
char *privileges = PQgetvalue(res, i, 2);
char *email = PQgetvalue(res, i, 3);
printf("Id: %s, Name: %s, Privileges: %d, Email: %s, \n", id, name,
privileges[0], email);
}
printf("Total: %d rows\n", nrows);
clearRes();
terminate(0);
return 0;
}
*/
+1 -1
View File
@@ -8,5 +8,5 @@ typedef struct {
int is_logged;
} o_auth_t;
int init_connection();
int init_db_connection();
int db_user_auth(i_auth_t *credentials, o_auth_t *response);
-8
View File
@@ -1,8 +0,0 @@
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
file_p.o: src/file_p.c src/file_p.h src/main.h src/session.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
user.o: src/user.c src/main.h src/session.h src/db.h
+60 -17
View File
@@ -1,4 +1,5 @@
#include "file_p.h"
#include "libs/murmur3/murmur3.h"
#include "main.h"
#include "session.h"
#include <arpa/inet.h>
@@ -12,6 +13,7 @@
#include <sys/mman.h>
#include <sys/select.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/statvfs.h>
#include <sys/syslog.h>
#include <sys/types.h>
@@ -44,7 +46,7 @@ void file_list(session *sess, server_data_t *s_d) {
full_str[i] = '\a';
}
}
write(sess->sd, full_str, f_len-1); // -1 : do not include \0
write(sess->sd, full_str, f_len - 1); // -1 : do not include \0
free(full_str);
} while ((current = current->next) != NULL);
write(sess->sd, list_end, sizeof(list_end));
@@ -84,6 +86,25 @@ int file_send_prepare(session *sess, char *line, server_data_t *s_d) {
return 0;
}
int directory_exists(const char *path) {
struct stat info;
if (stat(path, &info) != 0) {
// stat() failed, probably doesn't exist
return 0;
}
return S_ISDIR(info.st_mode); // true if it's a directory
}
void extract_names_from_hash(uint32_t file_hash, char *dirname, char *fname) {
char hashed_full_name[9];
sprintf(hashed_full_name, "%08x", file_hash);
strncpy(dirname, hashed_full_name, 2);
strncpy(fname, hashed_full_name + 2, 6);
dirname[2] = 0;
fname[6] = 0;
}
int file_receive_prepare(session *sess, char *line, server_data_t *s_d) {
int sd = sess->sd;
char fname[64];
@@ -93,8 +114,6 @@ int file_receive_prepare(session *sess, char *line, server_data_t *s_d) {
sess->fname = malloc(sizeof(char) * strlen(fname));
sess->f_perm = (char)perm;
strncpy(sess->fname, fname, strlen(fname) - 1); // remove the last \"
sess->fpath = malloc(strlen(sess->fname) + sizeof(STORAGE_FOLDER) + 2);
sprintf(sess->fpath, "%s/%s", STORAGE_FOLDER, sess->fname);
char mes[256];
char mes_len = 0;
@@ -114,19 +133,43 @@ int file_receive_prepare(session *sess, char *line, server_data_t *s_d) {
clear_file_from_sess(sess);
return -1;
}
int file_d = open(sess->fpath, O_WRONLY | O_CREAT | O_EXCL, 0666);
if (file_d == -1) {
if (errno == EEXIST) {
mes_len =
sprintf(mes, "File with name \"%s\" is already exist\n", sess->fname);
char hashed_dir_name[3];
char hashed_name[7];
int seed = FILE_HASH_SEED;
int file_d;
for (;;) {
MurmurHash3_x86_32(sess->fname, strlen(sess->fname), FILE_HASH_SEED,
&(sess->hash));
extract_names_from_hash(sess->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,
hashed_name);
if (!directory_exists(hashed_dir_name)) {
mkdir(hashed_dir_name, 0700);
}
chdir(hashed_dir_name);
file_d = open(sess->fpath, O_WRONLY | O_CREAT | O_EXCL, 0666);
if (file_d == -1) {
if (errno == EEXIST) {
seed++;
free(sess->fpath);
sess->fpath = NULL;
continue;
}
mes_len = sprintf(mes, "Can't create file with such name: \"%s\"\n",
sess->fname);
write(sd, mes, mes_len);
clear_file_from_sess(sess);
return -1;
}
mes_len =
sprintf(mes, "Can't create file with such name: \"%s\"\n", sess->fname);
write(sd, mes, mes_len);
clear_file_from_sess(sess);
return -1;
}
mes_len = sprintf(mes, "accept");
sess->fd = file_d;
sess->fsize = fsize;
@@ -257,19 +300,19 @@ void get_files_descriptions(server_data_t *s_d) {
/* file name */
sscanf(buf_pos, "%s\n", tmp);
buf_pos += strlen(tmp)+1;
buf_pos += strlen(tmp) + 1;
fl_item->name = malloc(sizeof(char) * (strlen(tmp) + 1));
strcpy(fl_item->name,tmp);
strcpy(fl_item->name, tmp);
/* file owner */
sscanf(buf_pos, "%s\n", tmp);
buf_pos += strlen(tmp)+1;
buf_pos += strlen(tmp) + 1;
fl_item->owner = malloc(sizeof(char) * (strlen(tmp) + 1));
strcpy(fl_item->owner, tmp);
/* file permissions */
sscanf(buf_pos, "%s\n", tmp);
buf_pos += strlen(tmp)+1;
buf_pos += strlen(tmp) + 1;
fl_item->permissions = atoi(tmp);
/* file size */
+314
View File
@@ -0,0 +1,314 @@
//-----------------------------------------------------------------------------
// MurmurHash3 was written by Austin Appleby, and is placed in the public
// domain. The author hereby disclaims copyright to this source code.
// Note - The x86 and x64 versions do _not_ produce the same results, as the
// algorithms are optimized for their respective platforms. You can still
// compile and run any of them on any platform, but your performance with the
// non-native version will be less than optimal.
#include "murmur3.h"
//-----------------------------------------------------------------------------
// Platform-specific functions and macros
#ifdef __GNUC__
#define FORCE_INLINE __attribute__((always_inline)) inline
#else
#define FORCE_INLINE inline
#endif
static FORCE_INLINE uint32_t rotl32 ( uint32_t x, int8_t r )
{
return (x << r) | (x >> (32 - r));
}
static FORCE_INLINE uint64_t rotl64 ( uint64_t x, int8_t r )
{
return (x << r) | (x >> (64 - r));
}
#define ROTL32(x,y) rotl32(x,y)
#define ROTL64(x,y) rotl64(x,y)
#define BIG_CONSTANT(x) (x##LLU)
//-----------------------------------------------------------------------------
// Block read - if your platform needs to do endian-swapping or can only
// handle aligned reads, do the conversion here
#define getblock(p, i) (p[i])
//-----------------------------------------------------------------------------
// Finalization mix - force all bits of a hash block to avalanche
static FORCE_INLINE uint32_t fmix32 ( uint32_t h )
{
h ^= h >> 16;
h *= 0x85ebca6b;
h ^= h >> 13;
h *= 0xc2b2ae35;
h ^= h >> 16;
return h;
}
//----------
static FORCE_INLINE uint64_t fmix64 ( uint64_t k )
{
k ^= k >> 33;
k *= BIG_CONSTANT(0xff51afd7ed558ccd);
k ^= k >> 33;
k *= BIG_CONSTANT(0xc4ceb9fe1a85ec53);
k ^= k >> 33;
return k;
}
//-----------------------------------------------------------------------------
void MurmurHash3_x86_32 ( const void * key, int len,
uint32_t seed, void * out )
{
const uint8_t * data = (const uint8_t*)key;
const int nblocks = len / 4;
int i;
uint32_t h1 = seed;
uint32_t c1 = 0xcc9e2d51;
uint32_t c2 = 0x1b873593;
//----------
// body
const uint32_t * blocks = (const uint32_t *)(data + nblocks*4);
for(i = -nblocks; i; i++)
{
uint32_t k1 = getblock(blocks,i);
k1 *= c1;
k1 = ROTL32(k1,15);
k1 *= c2;
h1 ^= k1;
h1 = ROTL32(h1,13);
h1 = h1*5+0xe6546b64;
}
//----------
// tail
const uint8_t * tail = (const uint8_t*)(data + nblocks*4);
uint32_t k1 = 0;
switch(len & 3)
{
case 3: k1 ^= tail[2] << 16;
case 2: k1 ^= tail[1] << 8;
case 1: k1 ^= tail[0];
k1 *= c1; k1 = ROTL32(k1,15); k1 *= c2; h1 ^= k1;
};
//----------
// finalization
h1 ^= len;
h1 = fmix32(h1);
*(uint32_t*)out = h1;
}
//-----------------------------------------------------------------------------
void MurmurHash3_x86_128 ( const void * key, const int len,
uint32_t seed, void * out )
{
const uint8_t * data = (const uint8_t*)key;
const int nblocks = len / 16;
int i;
uint32_t h1 = seed;
uint32_t h2 = seed;
uint32_t h3 = seed;
uint32_t h4 = seed;
uint32_t c1 = 0x239b961b;
uint32_t c2 = 0xab0e9789;
uint32_t c3 = 0x38b34ae5;
uint32_t c4 = 0xa1e38b93;
//----------
// body
const uint32_t * blocks = (const uint32_t *)(data + nblocks*16);
for(i = -nblocks; i; i++)
{
uint32_t k1 = getblock(blocks,i*4+0);
uint32_t k2 = getblock(blocks,i*4+1);
uint32_t k3 = getblock(blocks,i*4+2);
uint32_t k4 = getblock(blocks,i*4+3);
k1 *= c1; k1 = ROTL32(k1,15); k1 *= c2; h1 ^= k1;
h1 = ROTL32(h1,19); h1 += h2; h1 = h1*5+0x561ccd1b;
k2 *= c2; k2 = ROTL32(k2,16); k2 *= c3; h2 ^= k2;
h2 = ROTL32(h2,17); h2 += h3; h2 = h2*5+0x0bcaa747;
k3 *= c3; k3 = ROTL32(k3,17); k3 *= c4; h3 ^= k3;
h3 = ROTL32(h3,15); h3 += h4; h3 = h3*5+0x96cd1c35;
k4 *= c4; k4 = ROTL32(k4,18); k4 *= c1; h4 ^= k4;
h4 = ROTL32(h4,13); h4 += h1; h4 = h4*5+0x32ac3b17;
}
//----------
// tail
const uint8_t * tail = (const uint8_t*)(data + nblocks*16);
uint32_t k1 = 0;
uint32_t k2 = 0;
uint32_t k3 = 0;
uint32_t k4 = 0;
switch(len & 15)
{
case 15: k4 ^= tail[14] << 16;
case 14: k4 ^= tail[13] << 8;
case 13: k4 ^= tail[12] << 0;
k4 *= c4; k4 = ROTL32(k4,18); k4 *= c1; h4 ^= k4;
case 12: k3 ^= tail[11] << 24;
case 11: k3 ^= tail[10] << 16;
case 10: k3 ^= tail[ 9] << 8;
case 9: k3 ^= tail[ 8] << 0;
k3 *= c3; k3 = ROTL32(k3,17); k3 *= c4; h3 ^= k3;
case 8: k2 ^= tail[ 7] << 24;
case 7: k2 ^= tail[ 6] << 16;
case 6: k2 ^= tail[ 5] << 8;
case 5: k2 ^= tail[ 4] << 0;
k2 *= c2; k2 = ROTL32(k2,16); k2 *= c3; h2 ^= k2;
case 4: k1 ^= tail[ 3] << 24;
case 3: k1 ^= tail[ 2] << 16;
case 2: k1 ^= tail[ 1] << 8;
case 1: k1 ^= tail[ 0] << 0;
k1 *= c1; k1 = ROTL32(k1,15); k1 *= c2; h1 ^= k1;
};
//----------
// finalization
h1 ^= len; h2 ^= len; h3 ^= len; h4 ^= len;
h1 += h2; h1 += h3; h1 += h4;
h2 += h1; h3 += h1; h4 += h1;
h1 = fmix32(h1);
h2 = fmix32(h2);
h3 = fmix32(h3);
h4 = fmix32(h4);
h1 += h2; h1 += h3; h1 += h4;
h2 += h1; h3 += h1; h4 += h1;
((uint32_t*)out)[0] = h1;
((uint32_t*)out)[1] = h2;
((uint32_t*)out)[2] = h3;
((uint32_t*)out)[3] = h4;
}
//-----------------------------------------------------------------------------
void MurmurHash3_x64_128 ( const void * key, const int len,
const uint32_t seed, void * out )
{
const uint8_t * data = (const uint8_t*)key;
const int nblocks = len / 16;
int i;
uint64_t h1 = seed;
uint64_t h2 = seed;
uint64_t c1 = BIG_CONSTANT(0x87c37b91114253d5);
uint64_t c2 = BIG_CONSTANT(0x4cf5ad432745937f);
//----------
// body
const uint64_t * blocks = (const uint64_t *)(data);
for(i = 0; i < nblocks; i++)
{
uint64_t k1 = getblock(blocks,i*2+0);
uint64_t k2 = getblock(blocks,i*2+1);
k1 *= c1; k1 = ROTL64(k1,31); k1 *= c2; h1 ^= k1;
h1 = ROTL64(h1,27); h1 += h2; h1 = h1*5+0x52dce729;
k2 *= c2; k2 = ROTL64(k2,33); k2 *= c1; h2 ^= k2;
h2 = ROTL64(h2,31); h2 += h1; h2 = h2*5+0x38495ab5;
}
//----------
// tail
const uint8_t * tail = (const uint8_t*)(data + nblocks*16);
uint64_t k1 = 0;
uint64_t k2 = 0;
switch(len & 15)
{
case 15: k2 ^= (uint64_t)(tail[14]) << 48;
case 14: k2 ^= (uint64_t)(tail[13]) << 40;
case 13: k2 ^= (uint64_t)(tail[12]) << 32;
case 12: k2 ^= (uint64_t)(tail[11]) << 24;
case 11: k2 ^= (uint64_t)(tail[10]) << 16;
case 10: k2 ^= (uint64_t)(tail[ 9]) << 8;
case 9: k2 ^= (uint64_t)(tail[ 8]) << 0;
k2 *= c2; k2 = ROTL64(k2,33); k2 *= c1; h2 ^= k2;
case 8: k1 ^= (uint64_t)(tail[ 7]) << 56;
case 7: k1 ^= (uint64_t)(tail[ 6]) << 48;
case 6: k1 ^= (uint64_t)(tail[ 5]) << 40;
case 5: k1 ^= (uint64_t)(tail[ 4]) << 32;
case 4: k1 ^= (uint64_t)(tail[ 3]) << 24;
case 3: k1 ^= (uint64_t)(tail[ 2]) << 16;
case 2: k1 ^= (uint64_t)(tail[ 1]) << 8;
case 1: k1 ^= (uint64_t)(tail[ 0]) << 0;
k1 *= c1; k1 = ROTL64(k1,31); k1 *= c2; h1 ^= k1;
};
//----------
// finalization
h1 ^= len; h2 ^= len;
h1 += h2;
h2 += h1;
h1 = fmix64(h1);
h2 = fmix64(h2);
h1 += h2;
h2 += h1;
((uint64_t*)out)[0] = h1;
((uint64_t*)out)[1] = h2;
}
//-----------------------------------------------------------------------------
+29
View File
@@ -0,0 +1,29 @@
//-----------------------------------------------------------------------------
// MurmurHash3 was written by Austin Appleby, and is placed in the
// public domain. The author hereby disclaims copyright to this source
// code.
#ifndef _MURMURHASH3_H_
#define _MURMURHASH3_H_
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
//-----------------------------------------------------------------------------
void MurmurHash3_x86_32 (const void *key, int len, uint32_t seed, void *out);
void MurmurHash3_x86_128(const void *key, int len, uint32_t seed, void *out);
void MurmurHash3_x64_128(const void *key, int len, uint32_t seed, void *out);
//-----------------------------------------------------------------------------
#ifdef __cplusplus
}
#endif
#endif // _MURMURHASH3_H_
+1 -1
View File
@@ -10,7 +10,7 @@ int main(int argc, char *argv[]) {
server_data.welcome_message = get_welcome_mes();
server_data.fl_start = NULL;
server_data.fl_current = NULL;
init_connection();
init_db_connection();
get_files_descriptions(&server_data);
server_data.ls = start_server();
server_main_loop(&server_data);
+4
View File
@@ -1,6 +1,7 @@
#ifndef MAIN_H
#define MAIN_H
#include <stddef.h>
#include <stdint.h>
#define PORT 2000
#define MAX_CONNECTIONS 1024
#define INBUFSIZE 1024
@@ -56,6 +57,7 @@ typedef struct session {
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 */
@@ -77,4 +79,6 @@ typedef struct server_data_t {
int ls;
} server_data_t;
#define FILE_HASH_SEED 898
#endif