840 lines
24 KiB
C
840 lines
24 KiB
C
#define _POSIX_C_SOURCE 200809L
|
|
#include <string.h>
|
|
#include <errno.h>
|
|
#include <inttypes.h>
|
|
|
|
#include <conn.h>
|
|
#include <apiFile.h>
|
|
#include <fileQueue.h>
|
|
#include <taglialegna.h>
|
|
|
|
#define MAXLENMESS 512
|
|
#define LOGBUFSIZE 2048
|
|
|
|
#define MEOK "20" //OK
|
|
// #define ME "21" // not used
|
|
// #define ME "22" // not used
|
|
#define MEFP "25" // file purged
|
|
|
|
// #define ME "40" // not used
|
|
// #define ME "41" // not used
|
|
#define MESD "42" // shutting down
|
|
#define MENT "45" // requested file action not taken
|
|
|
|
#define MESY "50" // syntax error
|
|
// #define ME "51" // not used
|
|
// #define ME "52" // not used
|
|
#define MESE "55" // server error
|
|
|
|
// -----------------------------------------------------------------------------
|
|
/* funzioni ausiliarie */
|
|
|
|
// invio il messaggio al client e poi l'errno
|
|
void serror(char *m, long fd_c, taglia_t *taglia, char *mlog) {
|
|
if(!m) {
|
|
errno = EINVAL;
|
|
m = MESY;
|
|
}
|
|
if(writen(fd_c, m, strnlen(m, MAXLENMESS)+1) < 0) {
|
|
perror("writen");
|
|
goto _serror_cleanup;
|
|
}
|
|
if(writen(fd_c, &errno, sizeof(errno)) < 0) {
|
|
perror("writen");
|
|
goto _serror_cleanup;
|
|
}
|
|
|
|
if(taglia_write(taglia, mlog) < 0)
|
|
goto _serror_cleanup;
|
|
|
|
return;
|
|
|
|
_serror_cleanup:
|
|
return;
|
|
}
|
|
|
|
// invio il messaggio al client
|
|
void sendMessage(char *m, long fd_c, taglia_t *taglia, char *mlog) {
|
|
if(!m) {
|
|
m = MEOK;
|
|
}
|
|
|
|
if(writen(fd_c, m, strnlen(m, MAXLENMESS)+1) < 0) {
|
|
perror("writen");
|
|
goto _sendM_cleanup;
|
|
}
|
|
|
|
if(taglia_write(taglia, mlog) < 0)
|
|
goto _sendM_cleanup;
|
|
|
|
return;
|
|
|
|
_sendM_cleanup:
|
|
return;
|
|
}
|
|
|
|
// invia un file
|
|
int sendFile(fileT *f, long fd_c, taglia_t *taglia) {
|
|
if(!f || !taglia) {
|
|
errno = EINVAL;
|
|
return -1;
|
|
}
|
|
|
|
// send filepath dimension, then filepath
|
|
int64_t filepathLength = (int64_t) strnlen(f->filepath, MAXLENMESS)+1;
|
|
if (writen(fd_c, &filepathLength, sizeof(filepathLength)) < 0) {
|
|
perror("writen");
|
|
return -1;
|
|
}
|
|
if (writen(fd_c, f->filepath, (size_t) filepathLength) < 0) {
|
|
perror("writen");
|
|
return -1;
|
|
}
|
|
// send file dimension, then file
|
|
int64_t validLength = (int64_t) f->valid;
|
|
if (writen(fd_c, &validLength, sizeof(validLength)) < 0) {
|
|
perror("writen");
|
|
return -1;
|
|
}
|
|
if (writen(fd_c, f->data, f->valid) < 0) {
|
|
perror("writen");
|
|
return -1;
|
|
}
|
|
|
|
char tmp_log[LOGBUFSIZE];
|
|
int n = 0;
|
|
size_t m = sizeof(tmp_log);
|
|
|
|
n += snprintf(tmp_log+n, m-n, "File \"%s\", di dimensione %"PRId64" Bytes al client %ld .\n", f->filepath, validLength, fd_c);
|
|
if(taglia_write(taglia, tmp_log) < 0) {
|
|
perror("taglia_write");
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
// invio il messaggio al client e poi il file
|
|
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";
|
|
strncat(errmlog, mlog, sizeof(errmlog)-strlen(errmlog)-1);
|
|
serror(MESY, fd_c, taglia, errmlog);
|
|
goto _sendMF_cleanup;
|
|
}
|
|
if(!m) {
|
|
m = MEFP;
|
|
}
|
|
|
|
if(writen(fd_c, m, strnlen(m, MAXLENMESS)+1) < 0) {
|
|
perror("writen");
|
|
goto _sendMF_cleanup;
|
|
}
|
|
|
|
int n = 1;
|
|
if(writen(fd_c, &n, sizeof(n)) < 0) {
|
|
perror("writen");
|
|
goto _sendMF_cleanup;
|
|
}
|
|
|
|
if(sendFile(f, fd_c, taglia) < 0) {
|
|
perror("sendFile");
|
|
goto _sendMF_cleanup;
|
|
}
|
|
|
|
if(taglia_write(taglia, mlog) < 0) {
|
|
perror("log write");
|
|
goto _sendMF_cleanup;
|
|
}
|
|
|
|
return;
|
|
|
|
_sendMF_cleanup:
|
|
return;
|
|
}
|
|
|
|
// invio il messaggio al client e poi n file
|
|
void sendMessageFileN(char *m, fileT **f, int n, 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";
|
|
strncat(errmlog, mlog, sizeof(errmlog)-strlen(errmlog)-1);
|
|
serror(MESY, fd_c, taglia, errmlog);
|
|
goto _sendMFN_cleanup;
|
|
}
|
|
if(!m) {
|
|
m = MEFP;
|
|
}
|
|
|
|
if(writen(fd_c, m, strnlen(m, MAXLENMESS)+1) < 0) {
|
|
perror("writen");
|
|
goto _sendMFN_cleanup;
|
|
}
|
|
|
|
if(write(fd_c, &n, sizeof(n)) < 0) {
|
|
perror("writen");
|
|
goto _sendMFN_cleanup;
|
|
}
|
|
|
|
for(int i=0; i<n && (f[i]!=NULL); ++i) {
|
|
if(sendFile(f[i], fd_c, taglia) < 0) {
|
|
perror("sendFile");
|
|
goto _sendMFN_cleanup;
|
|
}
|
|
}
|
|
|
|
if(taglia_write(taglia, mlog) < 0)
|
|
goto _sendMFN_cleanup;
|
|
|
|
return;
|
|
|
|
_sendMFN_cleanup:
|
|
return;
|
|
}
|
|
|
|
|
|
// -----------------------------------------------------------------------------
|
|
void openFile(char *filepath, int flags, queueT *q, long fd_c, taglia_t *taglia) {
|
|
// messaggio da scrivere sul logfile
|
|
char tmp_buf[LOGBUFSIZE];
|
|
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);
|
|
errno = EINVAL;
|
|
serror(MESY, fd_c, taglia, tmp_buf);
|
|
return;
|
|
}
|
|
|
|
int found = searchFile(q, filepath); // cerco il file nella queue
|
|
int create = flags & 0x1; // also %2
|
|
int lock = flags >> 1 & 0x1; // also >>1%2
|
|
fileT *removed = NULL; // file che è stato rimosso
|
|
|
|
if(found && create) { // si vuole creare il file ma esiste già
|
|
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);
|
|
errno = EEXIST;
|
|
serror(MENT, fd_c, taglia, tmp_buf);
|
|
return;
|
|
}
|
|
|
|
if(!found && !create) { // si vuole aprire e non creare un file inesistente
|
|
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);
|
|
errno = ENOENT;
|
|
serror(MENT, fd_c, taglia, tmp_buf);
|
|
return;
|
|
}
|
|
|
|
if(found && !create) {
|
|
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\n", fd_c, flags, filepath);
|
|
perror("openFileInQueue");
|
|
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);
|
|
sendMessage(MEOK, fd_c, taglia, tmp_buf);
|
|
return;
|
|
}
|
|
|
|
if(!found && create) { // not found and creating new file
|
|
if(getLen(q) == q->maxLen) { // capacity miss
|
|
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("dequeue");
|
|
serror(MESE, fd_c, taglia, tmp_buf);
|
|
return;
|
|
}
|
|
|
|
fileT *f = createFileT(filepath, lock, fd_c, 1); // create new file
|
|
|
|
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("createFileT");
|
|
serror(MESE, fd_c, taglia, tmp_buf);
|
|
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("enqueue");
|
|
serror(MESE, fd_c, taglia, tmp_buf);
|
|
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);
|
|
sendMessageFile(MEFP, removed, fd_c, taglia, tmp_buf);
|
|
free(removed);
|
|
return;
|
|
}
|
|
|
|
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("createFileT");
|
|
serror(MESE, fd_c, taglia, tmp_buf);
|
|
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("enqueue");
|
|
serror(MESE, fd_c, taglia, tmp_buf);
|
|
return;
|
|
}
|
|
// abbiamo aggiunto un file quindi il numero di file è cambiato
|
|
// quindi bisogna fare un update del log
|
|
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);
|
|
sendMessage(MEOK, fd_c, taglia, tmp_buf);
|
|
return;
|
|
}
|
|
|
|
// codice non raggiungibile
|
|
return;
|
|
}
|
|
|
|
|
|
void readFile(char *filepath, queueT *q, long fd_c, taglia_t *taglia) {
|
|
// messaggio da scrivere sul logfile
|
|
char tmp_buf[LOGBUFSIZE];
|
|
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\n", fd_c, filepath);
|
|
errno = EINVAL;
|
|
serror(MESY, fd_c, taglia, tmp_buf);
|
|
return;
|
|
}
|
|
|
|
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\" e' terminata con errore\n", fd_c, filepath);
|
|
errno = ENOENT;
|
|
serror(MESE, fd_c, taglia, tmp_buf);
|
|
return;
|
|
}
|
|
|
|
if(f->open != 0) { // file already open
|
|
n += snprintf(tmp_buf+n, m-n, "Client %ld ha richiesto una readFile sul file \"%s\" e' terminata con errore\n", fd_c, filepath);
|
|
errno = EPERM;
|
|
serror(MENT, fd_c, taglia, tmp_buf);
|
|
destroyFile(f); // f is a copy so we need to cleen up
|
|
return;
|
|
}
|
|
|
|
n += snprintf(tmp_buf+n, m-n, "Client %ld ha richiesto una readFile sul file \"%s\" e' terminata con successo\n", fd_c, filepath);
|
|
sendMessageFile(MEOK, f, fd_c, taglia, tmp_buf);
|
|
destroyFile(f); // f is a copy so we need to cleen up
|
|
return;
|
|
}
|
|
|
|
|
|
void readNFiles(int num, queueT *q, long fd_c, taglia_t *taglia){
|
|
// messaggio da scrivere sul logfile
|
|
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);
|
|
errno = EINVAL;
|
|
serror(MESY, fd_c, taglia, tmp_buf);
|
|
return;
|
|
}
|
|
|
|
int oldNum = num;
|
|
num = (num<=0 || num>getLen(q))? getLen(q) : num;
|
|
fileT **toSend = calloc(num, sizeof(fileT *));
|
|
|
|
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, we dont check if the client can actually modify
|
|
// the files since we add them back immediatly
|
|
for(int i=0;i<num;++i) { /* TODO: fix here */
|
|
toSend[i] = dequeue(q);
|
|
if(!toSend[i]) {
|
|
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("dequeue");
|
|
serror(MESE, fd_c, taglia, tmp_buf);
|
|
return;
|
|
}
|
|
int tmp = enqueue(q, toSend[i]);
|
|
if(tmp<0) {
|
|
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("enqueue");
|
|
serror(MESE, fd_c, taglia, tmp_buf);
|
|
return;
|
|
}
|
|
n += snprintf(tmp_buf+n, m-n, "\t%d) \"%s\"\n", i, toSend[i]->filepath);
|
|
}
|
|
|
|
sendMessageFileN(MEOK, toSend, num, fd_c, taglia, tmp_buf);
|
|
free(toSend);
|
|
return;
|
|
}
|
|
|
|
|
|
void writeFile(char *filepath, size_t size, queueT *q, long fd_c, taglia_t *taglia, int append) {
|
|
// messaggio da scrivere sul logfile
|
|
char tmp_buf[LOGBUFSIZE];
|
|
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);
|
|
errno = EINVAL;
|
|
serror(MESY, fd_c, taglia, tmp_buf);
|
|
return;
|
|
}
|
|
|
|
// cerco il file
|
|
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 writeFile (append = %x) sul file \"%s\", dimensione = %ld, e' terminata con errore\n", fd_c, append, filepath, size);
|
|
errno = ENOENT;
|
|
serror(MENT, fd_c, taglia, tmp_buf);
|
|
destroyFile(f);
|
|
return;
|
|
}
|
|
|
|
// file non aperto || !append => locked || lock ma non si è proprietari
|
|
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\n", fd_c, append, filepath, size);
|
|
errno = EPERM;
|
|
serror(MENT, fd_c, taglia, tmp_buf);
|
|
destroyFile(f);
|
|
return;
|
|
}
|
|
int trueSizeAdded = 0; // we may have alredy some space allocated
|
|
if(append) {
|
|
trueSizeAdded = size - f->size + f->valid;
|
|
} else {
|
|
trueSizeAdded = (size>f->size)? size-f->size : 0;
|
|
}
|
|
destroyFile(f); // not needed anymore
|
|
|
|
fileT **removed = NULL; // array that may (worst case) hold all files to be sent to the client
|
|
|
|
if(trueSizeAdded + getSize(q) > q->maxSize) { // writing would be more than capacity
|
|
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\n", fd_c, append, filepath, size);
|
|
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. Ha causato una capacity miss e ha fatto espellere i seguenti file:", fd_c, append, filepath, size);
|
|
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);
|
|
|
|
sendMessageFileN(MEFP, removed, ln, fd_c, taglia, tmp_buf);
|
|
for(int i=0;i<ln && (removed[i]!=NULL);++i) {
|
|
destroyFile(removed[i]);
|
|
}
|
|
free(removed);
|
|
// now we can write the actual file
|
|
|
|
void *content = NULL;
|
|
content = malloc(size);
|
|
if(!content) {
|
|
perror("malloc");
|
|
return;
|
|
}
|
|
if((readn(fd_c, content, size)) == -1) {
|
|
perror("readn");
|
|
return;
|
|
}
|
|
|
|
if(append) {
|
|
if(appendFileInQueue(q, filepath, content, size, fd_c) == -1) {
|
|
perror("appendFileInQueue");
|
|
free(content);
|
|
return;
|
|
}
|
|
} else {
|
|
if(writeFileInQueue(q, filepath, content, size, fd_c) == -1) {
|
|
perror("writeFileInQueue");
|
|
free(content);
|
|
return;
|
|
}
|
|
}
|
|
|
|
taglia_update(taglia, q, 0);
|
|
free(content);
|
|
return;
|
|
}
|
|
|
|
// non c'è ancora bisogno di rimuovere file
|
|
void *content = NULL;
|
|
content = malloc(size);
|
|
if(!content) {
|
|
perror("malloc");
|
|
return;
|
|
}
|
|
if(readn(fd_c, content, size) == -1) {
|
|
perror("readn");
|
|
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);
|
|
|
|
if(append) {
|
|
if(appendFileInQueue(q, filepath, content, size, fd_c) == -1) {
|
|
perror("appendFileInQueue");
|
|
free(content);
|
|
return;
|
|
}
|
|
} else {
|
|
if(writeFileInQueue(q, filepath, content, size, fd_c) == -1) {
|
|
perror("writeFileInQueue");
|
|
free(content);
|
|
return;
|
|
}
|
|
}
|
|
|
|
taglia_write(taglia, tmp_buf);
|
|
|
|
taglia_update(taglia, q, 0);
|
|
|
|
free(content);
|
|
return;
|
|
}
|
|
|
|
|
|
void lockFile(char *filepath, queueT *q, long fd_c, taglia_t *taglia, pthread_mutex_t *lock, waiting_t **waiting) {
|
|
// messaggio da scrivere sul logfile
|
|
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 lockFile sul file \"%s\" e' terminata con errore.\n", fd_c, filepath);
|
|
errno = EINVAL;
|
|
serror(MESY, fd_c, taglia, tmp_buf);
|
|
return;
|
|
}
|
|
|
|
// cerco il file da impostare in modalita' locked
|
|
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);
|
|
errno = ENOENT;
|
|
serror(MENT, fd_c, taglia, tmp_buf);
|
|
destroyFile(f);
|
|
return;
|
|
}
|
|
|
|
// provo a prendere la lock
|
|
if (openFileInQueue(q, filepath, 1, fd_c) == -1) {
|
|
// non siamo riusciti a prendere la lock al file, quindi aspettiamo che
|
|
// venga rilasciata mettendoci in attesa nella waiting list
|
|
if (errno == EPERM) {
|
|
if (pthread_mutex_lock(lock) == -1) { // begin ME
|
|
perror("lock");
|
|
destroyFile(f);
|
|
return;
|
|
}
|
|
|
|
if (addWaiting(waiting, filepath, fd_c) == -1) {
|
|
perror("addWaiting");
|
|
pthread_mutex_unlock(lock);
|
|
destroyFile(f);
|
|
return;
|
|
}
|
|
|
|
if (pthread_mutex_unlock(lock) == -1) { // end ME
|
|
perror("unlock");
|
|
}
|
|
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);
|
|
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);
|
|
sendMessage(MEOK, fd_c, taglia, tmp_buf);
|
|
destroyFile(f);
|
|
return;
|
|
}
|
|
|
|
|
|
void unlockFile(char *filepath, queueT *q, long fd_c, taglia_t *taglia, pthread_mutex_t *lock, waiting_t **waiting) {
|
|
// messaggio da scrivere sul logfile
|
|
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);
|
|
errno = EINVAL;
|
|
serror(MESY, fd_c, taglia, tmp_buf);
|
|
return;
|
|
}
|
|
|
|
// cerco il file su cui rilasciare la lock
|
|
if(!searchFile(q, filepath)) { // file e' assente
|
|
n += snprintf(tmp_buf+n, m-n, "Client %ld ha richiesto una unlockFile sul file \"%s\" ma risulta assente.\n", fd_c, filepath);
|
|
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);
|
|
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);
|
|
sendMessage(MEOK, fd_c, taglia, tmp_buf);
|
|
|
|
// segnalo a un client in lista d'attesa che una lock e' stata rilasciata
|
|
if (pthread_mutex_lock(lock) == -1) { // begin ME
|
|
perror("lock");
|
|
return;
|
|
}
|
|
|
|
int waked = -1;
|
|
waked = removeFirstWaiting(waiting, filepath);
|
|
|
|
if (waked != -1) {
|
|
// we lock the file for the other client
|
|
lockFile(filepath, q, waked, taglia, lock, waiting);
|
|
}
|
|
|
|
if (pthread_mutex_unlock(lock) == -1) { // end ME
|
|
perror("unlock");
|
|
return;
|
|
}
|
|
return;
|
|
}
|
|
|
|
|
|
void closeFile(char *filepath, queueT *q, long fd_c, taglia_t *taglia, pthread_mutex_t *lock, waiting_t **waiting) {
|
|
// messaggio da scrivere sul logfile
|
|
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);
|
|
errno = EINVAL;
|
|
serror(MESY, fd_c, taglia, tmp_buf);
|
|
return;
|
|
}
|
|
|
|
// cerco il file da chiudere
|
|
if(!searchFile(q, filepath)) { // file e' assente
|
|
n += snprintf(tmp_buf+n, m-n, "Client %ld ha richiesto una closeFile sul file \"%s\" ma risulta assente.\n", fd_c, filepath);
|
|
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);
|
|
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);
|
|
sendMessage(MEOK, fd_c, taglia, tmp_buf);
|
|
|
|
// segnalo a un client in lista d'attesa che una lock e' stata rilasciata
|
|
if (pthread_mutex_lock(lock) == -1) { // begin ME
|
|
perror("lock");
|
|
return;
|
|
}
|
|
|
|
int waked = -1;
|
|
waked = removeFirstWaiting(waiting, filepath);
|
|
|
|
if (waked != -1) {
|
|
// we lock the file for the other client
|
|
lockFile(filepath, q, waked, taglia, lock, waiting);
|
|
}
|
|
|
|
if (pthread_mutex_unlock(lock) == -1) { // end ME
|
|
perror("unlock");
|
|
return;
|
|
}
|
|
return;
|
|
}
|
|
|
|
|
|
void removeFile(char *filepath, queueT *q, long fd_c, taglia_t *taglia, pthread_mutex_t *lock, waiting_t **waiting) {
|
|
// messaggio da scrivere sul logfile
|
|
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);
|
|
errno = EINVAL;
|
|
serror(MESY, fd_c, taglia, tmp_buf);
|
|
return;
|
|
}
|
|
|
|
// cerco il file da eliminare
|
|
if(!searchFile(q, filepath)) { // file e' assente
|
|
n += snprintf(tmp_buf+n, m-n, "Client %ld ha richiesto una removeFile sul file \"%s\" ma risulta assente.\n", fd_c, filepath);
|
|
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.\n", fd_c, filepath);
|
|
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);
|
|
sendMessage(MEOK, fd_c, taglia, tmp_buf);
|
|
|
|
// segnalo a un client in lista d'attesa che un file e' stato rimosso
|
|
if (pthread_mutex_lock(lock) == -1) { // begin ME
|
|
perror("lock");
|
|
return;
|
|
}
|
|
|
|
int waked = -1;
|
|
waked = removeFirstWaiting(waiting, filepath);
|
|
|
|
if (waked != -1) {
|
|
// we lock the file for the other client
|
|
lockFile(filepath, q, waked, taglia, lock, waiting);
|
|
}
|
|
|
|
if (pthread_mutex_unlock(lock) == -1) { // end ME
|
|
perror("unlock");
|
|
return;
|
|
}
|
|
return;
|
|
}
|
|
|
|
|
|
// -----------------------------------------------------------------------------
|
|
/* funzioni ausiliarie relative ai client in attesa di lock */
|
|
int addWaiting(waiting_t **waiting, char *filepath, int fd_c) {
|
|
if(!waiting || !filepath) {
|
|
errno = EINVAL;
|
|
return -1;
|
|
}
|
|
|
|
waiting_t *new = calloc(1, sizeof(waiting_t));
|
|
if (!new) {
|
|
perror("calloc");
|
|
return -1;
|
|
}
|
|
new->file = calloc(MAXLENMESS, sizeof(char));
|
|
if (!new->file) {
|
|
perror("calloc");
|
|
free(new);
|
|
return -1;
|
|
}
|
|
|
|
strncpy(new->file, filepath, strnlen(filepath, MAXLENMESS-1)+1);
|
|
new->fd = fd_c;
|
|
new->next = NULL;
|
|
|
|
// se la lista è vuota
|
|
if(*waiting == NULL) {
|
|
*waiting = new;
|
|
return 0;
|
|
}
|
|
|
|
// se la lista ha almeno un elemento
|
|
waiting_t *tail = *waiting;
|
|
while(tail->next) {
|
|
tail = tail->next;
|
|
}
|
|
tail->next = new;
|
|
|
|
return 0;
|
|
}
|
|
|
|
// remove first who is waiting on the lock for the file
|
|
int removeFirstWaiting(waiting_t **waiting, char *filepath) {
|
|
if(!waiting || !filepath) {
|
|
errno = EINVAL;
|
|
return -1;
|
|
}
|
|
|
|
// none waiting
|
|
if(*waiting == NULL) {
|
|
return -1;
|
|
}
|
|
|
|
waiting_t *curr = *waiting;
|
|
waiting_t *prec = NULL;
|
|
long fd_c = -1;
|
|
|
|
// first one waiting
|
|
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
|
|
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);
|
|
|
|
return fd_c;
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
// destroy waiting structure
|
|
void clearWaiting(waiting_t **waiting) {
|
|
if(!waiting) {
|
|
return;
|
|
}
|
|
waiting_t *curr = *waiting;
|
|
waiting_t *next = NULL;
|
|
|
|
while (curr) {
|
|
next = curr->next;
|
|
free(curr->file);
|
|
free(curr);
|
|
curr = next;
|
|
}
|
|
*waiting = NULL;
|
|
return;
|
|
}
|