#include #include #include #include #define MAXNAMELEN 256 // creazione di un fileT fileT* createFileT(char *f, int O_LOCK, int client, int open){ if(!f){ errno = EINVAL; return NULL; } fileT *file = malloc(sizeof(fileT)); if (file == NULL) { perror("Malloc createFileT"); return NULL; } file->O_LOCK = (O_LOCK == 0)? 0 : 1; file->owner = client; file->open = (open == 0)? 0 : 1; file->size = 0; file->valid = 0; if ((file->filepath = malloc(sizeof(char)*MAXNAMELEN)) == NULL) { perror("Malloc filepath"); destroyFile(file); return NULL; } strncpy(file->filepath, f, MAXNAMELEN); // in seguito semplicemente facciamo realloc if ((file->data = malloc(1)) == NULL) { perror("Malloc content"); return NULL; } return file; } // append su fileT int writeFileT(fileT *f, void *data, size_t size) { if(!f || !data || size < 0){ errno = EINVAL; return -1; } if ((f->data = realloc(f->data, f->valid + size)) == NULL) { perror("Realloc content"); return -1; } memcpy((char*) f->data + f->valid, data, size); f->valid = f->valid + size; f->size = (f->valid>f->size)?f->valid:f->size; return 0; } // destroy fileT void destroyFile(fileT *f) { if(!f) return; if(f->filepath) free(f->filepath); if(f->data) free(f->data); free(f); } // -------------- // creazione queue queueT* createQueue(size_t maxLen, size_t maxSize) { if(maxLen<0 || maxSize<0){ errno = EINVAL; return NULL; } queueT *q = malloc(sizeof(queueT)); if(q==NULL){ perror("Malloc createQueue"); return NULL; } // creazione lock if (pthread_mutex_init(&q->m, NULL) != 0) { perror("pthread_mutex_init createQueue"); destroyQueue(q); return NULL; } q->head = NULL; q->tail = NULL; q->maxLen = maxLen; q->len = 0; q->maxSize = maxSize; q->size = 0; return q; } // insert int enqueue(queueT *q, fileT* data) { if(!q || !data){ errno = EINVAL; return -1; } LOCK_RETURN(&q->m, -1); // begin me if (q->len == q->maxLen) { // too many files errno = ENFILE; goto _end_enqueue; } if (q->size + data->size > q->maxSize) { errno = EFBIG; goto _end_enqueue; } // inserisco l'elemento nodeT *newNode = malloc(sizeof(nodeT)); if (newNode == NULL) { perror("malloc newNode"); goto _end_enqueue; } newNode->data = data; newNode->next = NULL; nodeT *tmp = q->head; if (q->head == NULL) q->head = newNode; else { while (tmp->next) tmp = tmp->next; tmp->next = newNode; } q->tail = newNode; ++q->len; q->size += data->size; UNLOCK_RETURN(&q->m, -1); // end me return 0; _end_enqueue: UNLOCK_RETURN(&q->m, -1); return -1; } // remove fileT* dequeue(queueT *q) { if(!q) { errno = EINVAL; return NULL; } 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; } fileT *data = (q->head)->data; nodeT *tmp = NULL; tmp = q->head; q->head = (q->head)->next; if (q->head == NULL) { // coda diventa vuota q->tail = NULL; } --q->len; q->size -= data->size; free(tmp); // free del nodo UNLOCK_RETURN(&q->m, NULL); // end me return data; _end_dequeue: UNLOCK_RETURN(&q->m, NULL); 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; } fileT **returnList = NULL; // lista dei file rimossi tmp = NULL; returnList = calloc(1, sizeof(fileT*)); returnList[0] = NULL; int purged = 0; while(q->size + s > q->maxSize) { purged++; returnList = realloc(returnList, 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(returnList, purged+1 * sizeof(fileT*)); returnList[purged] = NULL; // null terminated tmp->data->size += s; q->size += s; UNLOCK_RETURN(&q->m, NULL); // end me return returnList; _end_dequeueN: UNLOCK_RETURN(&q->m, NULL); return NULL; } void voidDequeue(queueT *q) { if(!q) { errno = EINVAL; return; } LOCK(&q->m); // begin me if (q->head == NULL || q->len == 0) { // coda vuota errno = ENOENT; goto _end_void_dequeue; } nodeT *tmp = NULL; tmp = q->head; q->head = (q->head)->next; if (q->head == NULL) { // coda diventa vuota q->tail = NULL; } --q->len; q->size -= (tmp->data)->size; destroyFile(tmp->data); // free fileT free(tmp); // free nodo UNLOCK(&q->m); // end me return; _end_void_dequeue: UNLOCK(&q->m); return; } // print queue int printQueue(FILE *stream, queueT *q) { if(!q || !stream) { errno = EINVAL; return -1; } LOCK_RETURN(&q->m, -1); // begin me UNLOCK_RETURN(&q->m, -1); return 0; nodeT *tmp = q->head; fprintf(stream, "Lista file:"); fprintf(stream, "[Nome File] -> Dimensione in MB"); while (tmp!=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); tmp = tmp->next; } UNLOCK_RETURN(&q->m, -1); // end me return 0; } // acquisizione lock int lockFileInQueue(queueT *q, char *filepath, int owner) { if(!q || !filepath) { errno = EINVAL; return -1; } LOCK_RETURN(&q->m, -1); // begin me if (q->len == 0) { errno = ENOENT; goto _end_lock_file_queue; } // 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_lock_file_queue; } if ((tmp->data)->O_LOCK && (tmp->data)->owner != owner) { // lock non del owner errno = EPERM; goto _end_lock_file_queue; } // acquisisco lock sul file (tmp->data)->O_LOCK = 1; (tmp->data)->owner = owner; UNLOCK_RETURN(&q->m, -1); // end me return 0; _end_lock_file_queue: UNLOCK_RETURN(&q->m, -1); return -1; } int unlockFileInQueue(queueT *q, char *filepath, int owner) { if(!q || !filepath) { errno = EINVAL; return -1; } LOCK_RETURN(&q->m, -1); // begin me if (q->len == 0) { errno = ENOENT; goto _end_unlock_file_queue; } // 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_unlock_file_queue; } if((tmp->data)->O_LOCK == 0) { // nessuno ha il lock UNLOCK_RETURN(&q->m, -1); return 0; } if((tmp->data)->O_LOCK == 1 && (tmp->data)->owner != owner) { // lock non del owner errno = EPERM; goto _end_unlock_file_queue; } (tmp->data)->O_LOCK = 0; UNLOCK_RETURN(&q->m, -1); // end me return 0; _end_unlock_file_queue: UNLOCK_RETURN(&q->m, -1); return -1; } // open file int openFileInQueue(queueT *q, char *filepath, int O_LOCK, int owner) { if(!q || !filepath) { errno = EINVAL; return -1; } LOCK_RETURN(&q->m, -1); // begin me if (q->len == 0) { errno = ENOENT; goto _end_open_file_queue; } // 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_open_file_queue; } if((tmp->data)->O_LOCK == 1 && (tmp->data)->owner != owner) { // lock non del owner errno = EPERM; goto _end_open_file_queue; } (tmp->data)->open = 1; (tmp->data)->O_LOCK = (O_LOCK==0)?0:1; if(O_LOCK!=0) { (tmp->data)->owner = owner; } UNLOCK_RETURN(&q->m, -1); // end me return 0; _end_open_file_queue: UNLOCK_RETURN(&q->m, -1); return -1; } // close and relese lock int closeFileInQueue(queueT *q, char *filepath, int owner) { if(!q || !filepath) { errno = EINVAL; return -1; } LOCK_RETURN(&q->m, -1); // begin me if (q->len == 0) { errno = ENOENT; goto _end_close_file_queue; } // 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_close_file_queue; } if((tmp->data)->O_LOCK == 1 && (tmp->data)->owner != owner) { // lock non del owner errno = EPERM; goto _end_close_file_queue; } (tmp->data)->open = 0; (tmp->data)->O_LOCK = 0; (tmp->data)->owner = owner; UNLOCK_RETURN(&q->m, -1); // end me return 0; _end_close_file_queue: UNLOCK_RETURN(&q->m, -1); return -1; } int writeFileInQueue(queueT *q, char *filepath, void *data, size_t size, int owner) { if(!q || !filepath || !data) { errno = EINVAL; return -1; } if(size == 0) return 0; LOCK_RETURN(&q->m, -1); // begin me if (q->len == 0) { // coda vuota errno = ENOENT; goto _end_write_file_queue; } if (q->size + size > q->maxSize) { // non c'e' abbastanza spazio errno = EFBIG; goto _end_write_file_queue; } // 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_write_file_queue; } 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_write_file_queue; } // scrivo 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 return 0; _end_write_file_queue: UNLOCK_RETURN(&q->m, -1); return -1; } int appendFileInQueue(queueT *q, char *filepath, void *data, size_t size, int owner) { if (!q || !filepath || !data) { errno = EINVAL; return -1; } if (size == 0) return 0; LOCK_RETURN(&q->m, -1); // begin me if (q->len == 0) { // coda vuota errno = ENOENT; goto _end_append_file_queue; } if (q->size + size > q->maxSize) { // non c'e' abbastanza spazio errno = EFBIG; goto _end_append_file_queue; } // 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_append_file_queue; } 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_append_file_queue; } // scrivo if (((tmp->data)->data = realloc((tmp->data)->data, (tmp->data)->valid + size)) == NULL) { perror("Realloc content"); goto _end_append_file_queue; } memcpy(((char *)(tmp->data)->data) + (tmp->data)->valid, data, size); // memmove sarebbe un'alternativa (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; _end_append_file_queue: UNLOCK_RETURN(&q->m, -1); return -1; } int removeFileFromQueue(queueT *q, char *filepath, int owner) { if(!q || !filepath) { errno = EINVAL; return -1; } LOCK_RETURN(&q->m, -1); // begin me if (q->len == 0) { // coda vuota errno = ENOENT; goto _end_remove_file_queue; } // scorro la queue per trovare l'elemento nodeT *tmp = q->head; nodeT *pre = q->head; while (tmp) { if (strcmp(filepath, (tmp->data)->filepath) == 0) { // trovato break; } if(pre!=tmp) pre = pre->next; tmp = tmp->next; } if (!tmp) { // non trovato errno = ENOENT; goto _end_remove_file_queue; } if ((tmp->data)->open != 0 || ((tmp->data)->O_LOCK && (tmp->data)->owner != owner)) { // if file è aperto o la lock non è del owner errno = EPERM; goto _end_remove_file_queue; } if (tmp == pre) { // file è il primo q->head = tmp->next; if (tmp->next == NULL) { q->tail = tmp; } } else { // file non è il primo pre->next = tmp->next; if (pre->next == NULL) { q->tail = pre; } } --q->len; q->size -= (tmp->data)->size; destroyFile(tmp->data); // free file free(tmp); // free node UNLOCK_RETURN(&q->m, -1); // end me return 0; _end_remove_file_queue: UNLOCK_RETURN(&q->m, -1); return -1; } // ---------------- // cerco e ritorno una copia fileT* find(queueT *q, char *filepath) { if(!q || !filepath) { errno = EINVAL; return NULL; } LOCK_RETURN(&q->m, NULL); // begin me if (q->len == 0) goto _end_find_in_queue; fileT *res = NULL; nodeT *tmp = q->head; while (tmp) { if (strcmp(filepath, (tmp->data)->filepath) == 0) { // trovato break; } tmp = tmp->next; } if(!tmp) goto _end_find_in_queue; // creo una nuova istanza res = createFileT((tmp->data)->filepath, (tmp->data)->O_LOCK, (tmp->data)->owner, (tmp->data)->open); if (!res) { perror("createFileT res"); goto _end_find_in_queue; } if (writeFileT(res, (tmp->data)->data, (tmp->data)->size) == -1) { perror("writeFileT res"); goto _end_find_in_queue; } UNLOCK_RETURN(&q->m, NULL); // end me return res; _end_find_in_queue: UNLOCK_RETURN(&q->m, NULL); return NULL; } // cerco int searchFile(queueT *q, char *filepath) { if(!q || !filepath) { errno = EINVAL; return 0; } LOCK_RETURN(&q->m, 0); // begin me if (q->len == 0) goto _end_search_file_in_queue; nodeT *tmp = q->head; while (tmp) { if (strcmp(filepath, (tmp->data)->filepath) == 0) { // trovato break; } tmp = tmp->next; } if(!tmp) goto _end_search_file_in_queue; UNLOCK_RETURN(&q->m, 0); // end me return 1; _end_search_file_in_queue: UNLOCK_RETURN(&q->m, 0); return 0; } // numero di elementi della queue size_t getLen(queueT *q) { if(!q) { errno = EINVAL; return -1; } size_t len = -1; LOCK_RETURN(&q->m, -1); // begin me len = q->len; UNLOCK_RETURN(&q->m, -1); // end me return len; } // dimensione in byte size_t getSize(queueT *q) { if(!q) { errno = EINVAL; return -1; } size_t size = -1; LOCK_RETURN(&q->m, -1); // begin me size = q->size; UNLOCK_RETURN(&q->m, -1); // end me return size; } void destroyQueue(queueT *q) { if(!q) return; // no need for lock over queue while (q->len > 0) { errno = 0; voidDequeue(q); if (errno) { perror("voiDequeue"); } } pthread_mutex_destroy(&q->m); free(q); }