<repo_name>matteotolloso/file_storage_server<file_sep>/Makefile

flags = -g -O3 -Wall -I ./includes -std=c99 -pedantic #-Werror

obj = ./obj/server.o ./obj/parser.o ./obj/sharedqueue.o ./obj/connection.o \
	./obj/handler.o ./obj/filesystem.o ./obj/linkedlist.o 
	

src = ./src/server.c ./src/parser.c ./src/sharedqueue.c ./src/connection.c \
	./src/handler.c ./src/filesystem.c ./src/linkedlist.c 

includes = ./includes/myconnection.h ./includes/myhandler.h \
			./includes/myparser.h ./includes/mysharedqueue.h \
			./includes/myutil.h ./includes/myfilesystem.h \
			./includes/mylinkedlist.h

objpath = ./obj/

srcpath = ./src/

libpath = ./lib/

.PHONY: clean cleanall test1 test2 test3

#all 

all: ./server ./client

#linking

./server: $(obj)
	gcc $(obj) -o $@ -pthread

./client: $(objpath)client.o $(libpath)libServerApi.a
	gcc $< -o $@ -L $(libpath) -lServerApi

#obj file for server

$(objpath)server.o: $(srcpath)server.c $(includes)
	gcc $< $(flags) -c -o $@

$(objpath)parser.o: $(srcpath)parser.c $(includes)
	gcc $< $(flags) -c -o $@

$(objpath)sharedqueue.o: $(srcpath)sharedqueue.c $(includes)
	gcc $< $(flags) -c -o $@

$(objpath)connection.o: $(srcpath)connection.c $(includes)
	gcc $< $(flags) -c -o $@

$(objpath)handler.o: $(srcpath)handler.c $(includes)
	gcc $< $(flags) -c -o $@ -pthread

$(objpath)filesystem.o: $(srcpath)filesystem.c $(includes)
	gcc $< $(flags) -c -o $@ -pthread

$(objpath)linkedlist.o: $(srcpath)linkedlist.c $(includes)
	gcc $< $(flags) -c -o $@ -pthread

#obj file for client

$(objpath)client.o: $(srcpath)client.c $(includes)
	gcc $< $(flags) -c -o $@ 

$(libpath)libServerApi.a: $(objpath)serverApi.o
	ar rvs $(libpath)libServerApi.a $(objpath)serverApi.o

$(objpath)serverApi.o: $(srcpath)serverApi.c $(includes)
	gcc $< $(flags) -c -o $@ 


cleanall	: 
	./clean.sh


test1	: ./server ./client
	mkdir -p tests/fileLetti
	mkdir -p tests/fileEvict
	./tests/test1.sh

test2	: ./server ./client
	mkdir -p tests/fileLetti
	mkdir -p tests/fileEvict
	./tests/test2.sh

test3	: ./server ./client
	mkdir -p tests/fileLetti
	mkdir -p tests/fileEvict
	./tests/test3.sh
<file_sep>/src/handler.c
#include <myhandler.h>



void ter_handler(int sig){
    int n;
    if ((sig == SIGINT) || (sig == SIGQUIT)){
        n=2;
        if(write(pipeSigWriting, &n, sizeof(int)) != sizeof(int)){
            perror("write");
        }
        return;
    }
    if( sig == SIGHUP){
        n=1;
        if(write(pipeSigWriting, &n, sizeof(int)) != sizeof(int)){
            perror("write");
        }
        return;
    }

    EXIT_ON(write(1, "unknown signal", 15), <= 0);
}

void print_handler(int sig){
    EXIT_ON(write(2, "segnale ricevuto dal worker: %d", sig), == 0);
    return;
}

void handler_installer(){

    sigset_t fullmask, handlermask, complementar;
    sigfillset(&fullmask);
    sigemptyset(&handlermask);
    sigfillset(&complementar);
    EXIT_ON(pthread_sigmask(SIG_SETMASK, &fullmask, NULL), != 0);

    sigaddset(&handlermask, SIGINT);
    sigaddset(&handlermask, SIGQUIT);
    sigaddset(&handlermask, SIGHUP);
    sigdelset(&complementar, SIGINT);
    sigdelset(&complementar, SIGQUIT);
    sigdelset(&complementar, SIGHUP);
    
    struct sigaction sa;
    EXIT_ON(memset(&sa, 0, sizeof(struct sigaction)), == NULL);
    
    sa.sa_handler = ter_handler;
    sa.sa_mask = handlermask;
    EXIT_ON( sigaction(SIGINT, &sa, NULL), != 0);
    EXIT_ON( sigaction(SIGQUIT, &sa, NULL), != 0);
    EXIT_ON( sigaction(SIGHUP, &sa, NULL), != 0);

    EXIT_ON(pthread_sigmask(SIG_SETMASK, &complementar, NULL), != 0);
}

void worker_handler_installer(){

    sigset_t fullmask;
    sigfillset(&fullmask);
    EXIT_ON(pthread_sigmask(SIG_SETMASK, &fullmask, NULL), != 0);

}

<file_sep>/tests/test3support.sh
#!/bin/bash
while true
do
./client -f mysock -D tests/fileEvict/ -w tests/files 
./client -f mysock -d tests/fileLetti/ -r ./tests/files/100mb_file,./tests/files/30mb_file
./client -f mysock -d tests/fileLetti/ -l ./tests/files/100mb_file,./tests/files/30mb_file
done<file_sep>/src/linkedlist.c
#include <mylinkedlist.h>

void init(struct node **head, int data)
{
	EXIT_ON(*head = (struct node *)malloc(sizeof(struct node)), == NULL);

	(*head)->data = data;
	(*head)->next = NULL;

	return;
}

void list_insert(struct node **head, int data)
{

    if (*head == NULL){
        init(head,data);
		return;
    }

	struct node *current = *head;
	struct node *tmp;

	while(current){
		if(current->data == data) return;
		tmp = current;
		current = current->next;
	} 

	/* create a new node after tmp */
	struct node *new_node;
    EXIT_ON(new_node = (struct node *)malloc(sizeof(struct node)), == NULL);
	
	new_node->next = NULL;
	new_node->data = data;

	tmp->next = new_node;

	return;

}

int list_mem(struct node **head, int data)
{

    if (*head == NULL){
        return 0;
    }

	struct node *current = *head;

	while (current){

        if (current->data == data){
            return 1;
        }

		current = current->next;
	} 

	return 0;

}


void list_remove(struct node **head, int data)
{
	if(!list_mem(head, data)) return;
	
	struct node *current = *head;
	struct node *prev = NULL;

	do {
		if (current->data == data) {
			break;
		}
		prev = current;
		current = current->next;
	} while (current);

	/* if the first element */
	if (current == *head) {
		/* reuse prev */
		prev = *head;
		*head = current->next;
		free(prev);
		return;
	}

	/* if the last element */
	if (current->next == NULL) {
		prev->next = NULL;
		free(current);
		return;
	}

	prev->next = current->next;
	free(current);
	return;
}


void list_deinit(struct node **head)
{
	struct node *node = *head;
	while (node) {
		struct node *tmp;
		tmp = node;
		node = node->next;
		free(tmp);
	}
}<file_sep>/includes/myconnection.h
#ifndef _MY_CONNECTION_H
#define _MY_CONNECTION_H
#define _POSIX_C_SOURCE 200809L 

#include <sys/socket.h>
#include <sys/un.h>
#include <myutil.h>
#include <sys/select.h>
#include <string.h>
#include <stdio.h>
#define UNIX_PATH_MAX 108
#define MAX_CONNECTION_QUEUE 1024

int updatemax(fd_set set, int fdmax);

int init_server(char * sck_name);

int find_max(int a, int b , int c, int d, int e);

#endif /* _MY_CONNECTION_H */<file_sep>/src/serverApi.c

#include <myserverApi.h>
#include <time.h>


int socketfd = 0, myerrno;
char __sockname[UNIX_PATH_MAX];

extern int foundP;

int readNFiles(int n, char * dirname){

    if(dirname == NULL){
        myerrno = E_BAD_RQ;
        return -1;
    }

    char pth[MAX_PATH], pthToSave[MAX_PATH];
    
    int reqType = READ_N_F, resp = 0;

    if(writen(socketfd, &reqType, sizeof(int)) != sizeof(int)){  // scrivo il tipo di richesta
        myerrno = errno;
        return -1;
    }
    
    if(writen(socketfd, &n, sizeof(int)) != sizeof(int)){  // scrivo il numero di file
        myerrno = errno;
        return -1;
    }

    if(readn(socketfd, &resp, sizeof(int)) != sizeof(int)){  // leggo la risposta
        myerrno = errno;
        return -1;
    }
    if(resp != 1){ // c'è stato un errore (l'unica risposta corretta è 1)
        myerrno = resp;
        return -1;
    }

    FILE* outFile; int size; void * buf;
    while(1){

        if(readn(socketfd, &size, sizeof(int)) != sizeof(int)){ myerrno = errno; return -1;} // leggo la size, se è -1 ho finito
        if(size == -1){
            break;
        }
        
        if(readn(socketfd, pth, MAX_PATH) != MAX_PATH){ myerrno = errno; return -1;} // leggo il path

        EXIT_ON(buf = malloc(size), == NULL); // alloco il buffer
        
        if(readn(socketfd, buf, size) != size){ myerrno = errno; free(buf); return -1;} // leggo il contenuto
        
        strcpy(pthToSave, dirname);
        strcat(pthToSave, pth + onlyName(pth) );
        if (( outFile = fopen(pthToSave, "wb")) == NULL){
            myerrno = errno;
            return -1;
        }
        
        if(fwrite(buf, 1, size, outFile) != size){  // scrivo contenuto su file
            myerrno = errno;
            free(buf);
            fclose(outFile);
            return -1;
        }

        free(buf);
        fclose(outFile);
    }

    if(readn(socketfd, &resp, sizeof(int)) != sizeof(int)){  // leggo la risposta finale 
        myerrno = errno;
        return -1;
    }

    if(resp != 0){
        myerrno = resp;
        return -1;
    }
    else{
        return 0;
    }


}

int readFile(char * pathname, void ** buf, size_t * size){


    if(socketfd == 0){
        myerrno = E_NOT_CON;
        return -1;
    }
    
    if(pathname == NULL){ myerrno = E_INV_PTH; return -1;}

    char pth[MAX_PATH];
    strncpy(pth, pathname, MAX_PATH);
    pth[MAX_PATH-1] = '\0';
    int reqType = READ_F, resp = 0;

    if(writen(socketfd, &reqType, sizeof(int)) != sizeof(int)){  // scrivo il tipo di richesta
        myerrno = errno;
        return -1;
    }

    if(writen(socketfd, pth, MAX_PATH) != MAX_PATH){  // scrivo il path
        myerrno = errno;
        return -1;
    }

    if(readn(socketfd, &resp, sizeof(int)) != sizeof(int)){  // leggo la risposta
        myerrno = errno;
        return -1;
    }

    if(resp != 1){
        myerrno = resp;
        return -1;
    }

    int i_size;
    char * i_buf;

    if(readn(socketfd, &i_size, sizeof(int)) != sizeof(int)){  // leggo la size
        myerrno = errno;
        return -1;
    }

    EXIT_ON(i_buf = malloc(i_size), == NULL); // alloco il buffer

    if(readn(socketfd, i_buf, i_size) != i_size){  // leggo il contenuto
        free(i_buf);
        myerrno = errno;
        return -1;
    }

    if(readn(socketfd, &resp, sizeof(int)) != sizeof(int)){  // leggo la risposta
        free(i_buf);
        myerrno = errno;
        return -1;
    }

    if(resp != 0){
        free(i_buf);
        myerrno = resp;
        return -1;
    }
    else {
        *buf = i_buf;
        *size = i_size;
        return 0;
    }
}

int removeFile(char * pathname){

    if(socketfd == 0){
        myerrno = E_NOT_CON;
        return -1;
    }

    if(pathname == NULL){ myerrno = E_INV_PTH; return -1;}

    char pth[MAX_PATH];
    strncpy(pth, pathname, MAX_PATH);
    pth[MAX_PATH-1] = '\0';
    int reqType = REMOVE_F, resp = 0;

    if(writen(socketfd, &reqType, sizeof(int)) != sizeof(int)){  // scrivo il tipo di richesta
        myerrno = errno;
        return -1;
    }

    if(writen(socketfd, pth, MAX_PATH) != MAX_PATH){  // scrivo il path
        myerrno = errno;
        return -1;
    }

    if(readn(socketfd, &resp, sizeof(int)) != sizeof(int)){  // leggo la risposta
        myerrno = errno;
        return -1;
    }

    if(resp == 0){
        return 0;
    }
    else{
        myerrno = resp;
        return -1;
    }

}

int closeFile(char * pathname){

    if(socketfd == 0){
        myerrno = E_NOT_CON;
        return -1;
    }

    if(pathname == NULL){ myerrno = E_INV_PTH; return -1;}

    char pth[MAX_PATH];
    strncpy(pth, pathname, MAX_PATH);
    pth[MAX_PATH-1] = '\0';
    int reqType = CLOSE_F, resp = 0;

    if(writen(socketfd, &reqType, sizeof(int)) != sizeof(int)){  // scrivo il tipo di richesta
        myerrno = errno;
        return -1;
    }

    if(writen(socketfd, pth, MAX_PATH) != MAX_PATH){  // scrivo il path
        myerrno = errno;
        return -1;
    }

    if(readn(socketfd, &resp, sizeof(int)) != sizeof(int)){  // leggo la risposta
        myerrno = errno;
        return -1;
    }

    if(resp == 0){
        return 0;
    }
    else{
        myerrno = resp;
        return -1;
    }

}

int unlockFile(char * pathname){

    if(socketfd == 0){
        myerrno = E_NOT_CON;
        return -1;
    }

    if(pathname == NULL){ myerrno = E_INV_PTH; return -1;}

    char pth[MAX_PATH];
    strncpy(pth, pathname, MAX_PATH);
    pth[MAX_PATH-1] = '\0';
    int reqType = UNLOCK_F, resp = 0;

    if(writen(socketfd, &reqType, sizeof(int)) != sizeof(int)){  // scrivo il tipo di richesta
        myerrno = errno;
        return -1;
    }

    if(writen(socketfd, pth, MAX_PATH) != MAX_PATH){  // scrivo il path
        myerrno = errno;
        return -1;
    }

    if(readn(socketfd, &resp, sizeof(int)) != sizeof(int)){  // leggo la risposta
        myerrno = errno;
        return -1;
    }

    if(resp == 0){
        return 0;
    }
    else{
        myerrno = resp;
        return -1;
    }

}

int lockFile(char * pathname){

    if(socketfd == 0){
        myerrno = E_NOT_CON;
        return -1;
    }

    if(pathname == NULL){ myerrno = E_INV_PTH; return -1;}

    char pth[MAX_PATH];
    strncpy(pth, pathname, MAX_PATH);
    pth[MAX_PATH-1] = '\0';
    int reqType = LOCK_F, resp = 0;

    if(writen(socketfd, &reqType, sizeof(int)) != sizeof(int)){  // scrivo il tipo di richesta
        myerrno = errno;
        return -1;
    }

    if(writen(socketfd, pth, MAX_PATH) != MAX_PATH){  // scrivo il path
        myerrno = errno;
        return -1;
    }

    if(readn(socketfd, &resp, sizeof(int)) != sizeof(int)){  // leggo la risposta
        myerrno = errno;
        return -1;
    }

    if(resp == 0){
        return 0;
    }
    else{
        myerrno = resp;
        return -1;
    }

}

int appendToFile(char * pathname, void * buf, size_t size, char * dirname){

    if(socketfd == 0){
        myerrno = E_NOT_CON;
        return -1;
    }
    
    if(pathname == NULL){ myerrno = E_INV_PTH; return -1;}
    if(buf == NULL || size < 1){ myerrno = E_BAD_RQ; return -1;}

    char pth[MAX_PATH];
    strncpy(pth, pathname, MAX_PATH);
    pth[MAX_PATH-1] = '\0';
    int reqType = APPEND_T_F, resp = 0;

    if(writen(socketfd, &reqType, sizeof(int)) != sizeof(int)){  // scrivo il tipo di richesta
        myerrno = errno;
        return -1;
    }

    if(writen(socketfd, &size, sizeof(int)) != sizeof(int)){  // scrivo la size
        myerrno = errno;
        return -1;
    }
    
    if(writen(socketfd, pth, MAX_PATH) != MAX_PATH){  // scrivo il path
        myerrno = errno;
        return -1;
    }
    
    if(writen(socketfd, buf, size) != size){  // scrivo il buffer
        myerrno = errno;
        return -1;
    }
 
    if(readn(socketfd, &resp, sizeof(int)) != sizeof(int)){  // leggo la risposta
        myerrno = errno;
        return -1;
    }

    if(resp == 0){  // non devo fare altro
        return 0;
    }

    if(resp != 1){  // devo ricevere file
        myerrno = resp;
        return -1;
    }

    // lettura file di risposta
    
    if(resp == 1){ // devo leggere N file: size path cont
        FILE* outFile;
        char pthToSave[MAX_PATH];
        while(1){

            if(readn(socketfd, &size, sizeof(int)) != sizeof(int)){ myerrno = errno; return -1;} // leggo la size, se è -1 ho finito
            if(size == -1){
                break;
            }
            
            if(readn(socketfd, pth, MAX_PATH) != MAX_PATH){ myerrno = errno; return -1;} // leggo il path

            EXIT_ON(buf = malloc(size), == NULL); // alloco il buffer
            
            if(readn(socketfd, buf, size) != size){ myerrno = errno; free(buf); return -1;} // leggo il contenuto

            if(dirname != NULL){

                strcpy(pthToSave, dirname);
                strcat(pthToSave, pth + onlyName(pth) );
                if (( outFile = fopen(pthToSave, "wb")) == NULL){
                    myerrno = errno;
                    return -1;
                }
                if (( outFile = fopen(pthToSave, "wb")) == NULL){
                    myerrno = errno;
                    return -1;
                }
                
                if(fwrite(buf, 1, size, outFile) != size){  // scrivo contenuto su file
                    myerrno = errno;
                    free(buf);
                    fclose(outFile);
                    return -1;
                }
                fclose(outFile);
            }
            free(buf);
            
        }
    }
    
    if(readn(socketfd, &resp, sizeof(int)) != sizeof(int)){ myerrno = errno; return -1;}

    if(resp == 0){
        return 0;
    }
    else{
        myerrno = resp;
        return -1;
    }
    
}

int writeFile(char* pathname, char * dirname){

    if(socketfd == 0){
        myerrno = E_NOT_CON;
        return -1;
    }

    if(pathname == NULL){
        myerrno = E_INV_PTH;
        return -1;
    }

    char pth[MAX_PATH], *buf;
    strncpy(pth, pathname, MAX_PATH);
    pth[MAX_PATH-1] = '\0';
    int reqType = WRITE_F, resp = 0;
    FILE * inFile;

    if((inFile = fopen(pth, "rb")) == NULL){
        myerrno = errno;
        fprintf(stderr,"impossibile aprire file\n");
        return -1;
    }
 
    // leggo il file
    int size = 0;

    fseek(inFile, 0, SEEK_END);
    size = ftell(inFile);
    fseek(inFile, 0, SEEK_SET);
    EXIT_ON(buf = malloc(size), == NULL);
    if( fread(buf, 1, size, inFile) != size){
        fprintf(stderr, "impossibile leggere il file\n");
        myerrno = errno;
        free(buf);
        return -1;
    }
    
    fclose(inFile);

    if(writen(socketfd, &reqType, sizeof(int)) != sizeof(int)){  // scrivo il tipo di richesta
        myerrno = errno;
        return -1;
    }
    if(writen(socketfd, &size, sizeof(int)) != sizeof(int)){  // scrivo la size
        myerrno = errno;
        return -1;
    }
    if(writen(socketfd, pth, MAX_PATH) != MAX_PATH){  // scrivo il path
        myerrno = errno;
        return -1;
    }
    if(writen(socketfd, buf, size) != size){  // scrivo il contenuto
        myerrno = errno;
        return -1;
    }
    free(buf);

    if(readn(socketfd, &resp, sizeof(int)) != sizeof(int)){  // leggo la risposta
        myerrno = errno;
        return -1;
    }
    if(resp == 0){
        return 0;
    }

    if(resp != 1){
        myerrno = resp;
        return -1;
    }
    // lettura file di risposta
    
    if(resp == 1){ // devo leggere N file: size path cont
        FILE* outFile; char pthToSave[MAX_PATH];
        while(1){

            if(readn(socketfd, &size, sizeof(int)) != sizeof(int)){ myerrno = errno; return -1;} // leggo la size, se è -1 ho finito
            if(size == -1){
                break;
            }
            
            if(readn(socketfd, pth, MAX_PATH) != MAX_PATH){ myerrno = errno; return -1;} // leggo il path

            EXIT_ON(buf = malloc(size), == NULL); // alloco il buffer
            
            if(readn(socketfd, buf, size) != size){ myerrno = errno; free(buf); return -1;} // leggo il contenuto

            if(dirname != NULL){
                strcpy(pthToSave, dirname);
                strcat(pthToSave, pth + onlyName(pth) );
                
                if (( outFile = fopen(pthToSave, "wb")) == NULL){
                    myerrno = errno;
                    return -1;
                }
                if (( outFile = fopen(pthToSave, "wb")) == NULL){
                    myerrno = errno;
                    return -1;
                }
                
                if(fwrite(buf, 1, size, outFile) != size){  // scrivo contenuto su file
                    myerrno = errno;
                    free(buf);
                    fclose(outFile);
                    return -1;
                }
                fclose(outFile);
            }

            free(buf);
            

        }
    }

    if(readn(socketfd, &resp, sizeof(int)) != sizeof(int)){  // leggo la risposta
        myerrno = errno;
        return -1;
    }

    if(resp == 0){
        return 0;
    }
    else{
        myerrno = resp;
        return -1;
    }

}

int openFile(const char* pathname, int flags){

    if(socketfd == 0){
        myerrno = E_NOT_CON;
        return -1;
    }
    
    if(flags < 0 || flags > 3) {
        myerrno = E_INV_FLG;
        return -1;
    }

    char pth[MAX_PATH];
    strncpy(pth, pathname, MAX_PATH);
    pth[MAX_PATH-1] = '\0';
    int reqType = OPEN_F;
    int resp = 0;

    if(pth == NULL){
        myerrno = E_INV_PTH;
        return -1;
    }

    if(writen(socketfd, &reqType, sizeof(int)) != sizeof(int)){  // scrivo il tipo di richesta
        myerrno = errno;
        return -1;
    }

    if(writen(socketfd, &pth, MAX_PATH) != MAX_PATH){  // scrivo il path
        myerrno = errno;
        return -1;
    }

    if(writen(socketfd, &flags, sizeof(int)) != sizeof(int)){  // scrivo i flag
        myerrno = errno;
        return -1;
    }

    if(readn(socketfd, &resp, sizeof(int)) != sizeof(int)){  // leggo la risposta
        myerrno = errno;
        return -1;
    }

    if(resp == 0){
        return 0;
    }
    else if (resp != 1){
        myerrno = resp;
        return -1;
    }

    // c'è un file da salvare

    int size; void * buf;
    if(readn(socketfd, &size, sizeof(int)) != sizeof(int)){ myerrno = errno; return -1;} // leggo la size
    if(readn(socketfd, pth, MAX_PATH) != MAX_PATH){ myerrno = errno; return -1;} // leggo il path

    EXIT_ON(buf = malloc(size), == NULL); // alloco il buffer
            
    if(readn(socketfd, buf, size) != size){ myerrno = errno; free(buf); return -1;} // leggo il contenuto

    if(readn(socketfd, &resp, sizeof(int)) != sizeof(int)){ myerrno = errno; return -1;} // leggo la risposta di fine file

    if(resp != -1){     // è successo qualcosa di strano
        myerrno = E_BAD_RQ;
        return -1;
    }

    if(readn(socketfd, &resp, sizeof(int)) != sizeof(int)){ myerrno = errno; return -1;} // leggo la risposta finale 

    if(resp != 0){     // è successo qualcosa di strano
        myerrno = resp;
        return -1;
    }
    else{
        return 0;
    }
}


int openConnection(const char* sockname , int msec, const struct timespec abstime){
    
    if (sockname == NULL || strnlen(sockname, UNIX_PATH_MAX) >= UNIX_PATH_MAX) {
        myerrno = E_INV_SCK;
        return -1;
    }
    strcpy(__sockname, sockname);
    struct sockaddr_un server_addr;
    socketfd = socket(AF_UNIX, SOCK_STREAM, 0);
    if(socketfd == -1) {
        myerrno = errno;
        return -1;
    }
    if (memset(&server_addr, 0, sizeof(server_addr)) == NULL) return -1;

    server_addr.sun_family = AF_UNIX;
    strcpy(server_addr.sun_path, sockname);

    struct timespec toWait, _abstime = abstime;
    ms2ts(&toWait, msec);

    while(_abstime.tv_nsec > 0 || _abstime.tv_sec > 0){
        if (connect(socketfd, (struct sockaddr *)&server_addr, sizeof(server_addr)) != 0) {
            perror("Tentativo di connessione fallito");
        }
        else{
            return 0;
        }
        nanosleep(&toWait, NULL);
        timespec_diff(&_abstime, &toWait, &_abstime);
    }

    myerrno = errno;
    return -1;

    return 0;

}
void timespec_diff(struct timespec *a, struct timespec *b, struct timespec *result) {
    result->tv_sec  = a->tv_sec  - b->tv_sec;
    result->tv_nsec = a->tv_nsec - b->tv_nsec;
    if (result->tv_nsec < 0) {
        --result->tv_sec;
        result->tv_nsec += 1000000000L;
    }
}

void ms2ts(struct timespec *ts, unsigned long ms){
ts->tv_sec = ms / 1000;
ts->tv_nsec = (ms % 1000) * 1000000;
}

void msleep(int msec){
    struct timespec toWait;
    ms2ts(&toWait, msec);
    nanosleep(&toWait, NULL);
}


int closeConnection(const char* sockname){

    if(socketfd == 0){
        myerrno = E_NOT_CON;
        return -1;
    }

    if (sockname == NULL || (strncmp(__sockname, sockname, UNIX_PATH_MAX) != 0)) {
        myerrno = E_INV_SCK;
        return -1;
    }
    close(socketfd);
    socketfd = 0;
    return 0;
}

int onlyName(char * str){ // ./ciao/pluto
    int n = 0, last = 0;
    while(n < strlen(str)){
        if(str[n] == '/') last = n;
        n++;
    }
    return last;
    
}

int readn(int fd, void *ptr, size_t n) {  
    size_t   nleft;
    ssize_t  nread;

    nleft = n;
    while (nleft > 0) {
        if((nread = read(fd, ptr, nleft)) < 0) {
        if (nleft == n) return -1; /* error, return -1 */
        else break; /* error, return amount read so far */
    } else if (nread == 0) break; /* EOF */
    
    nleft -= nread;
    ptr   = (void*)((char*)ptr + nread);
    }
    return(n - nleft); /* return >= 0 */
}

int writen(int fd, void *ptr, size_t n) {  
    size_t   nleft;
    ssize_t  nwritten;

    nleft = n;
    while (nleft > 0) {
        if((nwritten = write(fd, ptr, nleft)) < 0) {
        if (nleft == n) return -1; /* error, return -1 */
        else break; /* error, return amount written so far */
        } else if (nwritten == 0) break; 
        nleft -= nwritten;
        ptr   = (void*)((char*)ptr + nwritten);
    }
    return(n - nleft); /* return >= 0 */
}

void myperror(const char * str){
    if(myerrno >= 140){
        fprintf(stderr, "Error in \"%s\": ", str);

        switch (myerrno)
        {
        case E_INV_FLG:
            fprintf(stderr, "Invalid flags\n");
            break;
        case E_INV_PTH:
            fprintf(stderr, "Invalid path\n");
            break;
        case E_LOCK:
            fprintf(stderr, "File locked\n");
            break;
        case E_NOT_EX:
            fprintf(stderr, "File not exists\n");
            break;
        case E_ALR_EX:
            fprintf(stderr, "File already exists\n");
            break;
        case E_BAD_RQ:
            fprintf(stderr, "Invalid request\n");
            break;
        case E_ALR_LK:
            fprintf(stderr, "File already locked\n");
            break;
        case E_NO_SPACE:
            fprintf(stderr, "No enough space (in server memory)\n");
            break;
        case E_NOT_OPN:
            fprintf(stderr, "File not open\n");
            break;
        case E_INV_SCK:
            fprintf(stderr, "Invalid socket path\n");
            break;
        case E_NOT_CON:
            fprintf(stderr, "Not connected\n");
            break;
        default:
            fprintf(stderr, "Unkown error\n");
            break;
        }
        
    }
    else{
        perror(str);
    }
}<file_sep>/src/server.c

#include <myparser.h>
#include <myutil.h>
#include <mysharedqueue.h>
#include <myconnection.h>
#include <myhandler.h>
#include <pthread.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/select.h>
#include <sys/time.h>
#include <myfilesystem.h>

int pipeSigWriting; // from myhandler.h
FILE * logFile; // from myutil.h

void server_log(char * format, ... );
char * flgToStr(int flg);

typedef struct _worker_args{
    SharedQueue_t * q;
    int pipeWriting_fd;
    FileSystem_t * fs;
}WorkerArgs;


void * worker(void * args){
    
    worker_handler_installer();

    SharedQueue_t * q = ((WorkerArgs *)(args))->q;
    int pipeWriting_fd = ((WorkerArgs *)(args))->pipeWriting_fd;
    FileSystem_t * fs = ((WorkerArgs *)(args))->fs;
    
    while(1){
        
        int clientFd = SharedQueue_pop(q); // preleva un client dalla coda condivisa
        
        if(clientFd == -1) return 0; // il manager mi dice di terminare

        int requestType;

        if(read(clientFd, &requestType, sizeof(int)) <= 0 ){ // leggi la richesta oppure il client ha chiuso
            EXIT_ON(fs_request_manager(fs, clientFd, CLOSE_ALL), != 0);
            clientFd*=-1;
            EXIT_ON(write(pipeWriting_fd, &clientFd, sizeof(int)), != sizeof(int)); // il manager si occuperà di chiuderlo per evitare racecondition con i fd
            continue;
        }

        int result = fs_request_manager(fs, clientFd, requestType);
        
        // se è 0 vuol dire che ho terminato correttamente la richiesta e devo dire al manager di rimettermi in ascolto di quel fd
        // altrimenti vuol dire che il client ha chiuso inaspettatamente durante le comunicazioni e devo dire al manager di chiudere il fd
        
        if (result == 0){
            EXIT_ON(write(pipeWriting_fd, &clientFd, sizeof(int)), != sizeof(int));
        }
        else{
            EXIT_ON(fs_request_manager(fs, clientFd, CLOSE_ALL), != 0);
            clientFd*=-1; // il client ha avuto problemi e lo chiudo
            EXIT_ON(write(pipeWriting_fd, &clientFd, sizeof(int)), != sizeof(int));
        }
    }
}


int main(int argc, char ** argv){

    /* INIZIO installazione gestore segnali */
    
    handler_installer();

    /* FINE installazione gestore segnali */

    /* INIZIO configurazione dei parametri dal file config.txt e del file di log */

    if (argc < 2) EXIT_ON("errore parametri",);
    
    char * sck_name, *log_path; int max_num_file, max_dim_storage, num_thread_worker;

    parse(argv[1], &sck_name, &log_path,  &max_num_file,  &max_dim_storage,  &num_thread_worker);

    EXIT_ON(logFile = fopen(log_path, "w"), == NULL);

    server_log("Configurazione:\nsocket name:%s\nlog_path:%s\nmax_num_file:%d\nmax_dim_storage:%d\nnum_thread_worker:%d\n", 
            sck_name,log_path, max_num_file, max_dim_storage, num_thread_worker);
    
    /* FINE configurazione dei parametri dal file config.txt e del file di log */
    
    
    
    /* INIZIO preparazione della coda concorrente, della pipe e del fs */

    SharedQueue_t * ready_clients = init_SharedQueue();

    int pipefd[2], pipeReadig_fd, pipeWriting_fd;
    int pipefd2[2], pipeSigReading;

    EXIT_ON( pipe(pipefd), != 0);
    EXIT_ON( pipe(pipefd2), != 0);

    pipeReadig_fd = pipefd[0];
    pipeWriting_fd = pipefd[1];
    pipeSigReading = pipefd2[0];
    pipeSigWriting = pipefd2[1];    // dichiarata come globale in myhandler.h

    FileSystem_t * fs = init_FileSystem(max_num_file, max_dim_storage);

    /* FINE preaprazione della coda concorrente,della pipe e del fs */


    /* INIZIO generazione dei thread worker */
    
    pthread_t * tidArr;
    EXIT_ON( tidArr = malloc(sizeof(pthread_t) * num_thread_worker), == NULL);
    WorkerArgs args;
    
    args.pipeWriting_fd = pipeWriting_fd;
    args.q = ready_clients;
    args.fs = fs;

    for(int i=0; i<num_thread_worker; ++i){
        pthread_t
        ret;
	    EXIT_ON(pthread_create(&ret, NULL, worker, (void*)&args), != 0);
        tidArr[i] = ret;
    }


    /* FINE generazione dei thread worker */


    /* INIZIO gestione delle richeste */
    int socket_fd = init_server(sck_name);
    int activeClients = 0;
    fd_set tmpset, set;
    FD_ZERO(&tmpset);
    FD_ZERO(&set);
    FD_SET(socket_fd, &set);
    FD_SET(pipeSigReading, &set);
    FD_SET(pipeReadig_fd, &set);
    int fd_max = find_max(socket_fd, pipeReadig_fd, pipeWriting_fd, pipeSigReading, pipeSigWriting);
    fd_max++; // per sicurezza, perchè c'è anche da considerare il fd del file config
    int endMode=0;

    server_log("Server pronto");

    while(endMode==0 || activeClients > 0){  // finchè non è richiesta la terminazione o ci sono client attivi
        //fprintf(stderr, "\nendMode = %d, activeClients = %d, fd_max = %d\n", endMode, activeClients, fd_max);
        tmpset = set;        
        if( select(fd_max + 1, &tmpset, NULL, NULL, NULL) == -1) // attenzione all'arrivo del segnale
        { 
            server_log("Segnale %d ricevuto", errno); 
        }
         
        if(FD_ISSET(pipeSigReading, &tmpset)){  // è arrivato un segnale
            EXIT_ON(read(pipeSigReading, &endMode, sizeof(int)), != sizeof(int));
            
            if(endMode == 1) {
                FD_CLR(socket_fd, &set);   // terminazione lenta, non ascolto più il socket
                fd_max = updatemax(set, fd_max);
                server_log("Inizio terminazione lenta");
            }

            if(endMode == 2){   // terminazione veloce 
                
                for(int i=0; i<fd_max+1; i++){  // chiudo i client connessi (ma che non hanno richieste in corso)
                    if(FD_ISSET(i, &set) && (i != pipeReadig_fd) && (i != socket_fd) && (i != pipeSigReading)){
                        close(i);
                        FD_CLR(i, &set);
                    }
                }
                FD_CLR(socket_fd, &set); // non ascolto nuove richieste di connessione
                fd_max = updatemax(set, fd_max);
                activeClients = 0;
                server_log("Inizio terminazione veloce");
            }
            continue;
        }

        for (int i = 0; i< fd_max +1; i++){
            if(FD_ISSET(i, &tmpset)){
                
                if( i == socket_fd){     // è arrivata una nuova richesta di connessione
                    int newConnFd;
                    EXIT_ON(newConnFd = accept(socket_fd, NULL, NULL), == -1);
                    FD_SET(newConnFd, &set);
                    activeClients++;
                    if(newConnFd > fd_max) fd_max = newConnFd;
                    server_log("Nuova connessione con client %d", newConnFd);
                }
                else if(i == pipeReadig_fd){  // fd di ritorno dalla pipe
                    int returnedConnFd;
                    EXIT_ON(read(pipeReadig_fd, &returnedConnFd, sizeof(int)), != sizeof(int));
                    
                    if ((endMode == 0) || (endMode == 1)){  // devo continuare a servire i client connessi
                        if(returnedConnFd < 0){ //il client ha chiuso
                            activeClients--;
                            returnedConnFd*=-1;   
                            close(returnedConnFd);
                        }
                        else{   // il client ha terminato la richiesta correttamente
                            FD_SET(returnedConnFd, &set); // lo rimetto in ascolto
                            if(returnedConnFd > fd_max) fd_max = returnedConnFd;
                        }
                    }
                    else{   // sto terminando velocemente
                        
                        if(returnedConnFd < 0){ //il client ha chiuso
                            activeClients--;   
                            close(-1 * returnedConnFd);
                        }
                        else{   // il client ha terminato la richiesta correttamente
                            activeClients--;   
                            close(returnedConnFd);                        
                        }
                    } 
                }
                else{   // un client già conesso ha inviato una richiesta (oppure ha chiuso)
                    if (endMode != 2){  // non sto terminando velocemente
                        SharedQueue_push(ready_clients, i); // verrà gestito da un worker
                        FD_CLR(i, &set);
                        if (i == fd_max) fd_max = updatemax(set, fd_max);
                    }
                    else{   // sto terminando velocemente
                        close(i);
                        FD_CLR(i, &set);
                        if (i == fd_max) fd_max = updatemax(set, fd_max);
                        activeClients--;
                    }
                }
            }
        }
    }

    server_log("Uscito dal ciclo manager");
    statistiche(fs);    
    /* FINE gestione delle richieste */



    /* INIZIO chiusura thread */

    for (int i=0; i<num_thread_worker; i++){
        SharedQueue_push(ready_clients, -1);
    }

    for (int i= 0; i< num_thread_worker; i++){
        EXIT_ON(pthread_join(tidArr[i], NULL), == -1);
    }

    
    /* FINE chiusura thread */
    
    

    /* INIZIO operazioni di chiusura */

    // dealloca il fs con tutti i file
        
    close(pipeReadig_fd);
    close(pipeWriting_fd);
    close(pipeSigReading);
    close(pipeSigWriting);
    remove(sck_name);
    free(sck_name);
    
    free(log_path);
    free(tidArr);
    //free(args);
    
    free(ready_clients->set);
    pthread_mutex_destroy(&ready_clients->lock);
    pthread_cond_destroy(&ready_clients->full);
    pthread_cond_destroy(&ready_clients->empty);
    free(ready_clients);
    deinit_FileSystem(fs);
    server_log("Server terminato");
    fclose(logFile);
    /* FINE operazioni di chiusura */

    return 0;

}

void server_log(char * format, ... ){
    va_list arglist;
    va_start(arglist, format);
    vfprintf(logFile, format, arglist);
    fprintf(logFile, "\n");
    fflush(logFile);
    va_end(arglist);
}
<file_sep>/tests/test1.sh
#!/bin/bash
 
 
valgrind --leak-check=full ./server tests/config3.txt &
SERVER_PID=$!
export SERVER_PID
bash -c 'sleep 3 && kill -s SIGHUP ${SERVER_PID}' &
./client -p -t 200 -f mysock -W tests/files/test1,tests/files/test2
./client -p -t 200 -f mysock -d tests/fileLetti/ -R n=0
./client -p -t 200 -f mysock  -l tests/files/test1,tests/files/test2 -u tests/files/test1,tests/files/test2
./client -p -t 200 -f mysock  -c tests/files/test1,tests/files/test2 
sleep 1
exit 0<file_sep>/src/sharedqueue.c
#include <mysharedqueue.h>


SharedQueue_t * init_SharedQueue(){

    SharedQueue_t * q;

    EXIT_ON( q = (SharedQueue_t*)malloc(sizeof(SharedQueue_t)), == NULL);

    EXIT_ON( memset(q, 0, sizeof(SharedQueue_t)), == NULL);

    EXIT_ON(q->set = malloc(sizeof(int) * SHARED_QUEUE_MAX_DIM), == NULL);

    EXIT_ON(pthread_mutex_init(&q->lock, NULL), != 0);

    EXIT_ON(pthread_cond_init(&q->full, NULL), != 0);

    EXIT_ON(pthread_cond_init(&q->empty, NULL), != 0);

    q->start = 0;

    q->current_size = 0;

    return q;

}

void SharedQueue_push(SharedQueue_t * q, int fd_c){
    EXIT_ON(q, == NULL);

    EXIT_ON(pthread_mutex_lock(&q->lock), != 0);

    while(q->current_size >= SHARED_QUEUE_MAX_DIM){
        EXIT_ON(pthread_cond_wait(&q->full, &q->lock), != 0);
    }

    q->set[ (q->start + q->current_size) % SHARED_QUEUE_MAX_DIM] = fd_c;

    q->current_size++;

    EXIT_ON(pthread_cond_signal(&q->empty), != 0);

    EXIT_ON(pthread_mutex_unlock(&q->lock), != 0);
}

int SharedQueue_pop(SharedQueue_t * q){
    EXIT_ON(q, == NULL);

    EXIT_ON(pthread_mutex_lock(&q->lock), != 0);

    while(q->current_size <= 0){
        EXIT_ON(pthread_cond_wait(&q->empty, &q->lock), != 0);
    }

    int ret = q->set[ q->start % SHARED_QUEUE_MAX_DIM];

    q->start++;

    q->current_size--;

    q->start = q->start % SHARED_QUEUE_MAX_DIM;

    EXIT_ON(pthread_cond_signal(&q->full), != 0);

    EXIT_ON(pthread_mutex_unlock(&q->lock), != 0);

    return ret;
}<file_sep>/clean.sh
#!/bin/bash

rm ./obj/*.o
rm ./tests/fileLetti/*
rm ./tests/fileEvict/*
rm ./tests/log*.txt
rm ./server ./client
rm ./lib/*.a


exit 0<file_sep>/includes/myserverApi.h
#ifndef _MYSERVERAPI_H
#define _MYSERVERAPI_H

#define _POSIX_C_SOURCE 200809L 
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <myutil.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <myutil.h>
#include <sys/select.h>
#include <string.h>
#include <stdio.h>

#define END_RET_FILE -1
#define SUCCESS 0
#define RET_FILE 1  
#define E_INV_FLG 140 //internal
#define E_INV_PTH 141 //internal
#define E_LOCK 142    // from server
#define E_NOT_EX 143  // from server
#define E_ALR_EX 144      // from server
#define E_BAD_RQ 145  // from server
#define E_ALR_LK 146
#define E_NO_SPACE 147
#define E_NOT_OPN 148 
#define E_INV_SCK 149 //internal
#define E_NOT_CON 150


#define O_CREATE 1
#define O_LOCK 2

#define MAX_PATH 1024
#define UNIX_PATH_MAX 108
#define BUF_SIZE 2048


#define OPEN_F 1
#define READ_F 2
#define READ_N_F 3
#define WRITE_F 4
#define APPEND_T_F 5
#define LOCK_F 6
#define UNLOCK_F 7
#define CLOSE_F 8
#define REMOVE_F 9

int openConnection(const char* sockname, int msec, const struct timespec abstime);
int closeConnection(const char* sockname);
int openFile(const char* pathname, int flags);
int writeFile(char* pathname, char * dirname);
int appendToFile(char * pathname, void * buf, size_t size, char * dirname);
int lockFile(char * pathname);
int unlockFile(char * pathname);
int closeFile(char * pathname);
int removeFile(char * pathname);
int readFile(char * pathname, void ** buf, size_t * size);
void myperror(const char * str);
int readNFiles(int n, char * dirname);
int onlyName(char * str);
void lock_file(char * str);
void unlock_file(char * str);
void remove_file(char * str);
int readn(int fd, void *ptr, size_t n);
int writen(int fd, void *ptr, size_t n);
void ms2ts(struct timespec *ts, unsigned long ms);
void timespec_diff(struct timespec *a, struct timespec *b, struct timespec *result);
void msleep(int msec);

#define PIE(exp) \
        if( (exp) == -1){ \
            myperror(#exp);\
        }\
    

#endif /*_MYSERVERAPI_H*/ <file_sep>/tests/test3.sh
#!/bin/bash

./server tests/config3.txt &
SERVER_PID=$!
export SERVER_PID
bash -c 'sleep 5 && kill -s SIGINT ${SERVER_PID}' &

pids=()
for i in {1..10}; do
    bash -c './tests/test3support.sh' &
    pids+=($!)
    sleep 0.1
done

sleep 3

for i in "${pids[@]}"; do
    kill -9 ${i}
    wait ${i}
done

wait ${SERVER_PID}
exit 0<file_sep>/includes/myfilesystem.h
#ifndef _MYFILESYSTEM_H
#define _MYFILESYSTEM_H
#include <stdio.h>
#include <pthread.h>
#include <string.h>
#include <myutil.h>
#include <mylinkedlist.h>
#include <unistd.h>
#include <assert.h>

#define OPEN_F 1
#define READ_F 2
#define READ_N_F 3
#define WRITE_F 4
#define APPEND_T_F 5
#define LOCK_F 6
#define UNLOCK_F 7
#define CLOSE_F 8
#define REMOVE_F 9
#define CLOSE_ALL 10

//messages server-client
#define END_RET_FILE -1
#define SUCCESS 0
#define RET_FILE 1  
#define E_INV_FLG 140 //internal
#define E_INV_PTH 141 //internal
#define E_LOCK 142    // from server
#define E_NOT_EX 143  // from server
#define E_ALR_EX 144      // from server
#define E_BAD_RQ 145  // from server
#define E_ALR_LK 146
#define E_NO_SPACE 147
#define E_NOT_OPN 148 
#define E_INV_SCK 149 //internal
#define E_NOT_CON 150

#define MAX_PATH 1024
#define ENDVAL "_end"

#define F_SIZE 1
typedef struct File_t{
    char path[MAX_PATH+1];
    int size;
    void * cont; //contenuto del file 

    struct File_t * prev;
    struct File_t * next;

    List_t* openedBy;   // lista di client che hanno il file aperto 

    int lockedBy;   // client che ha fatto la lock 

    pthread_mutex_t f_mutex; //accesso in mutua esclusione alle variabili condivise
    pthread_mutex_t f_order; //utilizzata per regolare l'accesso fair
    pthread_cond_t f_go;    //sospensione sia dei lettori che degli scrittori
    int f_activeReaders;
    int f_activeWriters;
}File_t;

typedef struct FileSystem_t{
    int actSize;    //dimensione attuale
    int actNumFile; //numero di file attuali
    int maxSize;    //massima dimensione possibile
    int maxNumFile; //massimo numero file possibile
    int maxRSize;   //massima dimensione raggiunta
    int maxRNumFile;//massimo numero di file raggiunto
    int evictCount; // numero di esecuzioni algoritmo cache

    pthread_mutex_t fs_lock;

    File_t * firstFile;
    File_t * lastFile;

}FileSystem_t;


int fs_request_manager(FileSystem_t * fs, int clientFd, int requestType);
FileSystem_t * init_FileSystem(int maxNumFile, int maxSize);
int openFile_handler(FileSystem_t * fs, int clientFd, char * path, int flags);
File_t * searchFile(FileSystem_t * fs, char * path);
int writen(int fd, void *ptr, size_t n);
int readn(int fd, void *ptr, size_t n);
File_t * init_File(char* path, int clientFd);
void printFs(FileSystem_t * fs);
int writeFile_handler(FileSystem_t * fs, int clientFd, char* path, int size, char * buf);
void f_startWrite(File_t * file);
void f_doneWrite(File_t * file);
void deleteFile(File_t * tmp);
File_t * cacheEvict(FileSystem_t * fs, File_t * f, int flag);
void f_startRead(File_t * file);
void f_doneRead(File_t * file);
void deinit_FileSystem(FileSystem_t * fs);
int appendToFile_handler(FileSystem_t * fs,int clientFd, char * path, char * buf, int size);
int lockFile_handler(FileSystem_t * fs, int clientFd, char * path);
int closeAll_handler(FileSystem_t * fs, int clientFd);
int unlockFile_handler(FileSystem_t * fs, int clientFd, char * path);
int closeFile_handler(FileSystem_t * fs, int clientFd, char * path);
int removeFile_handler(FileSystem_t * fs, int clientFd, char * path);
int readFile_handler(FileSystem_t * fs, int clientFd, char * path);
int readNFiles_handler(FileSystem_t * fs, int clientFd, int numFile);
void statistiche(FileSystem_t * fs);    


#endif /* _MYFILESYSTEM_H */<file_sep>/includes/myutil.h


#ifndef _MY_UTIL_H
#define _MY_UTIL_H
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdarg.h>

extern FILE * logFile;
void server_log(char * format, ... );

#define EXIT_ON( arg1, arg2) \
    if ((arg1) arg2){    \
        perror(#arg1);   \
        exit(-1);   \
    }
    
#endif /*_MY_UTIL_H*/<file_sep>/src/parser.c

#include <myparser.h>


int parse(char* configpath, char** socket_name, char ** logpath, int * max_num_file, int * max_dim_storage, int * num_thread_worker){

    FILE * fptr;
    EXIT_ON( fptr = fopen(configpath, "r"), ==  NULL);
    
    #ifdef DEBUG
    printf("success open file \n");
    #endif

    char * key, * value;

    EXIT_ON( key = malloc(PARSE_BUF_DIM), ==   NULL);
    EXIT_ON( value = malloc(PARSE_BUF_DIM), ==  NULL);

    while ( (memset(key,'\0', PARSE_BUF_DIM) != NULL) && (fscanf(fptr, "%[^=]", key) == 1 )){

        fgetc(fptr); // consuma il carattere '='
        key[strnlen(key, PARSE_BUF_DIM)] = '\0';
        EXIT_ON(memset(value, '\0', PARSE_BUF_DIM), == NULL);
        if (fscanf(fptr, "%[^;]", value) != 1 ) break;
        fgetc(fptr);  // consuma il carattere ';'
        value[strnlen(value, PARSE_BUF_DIM)] = '\0';
        (fgetc(fptr)); // consuma il carattere '\n' (se non è presente prenderò EOF)

        #ifdef DEBUG
        printf("key:%s: valore:%s:\n", key, value);
        #endif

        // gestisco i vari casi

        if (strncmp(key, ARG_1, strnlen(ARG_1, PARSE_BUF_DIM)) == 0){ // gestisco socket_name  
            EXIT_ON(*socket_name = malloc(PARSE_BUF_DIM), == NULL);
            EXIT_ON(memset(*socket_name, '\0', PARSE_BUF_DIM), == NULL);
            EXIT_ON(strncpy(*socket_name, value, PARSE_BUF_DIM), == NULL);
            continue;
        }

        if (strncmp(key, ARG_2, strnlen(ARG_2, PARSE_BUF_DIM)) == 0){ // gestisco max_num_file
            *max_num_file = atoi(value);
            continue;
        }

        if (strncmp(key, ARG_3, strnlen(ARG_3, PARSE_BUF_DIM)) == 0){ // gestisco max_dim_storage
            *max_dim_storage = atoi(value);
            continue;
        }

        if (strncmp(key, ARG_4, strnlen(ARG_4, PARSE_BUF_DIM)) == 0){ // gestisco num_thread_worker 
            *num_thread_worker = atoi(value);
            continue;
        }
        if (strncmp(key, ARG_5, strnlen(ARG_1, PARSE_BUF_DIM)) == 0){ // gestisco log_file_path  
            EXIT_ON(*logpath = malloc(PARSE_BUF_DIM), == NULL);
            EXIT_ON(memset(*logpath, '\0', PARSE_BUF_DIM), == NULL);
            EXIT_ON(strncpy(*logpath, value, PARSE_BUF_DIM), == NULL);
            continue;
        }

        printf("parametro di configurazione non riconosciuto\n");
        return -1;
        
    }

    if(feof(fptr)){    // uscito perchè fine del file 
        free(key);
        free(value);
        fclose(fptr);
        #ifdef DEBUG
        printf("parsing terminato correttamente\n");
        #endif
        return 0;
    }
    else{
        perror("lettura config.txt");
        exit(-1);
    }


}

<file_sep>/includes/myhandler.h
#ifndef _MY_HANDLER_H
#define _MY_HANDLER_H
#define _POSIX_C_SOURCE 200809L
#include <signal.h>
#include <myutil.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>


extern int pipeSigWriting;

void ter_handler(int sig);

void handler_installer();
void worker_handler_installer();
void print_handler(int sig);

#endif /* _MY_HANDLER_H */<file_sep>/src/client.c
#include <myserverApi.h>

#include <sys/stat.h>
#include <sys/types.h>
#include <dirent.h>
#include <time.h>


#define HELP "stringa di aiuto"

extern int socketfd, myerrno;
extern char __sockname[UNIX_PATH_MAX];
char returnDir[MAX_PATH] = "";
char readDir[MAX_PATH] = "";
int delay = 0, foundp = 0, r;

void listfile(const char nomedir[], int * n);
int isdot(const char dir[]) ;
int is_comand(char * str);
char to_comand(char * str);
void send_dir(char * str);
void send_file(char str[]);
void read_file(char * str);
void read_n_file(char * str);
void client_log(char * format, ... );

int main(int argc, char ** argv){

    if(argc == 1){return 0;}

    int foundf = 0, i = 1, foundW = 0,  
        foundD = 0, foundr = 0, foundw = 0, foundd = 0, foundR =0;
    char comand;

    while (i < argc){   // primo ciclo di controllo
        if(is_comand(argv[i])){
            comand = to_comand(argv[i]);
            switch (comand)
            {
            case 'h':;{
                printf(HELP); 
                return 0;
                break;
            }
            case 'p':;{
                foundp++;
                break;
            }
            case 'f':;{
                foundf++;
                if( argv[i+1] == NULL || is_comand(argv[i+1])){
                    fprintf(stderr, "opzione -f non usata correttamente\n");
                    return 0;
                }
                break;
            }
            case 'w':;{
                foundw = 1;
                if( argv[i+1] == NULL || is_comand(argv[i+1])){
                    fprintf(stderr, "opzione -w non usata correttamente\n");
                    return 0;
                }
                break;
            }
            case 'W':;{
                foundW = 1;
                if( argv[i+1] == NULL || is_comand(argv[i+1])){
                    fprintf(stderr, "opzione -W non usata correttamente\n");
                    return 0;
                }
                break;
            }
            case 'D':;{ 
                foundD = 1;
                if( argv[i+1] == NULL || is_comand(argv[i+1])){
                    fprintf(stderr, "opzione -D non usata correttamente\n");
                    return 0;
                }
                break;
            }
            case 'r':;{
                foundr = 1;
                if( argv[i+1] == NULL || is_comand(argv[i+1])){
                    fprintf(stderr, "opzione -r non usata correttamente\n");
                    return 0;
                }
                break;
            }
            case 'd':;{
                foundd = 1;
                if( argv[i+1] == NULL || is_comand(argv[i+1])){
                    fprintf(stderr, "opzione -d non usata correttamente\n");
                    return 0;
                }
                break;
            }
            case 'R':;{
                foundR = 1;
                break;
            }
            case 'l':;{
                if( argv[i+1] == NULL || is_comand(argv[i+1])){
                    fprintf(stderr, "opzione -l non usata correttamente\n");
                    return 0;
                }
                break;
            }
            case 'u':;{
                if( argv[i+1] == NULL || is_comand(argv[i+1])){
                    fprintf(stderr, "opzione -u non usata correttamente\n");
                    return 0;
                }
                break;
            }
            case 'c':;{
                if( argv[i+1] == NULL || is_comand(argv[i+1])){
                    fprintf(stderr, "opzione -c non usata correttamente\n");
                    return 0;
                }
                break;
            }
            case 't':;{
                if( argv[i+1] == NULL || is_comand(argv[i+1])){
                    fprintf(stderr, "opzione -t non usata correttamente\n");
                    return 0;
                }
                delay = atoi(argv[i+1]);
                break;
            }
            }
        }
        i++;
    }

    if(foundD == 1 && (foundW + foundw) <= 0){
        fprintf(stderr, "opzione -D non usata correttamente\n");
        return 0;
    }

    if(foundd == 1 && (foundR + foundr) <= 0){
        fprintf(stderr, "opzione -d non usata correttamente\n");
        return 0;
    }

    if(foundp > 1){
        fprintf(stderr, "opzione -p non usata correttamente\n");
        return 0;
    }
    
    if(foundf != 1){
        fprintf(stderr, "opzione -f non usata correttamente\n");
        return 0;
    }
    if(delay < 0){
        fprintf(stderr, "opzione -t non usata correttamente\n");
        return 0;
    }
    
    
    i = 1;
    while (i < argc){
        
        comand = to_comand(argv[i]);
        switch (comand)
        {
        
            case 'f':;{
                struct timespec abstime;
                abstime.tv_sec = 5;     // provo per 3 secondi (dando il tempo al server di avviarsi)
                abstime.tv_nsec = 0; 
                PIE(openConnection(argv[i+1], 500, abstime));   // ogni 500 ms
                client_log("Apro la connessione con il socket: %s", argv[i+1]);
                i++; // devo saltare un ulteriore parametro
                msleep(delay);
                break;
            }

            case 'w':;{   
                send_dir(argv[i+1]);
                i++;
                msleep(delay);
                break;
            }

            case 'W':;{
                send_file(argv[i+1]);
                i++;
                msleep(delay);
                break;
            }

            case 'D':;{ // testare questa opzione
                strcpy(returnDir, argv[i+1]);
                client_log("Cartella di salvataggio della cache aggiornata in: %s", returnDir);
                i++;
                break;
            }

            case 'r':;{
                read_file(argv[i+1]);
                i++;
                msleep(delay);
                break;
            }
            case 'd':;{
                strcpy(readDir, argv[i+1]);
                client_log("Cartella di lettura aggiornata in: %s", readDir);
                break;
            }
            case 'R':;{
                read_n_file(argv[i+1]);
                msleep(delay);
                break;
            }
            case 'l':;{
                lock_file(argv[i+1]);
                i++;
                msleep(delay);
                break;
            }
            case 'u':;{
                unlock_file(argv[i+1]);
                i++;
                msleep(delay);
                break;
            }
            case 'c':;{
                remove_file(argv[i+1]);
                i++;
                msleep(delay);
                break;
            }
        }   
            
        i++;
    }
    client_log("Chiudo la connessione con il server e termino");
    PIE(closeConnection(__sockname));
    
    return 0;

}
void remove_file(char * str){

    char file[MAX_PATH];
    int pos =0;

    while(1){
        
        if(str[pos] == '\0'){
            strncpy(file, str, pos +1);
            PIE(r = openFile(file, 0));
            PIE(r = removeFile(file));
            client_log("Rimosso il file %s con esito %d", file, r);
            return;
        }
        else if(str[pos] == ','){
            str[pos] = '\0';
            strncpy(file, str, pos +1);
            PIE(r = openFile(file, 0));
            PIE(r = removeFile(file));
            client_log("Rimosso il file %s con esito %d", file, r);
            str = str + pos + 1;
            pos = 0;
        }
        else{
            pos++;
        }
    }

}
void unlock_file(char * str){

    char file[MAX_PATH];
    int pos =0;

    while(1){
        
        if(str[pos] == '\0'){
            strncpy(file, str, pos +1);
            PIE(r = openFile(file, 0));
            PIE(r = unlockFile(file));
            client_log("Unlock del file %s con esito %d", file, r);
            return;
        }
        else if(str[pos] == ','){
            str[pos] = '\0';
            strncpy(file, str, pos +1);
            PIE(r = openFile(file, 0));
            PIE(r = unlockFile(file));
            client_log("Unlock del file %s con esito %d", file, r);
            str = str + pos + 1;
            pos = 0;
        }
        else{
            pos++;
        }
    }

}

void lock_file(char * str){

    char file[MAX_PATH];
    int pos =0;

    while(1){
        
        if(str[pos] == '\0'){
            strncpy(file, str, pos +1);
            PIE(r = openFile(file, 0));
            PIE(r = lockFile(file));
            client_log("Lock del file %s con esito %d", file, r);
            return;
        }
        else if(str[pos] == ','){
            str[pos] = '\0';
            strncpy(file, str, pos +1);
            PIE(r = openFile(file, 0));
            PIE(r = lockFile(file));
            client_log("Lock del file %s con esito %d", file, r);
            str = str + pos + 1;
            pos = 0;
        }
        else{
            pos++;
        }
    }

}

void read_n_file(char * str){

    int n;
    if(str == NULL || is_comand(str)) n=0; // devo leggere tutti i file
    else{
        str += 2;
        n = atoi(str);
    }

    if(strcmp(readDir, "") == 0){
        fprintf(stderr, "retDir non inizializzata\n");
        return;
    }

    PIE(readNFiles(n, readDir));
    client_log("Lettura di %d files con esito %d", n, r);

}

void read_file(char * str){
    
    char returnPath[MAX_PATH], file[MAX_PATH];
    int pos =0;

    while(1){
        void * buf = NULL; size_t size; FILE * fileptr;
        int r;
        
        if(str[pos] == '\0'){
            strncpy(file, str, pos +1);
            
            PIE(r = readFile(file, &buf, &size)); // legge dal server
            client_log("Lettura del file %s di %d byte con esito %d", file,size, r);
            if(r == -1) {return;}

            if(strcmp(readDir, "") != 0){   // se ho specificato una cartella in cui salvare i file letti
                strcpy(returnPath, readDir);
                strcat(returnPath, (file+onlyName(file) + 1));
                EXIT_ON( fileptr = fopen(returnPath, "wb"), == NULL);
                EXIT_ON(fwrite(buf, 1, size, fileptr), != size);
                client_log("Salvataggio del file %s nella cartella %s", file + onlyName(file) +1, readDir);
                free(buf);
            }

            return;
        }
        else if(str[pos] == ','){
            str[pos] = '\0';
            strncpy(file, str, pos +1);
            
            PIE(r = readFile(file, &buf, &size)); // legge dal server
            client_log("Lettura del file %s di %d byte con esito %d", file,size, r);

            if(strcmp(readDir, "") != 0){
                strcpy(returnPath, readDir);
                strcat(returnPath, (file+onlyName(file) + 1));
                EXIT_ON( fileptr = fopen(returnPath, "wb"), == NULL);
                EXIT_ON(fwrite(buf, 1, size, fileptr), != size);
                client_log("Salvataggio del file %s nella cartella %s", file + onlyName(file) +1, readDir);
                free(buf);
            }

            str = str + pos + 1;
            pos = 0;
        }
        else{
            pos++;
        }
    }
}


void send_file(char str[]){ 

    char file[MAX_PATH];
    int pos =0;

    while(1){
        
        if(str[pos] == '\0'){
            strncpy(file, str, pos +1);
            PIE(r = openFile(file, O_CREATE | O_LOCK));
            client_log("Apertura del file %s con flag %d, esito %d", file, O_CREATE | O_LOCK, r);
            if(strcmp(returnDir, "") == 0){ // cartella di ritorno non specificata
                PIE(r = writeFile(file, NULL));
                client_log("Scrittura del file %s nel server senza salvare i file evicted, esito: %d", file, r);
            }
            else{
                PIE(r = writeFile(file, returnDir));
                client_log("Scrittura del file %s nel server con salvataggio dei file evicted in %s, esito: %d", file, returnDir, r);
            }
            
            return;
        }
        else if(str[pos] == ','){
            str[pos] = '\0';
            strncpy(file, str, pos +1);
            PIE(openFile(file, O_CREATE | O_LOCK));
            if(strcmp(returnDir, "") == 0){ // cartella di ritorno non specificata
                PIE(r = writeFile(file, NULL));
                client_log("Scrittura del file %s nel server senza salvare i file evicted, esito: %d", file, r);
            }
            else{
                PIE(r = writeFile(file, returnDir));
                client_log("Scrittura del file %s nel server con salvataggio dei file evicted in %s, esito: %d", file, returnDir, r);
            }
            str = str + pos + 1;
            pos = 0;
        }
        else{
            pos++;
        }
    }

}

void listfile(const char nomedir[], int * n) {
    // controllo che il parametro sia una directory
    struct stat statbuf;
    
    EXIT_ON(stat(nomedir,&statbuf),!= 0);

    DIR * dir;
    
    if ((dir=opendir(nomedir)) == NULL) {
        perror("opendir");
        printf("Errore aprendo la directory %s\n", nomedir);
        return;
    } 
    
    struct dirent *file;
    
    while(((errno=0, file = readdir(dir)) != NULL) && *n != 0 ) {
        struct stat statbuf;
        char filename[MAX_PATH]; 
        int len1 = strlen(nomedir);
        int len2 = strlen(file->d_name);
        if ((len1+len2+2)>MAX_PATH) {
            fprintf(stderr, "ERRORE: MAXFILENAME troppo piccolo\n");
            exit(EXIT_FAILURE);
        }	    
        strncpy(filename,nomedir,      MAX_PATH-1);
        strncat(filename,"/",          MAX_PATH-1);
        strncat(filename,file->d_name, MAX_PATH-1);
        
        if (stat(filename, &statbuf)==-1) {
            perror("eseguendo la stat");
            printf("Errore nel file %s\n", filename);
            return;
        }
        if(S_ISDIR(statbuf.st_mode)) {
            if ( !isdot(filename) ) 
                listfile(filename, n);
        } 
        else {

            (*n)--;
            PIE(openFile(filename, O_CREATE | O_LOCK));   // creo il file nel server
            if(strcmp(returnDir, "") == 0){ // cartella di ritorno non specificata
                PIE(r = writeFile(filename, NULL));
                client_log("Scrittura del file %s nel server senza salvare i file evicted, esito: %d", filename, r);
            }
            else{
                PIE(r = writeFile(filename, returnDir));
                client_log("Scrittura del file %s nel server con salvataggio dei file evicted in %s, esito: %d", filename, returnDir, r);
            }
        }
        
    }
    if (errno != 0) perror("readdir");
    closedir(dir);
    
}

int isdot(const char dir[]) {
  int l = strlen(dir);
  
  if ( (l>0 && dir[l-1] == '.') ) return 1;
  return 0;
}

int is_comand(char * str){
    if((str != NULL) && (str[0] == '-') && ((str + 1) != NULL)  && (str[2] == '\0') ){
        return 1;
    }
    return 0;
}

char to_comand(char * str){
    return str[1];
}

void send_dir(char * str){

    if(strlen(str) > MAX_PATH -1){printf("error"); return;}

    int n = 0, virpos = 0;
    char dirname[MAX_PATH]; 
    
    while (str[virpos] != '\0' && str[virpos] != ','){ // finche arrivo alla fine o ad una virgola
        virpos++;
    }
    strncpy(dirname,str, virpos);
    dirname[virpos] = '\0'; // dirname è ok
    if(str[virpos] == ','){    //se sono arrivato alla virgola
        str = str + virpos + 3;    // salto n=
        if(str != NULL){ 
            n = atoi(str);
        }
        else{
            printf("error in number of files");
            printf(HELP);
            return;
        }
    }

    if (n<=0) n=-1;

    // navigare i file nelle cartelle e inviarli al server

    // controllo che l'argomaneto sia una directory
    struct stat statbuf;
    if (stat(dirname,&statbuf)!= 0 || !S_ISDIR(statbuf.st_mode)){
	    fprintf(stderr, " \"%s\" non e' una directory\n", dirname);
        printf(HELP);
        return;
    }    

    listfile(dirname, &n);

}


void client_log(char * format, ... ){
    if(foundp == 0) return;
    va_list arglist;
    va_start(arglist, format);
    vfprintf(stderr, format, arglist);
    fprintf(stderr, "\n");
    va_end(arglist);
}<file_sep>/includes/mysharedqueue.h

#ifndef _MY_SHARED_QUEUE_H
#define _MY_SHARED_QUEUE_H

#include <myutil.h>
#include <pthread.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

#define SHARED_QUEUE_MAX_DIM 2048

typedef struct _sq{
    int *set;
    int start;
    int current_size;
    pthread_mutex_t lock;
    pthread_cond_t full;
    pthread_cond_t empty;
}SharedQueue_t;

SharedQueue_t * init_SharedQueue();

void SharedQueue_push(SharedQueue_t * q, int fd_c);

int SharedQueue_pop(SharedQueue_t * q);

#endif /*_MY_SHARED_QUEUE_H */<file_sep>/tests/test2.sh
#!/bin/bash


./server ./tests/config2.txt &
SERVER_PID=$!
./client -p -t 200 -f mysock -D tests/fileEvict -w tests/files 

kill -s SIGINT ${SERVER_PID}

sleep 1
exit 0<file_sep>/includes/myparser.h
#ifndef _MY_PARSE_H
#define _MY_PARSE_H

#define _POSIX_C_SOURCE 200809L 
#include <stdlib.h>
#include <stdio.h>
#include <myutil.h>

#include <string.h>

#define PARSE_BUF_DIM 64


#define ARG_1 "socket_name"
#define ARG_2 "max_num_file"
#define ARG_3 "max_dim_storage"
#define ARG_4 "num_thread_worker"
#define ARG_5 "log_file_path"
/*
per aggiungere un altro parametro:
- aggiungere una define con il nome del parametro
- aggiungere alla firma della funzione parse
- aggiungere nel corpo di parse un blocco per gestire quella determinata coppia <key, value>

*/

int parse(char* configpath,char**  logpath, char ** socket_name, int * max_num_file, int * max_dim_storage, int * num_thread_worker);

#endif /* _MY_PARSE_H */<file_sep>/src/connection.c
#include <myconnection.h>

int updatemax(fd_set set, int fdmax) {
    for(int i=(fdmax);i>=0;--i)
	if (FD_ISSET(i, &set)) return i;
    EXIT_ON("error in updatemax", == NULL);
    return -1;
}

int init_server(char * sck_name){
    EXIT_ON(strnlen(sck_name, UNIX_PATH_MAX) >= UNIX_PATH_MAX,  != 0);
    sck_name[strnlen(sck_name, UNIX_PATH_MAX-1)] = '\0';
    int socket_fd;
    EXIT_ON(socket_fd = socket(AF_UNIX, SOCK_STREAM, 0), == -1);
    struct sockaddr_un server_addr;
    EXIT_ON(memset(&server_addr, 0, sizeof(struct sockaddr_un)), == NULL);
    server_addr.sun_family = AF_UNIX;
    EXIT_ON(strncpy(server_addr.sun_path, sck_name, UNIX_PATH_MAX-1),  == NULL);
    EXIT_ON(bind(socket_fd, (struct sockaddr *)&server_addr, sizeof(struct sockaddr_un)), != 0);
    EXIT_ON(listen(socket_fd, MAX_CONNECTION_QUEUE), != 0);
    return socket_fd; 
}

int find_max(int a, int b , int c, int d, int e){
    int max = 0;
    if(a>max) max = a;
    if(b>max) max = b;
    if(c>max) max = c;
    if(d>max) max = d;
    if(e>max) max = e;
    return max;

}
<file_sep>/src/filesystem.c

#include <myfilesystem.h>

int fs_request_manager(FileSystem_t * fs, int clientFd, int requestType){

    
    switch (requestType){
        
        case OPEN_F:;{
            
            int flags;  
            char path[MAX_PATH]; 
            
            if (readn(clientFd, path, MAX_PATH) != MAX_PATH) return -1;    // path
            if (readn(clientFd, &flags, sizeof(int)) != sizeof(int)) return -1; // flags

            return openFile_handler(fs, clientFd, path, flags);
            
        }
        break;

        case READ_F:;{
            char path[MAX_PATH];
            if (readn(clientFd, path, MAX_PATH) != MAX_PATH) return -1;  // path

            return readFile_handler(fs, clientFd, path);
        }

        break;

        case READ_N_F:;{
            int numFile;
            if (readn(clientFd, &numFile, sizeof(int)) != sizeof(int)) return -1; // lunghezza file

            return readNFiles_handler(fs, clientFd, numFile);
        }

        break;

        case WRITE_F:;{
            int size;
            char path[MAX_PATH], * buf;
            
            if (readn(clientFd, &size, sizeof(int)) != sizeof(int)) return -1; // lunghezza file
            if (readn(clientFd, path, MAX_PATH) != MAX_PATH) return -1;  // path
            EXIT_ON(buf = malloc(size), == NULL);
            if (readn(clientFd, buf, size) != size){free(buf); return -1;} // contenuto

            //scrive nel fs il file con path e contenuto buf, rimanda i file espulsi al client
            return writeFile_handler(fs, clientFd, path, size, buf);

        }
        break;

        case APPEND_T_F:;{
            int size;
            char path[MAX_PATH], * buf;
            if (readn(clientFd, &size, sizeof(int)) != sizeof(int)) return -1; // lunghezza buffer
            if (readn(clientFd, path, MAX_PATH) != MAX_PATH) return -1;  // path
            EXIT_ON(buf = malloc(size), == NULL);
            if (readn(clientFd, buf, size) != size){free(buf); return -1;} // buffer
            
            return appendToFile_handler(fs,clientFd, path, buf, size);
        }

        break;

        case LOCK_F:;{
            char path[MAX_PATH];
            if (readn(clientFd, path, MAX_PATH) != MAX_PATH) return -1;  // path

            return lockFile_handler(fs, clientFd, path);
        }

        break;

        case UNLOCK_F:;{
            char path[MAX_PATH];
            if (readn(clientFd, path, MAX_PATH) != MAX_PATH) return -1;  // path

            return unlockFile_handler(fs, clientFd, path);
        }

        break;

        case CLOSE_F:;{
            char path[MAX_PATH];
            if (readn(clientFd, path, MAX_PATH) != MAX_PATH) return -1;  // path

            return closeFile_handler(fs, clientFd, path);
        }

        break;

        case REMOVE_F:;{
            char path[MAX_PATH];
            if (readn(clientFd, path, MAX_PATH) != MAX_PATH) return -1;  // path

            return removeFile_handler(fs, clientFd, path);
        }

        break;

        case CLOSE_ALL:;{
            return closeAll_handler(fs, clientFd);
        }

        default:
            fprintf(stderr, "Richesta non disponibile\n");
            int retVal = E_BAD_RQ;
            if (writen(clientFd, &retVal, sizeof(int)) != sizeof(int)){
                return -1;
            }

        break;

    }
    return -1;

}

int openFile_handler(FileSystem_t * fs, int clientFd, char * path, int flags){
    
    EXIT_ON(pthread_mutex_lock(&fs->fs_lock), != 0);    // prendo lock fs

    server_log("Il client %d ha richiesto una open sul file %s con flag %d", clientFd, path, flags);

    int retVal = 0;
    File_t * file = searchFile(fs, path); // cerco il file 
    
    // agisco in base ai flag

    if(file == NULL){     // file non esisteva
        
        if(flags == 0 || flags == 2){     //nessun flag o solo O_LOCK
            retVal = E_NOT_EX; 
            goto openFile_handler_END;
        }

        // devo aggiungere un file
        
        if(fs->actNumFile + 1 > fs->maxNumFile){   // parte l'algoritmo della cache 
            File_t * tmp = cacheEvict(fs, NULL, 0);
            assert(tmp != NULL);
            f_startWrite(tmp);
            
            retVal = 1; // segnalo che sta per arrivare un file
            if (writen(clientFd, &retVal, sizeof(int)) != sizeof(int)) perror("i file verranno persi");

            server_log("Invio al client %d il file %s di %d byte", clientFd, tmp->path, tmp->size);
        
            if (writen(clientFd, &tmp->size, sizeof(int)) != sizeof(int))perror("i file verranno persi"); 
            if (writen(clientFd, tmp->path, MAX_PATH) != MAX_PATH) perror("i file verranno persi"); 
            if (writen(clientFd, tmp->cont, tmp->size) != tmp->size) perror("i file verranno persi"); 

            f_doneRead(tmp);
            deleteFile(tmp);

            retVal = -1; //segnalo al client che i file sono finiti
            if (writen(clientFd, &retVal, sizeof(int)) != sizeof(int)) perror("errore client");
        }

        File_t * newfile  = init_File(path, clientFd); 
        
        f_startWrite(newfile);
        if(flags == 3){  // O_CREATE | O_LOCK
            newfile->lockedBy = clientFd;
        }
        if(fs->actNumFile == 0){
            fs->lastFile = newfile;
            fs->firstFile = newfile;
        }
        else{
            (fs->lastFile)->next = newfile;
            newfile->prev = fs->lastFile;
            fs->lastFile = newfile;
        }
        list_insert(&newfile->openedBy, clientFd);
        f_doneWrite(newfile);
        fs->actNumFile++;
        if(fs->actNumFile > fs->maxRNumFile) fs->maxRNumFile = fs->actNumFile;        
        retVal = 0;   
        goto openFile_handler_END;   
    }

    if(file != NULL){ // il file esiste

        if (flags == 1 || flags == 3){    // O_CREATE oppure O_CREATE | O_LOCK
            retVal = E_ALR_EX;   
            goto openFile_handler_END;   

        }

        if(flags == 0){ // nessun flag
            f_startWrite(file);
            list_insert( &file->openedBy, clientFd);
            f_doneWrite(file);  
            retVal = 0;   
            goto openFile_handler_END;   

        }

        if (flags == 2){    // O_LOCK
            f_startWrite(file);
           
            if(file->lockedBy == 0){
                file->lockedBy = clientFd;
                list_insert(&file->openedBy, clientFd);
                f_doneWrite(file);
                retVal = 0;   
                goto openFile_handler_END;   
            }
            else{
                f_doneWrite(file);
                retVal = E_ALR_LK;
                goto openFile_handler_END;   
            }
        }
    }
    retVal = 0;
    openFile_handler_END:
    server_log("Il client %d ha completato la richiesta. Valore ritornato: %d", clientFd, retVal);
    EXIT_ON(pthread_mutex_unlock(&fs->fs_lock), != 0);   
    if (writen(clientFd, &retVal, sizeof(int)) != sizeof(int)) return -1;
    else return 0;
}


int writeFile_handler(FileSystem_t * fs, int clientFd, char* path, int size, char * buf){

    EXIT_ON(pthread_mutex_lock(&fs->fs_lock), != 0);    // prendo lock fs
    
    server_log("Il client %d ha richiesto una write sul file %s di %d byte", clientFd, path, size);

    int retVal = 0; // valore di ritorno che corrisponde a errno per il client
    File_t * file = searchFile(fs, path); // cerco il file con quel path
    
    if(file == NULL){
        retVal = E_NOT_EX;
        goto writeFile_handler_END; //test da fare: lanciare il client
    }

    f_startRead(file); // devo levvere il file
    
    if(!list_mem(&file->openedBy, clientFd)){    // controllo se ho aperto il file
        f_doneRead(file);
        retVal = E_NOT_OPN;
        goto writeFile_handler_END;
    }

    if(clientFd != file->lockedBy ){    // controllo se ho la lock sul file
        f_doneRead(file);
        retVal =  E_LOCK;
        goto writeFile_handler_END;
    }

    if(file->size != 0){        // controllo se il file è stato già scritto
        f_doneRead(file);
        retVal = E_BAD_RQ;
        goto writeFile_handler_END;
    }
    
    if(fs->maxSize < size){  // non riuscirò mai a trovare lo spazio necessario
        f_doneRead(file);
        retVal = E_NO_SPACE;
        goto writeFile_handler_END;
    }
    
    f_doneRead(file);
     
    // fase di evict e salvataggio dei file da mandare al client
    retVal = 0;
    while((fs->maxSize - fs->actSize < size)){  // se lo spazio libero è minore di quello che devo inserire
        
        if (retVal == 0){
            retVal = 1; // seganala che stanno per arrivare file
            if (writen(clientFd, &retVal, sizeof(int)) != sizeof(int)) perror("i file verranno persi"); 
        }
        File_t * tmp = cacheEvict(fs, file, F_SIZE);  // scollega il file dal fs e non ci sono scrittori o lettori attivi o in attesa
        
        server_log("Invio al client %d il file %s di %d byte", clientFd, tmp->path, tmp->size);
        
        if (writen(clientFd, &tmp->size, sizeof(int)) != sizeof(int))perror("i file verranno persi"); 
        if (writen(clientFd, tmp->path, MAX_PATH) != MAX_PATH) perror("i file verranno persi"); 
        if (writen(clientFd, tmp->cont, tmp->size) != tmp->size) perror("i file verranno persi"); 

        server_log("File %s eliminato dal server", tmp->path);
        deleteFile(tmp);
        
    }
    if(retVal == 1){    // se ho inviato file, devo segnalare che i file sono finiti
        retVal = -1;    // i file sono finiti
        if (writen(clientFd, &retVal, sizeof(int)) != sizeof(int)) perror("errore client");
    }
    
    // scrittura nel file 

    f_startWrite(file);
    file->cont = buf;
    file->size = size;
    fs->actSize += size;
    if(fs->actSize >fs->maxRSize) fs->maxRSize = fs->actSize;
    f_doneWrite(file);
    //fprintf(stderr, "scritto il file: %s con: %s\n", file->path, (char*)file->cont);

    // messaggio finale per il client
    retVal = 0;
    writeFile_handler_END:
    if(retVal != 0) free(buf);
    server_log("Il client %d ha completato la richiesta. Valore ritornato: %d", clientFd, retVal);
    EXIT_ON(pthread_mutex_unlock(&fs->fs_lock), != 0);
    if (writen(clientFd, &retVal, sizeof(int)) != sizeof(int)) return -1;
    else return 0;

}
int readNFiles_handler(FileSystem_t * fs, int clientFd, int numFile){

    EXIT_ON(pthread_mutex_lock(&fs->fs_lock), != 0);    // prendo lock fs

    server_log("Il client %d ha richiesto la lettura di %d files", clientFd, numFile);

    // size, path, cont

    if(numFile <= 0) numFile = fs->actNumFile;
    if(numFile > fs->actNumFile) numFile = fs->actNumFile;

    int retVal = 0, cont = 0;

    File_t * tmp = fs->firstFile, *next;

    
    retVal = 1; // seganala che stanno per arrivare file
    if (writen(clientFd, &retVal, sizeof(int)) != sizeof(int)) {retVal = E_BAD_RQ; goto readNFiles_handler_END;} 


    while(cont < numFile ){
        f_startRead(tmp);
        if(tmp->lockedBy != 0 && tmp->lockedBy != clientFd){
            f_doneRead(tmp);
            continue;
        }
        server_log("Invio al client %d il file %s di %d byte", clientFd, tmp->path, tmp->size); 
        if (writen(clientFd, &tmp->size, sizeof(int)) != sizeof(int)) {f_doneRead(tmp), retVal = E_BAD_RQ; goto readNFiles_handler_END;}
        if (writen(clientFd, &tmp->path, MAX_PATH) != MAX_PATH) {f_doneRead(tmp), retVal = E_BAD_RQ; goto readNFiles_handler_END;}
        if (writen(clientFd, tmp->cont, tmp->size) != tmp->size) {f_doneRead(tmp), retVal = E_BAD_RQ; goto readNFiles_handler_END;}
        next = tmp->next;
        f_doneRead(tmp);
        tmp = next;
        cont++;
    }

    retVal = -1; // seganala che sono finiti i file
    if (writen(clientFd, &retVal, sizeof(int)) != sizeof(int)) {retVal = E_BAD_RQ; goto readNFiles_handler_END;} 

    retVal = 0;
    readNFiles_handler_END:
    server_log("Il client %d ha completato la richiesta. Valore ritornato: %d", clientFd, retVal);
    EXIT_ON(pthread_mutex_unlock(&fs->fs_lock), != 0); 
    if (writen(clientFd, &retVal, sizeof(int)) != sizeof(int)) return -1;
    else return 0;

}

int readFile_handler(FileSystem_t * fs, int clientFd, char * path){

    EXIT_ON(pthread_mutex_lock(&fs->fs_lock), != 0);    // prendo lock fs

    server_log("Il client %d ha richiesto la lettura di %s", clientFd, path);

    int retVal = 0;
    
    File_t * file = searchFile(fs, path);

    if(file == NULL){ 
        retVal = E_NOT_EX; 
        EXIT_ON(pthread_mutex_unlock(&fs->fs_lock), != 0);
        goto readFile_handler_END;
    }

    f_startRead(file);

    EXIT_ON(pthread_mutex_unlock(&fs->fs_lock), != 0); // posso rilaciare la mutex del fs

    if(!list_mem(&file->openedBy, clientFd)){ retVal = E_NOT_OPN; f_doneRead(file); goto readFile_handler_END;}

    if(file->lockedBy != 0 && file->lockedBy != clientFd){retVal = E_LOCK; f_doneRead(file); goto readFile_handler_END;}

    retVal = 1; // seganala che stanno per arrivare file
    if (writen(clientFd, &retVal, sizeof(int)) != sizeof(int)) {f_doneRead(file), retVal = E_BAD_RQ; goto readFile_handler_END;} 

    server_log("Invio al client %d il file %s di %d byte", clientFd, file->path, file->size);
        
    if (writen(clientFd, &file->size, sizeof(int)) != sizeof(int)) {f_doneRead(file), retVal = E_BAD_RQ; goto readFile_handler_END;}
    if (writen(clientFd, file->cont, file->size) != file->size) {f_doneRead(file), retVal = E_BAD_RQ; goto readFile_handler_END;}

    f_doneRead(file);

    retVal = 0;
    readFile_handler_END:
    server_log("Il client %d ha completato la richiesta. Valore ritornato: %d", clientFd, retVal);
    if (writen(clientFd, &retVal, sizeof(int)) != sizeof(int)) return -1;
    else return 0;

}

int removeFile_handler(FileSystem_t * fs, int clientFd, char * path){  
    
    EXIT_ON(pthread_mutex_lock(&fs->fs_lock), != 0);    // prendo lock fs

    server_log("Il client %d ha richiesto l'eliminazione di %s", clientFd, path);

    int retVal = 0;
    
    File_t * file = searchFile(fs, path);

    if(file == NULL){ retVal = E_NOT_EX; goto removeFile_handler_END;}

    f_startWrite(file);

    if(file->lockedBy != 0 && file->lockedBy != clientFd){f_doneWrite(file); retVal = E_LOCK; goto removeFile_handler_END;}

    fs->actSize -= file->size;
    fs->actNumFile--;

    if(file->next != NULL) {
        f_startWrite(file->next);
        (file->next)->prev = file->prev;
        f_doneWrite(file->next);
    }
    if(file->prev != NULL) {
        f_startWrite(file->prev);
        (file->prev)->next = file->next;
        f_doneWrite(file->prev);
    }

    if (fs->firstFile == file) fs->firstFile = file->next;
    if (fs->lastFile == file) fs->lastFile = file->prev;
    if(fs->actNumFile == 0){
        fs->firstFile = NULL;
        fs->lastFile = NULL;
    }

    
    f_doneWrite(file);
    deleteFile(file);

    removeFile_handler_END:
    server_log("Il client %d ha completato la richiesta. Valore ritornato: %d", clientFd, retVal);
    EXIT_ON(pthread_mutex_unlock(&fs->fs_lock), != 0); 
    if (writen(clientFd, &retVal, sizeof(int)) != sizeof(int)) return -1;
    else return 0;
}

int closeFile_handler(FileSystem_t * fs, int clientFd, char * path){

    EXIT_ON(pthread_mutex_lock(&fs->fs_lock), != 0);    // prendo lock fs

    server_log("Il client %d ha richiesto la chiusura di %s", clientFd, path);

    int retVal = 0;
    
    File_t * file = searchFile(fs, path);

    if(file == NULL){ retVal = E_NOT_EX; goto closeFile_handler_END;}

    f_startWrite(file);

    list_remove(&file->openedBy, clientFd);

    f_doneWrite(file);

    retVal = 0;
    closeFile_handler_END:
    server_log("Il client %d ha completato la richiesta. Valore ritornato: %d", clientFd, retVal);
    EXIT_ON(pthread_mutex_unlock(&fs->fs_lock), != 0);
    if (writen(clientFd, &retVal, sizeof(int)) != sizeof(int)) return -1;
    else return 0;

}

int unlockFile_handler(FileSystem_t * fs, int clientFd, char * path){

    EXIT_ON(pthread_mutex_lock(&fs->fs_lock), != 0);    // prendo lock fs

    server_log("Il client %d ha richiesto una unlock su %s", clientFd, path);

    int retVal = 0;
    
    File_t * file = searchFile(fs, path);

    if(file == NULL){ retVal = E_NOT_EX; goto unlockFile_handler_END;}

    f_startWrite(file);

    if(!list_mem(&file->openedBy, clientFd)){ f_doneWrite(file), retVal = E_NOT_OPN; goto unlockFile_handler_END;}

    if(file->lockedBy != 0 && file->lockedBy != clientFd){ f_doneWrite(file); retVal = E_LOCK ; goto unlockFile_handler_END;}

    if(file->lockedBy == 0){ f_doneWrite(file), retVal = 0; goto unlockFile_handler_END;}

    file->lockedBy = 0;

    f_doneWrite(file);

    retVal = 0;
    unlockFile_handler_END:
    server_log("Il client %d ha completato la richiesta. Valore ritornato: %d", clientFd, retVal);
    EXIT_ON(pthread_mutex_unlock(&fs->fs_lock), != 0);
    if (writen(clientFd, &retVal, sizeof(int)) != sizeof(int)) return -1;
    else return 0;

}

int closeAll_handler(FileSystem_t * fs, int clientFd){

    EXIT_ON(pthread_mutex_lock(&fs->fs_lock), != 0);

    server_log("Chiudo il client %d e tutti i file aperti", clientFd);

    File_t * next,* tmp = fs->firstFile;

    while(tmp){
        f_startWrite(tmp);
        list_remove(&tmp->openedBy, clientFd);
        if(tmp->lockedBy == clientFd) tmp->lockedBy = 0;
        next = tmp->next;
        f_doneWrite(tmp);
        tmp = next;
    }
    
    EXIT_ON(pthread_mutex_unlock(&fs->fs_lock), != 0);

    return 0;

}

int lockFile_handler(FileSystem_t * fs, int clientFd, char * path){

    EXIT_ON(pthread_mutex_lock(&fs->fs_lock), != 0);    // prendo lock fs

    server_log("Il client %d ha richiesto una lock su %s", clientFd, path);

    int retVal = 0;
    
    File_t * file = searchFile(fs, path);

    if(file == NULL){ retVal = E_NOT_EX; goto lockFile_handler_END;}

    f_startWrite(file);

    if(!list_mem(&file->openedBy, clientFd)){ f_doneWrite(file), retVal = E_NOT_OPN; goto lockFile_handler_END;}

    if(file->lockedBy == clientFd){ f_doneWrite(file); retVal = 0 ; goto lockFile_handler_END;}

    if(file->lockedBy == 0){ 
        file->lockedBy = clientFd;
        f_doneWrite(file);
        retVal = 0;
        goto lockFile_handler_END;
    }

    if(file->lockedBy != 0 && file->lockedBy != clientFd){ 
        f_doneWrite(file); 
        retVal = E_ALR_LK; 
        goto lockFile_handler_END;
    }

    retVal = 0;
    lockFile_handler_END:
    server_log("Il client %d ha completato la richiesta. Valore ritornato: %d", clientFd, retVal);
    EXIT_ON(pthread_mutex_unlock(&fs->fs_lock), != 0);
    if (writen(clientFd, &retVal, sizeof(int)) != sizeof(int)) return -1;
    else return 0;

}

int appendToFile_handler(FileSystem_t * fs,int clientFd, char * path, char * buf, int size){
    
    EXIT_ON(pthread_mutex_lock(&fs->fs_lock), != 0);    // prendo lock fs

    server_log("Il client %d ha richiesto una append sul file %s di %d byte", clientFd, path, size);

    int retVal = 0;
    
    File_t * file = searchFile(fs, path);

    if(file == NULL){ retVal = E_NOT_EX; goto appendToFile_handler_END;}

    f_startRead(file);

    if(!list_mem(&file->openedBy, clientFd)){f_doneRead(file); retVal = E_NOT_OPN; goto appendToFile_handler_END;}

    if(file->lockedBy != 0 && file->lockedBy != clientFd){f_doneRead(file); retVal = E_LOCK; goto appendToFile_handler_END;}

    if(size + file->size > fs->maxSize){f_doneRead(file); retVal = E_NO_SPACE; goto appendToFile_handler_END;}
    
    f_doneRead(file);

    retVal = 0;
    while((fs->maxSize - fs->actSize < size)){
        
        if (retVal == 0){
            retVal = 1; // seganala che stanno per arrivare file
            if (writen(clientFd, &retVal, sizeof(int)) != sizeof(int)) perror("i file verranno persi"); 
        }
        File_t * tmp = cacheEvict(fs, file, F_SIZE);  // scollega il file dal fs e non ci sono scrittori o lettori attivi o in attesa
        
        server_log("Invio al client %d il file %s di %d byte", clientFd, tmp->path, tmp->size);
        
        if (writen(clientFd, &tmp->size, sizeof(int)) != sizeof(int)) perror("i file verranno persi"); 
        if (writen(clientFd, tmp->path, MAX_PATH) != MAX_PATH) perror("i file verranno persi"); 
        if (writen(clientFd, tmp->cont, tmp->size) != tmp->size) perror("i file verranno persi"); 

        server_log("File %s eliminato dal server", tmp->path);
        deleteFile(tmp);

    }
    if (retVal == 1){   // se ho inviato i file devo segnalare che sono finiti
        retVal = -1; // seganala che i file sono finiti
        if (writen(clientFd, &retVal, sizeof(int)) != sizeof(int)) perror("errore client"); 
    }

    f_startWrite(file);

    EXIT_ON(file->cont = realloc(file->cont, file->size + size), == NULL);
    memcpy((char*)file->cont + file->size, buf, size);
    file->size += size;
    f_doneWrite(file);
    fs->actSize+=size;
    if(fs->actSize > fs->maxRSize) fs->maxRSize = fs->actSize;


    retVal = 0;
    appendToFile_handler_END:
    server_log("Il client %d ha completato la richiesta. Valore ritornato: %d", clientFd, retVal);
    free(buf);
    EXIT_ON(pthread_mutex_unlock(&fs->fs_lock), != 0);
    if (writen(clientFd, &retVal, sizeof(int)) != sizeof(int)) return -1;
    else return 0;

}


File_t * cacheEvict(FileSystem_t * fs, File_t * f, int flag){ 
    // assume la lock sul fs, non ci sarà nessuno in attesa sul file ritornato
    // nessun altro file deve essere in scrittura o lettura
    // f indica un file escluso dall'evict
    // flag indica se devo recuperare spazio o se mi basta eliminare un file qualsiasi
    File_t * tmp = fs->firstFile;
    File_t * prev;

    while(tmp != NULL){
        f_startRead(tmp);

        if(tmp != f && ((tmp->size != 0) || !flag)){ // deve essere diverso dal file che sto scrivendo

            f_doneRead(tmp);
            f_startWrite(tmp);   
            fs->actSize -= tmp->size;
            fs->actNumFile--;
            
            if(fs->firstFile == tmp){
                fs->firstFile = tmp->next;
            }
            if(fs->lastFile == tmp){
                fs->lastFile = tmp->prev;
            }
            if(tmp->prev != NULL){
                f_startWrite(tmp->prev);
                (tmp->prev)->next = tmp->next;
                f_doneWrite(tmp->prev);
            }
            if(tmp->next != NULL){
                f_startWrite(tmp->next);
                (tmp->next)->prev = tmp->prev;
                f_doneWrite(tmp->next);
            }
            if(tmp->next == NULL){
                f_startWrite(tmp->prev);
                (tmp->prev)->next = NULL;
                f_doneWrite(tmp->prev);
                fs->lastFile = tmp->prev;
            }
            if(fs->actNumFile == 0){
                fs->firstFile = NULL;
                fs->lastFile = NULL;
            }
            f_doneWrite(tmp); // quando esco da un file in scrittura, non c'è più nessuno nemmeno in attesa
            
            fs->evictCount++;
            return tmp;
            
        }
        prev = tmp;
        tmp = tmp->next; 
        f_doneRead(prev);
    }
    EXIT_ON("evict fail", );    // per le precondizioni della chiamata, l'evict non dovrebbe mai fallire
    return NULL;
}

void deleteFile(File_t * tmp){
    if(tmp->cont != NULL) free(tmp->cont);
    list_deinit(&tmp->openedBy);
    EXIT_ON(pthread_mutex_destroy(&tmp->f_mutex), != 0);
    EXIT_ON(pthread_mutex_destroy(&tmp->f_order), != 0);
    EXIT_ON(pthread_cond_destroy(&tmp->f_go), != 0);
    free(tmp);
}

File_t * searchFile(FileSystem_t * fs, char * path){ // da cambiare con la tabella hash

    File_t * tmp = fs->firstFile;
    File_t * prev;

    while(tmp != NULL){
        f_startRead(tmp);
        if(strncmp(tmp->path, path, MAX_PATH) == 0){
            f_doneRead(tmp);
            return tmp;
        }
        prev = tmp;
        tmp = tmp->next;
        f_doneRead(prev);
    }

    return NULL;

}

FileSystem_t * init_FileSystem(int maxNumFile, int maxSize){
    
    FileSystem_t * fs;
    EXIT_ON(fs = malloc(sizeof(FileSystem_t)), == NULL);
    
    fs->actSize = 0;
    fs->actNumFile = 0;
    fs->maxSize = maxSize;
    fs->maxNumFile = maxNumFile;
    fs->maxRSize = 0;
    fs->maxRNumFile = 0;
    fs->evictCount = 0;

    EXIT_ON(pthread_mutex_init(&fs->fs_lock, NULL), != 0);

    fs->firstFile = NULL;
    fs->lastFile = NULL;

    return fs;
}

void deinit_FileSystem(FileSystem_t * fs){
    // assume che non ci sia più nessun thread worker, quindi ignora tutte le lock

    File_t *prev, * tmp = fs->firstFile;

    while(tmp != NULL){
        prev = tmp;
        tmp = tmp->next;
        deleteFile(prev);
    }

    //pthread_mutex_destroy(&fs->fs_lock);

    free(fs);
}

File_t * init_File(char* path, int clientFd){
    
    File_t * file;
    EXIT_ON(file = malloc(sizeof(File_t)), == NULL);

    
    EXIT_ON( strncpy(file->path, path, MAX_PATH), == NULL);
    file->size = 0;
    file->cont = NULL;
    file->prev = NULL;
    file->next = NULL;
    file->openedBy = NULL;
    list_insert(&file->openedBy, clientFd);
    EXIT_ON(pthread_mutex_init(&file->f_mutex, NULL), != 0);
    EXIT_ON(pthread_mutex_init(&file->f_order, NULL), != 0);
    EXIT_ON(pthread_cond_init(&file->f_go, NULL), != 0);
    file->f_activeReaders = 0;
    file -> f_activeWriters = 0;

    return file;
}

void f_startRead(File_t * file){
    EXIT_ON(pthread_mutex_lock(&file->f_order), != 0); // sono in fila
    EXIT_ON(pthread_mutex_lock(&file->f_mutex), != 0); // sono in sezione critica
    while(file->f_activeWriters > 0){     // se ci sono scrittori attivi mi sospendo (ma mantengo il posto in fila)
        EXIT_ON(pthread_cond_wait(&file->f_go, &file->f_mutex), != 0 );
    }
    file->f_activeReaders++;
    EXIT_ON(pthread_mutex_unlock(&file->f_order), != 0); // rilascio il posto in fila
    EXIT_ON(pthread_mutex_unlock(&file->f_mutex), != 0); // rilascio la mutex
}

void f_doneRead(File_t * file){
    EXIT_ON(pthread_mutex_lock(&file->f_mutex), != 0);
    file->f_activeReaders--;
    if(file->f_activeReaders == 0){
        EXIT_ON( pthread_cond_signal(&file->f_go), != 0);   // faccio entrare il prossimo in fila (se ci sono lettori attivi è inutile)
    }
    EXIT_ON( pthread_mutex_unlock(&file->f_mutex), != 0);
}

void f_startWrite(File_t * file){
    EXIT_ON(pthread_mutex_lock(&file->f_order), != 0); // sono in fila
    EXIT_ON(pthread_mutex_lock(&file->f_mutex), != 0 ); // sono in sezione critica
    while(file->f_activeReaders > 0 || file->f_activeWriters > 0){     // se ci sono scrittori o lettori attivi mi sospendo (ma mantenfo il posto in fila)
        EXIT_ON(pthread_cond_wait(&file->f_go, &file->f_mutex), != 0 );
    }
    file->f_activeWriters++;
    EXIT_ON(pthread_mutex_unlock(&file->f_order), != 0); // rilascio il posto in fila
    EXIT_ON(pthread_mutex_unlock(&file->f_mutex), != 0); // rilascio la mutex
}

void f_doneWrite(File_t * file){
    EXIT_ON(pthread_mutex_lock(&file->f_mutex), != 0);
    file->f_activeWriters--;
    EXIT_ON( pthread_cond_signal(&file->f_go), != 0);
    EXIT_ON( pthread_mutex_unlock(&file->f_mutex), != 0);
}

int readn(int fd, void *ptr, size_t n) {  
    size_t   nleft;
    ssize_t  nread;

    nleft = n;
    while (nleft > 0) {
        if((nread = read(fd, ptr, nleft)) < 0) {
        if (nleft == n) return -1; /* error, return -1 */
        else break; /* error, return amount read so far */
    } else if (nread == 0) break; /* EOF */
    
    nleft -= nread;
    ptr   = (void*)((char*)ptr + nread);
    }
    return(n - nleft); /* return >= 0 */
}

int writen(int fd, void *ptr, size_t n) {  
    size_t   nleft;
    ssize_t  nwritten;

    nleft = n;
    while (nleft > 0) {
        if((nwritten = write(fd, ptr, nleft)) < 0) {
        if (nleft == n) return -1; /* error, return -1 */
        else break; /* error, return amount written so far */
        } else if (nwritten == 0) break; 
        nleft -= nwritten;
        ptr   = (void*)((char*)ptr + nwritten);
    }
    return(n - nleft); /* return >= 0 */
}

void printFs(FileSystem_t * fs){
    File_t * f = fs->firstFile;

    while(f != NULL){
        printf(" \"%s\"", f->path);
        f = f->next;
    }
}

void statistiche(FileSystem_t * fs){
    printf("\n\n*************** Statistiche di utilizzo ***************\n");
    printf("Numero di file massimo memorizzato: %d\n", fs->maxRNumFile);
    printf("Occupazione di memoria massima raggiunta: %d\n", fs->maxRSize);
    printf("Numero di evict nella cache: %d\n", fs->evictCount);
    printf("Ci sono %d file nel server", fs->actNumFile);
    if(fs->actNumFile > 0){
        printf(":");
        printFs(fs);
        printf("\n");
    }
    else{
        printf("\n");
    }
}<file_sep>/includes/mylinkedlist.h
#ifndef _MYLINKEDLIST_H
#define _MYLINKEDLIST_H
#include <stdio.h>
#include <stdlib.h>
#include <myutil.h>

typedef struct node {
	int data;
	struct node *next;
}List_t;

void init(struct node **head, int data);

void list_insert(struct node **head, int data);

void list_remove(struct node **head, int data);

void list_deinit(struct node **head);

int list_mem(struct node **head, int data);
#endif /* _MYLINKEDLIST_H */