diff --git a/lib/threadpool/apiFile.c b/lib/threadpool/apiFile.c index 39a6d50..981f04f 100644 --- a/lib/threadpool/apiFile.c +++ b/lib/threadpool/apiFile.c @@ -18,6 +18,116 @@ // #define ME "52" // not used #define MESE "55" // server error +// ----------------------------------------------------------------------------- +/* funzioni ausiliarie */ + +// invio il messaggio al client +void sendMessage(char *m, long fd_c, taglia_t *taglia, char *mlog) { + if(!m) { + m = MEOK; + } + + if(writen(fd_c, m, strnlen(m, MAXLENMESS)+1) < 0) { + perror("writen"); + goto _sendM_cleanup; + } + + if(taglia_write(taglia, mlog) < 0) + goto _sendM_cleanup; + + return; + +_sendM_cleanup: + return; +} + +// invio il messaggio al client e poi il file +void sendMessageFile(char *m, fileT *f, long fd_c, taglia_t *taglia, char *mlog) { + if(!f) { + errno = EINVAL; + serror(MESY, fd_c); + goto _sendMF_cleanup; + } + if(!m) { + m = MEPF; + } + + if(writen(fd_c, m, strnlen(m, MAXLENMESS)+1) < 0) { + perror("writen"); + goto _sendMF_cleanup; + } + + if(sendFile(f, fd_c, taglia) < 0) { + perror("sendFile"); + goto _sendMF_cleanup; + } + + if(taglia_write(taglia, mlog) < 0) + goto _sendMF_cleanup; + + return; + +_sendMF_cleanup: + return; +} + +// invio il messaggio al client e poi n file +void sendMessageFileN(char *m, fileT **f, int n, long fd_c, taglia *taglia, char *mlog) { + if(!f) { + errno = EINVAL; + serror(MESY, fd_c); + goto _sendMFN_cleanup; + } + if(!m) { + m = MEPF; + } + + if(writen(fd_c, m, strnlen(m, MAXLENMESS)+1) < 0) { + perror("writen"); + goto _sendMF_cleanup; + } + + for(int i=0; iopen != 0) { // file already open + n += snprintf(tmp_buf+n, m-n, "Client %ld ha richiesto una readFile (flags = %x) sul file \"%s\" e' terminata con errore\n", fd_c, flags, filepath); + errno = EPERM; + serror(MENT, fd_c, taglia, tmp_buf); + destroyFile(f); // f is a copy so we need to cleen up + return; } - if(sendFile(f, fd_c, taglia) < 0) { - perror("sendFile"); - goto _sendMF_cleanup; - } - - if(taglia_write(taglia, mlog) < 0) - goto _sendMF_cleanup; - - return; - -_sendMF_cleanup: - return; -} - -// invio il messaggio al client e poi l'errno -void serror(char *m, long fd_c, taglia_t *taglia, char *mlog) { - if(!m) { - errno = EINVAL; - m = MESY; - } - if(writen(fd_c, m, strnlen(m, MAXLENMESS)+1) < 0) { - perror("writen"); - goto _serror_cleanup; - } - if(writen(fd_c, &errno, sizeof(errno)) < 0) { - perror("writen"); - goto _serror_cleanup; - } - - if(taglia_write(taglia, mlog) < 0) - goto _serror_cleanup; - - return; - -_serror_cleanup: + n += snprintf(tmp_buf+n, m-n, "Client %ld ha richiesto una readFile (flags = %x) sul file \"%s\" e' terminata con successo\n", fd_c, flags, filepath); + sendMessageFile(MEOK, f, fd_c, taglia, tmp_buf); + destroyFile(f); // f is a copy so we need to cleen up return; } -void readFile(char *filepath, queueT *q, long fd_c, taglia_t *taglia); +void readNFiles(char *numStr, queueT *q, long fd_c, taglia_t *taglia); // TODO -void readNFiles(char *numStr, queueT *q, long fd_c, taglia_t *taglia); +void writeFile(char *filepath, size_t size, queueT *q, long fd_c, taglia_t *taglia, int append) { + // messaggio da scrivere sul logfile + char tmp_buf[2048]; + int n = 0; + size_t m = sizeof(tmp_buf); + if(!filepath || !q || !taglia) { + n += snprintf(tmp_buf+n, m-n, "Client %ld ha richiesto una writeFile (append = %x) sul file \"%s\" e' terminata con errore\n", fd_c, append, filepath); + errno = EINVAL; + serror(MESY, fd_c, taglia, tmp_buf); + return; + } -void writeFile(char *filepath, size_t size, queueT *q, long fd_c, taglia_t *taglia, int append); + fileT *f = NULL; + f = find(q, filepath); + if(!f) { // file is not present + n += snprintf(tmp_buf+n, m-n, "Client %ld ha richiesto una writeFile (append = %x) sul file \"%s\", dimensione = %ld, e' terminata con errore\n", fd_c, append, filepath, size); + errno = ENOENT; + serror(MENT, fd_c, taglia, tmp_buf); + destroyFile(f); + return; + } + + // file non aperto || !append => locked || lock ma non si è proprietari + if(!f->open || (append || f->O_LOCK) || (f->O_LOCK && f->owner != fd_c)) { + n += snprintf(tmp_buf+n, m-n, "Client %ld ha richiesto una writeFile (append = %x) sul file \"%s\", dimensione = %ld, e' terminata con errore\n", fd_c, append, filepath, size); + errno = EPERM; + serror(MENT, fd_c, taglia, tmp_buf); + destroyFile(f); + return; + } + int trueSizeAdded = 0; // we may have alredy some space allocated + if(append) { + trueSizeAdded = size - f->size + f->valid; + } else { + trueSizeAdded = (size>f->size)? size-f->size : 0; + } + destroyFile(f); // not needed anymore + + fileT **removed = NULL; // array that may (worst case) hold all files to be sent to the client + + if(trueSizeAdded + getSize(q) > q->maxSize) { // writing would be more than capacity + removed = dequeueN(q, filepath, trueSizeAdded); + if(!removed) { // internal error + n += snprintf(tmp_buf+n, m-n, "Client %ld ha richiesto una writeFile (append = %x) sul file \"%s\", dimensione = %ld, e' terminata con errore\n", fd_c, append, filepath, size); + errno = ENOENT; + serror(MESY, fd_c, taglia, tmp_buf); + return; + } + int ln = 0; + fileT *tmp = removed[ln]; + n += snprintf(tmp_buf+n, m-n, "Client %ld ha richiesto una writeFile (append = %x) sul file \"%s\", dimensione = %ld, e' terminata con successo. Ha causato una capacity miss e ha fatto espellere i seguenti file:", fd_c, append, filepath, size); + while(tmp!=NULL) { + n += snprintf(tmp_buf+n, m-n, " \"%s\"", tmp->filepath); + ++ln; + tmp=removed[ln]; + } + n += snprintf(tmp_buf+n, m-n, "\n"); + taglia_update(taglia, q, ln); + + sendMessageFileN(MEFP, removed, ln, fd_c, taglia, tmp_buf); + for(int i=0;iowner = client; f->open = (open == 0)? 0 : 1; f->size = 0; + f->valid = 0; if ((f->filepath = malloc(sizeof(char)*NAMELEN)) == NULL) { perror("Malloc filepath"); @@ -44,13 +45,14 @@ int writeFileT(fileT *f, void *data, size_t size) { return -1; } - if ((f->data = realloc(f->data, f->size + size)) == NULL) { + if ((f->data = realloc(f->data, f->valid + size)) == NULL) { perror("Realloc content"); return -1; } - memcpy((char*) f->data + f->size, data, size); - f->size = f->size + size; + memcpy((char*) f->data + f->valid, data, size); + f->valid = f->valid + size; + f->size = (f->valid>f->size)?f->valid:f->size; } // destroy fileT @@ -158,6 +160,8 @@ fileT* dequeue(queueT *q) { LOCK_RETURN(&q->m, NULL); // begin me + // TODO: altri oltre fifo + if (q->head == NULL || q->len == 0) { // coda vuota errno = ENOENT; goto _end_dequeue; @@ -185,6 +189,91 @@ _end_dequeue: return NULL; } + +// dequeue until we have s free space and expand the file by s +fileT ** dequeueN(queueT *q, char *filepath, size_t s) { + if(!q) { + errno = EINVAL; + return NULL; + } + if(s<=0) { + return NULL; + } + + LOCK_RETURN(&q->m, NULL); // begin me + + /* TODO: altri oltre a fifo */ + + if (q->head == NULL || q->len == 0) { // coda vuota + errno = ENOENT; + goto _end_dequeueN; + } + + if(q->maxSize > s) { + errno = EINVAL; + goto _end_dequeueN; + } + + // scorro la queue per trovare l'elemento + nodeT *tmp = q->head; + while (tmp) { + if (strcmp(filepath, (tmp->data)->filepath) == 0) { // trovato + break; + } + tmp = tmp->next; + } + + if(!tmp) { // non trovato + errno = ENOENT; + goto _end_dequeueN; + } + + if ((tmp->data)->open == 0 || ((tmp->data)->O_LOCK && (tmp->data)->owner != owner)) { + // if file non è aperto o la lock non è del owner + errno = EPERM; + goto _end_dequeueN; + } + + fileT **returnList = NULL; // lista dei file rimossi + nodeT *tmp = NULL; + + returnList = calloc(1, sizeof(fileT*)); + returnList[0] = NULL; + + int purged = 0; + while(q->size + s > q->maxSize) { + purged++; + returnList = realloc(purged, sizeof(fileT*)); + if(!returnList) { + perror("realloc"); + goto _end_dequeueN; + } + tmp = q->head; + q->head = (q->head)->next; + + returnList[purged-1] = tmp->data; + --q->len; + q->size -= tmp->data->size; + + if (q->head == NULL) { // coda diventa vuota + q->tail = NULL; + break; // we eliminated everything so we must have enought space + } + } + returnList = realloc(purged+1, sizeof(fileT*)); + returnList[purged] = NULL; // null terminated + + tmp->data->size += size; + q->size += size; + + UNLOCK_RETURN(&q->m, NULL); // end me + return data; + +_end_dequeueN: + UNLOCK_RETURN(&q->m, NULL); + return NULL; +} + void voidDequeue(queueT *q) { if(!q) { errno = EINVAL; @@ -217,8 +306,8 @@ void voidDequeue(queueT *q) { return; _end_void_dequeue: - UNLOCK_RETURN(&q->m, NULL); - return NULL; + UNLOCK(&q->m); + return; } // print queue @@ -239,6 +328,7 @@ int printQueue(FILE *stream, queueT *q) { fprintf(stream, "[Nome File] -> Dimensione in MB"); while (temp!=NULL) { float res = ((float)(tmp->data)->size)/1000000; // in MB + // float res = ((float)(tmp->data)->valid)/1000000; // in MB fprintf(stream, "[%s]\t-> %f MB\n", (tmp->data)->filepath, res); temp = temp->next; } @@ -483,13 +573,14 @@ int writeFileInQueue(queueT *q, char *filepath, void *data, size_t size, int own } // scrivo - if (((tmp->data)->data = realloc((tmp->data)->data, (tmp->data)->size + size)) == NULL) { + if (((tmp->data)->data = realloc((tmp->data)->data, size)) == NULL) { perror("Realloc content"); goto _end_write_file_queue; } memcpy((tmp->data)->data, data, size); q->size = (q->size) - ((tmp->data)->size) + size; + (tmp->data)->valid = size; (tmp->data)->size = size; UNLOCK_RETURN(&q->m, -1); // end me @@ -542,15 +633,17 @@ int appendFileInQueue(queueT *q, char *filepath, void *data, size_t size, int ow } // scrivo - if (((tmp->data)->data = realloc((tmp->data)->data, (tmp->data)->size + size)) == NULL) { + if (((tmp->data)->data = realloc((tmp->data)->data, (tmp->data)->valid + size)) == NULL) { perror("Realloc content"); goto _end_append_file_queue; } - memcpy(((tmp->data)->data) + (tmp->data)->size, data, size); + memcpy(((tmp->data)->data) + (tmp->data)->valid, data, size); // memmove sarebbe un'alternativa - (tmp->data)->size += size; - q->size += size; + (tmp->data)->valid += size; + q->size -= (tmp->data)->size; + (tmp->data)->size = ((tmp->data)->size > (tmp->data)->valid) ? (tmp->data)->size : (tmp->data)->valid; + q->size += (tmp->data)->size; UNLOCK_RETURN(&q->m, -1); // end me return 0; diff --git a/lib/threadpool/fileQueue.h b/lib/threadpool/fileQueue.h index c623161..3a2870e 100644 --- a/lib/threadpool/fileQueue.h +++ b/lib/threadpool/fileQueue.h @@ -11,6 +11,7 @@ typedef struct { int open; // 1 se il file e' aperto void *data; // contenuto del file size_t size; // dimensione del file in bytes + size_t valid; // posizione fino a cui i dati sono validi } fileT; // nodo di una linked list @@ -88,6 +89,17 @@ int enqueue(queueT *q, fileT* data); */ fileT* dequeue(queueT *q); + +/** + * Estrae fileT dalla coda fino ad ottenere abbastanza spazio in q. + * \param q: puntatore alla coda + * \param filepath: file a cui bisogna aggiungere s di spazio + * \param s: dimensione da aggiungere al file + * + * \retval puntatore alla lista di file estratti (NULL terminated), NULL se errore + */ +fileT ** dequeueN(queueT *q, char *filepath, size_t s); + /** * Estrae un fileT dalla coda come la dequeue, ma invece di restituire il * file estratto lo distrugge immediatamente, liberandone la memoria.