#include #include #define NAMELEN 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 (f == NULL) { perror("Malloc createFileT"); return NULL; } f->O_LOCK = (O_LOCK == 0)? 0 : 1; f->owner = client; f->open = (open == 0)? 0 : 1; f->size = 0; if ((f->filepath = malloc(sizeof(char)*NAMELEN)) == NULL) { perror("Malloc filepath"); destroyFile(f); return NULL; } strncpy(f->filepath, f, NAMELEN); if ((f->data = malloc(1)) == NULL) { // così semplicemente facciamo realloc perror("Malloc content"); return NULL; } return f; } // 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->size + size)) == NULL) { perror("Realloc content"); return -1; } memcpy((char*) f->data + f->size, data, size); f->size = f->size + size; } // 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 = queue->head; if (q->head == NULL) q->head = newNode; else { while (tmp->next) tmp = temp->next; temp->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 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; } 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 -= data->size; destroyFile(tmp->data); // free fileT free(tmp); // free nodo UNLOCK(&q->m); // end me return; _end_void_dequeue: UNLOCK_RETURN(&q->m, NULL); return NULL; } // 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 (temp!=NULL) { float res = ((float)(tmp->data)->size)/1000000; // in MB fprintf(stream, "[%s]\t-> %f MB\n", (tmp->data)->filepath, res); temp = temp->next; } UNLOCK_RETURN(&q->m, -1); // end me return 0; _end_print_queue: UNLOCK_RETURN(&q->m, -1); return -1; } // 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 (temp->data)->O_LOCK = 1; (temp->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_lock_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 = client; } 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_open_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, (tmp->data)->size + 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)->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)->size + size)) == NULL) { perror("Realloc content"); goto _end_append_file_queue; } memcpy(((tmp->data)->data) + (tmp->data)->size, data, size); // memmove sarebbe un'alternativa (tmp->data)->size += size; q->size += 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(prc!=tmp) prc = prc->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_append_file_queue; } if (tmp == prc) { // file è il primo q->head = tmp->next; if (tmp->next == NULL) { q->tail = tmp; } } else { // file non è il primo prc->next = tmp->next; if (prc->next == NULL) { q->tail = prc; } } --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 NULL; } LOCK_RETURN(&q->m, NULL); // 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, NULL); // end me return 1; _end_search_file_in_queue: UNLOCK_RETURN(&q->m, NULL); 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 = queue->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; voiDequeue(q); if (errno) { perror("voiDequeue"); } } if (&queue->m) { pthread_mutex_destroy(&q->m); } free(queue); }