Files
progettoso/lib/threadpool/apiFile.c

1032 lines
28 KiB
C
Raw Normal View History

2022-04-11 19:19:17 +02:00
#define _POSIX_C_SOURCE 200809L
#include <string.h>
#include <errno.h>
2022-04-11 19:19:17 +02:00
#include <inttypes.h>
2022-04-08 21:32:52 +02:00
#include "conn.h"
#include "apiFile.h"
#include "fileQueue.h"
#include "taglialegna.h"
2022-03-31 22:26:44 +02:00
#define MAXLENMESS 512
2022-04-09 22:43:26 +02:00
#define LOGBUFSIZE 2048
2022-03-31 22:26:44 +02:00
#define MEOK "20" /* OK */
// #define ME "21" /* not used */
// #define ME "22" /* not used */
#define MEFP "25" /* file purged */
2022-03-31 22:26:44 +02:00
// #define ME "40" /* not used */
// #define ME "41" /* not used */
#define MESD "42" /* shutting down */
#define MENT "45" /* requested file action not taken */
2022-03-31 22:26:44 +02:00
#define MESY "50" /* syntax error */
// #define ME "51" /* not used */
// #define ME "52" /* not used */
#define MESE "55" /* server error */
2022-03-31 22:26:44 +02:00
2022-04-04 18:58:40 +02:00
// -----------------------------------------------------------------------------
// helper functions
2022-04-04 18:58:40 +02:00
/* send to the client the message m and then errno */
2022-04-08 21:32:52 +02:00
void serror(char *m, long fd_c, taglia_t *taglia, char *mlog) {
if(!m) {
errno = EINVAL;
m = MESY;
}
2022-04-27 21:18:25 +02:00
if(writen(fd_c, m, strnlen(m, MAXLENMESS)) < 0) {
perror("serror: writen");
2022-04-08 21:32:52 +02:00
goto _serror_cleanup;
}
if(writen(fd_c, &errno, sizeof(errno)) < 0) {
perror("serror: writen");
2022-04-08 21:32:52 +02:00
goto _serror_cleanup;
}
if(taglia_write(taglia, mlog) < 0)
goto _serror_cleanup;
return;
_serror_cleanup:
return;
}
/* send to the client the message m */
2022-04-04 18:58:40 +02:00
void sendMessage(char *m, long fd_c, taglia_t *taglia, char *mlog) {
if(!m) {
m = MEOK;
}
2022-04-24 01:36:43 +02:00
if(writen(fd_c, m, strnlen(m, MAXLENMESS)) < 0) {
perror("sendMessage: writen");
2022-04-04 18:58:40 +02:00
goto _sendM_cleanup;
}
if(taglia_write(taglia, mlog) < 0)
goto _sendM_cleanup;
return;
_sendM_cleanup:
return;
}
/* send to the client the file f */
2022-04-10 20:51:43 +02:00
int sendFile(fileT *f, long fd_c, taglia_t *taglia) {
if(!f || !taglia) {
errno = EINVAL;
return -1;
}
/* send filepath dimension, then filepath */
2022-04-10 20:51:43 +02:00
int64_t filepathLength = (int64_t) strnlen(f->filepath, MAXLENMESS)+1;
if (writen(fd_c, &filepathLength, sizeof(filepathLength)) < 0) {
perror("sendFile: writen");
2022-04-10 20:51:43 +02:00
return -1;
}
if (writen(fd_c, f->filepath, (size_t) filepathLength) < 0) {
perror("sendFile: writen");
2022-04-10 20:51:43 +02:00
return -1;
}
/* send file dimension, then file */
2022-04-10 20:51:43 +02:00
int64_t validLength = (int64_t) f->valid;
if (writen(fd_c, &validLength, sizeof(validLength)) < 0) {
perror("sendFile: writen");
2022-04-10 20:51:43 +02:00
return -1;
}
if(validLength != 0) { /* if file has length 0 dont write */
2022-04-29 01:26:31 +02:00
if (writen(fd_c, f->data, validLength) < 0) {
perror("sendFile: writen");
2022-04-29 01:26:31 +02:00
return -1;
}
2022-04-10 20:51:43 +02:00
}
char tmp_log[LOGBUFSIZE];
int n = 0;
size_t m = sizeof(tmp_log);
n += snprintf(tmp_log+n, m-n, "Inviato file \"%s\", di dimensione %"PRId64" Bytes al client %ld .\n",
f->filepath,
validLength,
fd_c);
2022-04-10 20:51:43 +02:00
if(taglia_write(taglia, tmp_log) < 0) {
perror("sendFile: taglia_write");
2022-04-10 20:51:43 +02:00
return 1;
}
return 0;
}
/* send to the client the message m then the file f */
2022-04-04 18:58:40 +02:00
void sendMessageFile(char *m, fileT *f, long fd_c, taglia_t *taglia, char *mlog) {
if(!f) {
errno = EINVAL;
char errmlog[2*LOGBUFSIZE] =
"Errore negli argomenti alla funzione sendMessagefile (fileT == NULL). "
"Messaggio originale:\n\t";
2022-04-08 21:32:52 +02:00
strncat(errmlog, mlog, sizeof(errmlog)-strlen(errmlog)-1);
2022-04-04 18:58:40 +02:00
goto _sendMF_cleanup;
serror(MESY, fd_c, taglia, errmlog);
2022-04-04 18:58:40 +02:00
}
if(!m) {
2022-04-08 21:32:52 +02:00
m = MEFP;
2022-04-04 18:58:40 +02:00
}
2022-04-27 21:18:25 +02:00
if(writen(fd_c, m, strnlen(m, MAXLENMESS)) < 0) {
perror("sendMessageFile: writen");
2022-04-04 18:58:40 +02:00
goto _sendMF_cleanup;
}
2022-04-27 21:18:25 +02:00
int64_t *n = calloc(1, sizeof(*n));
2022-04-29 01:26:31 +02:00
if(!n) {
perror("sendMessageFile: calloc");
2022-04-27 21:18:25 +02:00
goto _sendMF_cleanup;
}
*n = 1;
if(writen(fd_c, n, sizeof(int64_t)) < 0) {
perror("sendMessageFile: writen");
2022-04-22 21:59:40 +02:00
goto _sendMF_cleanup;
}
2022-04-27 21:18:25 +02:00
free(n);
2022-04-04 18:58:40 +02:00
if(sendFile(f, fd_c, taglia) < 0) {
perror("sendMessageFile: sendFile");
2022-04-04 18:58:40 +02:00
goto _sendMF_cleanup;
}
2022-04-10 20:51:43 +02:00
if(taglia_write(taglia, mlog) < 0) {
perror("sendMessageFile: taglia_write");
2022-04-04 18:58:40 +02:00
goto _sendMF_cleanup;
2022-04-10 20:51:43 +02:00
}
2022-04-04 18:58:40 +02:00
return;
_sendMF_cleanup:
return;
}
/* send to the client the message m then n files */
2022-04-29 21:04:45 +02:00
void sendMessageFileN(char *m, fileT **f, int64_t n, long fd_c, taglia_t *taglia, char *mlog) {
2022-04-04 18:58:40 +02:00
if(!f) {
errno = EINVAL;
char errmlog[2*LOGBUFSIZE] =
"Errore negli argomenti alla funzione sendMessagefile (fileT == NULL)."
" Messaggio originale:\n\t";
2022-04-08 21:32:52 +02:00
strncat(errmlog, mlog, sizeof(errmlog)-strlen(errmlog)-1);
serror(MESY, fd_c, taglia, errmlog);
2022-04-04 18:58:40 +02:00
goto _sendMFN_cleanup;
}
if(!m) {
2022-04-08 21:32:52 +02:00
m = MEFP;
2022-04-04 18:58:40 +02:00
}
2022-04-27 21:18:25 +02:00
if(writen(fd_c, m, strnlen(m, MAXLENMESS)) < 0) {
perror("sendMessageFileN: writen");
2022-04-08 21:32:52 +02:00
goto _sendMFN_cleanup;
2022-04-04 18:58:40 +02:00
}
2022-04-22 21:59:40 +02:00
if(write(fd_c, &n, sizeof(n)) < 0) {
perror("sendMessageFileN: writen");
2022-04-22 21:59:40 +02:00
goto _sendMFN_cleanup;
}
2022-04-04 18:58:40 +02:00
for(int i=0; i<n && (f[i]!=NULL); ++i) {
if(sendFile(f[i], fd_c, taglia) < 0) {
perror("sendMessageFileN: sendFile");
2022-04-08 21:32:52 +02:00
goto _sendMFN_cleanup;
2022-04-04 18:58:40 +02:00
}
}
if(taglia_write(taglia, mlog) < 0)
2022-04-08 21:32:52 +02:00
goto _sendMFN_cleanup;
2022-04-04 18:58:40 +02:00
return;
_sendMFN_cleanup:
return;
}
2022-03-31 22:26:44 +02:00
2022-04-10 20:51:43 +02:00
// -----------------------------------------------------------------------------
2022-03-31 22:26:44 +02:00
void openFile(char *filepath, int flags, queueT *q, long fd_c, taglia_t *taglia) {
// messaggio da scrivere sul logfile
2022-04-09 22:43:26 +02:00
char tmp_buf[LOGBUFSIZE];
2022-03-31 22:26:44 +02:00
int n = 0;
size_t m = sizeof(tmp_buf);
if(!filepath || !q || !taglia) {
n += snprintf(tmp_buf+n, m-n, "Client %ld ha richiesto una openFile (flags = %x) sul file \"%s\" e' terminata con errore\n",
fd_c,
flags,
filepath);
2022-03-31 22:26:44 +02:00
errno = EINVAL;
serror(MESY, fd_c, taglia, tmp_buf);
return;
}
int found = searchFile(q, filepath); /* search the file in the queue */
int create = (flags & C_CREATE)?1:0; /* also %2 */
int lock = (flags & C_LOCK)?1:0; /* also >>1%2 */
fileT *removed = NULL; /* file that was removed */
2022-03-31 22:26:44 +02:00
if(found && create) { /* file found but want to create new file */
n += snprintf(tmp_buf+n, m-n, "Client %ld ha richiesto una openFile (flags = %x) sul file \"%s\" ma il file esiste già\n",
fd_c,
flags,
filepath);
2022-03-31 22:26:44 +02:00
errno = EEXIST;
serror(MENT, fd_c, taglia, tmp_buf);
return;
}
if(!found && !create) { /* file not found but expected */
n += snprintf(tmp_buf+n, m-n, "Client %ld ha richiesto una openFile (flags = %x) sul file \"%s\" ma il file non esiste\n",
fd_c,
flags,
filepath);
2022-03-31 22:26:44 +02:00
errno = ENOENT;
serror(MENT, fd_c, taglia, tmp_buf);
return;
}
if(found && !create) { /* file found */
2022-04-08 21:32:52 +02:00
if(openFileInQueue(q, filepath, lock, fd_c) == -1) {
n += snprintf(tmp_buf+n, m-n, "Client %ld ha richiesto una openFile (flags = %x) sul file \"%s\" e' terminato con errore del server\n",
fd_c,
flags,
filepath);
perror("openFile: openFileInQueue");
2022-03-31 22:26:44 +02:00
serror(MESE, fd_c, taglia, tmp_buf);
return;
}
n += snprintf(tmp_buf+n, m-n, "Client %ld ha richiesto una openFile (flags = %x) sul file \"%s\" e' terminata con successo\n",
fd_c,
flags,
filepath);
2022-03-31 22:26:44 +02:00
sendMessage(MEOK, fd_c, taglia, tmp_buf);
return;
}
if(!found && create) { /* not found and creating new file */
if(getLen(q) == q->maxLen) { /* capacity miss */
2022-03-31 22:26:44 +02:00
removed = dequeue(q);
if(!removed) {
n += snprintf(tmp_buf+n, m-n, "Client %ld ha richiesto una openFile (flags = %x) sul file \"%s\" e' terminato con errore\n",
fd_c,
flags,
filepath);
perror("openFile: dequeue");
2022-03-31 22:26:44 +02:00
serror(MESE, fd_c, taglia, tmp_buf);
return;
}
/* create new file */
fileT *f = createFileT(filepath, lock, fd_c, 1);
2022-03-31 22:26:44 +02:00
if(!f) {
n += snprintf(tmp_buf+n, m-n, "Client %ld ha richiesto una openFile (flags = %x) sul file \"%s\" e' terminato con errore del server\n",
fd_c,
flags,
filepath);
perror("openFile: createFileT");
2022-04-08 21:32:52 +02:00
serror(MESE, fd_c, taglia, tmp_buf);
2022-03-31 22:26:44 +02:00
return;
}
if(enqueue(q, f) != 0) {
n += snprintf(tmp_buf+n, m-n, "Client %ld ha richiesto una openFile (flags = %x) sul file \"%s\" e' terminato con errore del server\n",
fd_c,
flags,
filepath);
perror("openFile: enqueue");
2022-04-08 21:32:52 +02:00
serror(MESE, fd_c, taglia, tmp_buf);
2022-03-31 22:26:44 +02:00
return;
}
taglia_update(taglia, q, 1); /* removed only one file */
n += snprintf(tmp_buf+n, m-n, "Client %ld ha richiesto una openFile (flags = %x) sul file \"%s\" ha causato una capacity miss. File espulso \"%s\"\n",
fd_c,
flags,
filepath,
removed->filepath);
2022-03-31 22:26:44 +02:00
sendMessageFile(MEFP, removed, fd_c, taglia, tmp_buf);
2022-04-29 01:26:31 +02:00
destroyFile(removed);
2022-03-31 22:26:44 +02:00
return;
}
/* no capacity miss */
2022-03-31 22:26:44 +02:00
fileT *f = createFileT(filepath, lock, fd_c, 1);
if(!f) {
n += snprintf(tmp_buf+n, m-n, "Client %ld ha richiesto una openFile (flags = %x) sul file \"%s\" e' terminato con errore del server\n",
fd_c,
flags,
filepath);
perror("openFile: createFileT");
2022-04-08 21:32:52 +02:00
serror(MESE, fd_c, taglia, tmp_buf);
2022-03-31 22:26:44 +02:00
return;
}
if(enqueue(q, f) != 0) {
n += snprintf(tmp_buf+n, m-n, "Client %ld ha richiesto una openFile (flags = %x) sul file \"%s\" e' terminato con errore del server\n",
fd_c,
flags,
filepath);
perror("openFile: enqueue");
2022-04-08 21:32:52 +02:00
serror(MESE, fd_c, taglia, tmp_buf);
2022-03-31 22:26:44 +02:00
return;
}
/* added a file, the number of files changed so update the log */
2022-03-31 22:26:44 +02:00
taglia_update(taglia, q, 0);
n += snprintf(tmp_buf+n, m-n, "Client %ld ha richiesto una openFile (flags = %x) sul file \"%s\" e' terminato con successo\n",
fd_c,
flags,
filepath);
2022-03-31 22:26:44 +02:00
sendMessage(MEOK, fd_c, taglia, tmp_buf);
return;
}
2022-04-09 01:11:46 +02:00
/* unreachable code */
2022-04-09 01:11:46 +02:00
return;
2022-03-31 22:26:44 +02:00
}
2022-04-04 18:58:40 +02:00
void readFile(char *filepath, queueT *q, long fd_c, taglia_t *taglia) {
/* message to write to the logfile */
2022-04-09 22:43:26 +02:00
char tmp_buf[LOGBUFSIZE];
2022-04-04 18:58:40 +02:00
int n = 0;
size_t m = sizeof(tmp_buf);
if(!filepath || !q || !taglia) {
n += snprintf(tmp_buf+n, m-n, "Client %ld ha richiesto una readFile sul file \"%s\" e' terminata con errore del server\n",
fd_c,
filepath);
2022-04-04 18:58:40 +02:00
errno = EINVAL;
serror(MESY, fd_c, taglia, tmp_buf);
return;
2022-03-31 22:26:44 +02:00
}
2022-04-04 18:58:40 +02:00
fileT *f = NULL;
f = find(q, filepath);
if(!f) {
n += snprintf(tmp_buf+n, m-n, "Client %ld ha richiesto una readFile sul file \"%s\" ma il file non esiste\n",
fd_c,
filepath);
2022-04-04 18:58:40 +02:00
errno = ENOENT;
serror(MESE, fd_c, taglia, tmp_buf);
return;
}
2022-03-31 22:26:44 +02:00
if(f->open == 0) { /* file not already open */
2022-05-18 02:24:43 +02:00
n += snprintf(tmp_buf+n, m-n, "Client %ld ha richiesto una readFile sul file \"%s\" e' terminata con errore, file non precedentemente aperto\n",
fd_c,
filepath);
2022-04-04 18:58:40 +02:00
errno = EPERM;
serror(MENT, fd_c, taglia, tmp_buf);
destroyFile(f); /* f is a copy so we need to cleen up */
2022-04-04 18:58:40 +02:00
return;
}
2022-03-31 22:26:44 +02:00
n += snprintf(tmp_buf+n, m-n, "Client %ld ha richiesto una readFile sul file \"%s\" di dimensione = %ld e' terminata con successo\n",
fd_c,
filepath,
f->valid);
2022-04-04 18:58:40 +02:00
sendMessageFile(MEOK, f, fd_c, taglia, tmp_buf);
destroyFile(f); /* f is a copy so we need to cleen up */
2022-03-31 22:26:44 +02:00
return;
}
2022-04-04 18:58:40 +02:00
void readNFiles(int num, queueT *q, long fd_c, taglia_t *taglia) {
/* message to write to the logfile */
2022-04-09 22:43:26 +02:00
char tmp_buf[LOGBUFSIZE];
int n = 0;
size_t m = sizeof(tmp_buf);
if(!q || !taglia) {
n += snprintf(tmp_buf+n, m-n, "Client %ld ha richiesto una readNFile (n = %d) e' terminata con errore\n",
fd_c,
num);
2022-04-09 22:43:26 +02:00
errno = EINVAL;
serror(MESY, fd_c, taglia, tmp_buf);
return;
}
int oldNum = num;
2022-04-29 21:04:45 +02:00
int64_t ntosend = (num<=0 || num>getLen(q))? getLen(q) : num;
fileT **toSend = NULL;
2022-04-09 22:43:26 +02:00
n += snprintf(tmp_buf+n, m-n, "Client %ld ha richiesto una readNFile (n = %d) e' terminata con successo. File inviati:\n",
fd_c,
num);
/* extract n files, but dont actually dequeue them */
toSend = request(q, (int) ntosend);
if(toSend == NULL) {
n = 0;
n += snprintf(tmp_buf+n, m-n, "Client %ld ha richiesto una readNFiles (n = %d) e' terminato con errore del server\n",
fd_c,
oldNum);
perror("readNFiles: request");
serror(MESE, fd_c, taglia, tmp_buf);
return;
}
2022-05-03 23:14:39 +02:00
size_t tot = 0;
2022-04-29 21:04:45 +02:00
for(int i=0;i<ntosend;++i) {
if(toSend[i] == NULL) {
2022-04-09 22:43:26 +02:00
n = 0;
n += snprintf(tmp_buf+n, m-n, "Client %ld ha richiesto una readNFiles (n = %d) e' terminato con errore del server (file estratti [%d] inferiori a file richiesti [%ld])\n",
fd_c,
oldNum,
i,
ntosend);
perror("readNFiles: request");
2022-04-09 22:43:26 +02:00
serror(MESE, fd_c, taglia, tmp_buf);
return;
}
2022-05-03 23:14:39 +02:00
tot += toSend[i]->valid;
n += snprintf(tmp_buf+n, m-n, "\t%d) \"%s\" dim = %ld\n",
i,
toSend[i]->filepath,
toSend[i]->valid);
2022-04-09 22:43:26 +02:00
}
n += snprintf(tmp_buf+n, m-n, "readNFile dimensione totale = %ld\n",
tot);
2022-04-09 22:43:26 +02:00
2022-04-29 21:04:45 +02:00
sendMessageFileN(MEOK, toSend, ntosend, fd_c, taglia, tmp_buf);
2022-04-09 22:43:26 +02:00
free(toSend);
2022-04-04 22:31:14 +02:00
return;
}
2022-04-04 18:58:40 +02:00
void writeFile(char *filepath, size_t size, queueT *q, long fd_c, taglia_t *taglia, int append) {
/* message to write to the logfile */
2022-04-09 22:43:26 +02:00
char tmp_buf[LOGBUFSIZE];
2022-04-04 18:58:40 +02:00
int n = 0;
size_t m = sizeof(tmp_buf);
if(!filepath || !q || !taglia) {
n += snprintf(tmp_buf+n, m-n, "Client %ld ha richiesto una writeFile (append = %x) sul file \"%s\" e' terminata con errore\n",
fd_c,
append,
filepath);
2022-03-31 22:26:44 +02:00
errno = EINVAL;
2022-04-04 18:58:40 +02:00
serror(MESY, fd_c, taglia, tmp_buf);
return;
2022-03-31 22:26:44 +02:00
}
2022-04-27 21:18:25 +02:00
/* search the file */
2022-04-04 18:58:40 +02:00
fileT *f = NULL;
f = find(q, filepath);
2022-04-27 21:18:25 +02:00
if(!f) { /* file is not present */
n += snprintf(tmp_buf+n, m-n, "Client %ld ha richiesto una writeFile (append = %x) sul file \"%s\", dimensione = %ld, e' terminata con errore, file non trovato\n",
fd_c,
append,
filepath,
size);
2022-04-04 18:58:40 +02:00
errno = ENOENT;
serror(MENT, fd_c, taglia, tmp_buf);
destroyFile(f);
return;
2022-03-31 22:26:44 +02:00
}
2022-03-18 20:49:28 +01:00
/* file not open || no append and no lock || not the owner of the lock */
2022-04-24 01:36:43 +02:00
if(!f->open || (!append && !f->O_LOCK) || (f->O_LOCK && f->owner != fd_c)) {
n += snprintf(tmp_buf+n, m-n, "Client %ld ha richiesto una writeFile (append = %x) sul file \"%s\", dimensione = %ld, e' terminata con errore, non proprietario del file\n",
fd_c,
append,
filepath,
size);
2022-04-04 18:58:40 +02:00
errno = EPERM;
serror(MENT, fd_c, taglia, tmp_buf);
destroyFile(f);
return;
2022-03-31 22:26:44 +02:00
}
long trueSizeAdded = 0; /* we may have alredy some space allocated */
2022-04-04 18:58:40 +02:00
if(append) {
trueSizeAdded = size - f->size + f->valid;
} else {
trueSizeAdded = (size>f->size)? size-f->size : 0;
}
destroyFile(f); /* not needed anymore */
2022-03-18 20:49:28 +01:00
if(trueSizeAdded > q->maxSize) { /* removing all files would not be enought */
n += snprintf(tmp_buf+n, m-n, "Client %ld ha richiesto una writeFile (append = %x) sul file \"%s\", dimensione = %ld ma il file e' piu' grande della dimensione massima\n",
fd_c,
append,
filepath,
size);
2022-05-03 23:14:39 +02:00
errno = EFBIG;
serror(MENT, fd_c, taglia, tmp_buf);
return;
}
2022-04-24 01:36:43 +02:00
if(trueSizeAdded + getSize(q) > q->maxSize) {
/* writing would be more than capacity */
fileT **removed = NULL; /* array that may (worst case) hold all files to
* be sent to the client */
2022-04-04 18:58:40 +02:00
removed = dequeueN(q, filepath, trueSizeAdded);
if(!removed) { /* internal error */
n += snprintf(tmp_buf+n, m-n, "Client %ld ha richiesto una writeFile (append = %x) sul file \"%s\", dimensione = %ld, e' terminata con errore del server\n",
fd_c,
append,
filepath,
size);
2022-04-04 18:58:40 +02:00
errno = ENOENT;
serror(MESY, fd_c, taglia, tmp_buf);
return;
}
int ln = 0;
fileT *tmp = removed[ln];
n += snprintf(tmp_buf+n, m-n, "Client %ld ha richiesto una writeFile (append = %x) sul file \"%s\", dimensione = %ld, e' terminata con successo, allocando %ld B in memoria. Ha causato una capacity miss e ha fatto espellere i seguenti file:",
fd_c,
append,
filepath,
size,
trueSizeAdded);
2022-04-04 18:58:40 +02:00
while(tmp!=NULL) {
n += snprintf(tmp_buf+n, m-n, " \"%s\"", tmp->filepath);
++ln;
tmp=removed[ln];
}
n += snprintf(tmp_buf+n, m-n, "\n");
taglia_update(taglia, q, ln);
2022-03-18 20:49:28 +01:00
2022-04-04 18:58:40 +02:00
sendMessageFileN(MEFP, removed, ln, fd_c, taglia, tmp_buf);
for(int i=0;i<ln && (removed[i]!=NULL);++i) {
destroyFile(removed[i]);
}
free(removed);
2022-03-18 20:49:28 +01:00
/* now we can get the actual file */
2022-04-04 18:58:40 +02:00
void *content = NULL;
2022-04-24 01:36:43 +02:00
content = calloc(size, sizeof(char));
2022-04-04 18:58:40 +02:00
if(!content) {
perror("writeFile: calloc");
2022-04-04 18:58:40 +02:00
return;
}
if((readn(fd_c, content, size)) == -1) {
perror("writeFile: readn");
2022-04-04 18:58:40 +02:00
return;
}
2022-03-18 20:49:28 +01:00
2022-04-24 01:36:43 +02:00
n = 0;
2022-04-04 18:58:40 +02:00
if(append) {
if(appendFileInQueue(q, filepath, content, size, fd_c) == -1) {
perror("writeFile: appendFileInQueue");
n += snprintf(tmp_buf+n, m-n, "Client %ld ha richiesto una writeFile (append = %x) sul file \"%s\", dimensione = %ld, errore del server\n",
fd_c,
append,
filepath,
size);
2022-04-24 01:36:43 +02:00
serror(MESY, fd_c, taglia, tmp_buf);
2022-04-08 21:32:52 +02:00
free(content);
2022-04-04 18:58:40 +02:00
return;
}
} else {
if(writeFileInQueue(q, filepath, content, size, fd_c) == -1) {
perror("writeFile: writeFileInQueue");
n += snprintf(tmp_buf+n, m-n, "Client %ld ha richiesto una writeFile (append = %x) sul file \"%s\", dimensione = %ld, errore del server\n",
fd_c,
append,
filepath,
size);
2022-04-24 01:36:43 +02:00
serror(MESY, fd_c, taglia, tmp_buf);
2022-04-08 21:32:52 +02:00
free(content);
2022-04-04 18:58:40 +02:00
return;
}
}
2022-03-18 20:49:28 +01:00
n += snprintf(tmp_buf+n, m-n, "Client %ld ha richiesto una writeFile (append = %x) sul file \"%s\", dimensione = %ld, e' terminata con successo\n",
fd_c,
append,
filepath,
size);
2022-04-24 01:36:43 +02:00
sendMessage(MEOK, fd_c, taglia, tmp_buf);
2022-04-04 18:58:40 +02:00
taglia_update(taglia, q, 0);
2022-04-08 21:32:52 +02:00
free(content);
2022-04-04 18:58:40 +02:00
return;
}
/* no dequeue */
n += snprintf(tmp_buf+n, m-n, "Client %ld ha richiesto una writeFile (append = %x) sul file \"%s\", dimensione = %ld, accettata la richiesta.\n",
fd_c,
append,
filepath,
size);
2022-04-24 01:36:43 +02:00
sendMessage(MEOK, fd_c, taglia, tmp_buf);
/* no reason to remove the file yet */
2022-04-04 18:58:40 +02:00
void *content = NULL;
2022-04-24 01:36:43 +02:00
content = calloc(size, sizeof(char));
2022-04-04 18:58:40 +02:00
if(!content) {
perror("writeFile: calloc");
2022-04-04 18:58:40 +02:00
return;
}
if(readn(fd_c, content, size) == -1) {
perror("writeFile: readn");
2022-04-04 18:58:40 +02:00
return;
}
2022-03-18 20:49:28 +01:00
2022-04-24 01:36:43 +02:00
n = 0;
2022-03-18 20:49:28 +01:00
2022-04-04 18:58:40 +02:00
if(append) {
if(appendFileInQueue(q, filepath, content, size, fd_c) == -1) {
n += snprintf(tmp_buf+n, m-n, "Client %ld ha richiesto una writeFile (append = %x) sul file \"%s\", dimensione = %ld, errore del server\n",
fd_c,
append,
filepath,
size);
2022-04-24 01:36:43 +02:00
serror(MESY, fd_c, taglia, tmp_buf);
perror("writeFile: appendFileInQueue");
2022-04-08 21:32:52 +02:00
free(content);
2022-04-04 18:58:40 +02:00
return;
}
} else {
if(writeFileInQueue(q, filepath, content, size, fd_c) == -1) {
n += snprintf(tmp_buf+n, m-n, "Client %ld ha richiesto una writeFile (append = %x) sul file \"%s\", dimensione = %ld, errore del server\n",
fd_c,
append,
filepath,
size);
2022-04-24 01:36:43 +02:00
serror(MESY, fd_c, taglia, tmp_buf);
perror("writeFile: writeFileInQueue");
2022-04-08 21:32:52 +02:00
free(content);
2022-04-04 18:58:40 +02:00
return;
}
}
n += snprintf(tmp_buf+n, m-n, "Client %ld ha richiesto una writeFile (append = %x) sul file \"%s\", dimensione = %ld, e' terminata con successo\n",
fd_c,
append,
filepath,
size);
2022-04-24 01:36:43 +02:00
sendMessage(MEOK, fd_c, taglia, tmp_buf);
2022-03-18 20:49:28 +01:00
2022-04-04 18:58:40 +02:00
taglia_update(taglia, q, 0);
2022-03-18 20:49:28 +01:00
2022-04-08 21:32:52 +02:00
free(content);
2022-04-04 18:58:40 +02:00
return;
}
2022-03-18 20:49:28 +01:00
2022-04-08 21:32:52 +02:00
void lockFile(char *filepath, queueT *q, long fd_c, taglia_t *taglia, pthread_mutex_t *lock, waiting_t **waiting) {
/* message to write to the logfile */
2022-04-09 22:43:26 +02:00
char tmp_buf[LOGBUFSIZE];
2022-04-09 01:11:46 +02:00
int n = 0;
size_t m = sizeof(tmp_buf);
if(!filepath || !q || !taglia || !lock || !waiting) {
n += snprintf(tmp_buf+n, m-n, "Client %ld ha richiesto una lockFile sul file \"%s\" e' terminata con errore.\n",
fd_c,
filepath);
2022-04-09 01:11:46 +02:00
errno = EINVAL;
serror(MESY, fd_c, taglia, tmp_buf);
return;
}
/* search the file to lock */
2022-04-09 01:11:46 +02:00
fileT *f = NULL;
f = find(q, filepath);
if(!f) { /* file is not present */
n += snprintf(tmp_buf+n, m-n, "Client %ld ha richiesto una lockFile sul file \"%s\" ma risulta assente.\n",
fd_c,
filepath);
2022-04-09 01:11:46 +02:00
errno = ENOENT;
serror(MENT, fd_c, taglia, tmp_buf);
destroyFile(f);
return;
}
/* try to lock */
2022-04-09 01:11:46 +02:00
if (openFileInQueue(q, filepath, 1, fd_c) == -1) {
/* unable to aquire the lock, wait to be released by inserting into
* the waiting queue */
2022-04-09 01:11:46 +02:00
if (errno == EPERM) {
if (pthread_mutex_lock(lock) == -1) { /* begin ME */
perror("lockFile: pthread_mutex_lock");
2022-04-09 01:11:46 +02:00
destroyFile(f);
return;
}
if (addWaiting(waiting, filepath, fd_c) == -1) {
perror("lockFile: addWaiting");
2022-04-09 01:11:46 +02:00
pthread_mutex_unlock(lock);
destroyFile(f);
return;
}
if (pthread_mutex_unlock(lock) == -1) { /* end ME */
perror("lockFile: pthread_mutex_unlock");
2022-04-09 01:11:46 +02:00
}
destroyFile(f);
return;
}
n += snprintf(tmp_buf+n, m-n, "Client %ld ha richiesto una lockFile sul file \"%s\" e' terminata con errore.\n",
fd_c,
filepath);
2022-04-09 01:11:46 +02:00
errno = ENOLCK;
serror(MESE, fd_c, taglia, tmp_buf);
destroyFile(f);
return;
}
n += snprintf(tmp_buf+n, m-n, "Client %ld ha richiesto una lockFile sul file \"%s\" e' terminata con successo\n",
fd_c,
filepath);
2022-04-09 01:11:46 +02:00
sendMessage(MEOK, fd_c, taglia, tmp_buf);
destroyFile(f);
2022-04-04 22:31:14 +02:00
return;
}
2022-03-18 20:49:28 +01:00
2022-04-08 21:32:52 +02:00
void unlockFile(char *filepath, queueT *q, long fd_c, taglia_t *taglia, pthread_mutex_t *lock, waiting_t **waiting) {
/* message to write to the logfile */
2022-04-10 20:51:43 +02:00
char tmp_buf[LOGBUFSIZE];
int n = 0;
size_t m = sizeof(tmp_buf);
if(!filepath || !q || !taglia || !lock || !waiting) {
n += snprintf(tmp_buf+n, m-n, "Client %ld ha richiesto una unlockFile sul file \"%s\" e' terminata con errore.\n",
fd_c,
filepath);
2022-04-10 20:51:43 +02:00
errno = EINVAL;
serror(MESY, fd_c, taglia, tmp_buf);
return;
}
/* search the file */
if(!searchFile(q, filepath)) { /* file does not exist */
n += snprintf(tmp_buf+n, m-n, "Client %ld ha richiesto una unlockFile sul file \"%s\" ma risulta assente.\n",
fd_c,
filepath);
2022-04-10 20:51:43 +02:00
errno = ENOENT;
serror(MENT, fd_c, taglia, tmp_buf);
return;
}
if (unlockFileInQueue(q, filepath, fd_c) != 0) {
n += snprintf(tmp_buf+n, m-n, "Client %ld ha richiesto una unlockFile sul file \"%s\" ma non è stata rilasciata la lock.\n",
fd_c,
filepath);
2022-04-10 20:51:43 +02:00
serror(MENT, fd_c, taglia, tmp_buf);
return;
}
n += snprintf(tmp_buf+n, m-n, "Client %ld ha richiesto una unlockFile sul file \"%s\" e' terminata con successo\n",
fd_c,
filepath);
2022-04-10 20:51:43 +02:00
sendMessage(MEOK, fd_c, taglia, tmp_buf);
/* signal another waiting client that a lock has been released */
if (pthread_mutex_lock(lock) == -1) { /* begin ME */
perror("unlockFile: pthread_mutex_lock");
2022-04-10 20:51:43 +02:00
return;
}
int waked = -1;
waked = removeFirstWaiting(waiting, filepath);
if (waked != -1) {
/* we lock the file for the other client */
2022-04-10 20:51:43 +02:00
lockFile(filepath, q, waked, taglia, lock, waiting);
}
if (pthread_mutex_unlock(lock) == -1) { /* end ME */
perror("unlockFile: pthread_mutex_unlock");
2022-04-10 20:51:43 +02:00
return;
}
2022-04-04 22:31:14 +02:00
return;
}
2022-03-18 20:49:28 +01:00
2022-03-31 22:26:44 +02:00
2022-04-08 21:32:52 +02:00
void closeFile(char *filepath, queueT *q, long fd_c, taglia_t *taglia, pthread_mutex_t *lock, waiting_t **waiting) {
/* message to write to the logfile */
2022-04-10 20:51:43 +02:00
char tmp_buf[LOGBUFSIZE];
int n = 0;
size_t m = sizeof(tmp_buf);
if(!filepath || !q || !taglia || !lock || !waiting) {
n += snprintf(tmp_buf+n, m-n, "Client %ld ha richiesto una closeFile sul file \"%s\" e' terminata con errore.\n",
fd_c,
filepath);
2022-04-10 20:51:43 +02:00
errno = EINVAL;
serror(MESY, fd_c, taglia, tmp_buf);
return;
}
if(!searchFile(q, filepath)) { /* file does not exist */
n += snprintf(tmp_buf+n, m-n, "Client %ld ha richiesto una closeFile sul file \"%s\" ma risulta assente.\n",
fd_c,
filepath);
2022-04-10 20:51:43 +02:00
errno = ENOENT;
serror(MENT, fd_c, taglia, tmp_buf);
return;
}
if (closeFileInQueue(q, filepath, fd_c) == -1) {
n += snprintf(tmp_buf+n, m-n, "Client %ld ha richiesto una closeFile sul file \"%s\" e' terminata con errore.\n",
fd_c,
filepath);
2022-04-10 20:51:43 +02:00
serror(MENT, fd_c, taglia, tmp_buf);
return;
}
n += snprintf(tmp_buf+n, m-n, "Client %ld ha richiesto una closeFile sul file \"%s\" e' terminata con successo\n",
fd_c,
filepath);
2022-04-10 20:51:43 +02:00
sendMessage(MEOK, fd_c, taglia, tmp_buf);
/* signal another waiting client that a lock has been released */
if (pthread_mutex_lock(lock) == -1) { /* begin ME */
perror("closeFile: pthread_mutex_lock");
2022-04-10 20:51:43 +02:00
return;
}
int waked = -1;
waked = removeFirstWaiting(waiting, filepath);
if (waked != -1) {
/* we lock the file for the other client */
2022-04-10 20:51:43 +02:00
lockFile(filepath, q, waked, taglia, lock, waiting);
}
if (pthread_mutex_unlock(lock) == -1) { /* end ME */
perror("closeFile: pthread_mutex_unlock");
2022-04-10 20:51:43 +02:00
return;
}
2022-04-04 22:31:14 +02:00
return;
}
2022-03-31 22:26:44 +02:00
2022-04-08 21:32:52 +02:00
void removeFile(char *filepath, queueT *q, long fd_c, taglia_t *taglia, pthread_mutex_t *lock, waiting_t **waiting) {
/* message to write to the logfile */
2022-04-10 20:51:43 +02:00
char tmp_buf[LOGBUFSIZE];
int n = 0;
size_t m = sizeof(tmp_buf);
if(!filepath || !q || !taglia || !lock || !waiting) {
n += snprintf(tmp_buf+n, m-n, "Client %ld ha richiesto una removeFile sul file \"%s\" e' terminata con errore.\n",
fd_c,
filepath);
2022-04-10 20:51:43 +02:00
errno = EINVAL;
serror(MESY, fd_c, taglia, tmp_buf);
return;
}
/* search for the file to delete */
if(!searchFile(q, filepath)) { /* file does not exist */
n += snprintf(tmp_buf+n, m-n, "Client %ld ha richiesto una removeFile sul file \"%s\" ma risulta assente.\n",
fd_c,
filepath);
2022-04-10 20:51:43 +02:00
errno = ENOENT;
serror(MENT, fd_c, taglia, tmp_buf);
return;
}
if (removeFileFromQueue(q, filepath, fd_c) == -1) {
n += snprintf(tmp_buf+n, m-n, "Client %ld ha richiesto una removeFile sul file \"%s\" e' terminata con errore del server.\n",
fd_c,
filepath);
2022-04-10 20:51:43 +02:00
serror(MENT, fd_c, taglia, tmp_buf);
return;
}
n += snprintf(tmp_buf+n, m-n, "Client %ld ha richiesto una removeFile sul file \"%s\" e' terminata con successo\n",
fd_c,
filepath);
2022-04-10 20:51:43 +02:00
sendMessage(MEOK, fd_c, taglia, tmp_buf);
/* signal another waiting client that a lock has been released */
if (pthread_mutex_lock(lock) == -1) { /* begin ME */
perror("removeFile: pthread_mutex_lock");
2022-04-10 20:51:43 +02:00
return;
}
int waked = -1;
waked = removeFirstWaiting(waiting, filepath);
if (waked != -1) {
/* we lock the file for the other client */
2022-04-10 20:51:43 +02:00
lockFile(filepath, q, waked, taglia, lock, waiting);
}
if (pthread_mutex_unlock(lock) == -1) { /* end ME */
perror("removeFile: pthread_mutex_unlock");
2022-04-10 20:51:43 +02:00
return;
}
2022-04-04 22:31:14 +02:00
return;
}
2022-03-31 22:26:44 +02:00
2022-04-10 20:51:43 +02:00
// -----------------------------------------------------------------------------
// helper functions for clients waiting locks
/* add a client to the waiting list */
2022-04-10 20:51:43 +02:00
int addWaiting(waiting_t **waiting, char *filepath, int fd_c) {
if(!waiting || !filepath) {
errno = EINVAL;
return -1;
}
2022-03-31 22:26:44 +02:00
2022-04-10 20:51:43 +02:00
waiting_t *new = calloc(1, sizeof(waiting_t));
if (!new) {
perror("addWaiting: calloc");
2022-04-10 20:51:43 +02:00
return -1;
}
new->file = calloc(MAXLENMESS, sizeof(char));
if (!new->file) {
perror("addWaiting: calloc");
2022-04-10 20:51:43 +02:00
free(new);
return -1;
}
2022-03-18 20:49:28 +01:00
2022-04-10 20:51:43 +02:00
strncpy(new->file, filepath, strnlen(filepath, MAXLENMESS-1)+1);
new->fd = fd_c;
new->next = NULL;
2022-03-18 20:49:28 +01:00
/* if the list is empty */
2022-04-10 20:51:43 +02:00
if(*waiting == NULL) {
*waiting = new;
return 0;
}
2022-03-18 20:49:28 +01:00
/* if the list has at least 1 element */
2022-04-10 20:51:43 +02:00
waiting_t *tail = *waiting;
while(tail->next) {
tail = tail->next;
}
tail->next = new;
2022-03-18 20:49:28 +01:00
2022-04-08 21:32:52 +02:00
return 0;
2022-04-04 22:31:14 +02:00
}
2022-03-18 20:49:28 +01:00
/* remove first who is waiting on the lock for the file
* if no one is waiting for the lock it returns -1 */
2022-04-10 20:51:43 +02:00
int removeFirstWaiting(waiting_t **waiting, char *filepath) {
if(!waiting || !filepath) {
errno = EINVAL;
return -1;
}
/* none waiting */
2022-04-10 20:51:43 +02:00
if(*waiting == NULL) {
return -1;
}
waiting_t *curr = *waiting;
waiting_t *prec = NULL;
long fd_c = -1;
/* first one waiting */
2022-04-10 20:51:43 +02:00
if (strcmp(curr->file, filepath) == 0) {
fd_c = curr->fd;
*waiting = curr->next;
free(curr->file);
free(curr);
return fd_c;
}
/* more than one waiting */
2022-04-10 20:51:43 +02:00
while (curr->next) {
prec = curr;
curr = curr->next;
if (strcmp(curr->file, filepath) == 0) {
fd_c = curr->fd;
prec->next = curr->next;
free(curr->file);
free(curr);
2022-03-18 20:49:28 +01:00
2022-04-10 20:51:43 +02:00
return fd_c;
}
}
return -1;
}
/* free waiting structure */
2022-04-08 21:32:52 +02:00
void clearWaiting(waiting_t **waiting) {
2022-04-10 20:51:43 +02:00
if(!waiting) {
return;
}
waiting_t *curr = *waiting;
waiting_t *next = NULL;
while (curr) {
next = curr->next;
2022-04-23 17:43:38 +02:00
if(curr->file)
free(curr->file);
2022-04-10 20:51:43 +02:00
free(curr);
curr = next;
}
*waiting = NULL;
2022-04-04 22:31:14 +02:00
return;
}