/* file di header base-function.h * * dichiarazione dei prototipi delle funzioni di base per la gestione * del vfs */ // inclusioni fondamentali #include "const.h" #include "coderr.h" #include "structures.h" #include <time.h> #include <stdio.h> #include <stdlib.h> #include <fcntl.h> #include <sys/types.h> #include <sys/uio.h> #include <unistd.h> // prototipo per la create_vfs, funzione che crea e inizializza il vfs int create_vfs(int num_files); // prototipo per la allocate_block, funzione per occupare un blocco e // legarla all'inode int allocate_block(I_TYPE itype, I_NODE *inode); // prototipo per la deallocate_block, funzione per liberare spazio nel // vfs int deallocate_block(I_NODE *inode, unsigned int i_node_offset); // prototipo per la get_i_node, funzione per risalire all'inode // associato ad uno specifico path int get_i_node(char *path, I_NODE *inode); // prototipo per la make_named_socket, funzione per creare una socket // con nome int make_named_socket (const char *filename); // prototipo per la error_handler, funzione per creare il messaggio // di errore da inviare poi al server void error_handler(char *error, char **message); /* fine file */
/* file di intestazione coderr.h
*
* definizione di tutti i codici di errore necessari per gestire
* tutti i problemi che si possono verificare
*/
// DEFINIZIONE CODICI DI ERRORE
// uscita con successo
#define EXIT_SUCCESS 0
// errore generico
#define GEN_FAIL -1
// errore nella creazione del vfs, troppi pochi files
#define NUM_FILES_ERROR -6
// DEFINIZIONE MESSAGGI DI ERRORE E ALTRO
#define NUM_FILES_ERROR_MESSAGE \
"VFS must have 3 or more files\n"
#define GET_INODE_ERROR_MESSAGE \
"Error in i-node resolution"
#define VOID_DIR_MESSAGE \
"0 files 0 directory"
#define OPEN_ERROR_MESSAGE \
"Cannot access file system"
#define INVALID_PATH_MESSAGE \
"Not such a path"
#define NOT_A_DIRECTORY_ERROR_MESSAGE \
"Not a directory"
#define FULL_DIR_ERROR_MESSAGE \
"Directory full"
#define VFS_INTERNAL_ERROR_MESSAGE \
"File system internal error"
#define FULL_DISK_ERROR_MESSAGE \
"Virtual disk full"
#define PATH_ALREADY_EXIST_ERROR_MESSAGE \
"Specified path already exist"
#define NOT_ENOUGH_MEMORY_ERROR_MESSAGE \
"Not enough memory"
#define INVALID_PATH_OS_FS_ERROR_MESSAGE \
"Invalid path on the OS file system"
#define CANNOT_WRITE_OS_FS_ERROR_MESSAGE \
"Can't write on the OS file system"
#define CANNOT_READ_OS_FS_ERROR_MESSAGE \
"Can't read from the OS file system"
#define FILE_SIZE_EXCEED_ERROR_MESSAGE \
"File to be copied too large"
#define CANNOT_CP_DIRECTORY_ERROR_MESSAGE \
"Cannot copy a directory"
#define CANNOT_CP_INVALID_FILE_ERROR_MESSAGE \
"Cannot copy anything but links or r-files"
#define CANNOT_OVERWRITE_FILE_ERROR_MESSAGE \
"Cannot overwrite file/directory"
#define CANNOT_OVERWRITE_OS_FILE_ERROR_MESSAGE \
"Cannot overwrite file on the OS file system"
#define INVALID_TARGET_PATH_ERROR_MESSAGE \
"Invalid link target"
#define CANNOT_LINK_DIR_ERROR_MESSAGE \
"Hard link not allowed for directory"
#define INVALID_LINK_PATH_ERROR_MESSAGE \
"Invalid link name"
#define CANNOT_PURGE_NOT_EMPTY_DIR_ERROR_MESSAGE \
"Directory is not empty"
#define CANNOT_DELETE_DIR_ERROR_MESSAGE \
"Cannot remove: is a directory"
#define CANNOT_UNDEL_EXISTING_FILE_ERROR_MESSAGE \
"Cannot undel existing file"
/* fine file */
/* file di header const.h
*
* definizione di alcune utili costanti
*/
// dimensione del blocco
#define BLOCK_SIZE 262144
/* dimensione dell'i-node (ricordando che la struttura I_NODE e' formata
* da 5 interi e dalla struttura I_TYPE, che ha la dimensione di un int)
*/
#define I_NODE_SIZE 6*sizeof(int)
// lunghezza massima del nome di un file/directory
#define FILE_NAME_SIZE 256
// numero massimo di entry per una directory
#define NUM_DIR_ENTRY BLOCK_SIZE / (FILE_NAME_SIZE * sizeof(char) \
+ sizeof(int))
// file utilizzato per creare vfs
#define PATH "/tmp/vfs.tmp"
// file utilizzato per creare vfs
#define SOCK_PATH "/tmp/vfs.sock"
// tempo dopo il quale la socket, se non riceve dati, viene terminata
#define SOCKET_TIMEOUT_VAL 7
// numero di file che il vfs potra' contenere
#define VFS_NUM_FILES 50
// posizione del primo i-node (ossia la /)
#define ROOT_DIR_OFFSET sizeof(int)+sizeof(int)
/* fine file */
/* file di header structures.h
*
* definizione delle strutture dati fondamentali per la
* gestione del VFS
*/
// enumerazione per definire il tipo a cui poi puntera' un INODE
typedef enum {
RFILE, // regular file
DIR // directory
} I_TYPE;
// definizione della struttura di un INODE
typedef struct {
// tipo di oggetto puntato
I_TYPE type;
// timestamp dell'unix epoch
unsigned int timedate;
// contatore di condivisione (per gli hard link)
unsigned int sharing;
// offset al blocco in cui il file e contenuto
unsigned int block;
// dimensione in byte dell'oggetto definito (in caso di
// file), o il numero di elementi contenuti (in caso di
// directory)
unsigned int size;
// offset che punta al prossimo i-node libero se il presente non
// e' utilizzato
unsigned int nextfree;
} I_NODE;
// definizione di una directory entry
typedef struct {
// rappresenta il nome dell'oggetto puntato
char name[FILE_NAME_SIZE];
// puntatore all'inode
int i_node;
} DIRECTORY_ENTRY;
// definizione di un array per una intera directory
typedef DIRECTORY_ENTRY DIRECTORY[NUM_DIR_ENTRY];
/* fine file */
/* file sorgente allocate-block.c
*
* definizione della funzione allocate_block che si occupera di
* collegare il primo blocco libero al primo inode libero
*/
#include "base-functions.h"
int allocate_block(I_TYPE itype, I_NODE *inode) {
// variabili di appoggio
int fli,flb,nfli,nflb,vfs;
I_NODE *in = (I_NODE *)malloc(sizeof(I_NODE));
// si apre il file in lettura e si gestiscono eventuali errori
if ((vfs = open(PATH,O_RDONLY)) == -1) {
free(in); // libero la memoria allocata per l'inode d'appoggio
return GEN_FAIL;
}
// da qui si leggono fli e flb e si gestiscono gli errori
if(read(vfs,&fli,sizeof(int)) < sizeof(int)) { // accedo ad fli
close(vfs);
free(in); // libero la memoria allocata per l'inode d'appoggio
return GEN_FAIL;
}
// se trovo che fli e' uguale a 0 vuol dire che il file system e'
// pieno
if (fli == 0) {
close(vfs);
free(in); // libero la memoria allocata per l'inode d'appoggio
return GEN_FAIL;
}
// leggo il blocco libero da associare all'inode
if(read(vfs,&flb,sizeof(int)) < sizeof(int)) { // accedo ad flb
close(vfs);
return GEN_FAIL;
}
// se trovo flb uguale a 0 ho il file system pieno
if (flb == 0) {
close(vfs);
free(in); // libero la memoria allocata per l'inode d'appoggio
return GEN_FAIL;
}
// si va a leggere dentro l'inode libero l'offset del prossimo
// inode libero
if (lseek(vfs,fli,SEEK_SET) == -1) {
free(in); // libero la memoria allocata per l'inode d'appoggio
close(vfs);
return GEN_FAIL;
}
// lettura dell'i-node
if(read(vfs,in,I_NODE_SIZE) < I_NODE_SIZE) {
free(in); // libero la memoria allocata per l'inode d'appoggio
close(vfs);
return GEN_FAIL;
}
nfli = in->nextfree; // trovo il prossimo i-node libero
free(in); // libero la memoria allocata per l'inode d'appoggio
// si va a leggere dentro il blocco libero l'offset del prossimo
// blocco libero
if(lseek(vfs,flb,SEEK_SET) == -1) {
close(vfs);
return GEN_FAIL;
}
// leggo l'indirizzo
if(read(vfs,&nflb,sizeof(int)) < sizeof(int)) {
close(vfs);
return GEN_FAIL;
}
close(vfs);
// configuro l'inode in uscita in modo da essere pronto
inode->type = itype;
inode->timedate = time(NULL);
inode->sharing = 1;
inode->block = flb;
inode->size = 0;
inode->nextfree = 0;
// si apre il file in scrittura e si gestiscono gli errori
vfs = open(PATH,O_WRONLY);
if(vfs == -1)
return GEN_FAIL;
// scrivo nella prima parte del VFS l'offset del prossimo i-node
// libero da usare
if(write(vfs,(int *)&nfli,sizeof(int)) < sizeof(int)) {
close(vfs);
return GEN_FAIL;
}
// scrivo nel byte successivo a fli l'offset del prossimo blocco
// libero
if(write(vfs,(int *)&nflb,sizeof(int)) < sizeof(int)) {
close(vfs);
return GEN_FAIL;
}
// mi sposto sull'inode da utilizzare
if(lseek(vfs,fli,SEEK_SET) == -1) {
close(vfs);
return GEN_FAIL;
}
// salvo le modifiche apportate all'inode
if(write(vfs,inode,I_NODE_SIZE) < I_NODE_SIZE) {
close(vfs);
return GEN_FAIL;
}
close(vfs);
// tutto e andato bene
return fli;
}
/* fine file */
/* file sorgente cp_fs2vd.c
*
* definizione della funzione che si occupa di effettuare le copie
* da FS a VFS
*/
#include <sys/stat.h>
#include <string.h>
#include "base-functions.h"
// funzione di appoggio per copiare il file sul VFS
int insert_file_fs2vd(char *path_fs, int size);
// copia un file contenuto in un file system esterno all'interno del VFS
int cp_fs2vd(char * path_fs, char * path_vd, char **message) {
// struttura per leggere le informazioni sul file reale
struct stat temp;
// descrittore per i file
int dsc;
// valore del puntatore al primo inode libero
int fli;
// parte sinistra del path di destinazione (escluso l'ultimo token)
char *safe_dest_path;
// parte destra del path di destinazione (ultimo token)
char *terminal_name;
// parte destra del path sorgente (ultimo token)
char *terminal_source;
// inode per la allocate
I_NODE temp_inode;
// temporanei per le seek nella directory entry
int offset_block;
// variabili d'appoggio
int k,found_duplicate;
DIRECTORY_ENTRY temp_dir_entry;
int allocated_offset_inode;
// offset per l'i-node della directory entry
int offset_inode_directory;
// ricaviamo le varie informazioni riguardanti il file reale
// e quindi controlliamo anche se esiste
if(stat(path_fs, &temp) == GEN_FAIL) {
error_handler(INVALID_PATH_OS_FS_ERROR_MESSAGE, message);
return GEN_FAIL;
}
// se il path_fs e' una directory rispondo con un errore
if(S_ISDIR(temp.st_mode)) {
error_handler(CANNOT_CP_DIRECTORY_ERROR_MESSAGE, message);
return GEN_FAIL;
}
// se il path_fs e' un file non copiabile (es. socket, device, ecc.)
if(!(S_ISREG(temp.st_mode) || S_ISLNK(temp.st_mode))) {
error_handler(CANNOT_CP_INVALID_FILE_ERROR_MESSAGE, message);
return GEN_FAIL;
}
// apro il file per leggere fli
if((dsc = open(PATH,O_RDONLY)) == GEN_FAIL) {
error_handler(OPEN_ERROR_MESSAGE, message);
return GEN_FAIL;
}
// leggiamo il valore di fli
if (read(dsc, &fli, sizeof(int)) < sizeof(int)) {
error_handler(VFS_INTERNAL_ERROR_MESSAGE,message);
close(dsc);
return GEN_FAIL;
}
// si controlla il valore di fli: se uguale a zero significa
// che il disco e' pieno
if(fli == 0){
error_handler(FULL_DISK_ERROR_MESSAGE,message);
close(dsc);
return GEN_FAIL;
}
// chiudo il file
close(dsc);
// dobbiamo prima verificare che il file che copiamo nel nostro disco
// sia di dimensione massima pari a quella definita in const.h come
// BLOCK_SIZE
if(temp.st_size > BLOCK_SIZE) {
error_handler(FILE_SIZE_EXCEED_ERROR_MESSAGE, message);
return GEN_FAIL;
}
// se il path_vd non contiene barre (e' malformato) usciamo
if((terminal_name = strrchr(path_vd,'/')) == NULL) {
error_handler(INVALID_PATH_MESSAGE, message);
return GEN_FAIL;
}
// se la strrchr va a buon fine con il ++ eliminiamo la barra
// iniziale che non ci interessa
terminal_name++;
// inserisco in safe_dest_path la parte sinistra
safe_dest_path = (char*)malloc((terminal_name - path_vd)+1);
safe_dest_path[0] = '\0';
strncat(safe_dest_path, path_vd,(size_t)((terminal_name - path_vd)));
// controllo che il safe_dest_path sia valido nel vfs
if((offset_inode_directory=get_i_node(safe_dest_path,&temp_inode)) \
== GEN_FAIL) {
error_handler(INVALID_PATH_MESSAGE, message);
free(safe_dest_path);
return GEN_FAIL;
}
// libero la memoria
free(safe_dest_path);
// controllo se si tratta di una directory: non si puo' copiare un
// file 'dentro' un file
if(temp_inode.type == RFILE) {
error_handler(INVALID_PATH_MESSAGE, message);
return GEN_FAIL;
}
// se terminal_name e' vuoto inserisco terminal_source
terminal_source = strrchr(path_fs,'/')+1;
if(strcmp(terminal_name,"") == 0) {
strncat(terminal_name,terminal_source,256);
}
// la directory contiene gia' una entry terminal_name?
if((dsc = open(PATH,O_RDONLY)) == GEN_FAIL) {
error_handler(OPEN_ERROR_MESSAGE, message);
return GEN_FAIL;
}
// mi sposto alla posizione del blocco della directory table
// non gestisco l'errore perche' non puo' fallire
offset_block = temp_inode.block;
if(lseek(dsc,offset_block,SEEK_SET) == GEN_FAIL) {
error_handler(VFS_INTERNAL_ERROR_MESSAGE, message);
close(dsc);
return GEN_FAIL;
}
// controllo se esiste gia' una entry nella directory
found_duplicate = 0;
for(k = 0; k < NUM_DIR_ENTRY; k++) {
if(read(dsc,&temp_dir_entry,sizeof(DIRECTORY_ENTRY)) \
< sizeof(DIRECTORY_ENTRY)) {
close(dsc);
return GEN_FAIL;
}
if(strcmp(temp_dir_entry.name,terminal_name) == 0) {
found_duplicate = 1;
break;
}
}
// chiudo il file
close(dsc);
// se non c'e' la entry
if(found_duplicate == 0) {
// la directory e' piena?
if(temp_inode.size >= NUM_DIR_ENTRY) {
error_handler(FULL_DIR_ERROR_MESSAGE, message);
return GEN_FAIL;
}
// chiamo la funzione che alloca il blocco per il nuovo file, e
// lo scrive nel vfs, mi restituisce l'offset all'i-node da
// aggiungere alla directory
if((allocated_offset_inode = insert_file_fs2vd(path_fs, \
temp.st_size)) == GEN_FAIL) {
error_handler(VFS_INTERNAL_ERROR_MESSAGE, message);
return GEN_FAIL;
}
// aggiorno l'i-node della directory entry incrementandone il size
temp_inode.size++;
// preparo la nuova entry per la directory
strcpy(temp_dir_entry.name,terminal_name);
temp_dir_entry.i_node = allocated_offset_inode;
// apro il vfs
if((dsc = open(PATH, O_WRONLY)) == GEN_FAIL) {
error_handler(OPEN_ERROR_MESSAGE, message);
return GEN_FAIL;
}
// mi sposto alla posizione della directory entry
if(lseek(dsc,offset_block + (temp_inode.size - 1) \
* sizeof(DIRECTORY_ENTRY),SEEK_SET) == GEN_FAIL) {
error_handler(VFS_INTERNAL_ERROR_MESSAGE, message);
close(dsc);
return GEN_FAIL;
}
// aggiungo la nuova entry (nome e size)
if(write(dsc,&temp_dir_entry,sizeof(DIRECTORY_ENTRY)) \
< sizeof(DIRECTORY_ENTRY)) {
error_handler(VFS_INTERNAL_ERROR_MESSAGE, message);
close(dsc);
return GEN_FAIL;
}
// mi sposto alla posizione dell'i-node della directory
if(lseek(dsc,offset_inode_directory,SEEK_SET) == GEN_FAIL) {
error_handler(VFS_INTERNAL_ERROR_MESSAGE, message);
close(dsc);
return GEN_FAIL;
}
// a questo punto posso aggiornare l'inode
if(write(dsc,&temp_inode,I_NODE_SIZE) < I_NODE_SIZE) {
error_handler(VFS_INTERNAL_ERROR_MESSAGE, message);
close(dsc);
return GEN_FAIL;
}
// chiudo il file
close(dsc);
// termino con successo
(*message)[0] = '0';
(*message)[1] = '\0';
return EXIT_SUCCESS;
} else {
// se invece ho un duplicato
// ottengo il suo i-node per verificare se e' una directory
if((offset_inode_directory = get_i_node(path_vd, &temp_inode)) \
== GEN_FAIL) {
error_handler(VFS_INTERNAL_ERROR_MESSAGE, message);
return GEN_FAIL;
}
// se non e' una directory errore
if(temp_inode.type != DIR) {
error_handler(CANNOT_OVERWRITE_FILE_ERROR_MESSAGE, message);
return GEN_FAIL;
}
// la directory contiene gia' una entry terminal_source?
if((dsc = open(PATH,O_RDONLY)) == GEN_FAIL) {
error_handler(OPEN_ERROR_MESSAGE, message);
return GEN_FAIL;
}
// mi sposto alla posizione del blocco della directory table
// non gestisco l'errore perche' non puo' fallire
offset_block = temp_inode.block;
if(lseek(dsc,offset_block,SEEK_SET) == GEN_FAIL) {
error_handler(VFS_INTERNAL_ERROR_MESSAGE, message);
close(dsc);
return GEN_FAIL;
}
// controllo se esiste gia' una entry nella directory
found_duplicate = 0;
for(k = 0; k < NUM_DIR_ENTRY; k++) {
if(read(dsc,&temp_dir_entry,sizeof(DIRECTORY_ENTRY)) \
< sizeof(DIRECTORY_ENTRY)) {
close(dsc);
return GEN_FAIL;
}
if(strcmp(temp_dir_entry.name,terminal_source) == 0) {
found_duplicate = 1;
break;
}
}
// chiudo il file
close(dsc);
// se esiste gia' la entry non si puo' sovrascrivere
if(found_duplicate == 1) {
error_handler(CANNOT_OVERWRITE_FILE_ERROR_MESSAGE, message);
return GEN_FAIL;
}
// c'e' spazio nella directory?
if(temp_inode.size >= NUM_DIR_ENTRY) {
error_handler(FULL_DIR_ERROR_MESSAGE, message);
return GEN_FAIL;
}
// se c'e' spazio copio il file e aggiungo la entry
// chiamo la funzione che alloca il blocco per il nuovo file, e
// lo scrive nel vfs, mi restituisce l'offset all'i-node da
// aggiungere alla directory
if((allocated_offset_inode = insert_file_fs2vd(path_fs, \
temp.st_size)) == GEN_FAIL) {
error_handler(VFS_INTERNAL_ERROR_MESSAGE, message);
return GEN_FAIL;
}
// aggiorno l'i-node della directory entry incrementandone il size
temp_inode.size++;
// preparo la nuova entry per la directory
strcpy(temp_dir_entry.name,terminal_source);
temp_dir_entry.i_node = allocated_offset_inode;
// apro il vfs
if((dsc = open(PATH, O_WRONLY)) == GEN_FAIL) {
error_handler(OPEN_ERROR_MESSAGE, message);
return GEN_FAIL;
}
// mi sposto alla posizione della directory entry
if(lseek(dsc,temp_inode.block + (temp_inode.size - 1) \
* sizeof(DIRECTORY_ENTRY),SEEK_SET) == GEN_FAIL) {
error_handler(VFS_INTERNAL_ERROR_MESSAGE, message);
close(dsc);
return GEN_FAIL;
}
// aggiungo la nuova entry (nome e size)
if(write(dsc,&temp_dir_entry,sizeof(DIRECTORY_ENTRY)) \
< sizeof(DIRECTORY_ENTRY)) {
error_handler(VFS_INTERNAL_ERROR_MESSAGE, message);
close(dsc);
return GEN_FAIL;
}
// mi sposto alla posizione dell'i-node della directory
if(lseek(dsc,offset_inode_directory,SEEK_SET) == GEN_FAIL) {
error_handler(VFS_INTERNAL_ERROR_MESSAGE, message);
close(dsc);
return GEN_FAIL;
}
// a questo punto posso aggiornare l'inode
if(write(dsc,&temp_inode,I_NODE_SIZE) \
< I_NODE_SIZE) {
error_handler(VFS_INTERNAL_ERROR_MESSAGE, message);
close(dsc);
return GEN_FAIL;
}
// chiudo il file
close(dsc);
// termino con successo
(*message)[0] = '0';
(*message)[1] = '\0';
return EXIT_SUCCESS;
}
}
// restituiamo come int l'offset
int insert_file_fs2vd(char *path_fs,int size) {
int dsc, offset_temp_inode;
char *swap;
I_NODE temp_inode;
// a questo punto possiamo leggere il file dal file system reale:
// inizializzo il descrittore per accedere ai dati, in sola lettura
if((dsc = open(path_fs, O_RDONLY)) == GEN_FAIL) {
return GEN_FAIL;
}
// alloco una memoria sufficiente per contenere il file puntato
// da path_fs
if((swap = (char *)malloc(size)) == NULL) {
close(dsc);
return GEN_FAIL;
}
// leggo per intero il file coinvolto nel trasferimento dal path_fs
if(read(dsc,swap,size) < size) {
close(dsc);
free(swap);
return GEN_FAIL;
}
// chiudo il file path_fs
close(dsc);
// alloco un nuovo blocco libero
if((offset_temp_inode = allocate_block(RFILE, &temp_inode)) \
== GEN_FAIL) {
free(swap);
return GEN_FAIL;
}
// scrivo la size del file
temp_inode.size = size;
// aggiorno l'i-node:
// accedo al file system virtuale
if((dsc = open(PATH,O_WRONLY)) == GEN_FAIL) {
free(swap);
return GEN_FAIL;
}
// mi sposto all'offset dell'i-node nel vfs
if(lseek(dsc,offset_temp_inode,SEEK_SET) == GEN_FAIL) {
close(dsc);
free(swap);
return GEN_FAIL;
}
// scrivo l'i-node
if(write(dsc,&temp_inode,I_NODE_SIZE) < I_NODE_SIZE) {
close(dsc);
free(swap);
return GEN_FAIL;
}
// mi sposto nel punto corrispondente al blocco in cui devo scrivere
// il file
if(lseek(dsc,temp_inode.block,SEEK_SET) == GEN_FAIL) {
close(dsc);
free(swap);
return GEN_FAIL;
}
// a questo punto posso scrivere il blocco
if(write(dsc,swap,size) < size) {
close(dsc);
free(swap);
return GEN_FAIL;
}
// libero la memoria
free(swap);
// chiudo il file path_vd
close(dsc);
return offset_temp_inode;
}
/* fine file */
/* file sorgente cp_vd2fs.c
*
* definizione della funzione che si occupa di effettuare le copie
* da VFS a FS
*/
#include <sys/stat.h>
#include <string.h>
#include "base-functions.h"
int cp_vd2fs(char * path_vd, char * path_fs, char **message) {
// inode per la lettura del file dal vfs
I_NODE temp_inode;
// descrittore del file
int dsc;
// buffer nel quale leggere il file
char *swap;
// variabili d'appoggio
char *aux;
// nuovo path
char *new_path;
// ultimo token di path_fs
char *terminal_source;
// parte sinistra del path_fs
char *safe_dest_path;
// struttura per l'accesso ai file sull'OS FS
struct stat temp;
// controllo che il path sia ben formato
aux = strrchr(path_vd,'/');
if(aux == NULL) {
error_handler(OPEN_ERROR_MESSAGE,message);
return GEN_FAIL;
}
// controllo che il path esista e che venga correttamente risolto
if(get_i_node(path_vd,&temp_inode) == GEN_FAIL) {
error_handler(GET_INODE_ERROR_MESSAGE,message);
return GEN_FAIL;
}
// controllo che sia un regular-file
if(temp_inode.type == DIR) {
error_handler(CANNOT_CP_INVALID_FILE_ERROR_MESSAGE, message);
return GEN_FAIL;
}
// alloco una memoria sufficiente per poter leggere il file
if((swap = (char *)malloc(sizeof(char) * temp_inode.size)) == NULL) {
error_handler(NOT_ENOUGH_MEMORY_ERROR_MESSAGE, message);
return GEN_FAIL;
}
// apro il file nel vd in modo da leggerlo
if((dsc = open(PATH,O_RDONLY)) == GEN_FAIL) {
error_handler(OPEN_ERROR_MESSAGE, message);
free(swap);
return GEN_FAIL;
}
// mi sposto nel punto in cui e' memorizzato il file nel vd
if(lseek(dsc,temp_inode.block,SEEK_SET) == GEN_FAIL) {
error_handler(VFS_INTERNAL_ERROR_MESSAGE, message);
free(swap);
close(dsc);
return GEN_FAIL;
}
// a questo punto posso leggere dal vd il file da copiare
if(read(dsc,swap,temp_inode.size) < temp_inode.size) {
error_handler(VFS_INTERNAL_ERROR_MESSAGE,message);
free(swap);
close(dsc);
return GEN_FAIL;
}
// chiudo il file
close(dsc);
// verifico se il path passato per la scrittura sia ben formato
terminal_source = strrchr(path_fs,'/');
if(terminal_source == NULL) {
error_handler(INVALID_PATH_OS_FS_ERROR_MESSAGE, message);
free(swap);
return GEN_FAIL;
}
if(stat(path_fs, &temp) != GEN_FAIL) {
// se il path nell'OS FS esiste:
// se non si tratta di una cartella
if(!S_ISDIR(temp.st_mode)) {
error_handler(CANNOT_OVERWRITE_OS_FILE_ERROR_MESSAGE, message);
free(swap);
return GEN_FAIL;
}
// se l'ultimo carattere e' una '/' lo sostituisco con \0
if((terminal_source - path_fs) == strlen(path_fs) - 1) {
path_fs[(terminal_source - path_fs)] = '\0';
terminal_source = strrchr(path_fs,'/');
}
new_path = (char*)malloc(strlen(path_fs)+FILE_NAME_SIZE+2);
new_path[0] = '\0';
// se si tratta di una cartella aggiungo "/aux"
aux = strrchr(path_vd,'/')+1;
strcpy(new_path,path_fs);
strncat(new_path,"/",1);
strncat(new_path,aux,FILE_NAME_SIZE+1);
// se esiste il nuovo path errore
if(stat(new_path, &temp) != GEN_FAIL) {
error_handler(CANNOT_OVERWRITE_OS_FILE_ERROR_MESSAGE, message);
free(swap);
free(new_path);
return GEN_FAIL;
}
// altrimenti creo il file nel nuovo path
if((dsc = open(new_path,O_WRONLY | O_CREAT, 0644)) == GEN_FAIL) {
error_handler(INVALID_PATH_OS_FS_ERROR_MESSAGE, message);
free(swap);
free(new_path);
return GEN_FAIL;
}
// scrivo il file sul file system reale
if(write(dsc,swap,temp_inode.size) < temp_inode.size) {
error_handler(CANNOT_WRITE_OS_FS_ERROR_MESSAGE, message);
free(swap);
free(new_path);
close(dsc);
return GEN_FAIL;
}
// chiudo il file
close(dsc);
// libero la memoria
free(swap);
free(new_path);
// termino con successo
(*message)[0] = '0';
(*message)[1] = '\0';
return EXIT_SUCCESS;
} else {
// se il path nell'OS FS non esiste:
// se l'ultimo carattere e' una '/' il path e' invalido
if((terminal_source - path_fs) == strlen(path_fs) - 1) {
//path_fs[(terminal_source - path_fs)] = '\0';
//terminal_source = strrchr(path,'/');
error_handler(INVALID_PATH_OS_FS_ERROR_MESSAGE, message);
free(swap);
return GEN_FAIL;
}
// creo una stringa con la parte sinistra del path_fs
safe_dest_path = (char*)malloc(strlen(path_fs)+1);
safe_dest_path[0] = '\0';
strcpy(safe_dest_path,path_fs);
safe_dest_path[terminal_source-path_fs] = '\0';
// controllo se esiste la parte sx del path
if(stat(safe_dest_path, &temp) == GEN_FAIL) {
error_handler(INVALID_PATH_OS_FS_ERROR_MESSAGE, message);
free(swap);
free(safe_dest_path);
return GEN_FAIL;
}
// se non si tratta di una cartella errore
if(!S_ISDIR(temp.st_mode)) {
error_handler(CANNOT_OVERWRITE_OS_FILE_ERROR_MESSAGE, message);
free(swap);
free(safe_dest_path);
return GEN_FAIL;
}
// altrimenti creo il file nel nuovo path
if((dsc = open(path_fs,O_WRONLY | O_CREAT, 0644)) == GEN_FAIL) {
error_handler(INVALID_PATH_OS_FS_ERROR_MESSAGE, message);
free(swap);
free(safe_dest_path);
return GEN_FAIL;
}
// scrivo il file sul file system reale
if(write(dsc,swap,temp_inode.size) < temp_inode.size) {
error_handler(CANNOT_WRITE_OS_FS_ERROR_MESSAGE, message);
free(swap);
free(safe_dest_path);
close(dsc);
return GEN_FAIL;
}
// chiudo il file
close(dsc);
// libero la memoria
free(swap);
free(safe_dest_path);
// termino con successo
(*message)[0] = '0';
(*message)[1] = '\0';
return EXIT_SUCCESS;
}
}
/* fine file */
/* file sorgente cp_vd2vd.c
*
* definizione della funzione che si occupa di effettuare le copie
* all'interno del disco virtuale stesso
*/
#include <sys/stat.h>
#include <string.h>
#include "base-functions.h"
// funzione di appoggio per copiare il file sul VFS
int insert_file_vd2vd(char *path_dest, char *swap, int size);
int cp_vd2vd(char *path_source, char *path_dest, char **message) {
// i-node per il file sorgente
I_NODE source_inode;
// swap per la lettura scrittura
char *swap;
// il nome del file (parte destra del path)
char *terminal_name;
// variabili di appoggio
int fli;
int dsc;
char *safe_dest_path;
int offset_inode_directory;
I_NODE temp_inode;
char *terminal_source;
int offset_block;
int found_duplicate;
int k;
DIRECTORY_ENTRY temp_dir_entry;
int allocated_offset_inode;
// accedo al file system virtuale
if((dsc = open(PATH,O_RDONLY)) == GEN_FAIL) {
error_handler(OPEN_ERROR_MESSAGE, message);
free(swap);
return GEN_FAIL;
}
// in path_source ho la sorgente da ricercare nel vfs
if(get_i_node(path_source,&source_inode) == GEN_FAIL) {
error_handler(INVALID_PATH_MESSAGE, message);
return GEN_FAIL;
}
// se il path_source e' una directory rispondo con un errore
if(source_inode.type == DIR) {
error_handler(CANNOT_CP_DIRECTORY_ERROR_MESSAGE, message);
return GEN_FAIL;
}
// alloco una memoria sufficiente per contenere il file puntato da
// path
if ((swap = (char *)malloc(sizeof(char)*source_inode.size)) == NULL) {
error_handler(NOT_ENOUGH_MEMORY_ERROR_MESSAGE, message);
return GEN_FAIL;
}
// mi sposto sul blocco giusto nel file system virtuale
if(lseek(dsc,source_inode.block,SEEK_SET) == GEN_FAIL) {
error_handler(VFS_INTERNAL_ERROR_MESSAGE, message);
free(swap);
return GEN_FAIL;
}
// leggo per intero il file coinvolto nel trasferimento dal vfs
if(read(dsc,swap,source_inode.size) < source_inode.size) {
error_handler(VFS_INTERNAL_ERROR_MESSAGE, message);
close(dsc);
free(swap);
return GEN_FAIL;
}
// il primo test che dobbiamo effettuare e' che il disco virtuale non
// sia pieno, controllando che il valore di fli non sia pari a 0,
// pertanto ci spostiamo sul blocco giusto nel file system virtuale
if(lseek(dsc,0,SEEK_SET) == GEN_FAIL) {
error_handler(VFS_INTERNAL_ERROR_MESSAGE, message);
free(swap);
return GEN_FAIL;
}
// leggiamo il valore di fli
if (read(dsc, &fli, sizeof(int)) < sizeof(int)) {
error_handler(VFS_INTERNAL_ERROR_MESSAGE,message);
close(dsc);
return GEN_FAIL;
}
// verifichiamo il valore di fli
if(fli == 0){
error_handler(FULL_DISK_ERROR_MESSAGE,message);
close(dsc);
return GEN_FAIL;
}
close(dsc);
// se il path_dest non contiene barre (e' malformato) usciamo
if((terminal_name = strrchr(path_dest,'/')) == NULL) {
error_handler(INVALID_PATH_MESSAGE, message);
return GEN_FAIL;
}
// se la strrchr va a buon fine con il ++ eliminiamo la barra
// iniziale che non ci interessa
terminal_name++;
// inserisco in safe_dest_path la parte sinistra
safe_dest_path = (char*)malloc((terminal_name - path_dest)+1);
safe_dest_path[0] = '\0';
strncat(safe_dest_path, path_dest,(size_t)((terminal_name - \
path_dest)));
// controllo che il safe_dest_path sia valido nel vfs
if((offset_inode_directory=get_i_node(safe_dest_path,&temp_inode)) \
== GEN_FAIL) {
error_handler(INVALID_PATH_MESSAGE, message);
free(safe_dest_path);
return GEN_FAIL;
}
// libero la memoria
free(safe_dest_path);
// controllo se si tratta di una directory: non si puo' copiare un
// file 'dentro' un file
if(temp_inode.type == RFILE) {
error_handler(INVALID_PATH_MESSAGE, message);
return GEN_FAIL;
}
// se terminal_name e' vuoto inserisco terminal_source
terminal_source = strrchr(path_source,'/')+1;
if(strcmp(terminal_name,"") == 0) {
strncat(terminal_name,terminal_source,256);
}
// la directory contiene gia' una entry terminal_name?
if((dsc = open(PATH,O_RDONLY)) == GEN_FAIL) {
error_handler(OPEN_ERROR_MESSAGE, message);
return GEN_FAIL;
}
// mi sposto alla posizione del blocco della directory table
// non gestisco l'errore perche' non puo' fallire
offset_block = temp_inode.block;
if(lseek(dsc,offset_block,SEEK_SET) == GEN_FAIL) {
error_handler(VFS_INTERNAL_ERROR_MESSAGE, message);
close(dsc);
return GEN_FAIL;
}
// controllo se esiste gia' una entry nella directory
found_duplicate = 0;
for(k = 0; k < NUM_DIR_ENTRY; k++) {
if(read(dsc,&temp_dir_entry,sizeof(DIRECTORY_ENTRY)) \
< sizeof(DIRECTORY_ENTRY)) {
close(dsc);
return GEN_FAIL;
}
if(strcmp(temp_dir_entry.name,terminal_name) == 0) {
found_duplicate = 1;
break;
}
}
// chiudo il file
close(dsc);
// se non c'e' la entry
if(found_duplicate == 0) {
// la directory e' piena?
if(temp_inode.size >= NUM_DIR_ENTRY) {
error_handler(FULL_DIR_ERROR_MESSAGE, message);
return GEN_FAIL;
}
// chiamo la funzione che alloca il blocco per il nuovo file, e
// lo scrive nel vfs, mi restituisce l'offset all'i-node da
// aggiungere alla directory
if((allocated_offset_inode = insert_file_vd2vd(path_source, swap,\
source_inode.size)) == GEN_FAIL) {
error_handler(VFS_INTERNAL_ERROR_MESSAGE, message);
return GEN_FAIL;
}
// aggiorno l'i-node della directory entry incrementandone il size
temp_inode.size++;
// preparo la nuova entry per la directory
strcpy(temp_dir_entry.name,terminal_name);
temp_dir_entry.i_node = allocated_offset_inode;
// apro il vfs
if((dsc = open(PATH, O_WRONLY)) == GEN_FAIL) {
error_handler(OPEN_ERROR_MESSAGE, message);
return GEN_FAIL;
}
// mi sposto alla posizione della directory entry
if(lseek(dsc,offset_block + (temp_inode.size - 1) \
* sizeof(DIRECTORY_ENTRY),SEEK_SET) == GEN_FAIL) {
error_handler(VFS_INTERNAL_ERROR_MESSAGE, message);
close(dsc);
return GEN_FAIL;
}
// aggiungo la nuova entry (nome e size)
if(write(dsc,&temp_dir_entry,sizeof(DIRECTORY_ENTRY)) \
< sizeof(DIRECTORY_ENTRY)) {
error_handler(VFS_INTERNAL_ERROR_MESSAGE, message);
close(dsc);
return GEN_FAIL;
}
// mi sposto alla posizione dell'i-node della directory
if(lseek(dsc,offset_inode_directory,SEEK_SET) == GEN_FAIL) {
error_handler(VFS_INTERNAL_ERROR_MESSAGE, message);
close(dsc);
return GEN_FAIL;
}
// a questo punto posso aggiornare l'inode
if(write(dsc,&temp_inode,I_NODE_SIZE) < I_NODE_SIZE) {
error_handler(VFS_INTERNAL_ERROR_MESSAGE, message);
close(dsc);
return GEN_FAIL;
}
// chiudo il file
close(dsc);
// termino con successo
(*message)[0] = '0';
(*message)[1] = '\0';
return EXIT_SUCCESS;
} else {
// se invece ho un duplicato
// ottengo il suo i-node per verificare se e' una directory
if((offset_inode_directory = get_i_node(path_dest, &temp_inode)) \
== GEN_FAIL) {
error_handler(VFS_INTERNAL_ERROR_MESSAGE, message);
return GEN_FAIL;
}
// se non e' una directory errore
if(temp_inode.type != DIR) {
error_handler(CANNOT_OVERWRITE_FILE_ERROR_MESSAGE, message);
return GEN_FAIL;
}
// la directory contiene gia' una entry terminal_source?
if((dsc = open(PATH,O_RDONLY)) == GEN_FAIL) {
error_handler(OPEN_ERROR_MESSAGE, message);
return GEN_FAIL;
}
// mi sposto alla posizione del blocco della directory table
// non gestisco l'errore perche' non puo' fallire
offset_block = temp_inode.block;
if(lseek(dsc,offset_block,SEEK_SET) == GEN_FAIL) {
error_handler(VFS_INTERNAL_ERROR_MESSAGE, message);
close(dsc);
return GEN_FAIL;
}
// controllo se esiste gia' una entry nella directory
found_duplicate = 0;
for(k = 0; k < NUM_DIR_ENTRY; k++) {
if(read(dsc,&temp_dir_entry,sizeof(DIRECTORY_ENTRY)) \
< sizeof(DIRECTORY_ENTRY)) {
close(dsc);
return GEN_FAIL;
}
if(strcmp(temp_dir_entry.name,terminal_source) == 0) {
found_duplicate = 1;
break;
}
}
// chiudo il file
close(dsc);
// se esiste gia' la entry non si puo' sovrascrivere
if(found_duplicate == 1) {
error_handler(CANNOT_OVERWRITE_FILE_ERROR_MESSAGE, message);
return GEN_FAIL;
}
// c'e' spazio nella directory?
if(temp_inode.size >= NUM_DIR_ENTRY) {
error_handler(FULL_DIR_ERROR_MESSAGE, message);
return GEN_FAIL;
}
// se c'e' spazio copio il file e aggiungo la entry
// chiamo la funzione che alloca il blocco per il nuovo file, e
// lo scrive nel vfs, mi restituisce l'offset all'i-node da
// aggiungere alla directory
if((allocated_offset_inode = insert_file_vd2vd(path_source, swap,\
source_inode.size)) == GEN_FAIL) {
error_handler(VFS_INTERNAL_ERROR_MESSAGE, message);
return GEN_FAIL;
}
// aggiorno l'i-node della directory entry incrementandone il size
temp_inode.size++;
// preparo la nuova entry per la directory
strcpy(temp_dir_entry.name,terminal_source);
temp_dir_entry.i_node = allocated_offset_inode;
// apro il vfs
if((dsc = open(PATH, O_WRONLY)) == GEN_FAIL) {
error_handler(OPEN_ERROR_MESSAGE, message);
return GEN_FAIL;
}
// mi sposto alla posizione della directory entry
if(lseek(dsc,temp_inode.block + (temp_inode.size - 1) \
* sizeof(DIRECTORY_ENTRY),SEEK_SET) == GEN_FAIL) {
error_handler(VFS_INTERNAL_ERROR_MESSAGE, message);
close(dsc);
return GEN_FAIL;
}
// aggiungo la nuova entry (nome e size)
if(write(dsc,&temp_dir_entry,sizeof(DIRECTORY_ENTRY)) \
< sizeof(DIRECTORY_ENTRY)) {
error_handler(VFS_INTERNAL_ERROR_MESSAGE, message);
close(dsc);
return GEN_FAIL;
}
// mi sposto alla posizione dell'i-node della directory
if(lseek(dsc,offset_inode_directory,SEEK_SET) == GEN_FAIL) {
error_handler(VFS_INTERNAL_ERROR_MESSAGE, message);
close(dsc);
return GEN_FAIL;
}
// a questo punto posso aggiornare l'inode
if(write(dsc,&temp_inode,I_NODE_SIZE) \
< I_NODE_SIZE) {
error_handler(VFS_INTERNAL_ERROR_MESSAGE, message);
close(dsc);
return GEN_FAIL;
}
// chiudo il file
close(dsc);
// termino con successo
(*message)[0] = '0';
(*message)[1] = '\0';
return EXIT_SUCCESS;
}
}
// restituiamo come int l'offset
int insert_file_vd2vd(char *path_dest, char *swap, int size) {
int dsc, offset_temp_inode;
I_NODE temp_inode;
// alloco un nuovo blocco libero
if((offset_temp_inode = allocate_block(RFILE, &temp_inode)) \
== GEN_FAIL) {
free(swap);
return GEN_FAIL;
}
// scrivo la size del file
temp_inode.size = size;
// aggiorno l'i-node:
// accedo al file system virtuale
if((dsc = open(PATH,O_WRONLY)) == GEN_FAIL) {
free(swap);
return GEN_FAIL;
}
// mi sposto all'offset dell'i-node nel vfs
if(lseek(dsc,offset_temp_inode,SEEK_SET) == GEN_FAIL) {
close(dsc);
free(swap);
return GEN_FAIL;
}
// scrivo l'i-node
if(write(dsc,&temp_inode,I_NODE_SIZE) < I_NODE_SIZE) {
close(dsc);
free(swap);
return GEN_FAIL;
}
// mi sposto nel punto corrispondente al blocco in cui devo scrivere
// il file
if(lseek(dsc,temp_inode.block,SEEK_SET) == GEN_FAIL) {
close(dsc);
free(swap);
return GEN_FAIL;
}
// a questo punto posso scrivere il blocco
if(write(dsc,swap,size) < size) {
close(dsc);
free(swap);
return GEN_FAIL;
}
// libero la memoria
free(swap);
// chiudo il file path_vd
close(dsc);
return offset_temp_inode;
}
/* fine file */
/* file sorgente create-vfs.c
*
* definizione della funzione che crea il file di nome vfs.tmp in /tmp
* con tutta la struttura in base a num_files da contenere
*/
#include "base-functions.h"
int create_vfs(int num_files) {
int i; // contatore per i for
int vfs; // file descriptor
// aggiungo un I_NODE_SIZE perche' il primo i-node lo
// preparo gia' per la directory di root
// fli = spazio_fli + spazio_flb + spazio_inode_root
int fli = 8 + I_NODE_SIZE;
// aggiungo un BLOCK_SIZE a flb perche' il primo blocco lo
// preparo gia' per la directory di root
// flb = spazio_fli + spazio_flb + spazio_inode + blocchi_occupati
int flb = 8 + num_files * I_NODE_SIZE + BLOCK_SIZE;
// variabili di appoggio
int offset;
char padding[BLOCK_SIZE-sizeof(int)];
I_NODE temp;
// gestiamo il caso in cui num_files sia inferiore a 3
if(num_files < 3) {
fprintf(stderr,NUM_FILES_ERROR_MESSAGE);
return GEN_FAIL;
}
// creo il file vfs.tmp
vfs = open(PATH, O_WRONLY | O_CREAT, 0755);
// se l'apertura del file e' fallita
if (vfs < 0) {
perror("vfs file creation failed");
return GEN_FAIL;
}
// inizializzo il valore della testa della free-list degli i-node
if (write(vfs, &fli, sizeof(int)) < sizeof(int)) {
perror("vfs fli writing failed");
close(vfs);
return GEN_FAIL;
}
// inizializzo il valore della testa della free-list dei blocchi lib.
if (write(vfs, &flb, sizeof(int)) < sizeof(int)) {
perror("vfs flb writing failed");
close(vfs);
return GEN_FAIL;
}
// il primo i-node che viene creato e' quello relativo alla cartella
// radice "/"
temp.type = DIR;
temp.timedate = time(NULL);
temp.sharing = 1;
temp.block = flb - BLOCK_SIZE;
// size nel caso di i-node che puntato a directory contiene il numero
// di file contenuti nella directory stessa
temp.size = 0;
// gli i-node utilizzati non sono concatenati
temp.nextfree = 0;
if(write(vfs, &temp, I_NODE_SIZE) < I_NODE_SIZE) {
perror("vfs first i-node writing failed");
close(vfs);
return GEN_FAIL;
}
// i-node liberi
temp.type = RFILE;
temp.timedate = 0;
temp.sharing = 0;
temp.block = 0;
temp.size = 0;
temp.nextfree = 8 + I_NODE_SIZE;
// creo gli i-node liberi
for(i = 1; i < num_files - 1; i++){
// offset che punta al prossimo i-node libero
temp.nextfree+=I_NODE_SIZE;
// scrittura dell'i-node
if(write(vfs,&temp,I_NODE_SIZE) < I_NODE_SIZE) {
perror("vfs i-node writing failed");
close(vfs);
return GEN_FAIL;
}
}
// questo siccome e' l'ultimo ha nextfree posto a 0
temp.nextfree = 0;
if(write(vfs, &temp, I_NODE_SIZE) < I_NODE_SIZE) {
perror("vfs last i-node writing failed");
return GEN_FAIL;
}
// preparo il padding per i blocchi liberi
for(i = 0; i < BLOCK_SIZE - sizeof(int); i++)
padding[i]=0xff;
// creo un primo blocco vuoto (quello associato alla root)
offset=0;
if(write(vfs, &offset, sizeof(int)) < sizeof(int)) {
perror("vfs first block writing failed");
close(vfs);
return GEN_FAIL;
}
// scrivo su disco il padding per occupare il blocco
if(write(vfs, padding, BLOCK_SIZE - sizeof(int)) < \
BLOCK_SIZE - sizeof(int)) {
perror("vfs first block writing failed");
close(vfs);
return GEN_FAIL;
}
// scrivo tutti i blocchi liberi
offset = flb;
for(i = 1; i < num_files - 1; i++){
offset += BLOCK_SIZE;
if(write(vfs, &offset, sizeof(int)) < sizeof(int)) {
perror("vfs block writing failed");
close(vfs);
return GEN_FAIL;
}
if(write(vfs, padding, BLOCK_SIZE - sizeof(int)) < \
BLOCK_SIZE - sizeof(int)) {
perror("vfs block writing failed");
close(vfs);
return GEN_FAIL;
}
}
// scrivo l'ultimo blocco che non punta a nulla
offset=0;
if(write(vfs, &offset, sizeof(int)) < sizeof(int)) {
perror("vfs last block writing failed");
close(vfs);
return GEN_FAIL;
}
if(write(vfs, padding, BLOCK_SIZE - sizeof(int)) < \
BLOCK_SIZE - sizeof(int)) {
perror("vfs last block writing failed");
close(vfs);
return GEN_FAIL;
}
// chiudo il file
if(close(vfs) < 0) {
perror("closing vfs file failed");
close(vfs);
return GEN_FAIL;
}
close(vfs);
return EXIT_SUCCESS;
}
/* file sorgente deallocate-block.c
*
* definizione della funzione deallocate_block che si occupera' di
* scollegare un blocco da un'i-node e renderli entrambi liberi
*/
#include "base-functions.h"
int deallocate_block(I_NODE *inode, unsigned int i_node_offset) {
// variabili di appoggio
int vfs,fli,flb;
// se il contatore sharing e' maggiore di 1 devo semplicemente
// diminuirlo
if (inode->sharing > 1) {
inode->sharing -= 1;
// si apre il file in lettura e si gestiscono eventuali errori
if ((vfs = open(PATH,O_WRONLY)) == -1) {
return GEN_FAIL;
}
// mi sposto al punto giusto
if(lseek(vfs,i_node_offset,SEEK_SET) == GEN_FAIL) {
close(vfs);
return GEN_FAIL;
}
// aggiorno l'inode
if(write(vfs,inode,I_NODE_SIZE) < I_NODE_SIZE) {
close(vfs);
return GEN_FAIL;
}
// chiudo il file
close(vfs);
} else {
// altrimenti devo rendere liberi sia l'inode sia il blocco
// collegato.
// si apre il file in lettura e si gestiscono eventuali errori
if ((vfs = open(PATH,O_RDONLY)) == -1) {
return GEN_FAIL;
}
// da qui si leggono fli e flb e si gestiscono gli errori
if (read(vfs,&fli,sizeof(int)) < sizeof(int)) {
close(vfs);
return GEN_FAIL;
}
if (read(vfs,&flb,sizeof(int)) < sizeof(int)) {
close(vfs);
return GEN_FAIL;
}
// chiudo il file
close(vfs);
// inserisco l'i-node in testa
inode->nextfree = fli;
// si apre il file in scrittura e si gestiscono gli errori
if (open(PATH,O_WRONLY) == -1)
return GEN_FAIL;
// aggiorno l'offset in fli
if (write(vfs,(int *)&i_node_offset,sizeof(int)) < sizeof(int)) {
close(vfs);
return GEN_FAIL;
}
// aggiorno l'offset in flb
if (write(vfs,(int *)&(inode->block),sizeof(int)) < sizeof(int)) {
close(vfs);
return GEN_FAIL;
}
// mi sposto sul blocco da modificare
if (lseek(vfs,inode->block,SEEK_SET) == -1) {
close(vfs);
return GEN_FAIL;
}
// concludo l'inserimento in testa di flb
if(write(vfs,(int *)&flb,sizeof(int)) < sizeof(int)) {
close(vfs);
return GEN_FAIL;
}
inode->block = 0;
inode->sharing = 0;
inode->timedate = 0;
inode->type = RFILE;
inode->size = 0;
// mi sposto sull' inode da modificare
if (lseek(vfs,i_node_offset,SEEK_SET) == -1) {
close(vfs);
return GEN_FAIL;
}
// concludo l'inserimento in testa di fli
if(write(vfs,inode,sizeof(I_NODE)) < sizeof(I_NODE)) {
close(vfs);
return GEN_FAIL;
}
close(vfs);
}
return EXIT_SUCCESS;
}
/* fine file */
/* file sorgente del.c
*
* definizione della funzione del che si occupera di
* rimuovere con possibilita' di recupero un
* file o un link hard
*/
#include <string.h>
#include "base-functions.h"
int del(char *path, char **message) {
// inode temporaneo
I_NODE temp_inode;
// offset dell'inode
int temp_inode_offset;
// parte sinistra del path
char *safe_path;
// parte destra del path
char *terminal_name;
// DIRECTORY_ENTRY di appoggio
DIRECTORY_ENTRY temp_dir_entry;
// descrittore per il file system virtuale
int vfs;
// contatore
int i;
// se il path non contiene barre (e' malformato) usciamo e
// mi ricavo la parte destra del path
if((terminal_name = strrchr(path,'/')) == NULL) {
error_handler(INVALID_PATH_MESSAGE, message);
return GEN_FAIL;
}
// elimino la barra
terminal_name++;
// controllo se il path esiste
if((temp_inode_offset = get_i_node(path, &temp_inode)) == GEN_FAIL) {
error_handler(INVALID_PATH_MESSAGE, message);
return GEN_FAIL;
}
// se si tratta di un file gia' cancellato
if(temp_inode_offset<0) {
error_handler(INVALID_PATH_MESSAGE, message);
return GEN_FAIL;
}
// controllo che non stiamo tentando di cancellare una directory
if((temp_inode.type == DIR) && (temp_inode.size != 0)){
error_handler(CANNOT_DELETE_DIR_ERROR_MESSAGE, message);
return GEN_FAIL;
}
// mi ricavo la parte sinistra del path
safe_path = (char*)malloc((terminal_name - path)+1);
safe_path[0] = '\0';
strncat(safe_path, path,(size_t)((terminal_name - path)));
// mi ricavo l'inode della cartella in cui e' contenuto il file da
// eliminare (dobbiamo modificare la rispettiva directory entry)
if((temp_inode_offset = get_i_node(safe_path, &temp_inode)) \
== GEN_FAIL) {
error_handler(INVALID_PATH_MESSAGE, message);
return GEN_FAIL;
}
// apriamo il file del vfs
if((vfs = open(PATH,O_RDWR)) == GEN_FAIL) {
error_handler(OPEN_ERROR_MESSAGE, message);
return GEN_FAIL;
}
// ci spostiamo all'offset della directory table
if(lseek(vfs,temp_inode.block,SEEK_SET) == GEN_FAIL) {
error_handler(VFS_INTERNAL_ERROR_MESSAGE, message);
close(vfs);
return GEN_FAIL;
}
// ciclo per trovare l'entry giusta, quando la troviamo usciamo
// dal ciclo
i=0;
while(strcmp(temp_dir_entry.name, terminal_name) != 0){
// leggiamo una entry
if(read(vfs,&temp_dir_entry,sizeof(DIRECTORY_ENTRY)) \
< sizeof(DIRECTORY_ENTRY)) {
close(vfs);
return GEN_FAIL;
}
i++;
}
if(lseek(vfs,((i-1)*sizeof(DIRECTORY_ENTRY))+ temp_inode.block, \
SEEK_SET) == GEN_FAIL) {
error_handler(VFS_INTERNAL_ERROR_MESSAGE, message);
close(vfs);
return GEN_FAIL;
}
// ricordiamo che l'entry giusta deve essere trovata per forza, a
// causa del controllo all'inizio del listato
// la modifichiamo rendendo negativo il valore del campo inode
temp_dir_entry.i_node = - temp_dir_entry.i_node;
// e la riscriviamo
if(write(vfs,&temp_dir_entry,sizeof(DIRECTORY_ENTRY)) \
< sizeof(DIRECTORY_ENTRY)) {
error_handler(VFS_INTERNAL_ERROR_MESSAGE, message);
close(vfs);
return GEN_FAIL;
}
// a questo punto aggiorno il campo size dell'inode della
// directory padre
//temp_inode.size--;
// e vado a scrivere la modifica
if(lseek(vfs,temp_inode_offset,SEEK_SET) == GEN_FAIL) {
error_handler(VFS_INTERNAL_ERROR_MESSAGE, message);
close(vfs);
return GEN_FAIL;
}
if(write(vfs,&temp_inode,I_NODE_SIZE) < I_NODE_SIZE) {
error_handler(VFS_INTERNAL_ERROR_MESSAGE, message);
close(vfs);
return GEN_FAIL;
}
// chiudo il file
close(vfs);
// termino con successo
(*message)[0] = '0';
(*message)[1] = '\0';
return EXIT_SUCCESS;
}
/* fine file */
/* file sorgente error_handler.c
*
* funzione che gestisce la creazione dei messaggi di errore in memoria
* dinamica (sono poi passati al server che gestisce la comunicazione)
*/
#include <string.h>
#include <stdlib.h>
void error_handler(char *error, char **message){
// copio un 1 come primo carattere di *message (errore)
(*message)[0] = '1';
(*message)[1] = '\0';
// ridimensiono l'array in mem. din. per contenere l'output
*message = (char *)realloc(*message, 1 + strlen(error) + 1);
// concateno in *message il messaggio di errore specifico
strcat(*message, error);
}
/* fine file */
/* file sorgente get-i-node.c
*
* definizione della funzione get_i_node che restituisce
* l'offset all'i-node associato ad uno specifico path
*/
#include <string.h>
#include "base-functions.h"
int free_exploded_path(char * exploded_path[], int j);
int get_i_node(char * path, I_NODE * inode) {
// path suddiviso in token
char * exploded_path[100];
char temp;
int i,k;
// conterra' il numero di token
int j=0;
int num_el;
// inizializzato alla posizione dell'i-node di /
int seek_temp = ROOT_DIR_OFFSET;
// file descriptor
int vfs;
// puntatore ad i-node per quando lo leggo da vfs
I_NODE *inode_in = (I_NODE *)malloc(sizeof(I_NODE));
// array per il blocco della directory
DIRECTORY block_in;
// boolean per ricordare se ho fatto seek su un file
// cancellato in modo soft
int deleted = 0;
// il path deve iniziare con una /
if(path[0] != '/') {
free(inode_in);
return GEN_FAIL;
}
// se si vuole accedere alla root e' banale
if(path[1] == '\0') {
// apro il file vfs
vfs = open(PATH,O_RDONLY);
if(vfs == -1) {
free(inode_in);
return GEN_FAIL;
}
// mi sposto opportunamente all'i-node
if(lseek(vfs,seek_temp,SEEK_SET) == -1) {
close(vfs);
free(inode_in);
return GEN_FAIL;
}
// lettura dell'i-node
if(read(vfs,inode_in,I_NODE_SIZE) < I_NODE_SIZE) {
close(vfs);
free(inode_in);
return GEN_FAIL;
}
} else {
// inizializzo le variabili necessarie
i = j = k = num_el = 0;
temp = '0';
// leggo tutto il path in ingresso
while(temp != '\0') {
i++;
// carico ogni carattere
temp = path[i];
// controllo se sono arrivato alla fine di un token
if(temp == '/' || temp == '\0') {
if(num_el != 0) {
// se sono alla fine del token inserisco il \0
exploded_path[j][num_el] = '\0';
// e mi preparo per il prossimo token
j++;
num_el = 0;
}
} else {
// se leggo una lettera del token
if(num_el == 0) {
// se e' la prima alloco memoria
exploded_path[j] = (char *)malloc(sizeof(char));
}
// la scrivo
exploded_path[j][num_el] = temp;
num_el++;
// incremento la dimensione in memoria
exploded_path[j] = (char *)realloc(exploded_path[j], \
(1 + num_el) * sizeof(char));
}
}
// apro il file vfs
vfs = open(PATH,O_RDONLY);
if(vfs == -1) {
free(inode_in);
free_exploded_path(exploded_path, j);
return GEN_FAIL;
}
for(i = 0; i <= j; i++) {
if(seek_temp<0) {
seek_temp = - seek_temp;
deleted=1;
}
// mi sposto opportunamente all'i-node
if(lseek(vfs,seek_temp,SEEK_SET) == -1) {
close(vfs);
free(inode_in);
free_exploded_path(exploded_path, j);
return GEN_FAIL;
}
if(deleted==1) {
seek_temp = - seek_temp;
deleted = 0;
}
// lettura dell'i-node
if(read(vfs,inode_in,I_NODE_SIZE) < I_NODE_SIZE) {
close(vfs);
free(inode_in);
free_exploded_path(exploded_path, j);
return GEN_FAIL;
}
// controllo se non e' una directory
if(inode_in->type != DIR) {
// se non lo e' ma non siamo alla fine: errore
if(i != j) {
close(vfs);
free(inode_in);
free_exploded_path(exploded_path, j);
return GEN_FAIL;
}
// esco per restituire l'i-node
break;
} else {
// se si tratta dell'ultima directory
if(i == j) {
// esco per restituire l'i-node
break;
}
}
// mi sposto alla posizione del blocco puntato dall'i-node
if(lseek(vfs,inode_in->block,SEEK_SET) == -1) {
close(vfs);
free(inode_in);
free_exploded_path(exploded_path, j);
return GEN_FAIL;
}
// lettura dal blocco delle strutture di directory
for(k = 0; k < NUM_DIR_ENTRY; k++) {
if(read(vfs,&block_in[k],sizeof(DIRECTORY_ENTRY)) \
< sizeof(DIRECTORY_ENTRY)) {
close(vfs);
free(inode_in);
free_exploded_path(exploded_path, j);
return GEN_FAIL;
}
}
// cerchiamo all'interno della directory il prox token
for(k = 0; k < NUM_DIR_ENTRY; k++) {
if(strcmp(exploded_path[i],block_in[k].name)==0) {
// abbiamo trovato il token e aggiorniamo
seek_temp = block_in[k].i_node;
// esco dal ciclo interno
break;
}
}
// se siamo arrivati alla fine senza trovare il token
if(k == NUM_DIR_ENTRY) {
// il path non e' valido!
close(vfs);
free(inode_in);
free_exploded_path(exploded_path, j);
return GEN_FAIL;
}
}
free_exploded_path(exploded_path,j);
}
// chiudo il file
close(vfs);
// aggiorno il parametro
inode->type=inode_in->type;
inode->timedate=inode_in->timedate;
inode->sharing=inode_in->sharing;
inode->block=inode_in->block;
inode->size=inode_in->size;
inode->nextfree=0; // e' banale
free(inode_in);
// return dell'offset all'i-node
return seek_temp;
}
int free_exploded_path(char * exploded_path[], int j) {
int i;
for(i = 0; i < j; i++)
free(exploded_path[i]);
return 0;
}
/* fine file */
/* file sorgente ln.c
*
* definizione delle funzioni che si occupano di effettuare la
* creazione di link simbolici e link hard all'interno del VFS
*/
#include <sys/stat.h>
#include <string.h>
#include "base-functions.h"
int ln(char * target, char * link_name, char ** message) {
// descrittore per gli accessi al disco virtuale
int vfs;
// parte dx del path "target" (dopo l'ultima '/')
char * terminal_target;
// parte dx del path "link_name" (dopo l'ultima '/')
char * terminal_link;
// parte sx del path "link_name" (prima dell'ultima '/')
char *safe_link;
// variabile per la struttura i-node del target
I_NODE target_inode;
// variabile per la struttura i-node del link_name
I_NODE link_inode;
// offset dell'i-node della directory che conterra' il link
int link_inode_offset;
// offset dell'i-node del file target
int target_inode_offset;
// directory entry temporanea
DIRECTORY_ENTRY temp_dir_entry;
// flag per i duplicati
int found_duplicate = 0;
// indice per i cicli
int k;
// controllo che il target sia ben formato
if((terminal_target = strrchr(target,'/')) == NULL) {
error_handler(INVALID_TARGET_PATH_ERROR_MESSAGE, message);
return GEN_FAIL;
}
// controllo che il target esista e prendo l'offset del suo i-node
// di cui dovro' aggiornare il campo sharing
if((target_inode_offset = get_i_node(target, &target_inode)) \
== GEN_FAIL) {
error_handler(INVALID_PATH_MESSAGE, message);
return GEN_FAIL;
}
// controllo che il target non sia una directory
if(target_inode.type == DIR) {
error_handler(CANNOT_LINK_DIR_ERROR_MESSAGE, message);
return GEN_FAIL;
}
// controllo che il link_name sia ben formato
if((terminal_link = strrchr(link_name,'/')) == NULL) {
error_handler(INVALID_LINK_PATH_ERROR_MESSAGE, message);
return GEN_FAIL;
}
// elimino la barra iniziale da terminal_link
terminal_link++;
// ottengo la parte sx del link_name
safe_link = (char*)malloc((terminal_link - link_name)+1);
safe_link[0] = '\0';
strncat(safe_link, link_name,(size_t) ((terminal_link - link_name)));
// controllo che il safe_link sia valido
if((link_inode_offset = get_i_node(safe_link,&link_inode))\
== GEN_FAIL) {
error_handler(INVALID_PATH_MESSAGE, message);
free(safe_link);
return GEN_FAIL;
}
free(safe_link);
// rileva un altro tipo di path (linkname) malformato, ossia rileva
// quando stiamo tentando di creare un link hard all'interno di un
// file (trattandolo come se fosse una directory)
if(link_inode.type == RFILE) {
error_handler(INVALID_PATH_MESSAGE, message);
return GEN_FAIL;
}
// se terminal_link e' vuoto inserisco terminal_target
// (siamo nel caso in cui creare un link con il nome originale)
terminal_target = strrchr(target,'/')+1;
if(strcmp(terminal_link,"") == 0) {
strncat(terminal_link,terminal_target,256);
}
// la directory contiene gia' una entry terminal_link?
if((vfs = open(PATH,O_RDONLY)) == GEN_FAIL) {
error_handler(OPEN_ERROR_MESSAGE, message);
return GEN_FAIL;
}
// mi sposto alla posizione del blocco della directory table
// non gestisco l'errore perche' non puo' fallire
if(lseek(vfs,link_inode.block,SEEK_SET) == GEN_FAIL) {
error_handler(VFS_INTERNAL_ERROR_MESSAGE, message);
close(vfs);
return GEN_FAIL;
}
// controllo se esiste gia' una entry con lo stesso nome nella
// directory
found_duplicate = 0;
for(k = 0; k < NUM_DIR_ENTRY; k++) {
if(read(vfs,&temp_dir_entry,sizeof(DIRECTORY_ENTRY)) \
< sizeof(DIRECTORY_ENTRY)) {
close(vfs);
return GEN_FAIL;
}
if(strcmp(temp_dir_entry.name,terminal_link) == 0) {
found_duplicate = 1;
break;
}
}
// chiudo il file
close(vfs);
// se non c'e' la entry
if(found_duplicate == 0) {
// controllo se la directory e' piena (limite max entry)
if(link_inode.size >= NUM_DIR_ENTRY) {
error_handler(FULL_DIR_ERROR_MESSAGE, message);
return GEN_FAIL;
}
// in questo ramo devo creare un link con il nome originale
// controllo che non esistano file con lo stesso nome del file
// originale
// incremento il size dell'inode della directory entry
link_inode.size++;
// preparo la nuova entry per la directory
strcpy(temp_dir_entry.name,terminal_link);
temp_dir_entry.i_node = target_inode_offset;
// apro il vfs
if((vfs = open(PATH, O_WRONLY)) == GEN_FAIL) {
error_handler(OPEN_ERROR_MESSAGE, message);
return GEN_FAIL;
}
// mi sposto alla posizione della directory entry
if(lseek(vfs,link_inode.block + \
(link_inode.size - 1) \
* sizeof(DIRECTORY_ENTRY),SEEK_SET) == GEN_FAIL) {
error_handler(VFS_INTERNAL_ERROR_MESSAGE, message);
close(vfs);
return GEN_FAIL;
}
// aggiungo la nuova entry (nome e size)
if(write(vfs,&temp_dir_entry,sizeof(DIRECTORY_ENTRY)) \
< sizeof(DIRECTORY_ENTRY)) {
error_handler(VFS_INTERNAL_ERROR_MESSAGE, message);
close(vfs);
return GEN_FAIL;
}
// mi sposto alla posizione dell'i-node della directory
if(lseek(vfs,link_inode_offset,SEEK_SET) == GEN_FAIL) {
error_handler(VFS_INTERNAL_ERROR_MESSAGE, message);
close(vfs);
return GEN_FAIL;
}
// a questo punto posso aggiornare l'inode
if(write(vfs,&link_inode,I_NODE_SIZE) \
< I_NODE_SIZE) {
error_handler(VFS_INTERNAL_ERROR_MESSAGE, message);
close(vfs);
return GEN_FAIL;
}
// ora devo scrivere l'inode del file originale (ho modificato
// lo sharing)
target_inode.sharing++;
// e ora lo aggiorno su disco:
// mi sposto alla posizione dell'i-node del target
if(lseek(vfs,target_inode_offset,SEEK_SET) == GEN_FAIL) {
error_handler(VFS_INTERNAL_ERROR_MESSAGE, message);
close(vfs);
return GEN_FAIL;
}
// e lo scrivo
if(write(vfs,&target_inode,I_NODE_SIZE) \
< I_NODE_SIZE) {
error_handler(VFS_INTERNAL_ERROR_MESSAGE, message);
close(vfs);
return GEN_FAIL;
}
// chiudo il file
close(vfs);
// termino con successo
(*message)[0] = '0';
(*message)[1] = '\0';
return EXIT_SUCCESS;
}else{
// se invece ho un duplicato
// ottengo il suo i-node
if((link_inode_offset = get_i_node(link_name, &link_inode)) \
== GEN_FAIL) {
error_handler(VFS_INTERNAL_ERROR_MESSAGE, message);
return GEN_FAIL;
}
// se non e' una directory errore
if(link_inode.type != DIR) {
error_handler(CANNOT_OVERWRITE_FILE_ERROR_MESSAGE, message);
return GEN_FAIL;
}
// in questo ramo controllo se la directory contiene gia' una
// entry terminal_target, se si' errore
if((vfs = open(PATH,O_RDONLY)) == GEN_FAIL) {
error_handler(OPEN_ERROR_MESSAGE, message);
return GEN_FAIL;
}
// mi sposto alla posizione del blocco della directory table
if(lseek(vfs,link_inode.block,SEEK_SET) == GEN_FAIL) {
error_handler(VFS_INTERNAL_ERROR_MESSAGE, message);
close(vfs);
return GEN_FAIL;
}
// controllo se esiste gia' una entry nella directory
found_duplicate = 0;
for(k = 0; k < NUM_DIR_ENTRY; k++) {
if(read(vfs,&temp_dir_entry,sizeof(DIRECTORY_ENTRY)) \
< sizeof(DIRECTORY_ENTRY)) {
close(vfs);
return GEN_FAIL;
}
if(strcmp(temp_dir_entry.name,terminal_target) == 0) {
found_duplicate = 1;
break;
}
}
// chiudo il file
close(vfs);
// controllo che la directory non sia piena
if(link_inode.size >= NUM_DIR_ENTRY) {
error_handler(FULL_DIR_ERROR_MESSAGE, message);
return GEN_FAIL;
}
// aggiorno l'i-node della directory entry incrementandone size
link_inode.size++;
// preparo la nuova entry per la directory
strcpy(temp_dir_entry.name,terminal_target);
temp_dir_entry.i_node = target_inode_offset;
// apro il vfs
if((vfs = open(PATH, O_WRONLY)) == GEN_FAIL) {
error_handler(OPEN_ERROR_MESSAGE, message);
return GEN_FAIL;
}
// mi sposto alla posizione della directory entry
if(lseek(vfs,link_inode.block + \
(link_inode.size - 1) \
* sizeof(DIRECTORY_ENTRY),SEEK_SET) == GEN_FAIL) {
error_handler(VFS_INTERNAL_ERROR_MESSAGE, message);
close(vfs);
return GEN_FAIL;
}
// aggiungo la nuova entry (nome e size)
if(write(vfs,&temp_dir_entry,sizeof(DIRECTORY_ENTRY)) \
< sizeof(DIRECTORY_ENTRY)) {
error_handler(VFS_INTERNAL_ERROR_MESSAGE, message);
close(vfs);
return GEN_FAIL;
}
// mi sposto alla posizione dell'i-node della directory
if(lseek(vfs,link_inode_offset,SEEK_SET) == GEN_FAIL) {
error_handler(VFS_INTERNAL_ERROR_MESSAGE, message);
close(vfs);
return GEN_FAIL;
}
// a questo punto posso scrivere l'inode
if(write(vfs,&link_inode,I_NODE_SIZE) \
< I_NODE_SIZE) {
error_handler(VFS_INTERNAL_ERROR_MESSAGE, message);
close(vfs);
return GEN_FAIL;
}
// ora devo aggiornare l'inode del file originale (ho modificato
// lo sharing)
target_inode.sharing++;
// mi sposto alla posizione dell'i-node del target
if(lseek(vfs,target_inode_offset,SEEK_SET) == GEN_FAIL) {
error_handler(VFS_INTERNAL_ERROR_MESSAGE, message);
close(vfs);
return GEN_FAIL;
}
// a questo punto posso scrivere l'inode
if(write(vfs,&target_inode,I_NODE_SIZE) \
< I_NODE_SIZE) {
error_handler(VFS_INTERNAL_ERROR_MESSAGE, message);
close(vfs);
return GEN_FAIL;
}
// chiudo il file
close(vfs);
// termino con successo
(*message)[0] = '0';
(*message)[1] = '\0';
return EXIT_SUCCESS;
}
}
/* fine file */
/* file sorgente ls.c
*
* definizione della funzione ls che si occupera' di listare
* il contenuto della directory puntata da un certo i-node con
* varie informazioni aggiuntive
*/
#include <string.h>
#include "base-functions.h"
int ls(char *path, char ** message){
// variabili temporanee per memorizzare gli inode letti
I_NODE inode, sub_inode;
// descrittore per accedere al file system
int vfs;
// variabili di appoggio e contatori
int i, num_el, offset, block_offset;
char temp[FILE_NAME_SIZE];
char * aux;
char * time_aux;
char * path_temp;
char buffer[30];
char timedate[26];
int num_files=0, num_folders=0;
int offset_inode;
// variabile per la conversione da timestamp a stringa 'umana'
time_t time_t_aux;
// restituisco il puntatore all'ultima '/' in path
aux = strrchr(path,'/');
// gestione path malformato
if(aux == NULL) {
error_handler(INVALID_PATH_MESSAGE, message);
return GEN_FAIL;
}
// inizializzo il descrittore per accedere ai dati, in sola lettura
if ((vfs = open(PATH, O_RDONLY)) == GEN_FAIL) {
error_handler(OPEN_ERROR_MESSAGE, message);
return GEN_FAIL;
}
// ricaviamo l'i-node corrispondente alla directory da listare
if ((offset = get_i_node(path, &inode)) == GEN_FAIL) {
error_handler(INVALID_PATH_MESSAGE, message);
return GEN_FAIL;
}
// se il campo size dell'inode e' nullo significa che la cartella
// ad esso relativa non contiene niente, quindi non ci serve
// e restituisco successo dando il messaggio di directory vuota
if (inode.size == 0) {
// copio uno 0 come primo carattere di message (esito positivo)
(*message)[0] = '0';
(*message)[1] = '\0';
// ridimensiono l'array in mem. din. per contenere l'output
*message = (char *)realloc(*message, \
1 + strlen(VOID_DIR_MESSAGE) + 1);
// concateno in message il messaggio che la cartella e' vuota
strcat(*message, VOID_DIR_MESSAGE);
return EXIT_SUCCESS;
}
// per chiarezza assegno l'indirizzo del blocco che ci interessa ad
// una variabile
block_offset = inode.block;
// copio uno 0 come primo carattere di message (esito positivo)
(*message)[0] = '0';
(*message)[1] = '\0';
// ora posso leggere il contenuto della colonna name della tabella
// DIRECTORY_ENTRY
// ciclo n volte, con n = size dell'inode, ossia al numero di entry
for (i = 0; i < inode.size; i++){
if(i==0) {
// ridimensiono l'array in mem. din. per contenere l'output
*message = (char *)realloc(*message, 30);
// aggiungo la maschera a message
sprintf(buffer, "Date\t\t\t\tSharing\t\tSize\t\tName\n");
strncat(*message, buffer, 30);
}
// per chiarezza teniamo un indice delle voci inserite
num_el = i+1;
if(lseek(vfs,block_offset + i * sizeof(DIRECTORY_ENTRY), \
SEEK_SET) == -1) {
error_handler(VFS_INTERNAL_ERROR_MESSAGE, message);
close(vfs);
return GEN_FAIL;
}
// leggo il campo name della struttura directory
if(read(vfs,temp,FILE_NAME_SIZE) < FILE_NAME_SIZE) {
error_handler(VFS_INTERNAL_ERROR_MESSAGE, message);
close(vfs);
return GEN_FAIL;
}
// ridimensiono adeguatamente l'array di output, per contenere:
// 0/1, tabulazione, barra in caso di directory, tabulazione,
// dimensione directory/file, tabulazione, nome della entry,
// tabulazione, orario, \n e \0
// il tutto ripetuto per il numero di entry e sommato alla
// dimensione della stringa con il numero di file e cartelle
*message = (char *)realloc(*message,\
(strlen(temp)+52)*num_el+27+30);
// ricavo l'inode dell'entry che mi interessa e concateno in
// message le varie informazioni
// creo il path per la get_i_node
path_temp = (char *)malloc(sizeof(char) * \
(strlen(path) + 1 + strlen(temp) + 1));
strcpy(path_temp,path);
strncat(path_temp,"/",1);
// leggo l'i-node
offset_inode = get_i_node(strncat(path_temp,temp, \
FILE_NAME_SIZE), &sub_inode);
// libero la memoria
free(path_temp);
if(offset_inode>0) {
// concateno in message la stringa con data/orario
time_t_aux = (time_t)sub_inode.timedate;
time_aux = ctime(&time_t_aux);
strcpy(timedate, time_aux);
timedate[24]='\0';
strncat(*message, timedate, 24);
// concateno in message una tabulazione
strncat(*message, "\t",1);
// concateno lo sharing
sprintf(buffer, "%d", sub_inode.sharing);
strncat(*message, buffer, 30);
// concateno in message una tabulazione
strncat(*message, "\t\t",2);
// concateno la dimensione
sprintf(buffer, "%d", sub_inode.size);
strncat(*message, buffer, 30);
// concateno in message una tabulazione
strncat(*message, "\t\t", 2);
// controllo se si tratta di una directory e nel caso aggiungo
// una '/' all'inizio del nome
if(sub_inode.type == DIR) {
strncat(*message,"/",1);
strncat(*message, temp, FILE_NAME_SIZE);
// incremento il contatore delle directory
num_folders++;
} else {
// se e' un file concateno semplicemente il nome
strncat(*message, temp, FILE_NAME_SIZE);
// incremento il contatore dei file
num_files++;
}
// concateno un ritorno a capo
strncat(*message, "\n",1);
}
}
// concateno il messaggio con il numero di file e cartelle
sprintf(buffer, "%d files and %d folders", num_files, num_folders);
strncat(*message, buffer, 30);
// chiudo il descrittore
close(vfs);
// restituisco un exit status positivo
return EXIT_SUCCESS;
}
/* file sorgente mkdir.c
*
* definizione della funzione mkdir che crea una directory
* all'interno di un path
*/
#include <string.h>
#include "base-functions.h"
int mkdir(char * path, char ** message) {
// variabili di appoggio
char * aux;
char * temp;
I_NODE found;
I_NODE new;
// offset alla posizione degli i-node
int offset_new;
int offset_inode;
// contatori per i cicli
int i,k;
// descrittore per il vfs
int vfs;
// array per il blocco della directory
DIRECTORY block_in;
// restituisco il puntatore all'ultima '/' in path
aux = strrchr(path,'/');
// gestione path malformato
if(aux == NULL) {
error_handler(INVALID_PATH_MESSAGE, message);
return GEN_FAIL;
}
// se l'ultimo carattere e' una '/' la sostituisco con uno '\0'
if((aux - path) == strlen(path) - 1) {
path[(aux - path)] = '\0';
aux = strrchr(path,'/');
}
// gestione nel caso in cui il path sia gia' esistente
if(get_i_node(path,&found) != GEN_FAIL) {
error_handler(PATH_ALREADY_EXIST_ERROR_MESSAGE, message);
return GEN_FAIL;
}
// se il puntatore all'ultima '/' coincide con l'inizio allora
// devo accedere direttamente alla root
if(aux == path) {
// ottengo l'i-node di '/'
offset_inode = get_i_node("/",&found);
if(offset_inode == GEN_FAIL) {
error_handler(GET_INODE_ERROR_MESSAGE, message);
return GEN_FAIL;
}
} else {
// se invece devo accedere ad un certo path creo la stringa da
// passare a get_i_node che e' formata da tutto il path esclusa
// la nuova cartella da creare
// abbiamo usato l'aritmetica dei puntatori per avere la
// lunghezza della stringa da allocare (aux-path)
temp = calloc((aux-path) + 1, sizeof(char));
for(i = 0; i < (aux-path); i++) {
temp[i] = path[i];
}
temp[i] = '\0';
// ottengo l'inode di tale path
offset_inode = get_i_node(temp, &found);
if(offset_inode == GEN_FAIL) {
free(temp);
error_handler(GET_INODE_ERROR_MESSAGE, message);
return GEN_FAIL;
}
}
// se il tipo e' file dai errore: non si possono creare cartelle
// al di sotto dei file
if(found.type == RFILE) {
error_handler(NOT_A_DIRECTORY_ERROR_MESSAGE, message);
return GEN_FAIL;
}
// errore se non c'e' piu' spazio nella directory
if(found.size == NUM_DIR_ENTRY) {
error_handler(FULL_DIR_ERROR_MESSAGE, message);
return GEN_FAIL;
}
// apro il file vfs per leggere la struttura della directory
// in modo da poterne poi aggiornare i valori
vfs = open(PATH,O_RDONLY);
if(vfs == -1) {
error_handler(OPEN_ERROR_MESSAGE, message);
return GEN_FAIL;
}
// mi sposto alla posizione del blocco puntato dall'i-node
if(lseek(vfs,found.block,SEEK_SET) == -1) {
error_handler(VFS_INTERNAL_ERROR_MESSAGE, message);
return GEN_FAIL;
}
// lettura dal blocco delle strutture di directory
for(k = 0; k < NUM_DIR_ENTRY; k++) {
if(read(vfs,&block_in[k],sizeof(DIRECTORY_ENTRY)) \
< sizeof(DIRECTORY_ENTRY)) {
error_handler(VFS_INTERNAL_ERROR_MESSAGE, message);
close(vfs);
return GEN_FAIL;
}
}
// chiudo il file
close(vfs);
// alloco un blocco per la nuova directory
if((offset_new = allocate_block(DIR,&new)) == GEN_FAIL) {
error_handler(FULL_DISK_ERROR_MESSAGE, message);
return GEN_FAIL;
}
// aggiorno il blocco della directory madre
found.size++; // incremento il numero di elementi
// scrivo nella struttura del blocco la nuova entry
strcpy(block_in[found.size].name,(aux+1));
block_in[found.size].i_node = offset_new;
// aggiorno sul vfs l'i-node e il blocco modificati
// apro il file
vfs = open(PATH,O_WRONLY);
if(vfs == -1) {
error_handler(OPEN_ERROR_MESSAGE, message);
return GEN_FAIL;
}
// mi sposto alla posizione dell'i-node
if(lseek(vfs,offset_inode,SEEK_SET) == -1) {
error_handler(VFS_INTERNAL_ERROR_MESSAGE, message);
close(vfs);
return GEN_FAIL;
}
// scrivo l'inode aggiornato
if(write(vfs,&found,I_NODE_SIZE) < I_NODE_SIZE) {
error_handler(VFS_INTERNAL_ERROR_MESSAGE, message);
close(vfs);
return GEN_FAIL;
}
// mi sposto alla posizione del blocco
if(lseek(vfs, found.block + \
(found.size - 1) * sizeof(DIRECTORY_ENTRY) \
,SEEK_SET) == -1) {
error_handler(VFS_INTERNAL_ERROR_MESSAGE, message);
close(vfs);
return GEN_FAIL;
}
// scrivo l'entry aggiornata nel blocco
if(write(vfs,&(block_in[found.size]),sizeof(DIRECTORY_ENTRY)) \
< sizeof(DIRECTORY_ENTRY)) {
error_handler(VFS_INTERNAL_ERROR_MESSAGE, message);
close(vfs);
return GEN_FAIL;
}
// chiudo il file
close(vfs);
// e' andato tutto bene
(*message)[0] = '0';
(*message)[1] = '\0';
return EXIT_SUCCESS;
}
/* fine file */
/* file sorgente purge.c
*
* definizione della funzione purge che si occupera di
* rimuovere completamente senza possibilita' di recupero un
* file o un link hard
*
*/
#include <string.h>
#include "base-functions.h"
int purge(char *path, char **message) {
// inode che si riferisce al path
I_NODE temp_inode;
// offset dell'inode
int offset_temp_inode;
// parte sinistra del path
char *left_side;
// parte destra del path
char *terminal_name;
// array che rappresenta una directory
DIRECTORY dir;
// descrittore del file
int vfs;
// variabili d'appoggio
char *aux;
int i,k;
// controllo che il path sia ben formato
aux = strrchr(path,'/');
if(aux == NULL) {
error_handler(INVALID_PATH_MESSAGE, message);
return GEN_FAIL;
}
// se l'ultimo carattere e' una '/' la sostituisco con uno '\0'
if((aux - path) == strlen(path) - 1) {
path[(aux - path)] = '\0';
aux = strrchr(path,'/');
}
// acquisisco l'inode da eliminare
if((offset_temp_inode = get_i_node(path,&temp_inode)) == GEN_FAIL) {
error_handler(GET_INODE_ERROR_MESSAGE, message);
return GEN_FAIL;
}
// se l'inode e' negativo (c'e' stata una cancellazione soft)
// lo inverto di segno per renderlo positivo e utilizzarlo
if(offset_temp_inode < 0) {
offset_temp_inode = -offset_temp_inode;
}
// se l'inode rappresenta una directory con almeno un elemento
// restituisco immediatamente un errore
if((temp_inode.type == DIR) && (temp_inode.size > 0)) {
error_handler(CANNOT_PURGE_NOT_EMPTY_DIR_ERROR_MESSAGE, message);
return GEN_FAIL;
}
if(deallocate_block(&temp_inode,offset_temp_inode) == GEN_FAIL) {
error_handler(VFS_INTERNAL_ERROR_MESSAGE,message);
return GEN_FAIL;
}
// se il path non contiene barre (e' malformato) usciamo
if((terminal_name = strrchr(path,'/')) == NULL) {
error_handler(INVALID_PATH_MESSAGE, message);
return GEN_FAIL;
}
// se la strrchr va a buon fine con il ++ eliminiamo la barra
// iniziale che non ci interessa
terminal_name++;
// inserisco in left_side la parte sinistra
left_side = (char*)malloc((terminal_name - path)+1);
left_side[0] = '\0';
strncat(left_side, path,(size_t)((terminal_name - path)));
if((offset_temp_inode = get_i_node(left_side,&temp_inode)) == \
GEN_FAIL) {
error_handler(GET_INODE_ERROR_MESSAGE, message);
free(left_side);
return GEN_FAIL;
}
// se l'inode e' negativo (c'e' stata una cancellazione soft)
// lo inverto di segno per renderlo positivo e utilizzarlo
if(offset_temp_inode < 0)
offset_temp_inode = -offset_temp_inode;
// si apre il file in lettura e si gestiscono eventuali errori
if ((vfs = open(PATH,O_RDONLY)) == -1) {
return GEN_FAIL;
}
// mi posiziono al punto giusto
if(lseek(vfs,temp_inode.block,SEEK_SET) == GEN_FAIL) {
error_handler(VFS_INTERNAL_ERROR_MESSAGE,message);
free(left_side);
close(vfs);
return GEN_FAIL;
}
// carico in memoria le directory entry
for(i = 0; i < temp_inode.size; i++) {
// leggo una directory entry
if(read(vfs,&(dir[i]),sizeof(DIRECTORY_ENTRY)) < \
sizeof(DIRECTORY_ENTRY)) {
error_handler(VFS_INTERNAL_ERROR_MESSAGE,message);
free(left_side);
close(vfs);
return GEN_FAIL;
}
}
// chiudo il file
close(vfs);
// disalloco la memoria
free(left_side);
// scansiono tutte le dir entry finche' non trovo quella giusta
for(i = 0; i < temp_inode.size; i++) {
if(strcmp(dir[i].name,terminal_name) == 0) {
break;
}
}
// questo controllo non sarebbe strettamente necessario:
// se la get_i_node non aveva dato errori, vuol dire che
// la entry era giĆ stata trovata
if(i == temp_inode.size) {
error_handler(VFS_INTERNAL_ERROR_MESSAGE,message);
return GEN_FAIL;
}
// tiro su tutte le dir entry seguenti a quella cancellata
for(k = i + 1; k < temp_inode.size; k++, i++) {
dir[i] = dir[k];
}
// cancello l'ultima entry che e' stata inevitabilmente tirata su
strcpy((dir[k - 1]).name, "");
(dir[k - 1]).i_node = -1;
// aggiorno le directory
// si apre il file in lettura e si gestiscono eventuali errori
if ((vfs = open(PATH,O_WRONLY)) == -1) {
return GEN_FAIL;
}
// mi posiziono al punto giusto
if(lseek(vfs,temp_inode.block,SEEK_SET) == GEN_FAIL) {
error_handler(VFS_INTERNAL_ERROR_MESSAGE,message);
close(vfs);
return GEN_FAIL;
}
// scrivo su disco le directory entry
for(i = 0; i < temp_inode.size; i++) {
// scrivo una directory entry
if(write(vfs,&(dir[i]),sizeof(DIRECTORY_ENTRY)) < \
sizeof(DIRECTORY_ENTRY)) {
error_handler(VFS_INTERNAL_ERROR_MESSAGE,message);
close(vfs);
return GEN_FAIL;
}
}
// evito che size vada a valori negativi
if(temp_inode.size>0) {
temp_inode.size--;
}
// vado ad aggiornare la nuova size dell'inode:
// mi posiziono nel punto giusto
if(lseek(vfs,offset_temp_inode,SEEK_SET) == GEN_FAIL) {
error_handler(VFS_INTERNAL_ERROR_MESSAGE,message);
close(vfs);
return GEN_FAIL;
}
// scrivo l'i-node
if(write(vfs,&temp_inode,I_NODE_SIZE) == GEN_FAIL) {
error_handler(VFS_INTERNAL_ERROR_MESSAGE,message);
close(vfs);
return GEN_FAIL;
}
// chiudo il file
close(vfs);
// termino con successo
(*message)[0] = '0';
(*message)[1] = '\0';
return EXIT_SUCCESS;
}
/* fine file */
/* file sorgente server.c
*
* sorgente del server
*/
#include <sys/socket.h>
#include <sys/un.h>
#include <string.h>
#include <signal.h>
#include "base-functions.h"
int make_named_socket(const char *filename);
void suicide(int sig);
// funzioni ad 'alto' livello
int ls(char *path, char ** message);
int mkdir(char * path, char ** message);
int cp_fs2vd(char * path_fs, char * path_vd, char **message);
int cp_vd2fs(char * path_vd, char * path_fs, char **message);
int cp_vd2vd(char *path_source, char *path_dest, char **message);
int ln(char * target, char * link_name, char ** message);
int purge(char *path, char **message);
int del(char *path, char **message);
int undel(char *path, char **message);
int main(int argc, char *argv[]) {
int sock;
int client;
char message='0';
char comando[100][100];
int i=0,j;
const char *filename = SOCK_PATH;
// verra' riempita con l'indirizzo del client
struct sockaddr addr;
// verra' riempita con dimensione della struttura addr
unsigned int adLen = sizeof(struct sockaddr_un);
char * output;
// cancella e crea il file temporaneo create-vfs
unlink(PATH);
if(create_vfs(VFS_NUM_FILES)==-1) {
fprintf(stderr,"Error creating vfs temporary file\n");
unlink(PATH);
return -1;
}
// intercetto i segnali di terminazione (se possibile)
// per poter cancellare il file temporaneo
signal(SIGHUP,suicide);
signal(SIGINT,suicide);
signal(SIGPIPE,suicide);
signal(SIGALRM,suicide);
signal(SIGTERM,suicide);
signal(SIGUSR1,suicide);
signal(SIGUSR2,suicide);
signal(SIGSTOP,suicide);
signal(SIGTTIN,suicide);
signal(SIGTTOU,suicide);
signal(SIGPROF,suicide);
// elimina un eventuale socket e lo crea
unlink(filename);
sock = make_named_socket(filename);
// dichiara il num di richieste accodabili con listen()
if(listen(sock,1) != 0) {
perror("listen");
exit(EXIT_FAILURE);
}
// divento demone
daemon(0,0);
while(1) {
// accetta una connessione con accept()
if ((client = accept(sock, &addr, &adLen)) == -1) {
perror("accept");
exit(EXIT_FAILURE);
}
// opera sul socket con read() e write()
message = '0';
i = 0;
while(message != '&') {
message = '0';
j = 0;
while(message != '\0' && message != '&') {
read(client,&message,1);
// non devo inserire l'& di terminazione
if(message != '&') {
comando[i][j] = message;
j++;
}
}
i++; // variabile importante indica il numero di parole
}
// inizializzo output in memoria dinamica
output = (char *)malloc(sizeof(char)*2);
// eseguo il comando
if(strcmp(comando[0],"cp_fs2vd") == 0 && i == 4) {
cp_fs2vd(comando[1],comando[2],&output);
write(client,output,strlen(output) + 1);
} else if(strcmp(comando[0],"cp_vd2fs") == 0 && i == 4) {
cp_vd2fs(comando[1],comando[2],&output);
write(client,output,strlen(output) + 1);
} else if(strcmp(comando[0],"cp_vd2vd") == 0 && i == 4) {
cp_vd2vd(comando[1],comando[2],&output);
write(client,output,strlen(output) + 1);
} else if(strcmp(comando[0],"ln") == 0 && i == 4) {
ln(comando[1],comando[2],&output);
write(client,output,strlen(output) + 1);
} else if(strcmp(comando[0],"ls") == 0 && i == 3) {
ls(comando[1],&output);
write(client,output,strlen(output) + 1);
} else if(strcmp(comando[0],"mkdir") == 0 && i == 3) {
mkdir(comando[1],&output);
write(client,output,strlen(output) + 1);
} else if(strcmp(comando[0],"del") == 0 && i == 3) {
del(comando[1],&output);
write(client,output,strlen(output) + 1);
} else if(strcmp(comando[0],"undel") == 0 && i == 3) {
undel(comando[1],&output);
write(client,output,strlen(output) + 1);
} else if(strcmp(comando[0],"purge") == 0 && i == 3) {
purge(comando[1],&output);
write(client,output,strlen(output) + 1);
} else if(strcmp(comando[0],"stop") == 0 && i == 2) {
output[0]='0';
output[1]='\0';
write(client,output,strlen(output) + 1);
unlink(PATH);
free(output);
close(client);
close(sock);
return 0;
} else {
write(client,"1Command not found",19);
}
free(output);
// chiudo i socket
close(client);
}
close(sock);
return 0;
}
int make_named_socket(const char *filename) {
struct sockaddr_un name;
int sock;
sock = socket (AF_UNIX, SOCK_STREAM, 0);
if (sock < 0) {
// controllare le perror che non creino problemi
perror ("socket");
exit (EXIT_FAILURE);
}
name.sun_family = AF_UNIX;
strcpy(name.sun_path, filename);
if (bind(sock, (struct sockaddr *) &name, sizeof(name)) < 0) {
perror("bind");
exit(EXIT_FAILURE);
}
return sock;
}
void suicide(int sig) {
unlink(PATH);
exit(GEN_FAIL);
}
/* file sorgente undel.c
*
* definizione della funzione del che si occupera di
* recuperare un file o un link hard
*
*/
#include <string.h>
#include "base-functions.h"
int undel(char *path, char **message) {
// inodes temporanei
I_NODE temp_inode;
I_NODE maybe_purged_inode;
// offset dell'inode
int temp_inode_offset;
// parte sinistra del path
char *safe_path;
// parte destra del path
char *terminal_name;
// DIRECTORY_ENTRY di appoggio
DIRECTORY_ENTRY temp_dir_entry;
// descrittore per il file system virtuale
int vfs;
// contatore
int i;
// se il path non contiene barre (e' malformato) usciamo.
// Se tutto va bene, mi ricavo la parte destra del path
if((terminal_name = strrchr(path,'/')) == NULL) {
error_handler(INVALID_PATH_MESSAGE, message);
return GEN_FAIL;
}
// elimino la barra
terminal_name++;
// controllo se il path esiste
if((temp_inode_offset = get_i_node(path, &temp_inode)) == GEN_FAIL) {
error_handler(INVALID_PATH_MESSAGE, message);
return GEN_FAIL;
}
// controllo che abbia l'inode negativo
if(temp_inode_offset>=0) {
error_handler(CANNOT_UNDEL_EXISTING_FILE_ERROR_MESSAGE, message);
return GEN_FAIL;
}
// mi ricavo la parte sinistra del path
safe_path = (char*)malloc((terminal_name - path)+1);
safe_path[0] = '\0';
strncat(safe_path, path,(size_t)((terminal_name - path)));
// mi ricavo l'inode della cartella in cui e' contenuto il file da
// eliminare (dobbiamo modificare la rispettiva directory entry)
if((temp_inode_offset = get_i_node(safe_path, &temp_inode)) \
== GEN_FAIL) {
error_handler(INVALID_PATH_MESSAGE, message);
return GEN_FAIL;
}
// apriamo il file del vfs
if((vfs = open(PATH,O_RDWR)) == GEN_FAIL) {
error_handler(OPEN_ERROR_MESSAGE, message);
return GEN_FAIL;
}
// ci spostiamo all'offset della directory table
if(lseek(vfs,temp_inode.block,SEEK_SET) == GEN_FAIL) {
error_handler(VFS_INTERNAL_ERROR_MESSAGE, message);
close(vfs);
return GEN_FAIL;
}
// ciclo per trovare l'entry giusta, quando la troviamo usciamo
// dal ciclo
i = 0;
temp_dir_entry.name[0]='\0';
while(strcmp(temp_dir_entry.name, terminal_name) != 0){
i++;
// leggiamo una entry
if(read(vfs,&temp_dir_entry,sizeof(DIRECTORY_ENTRY)) \
< sizeof(DIRECTORY_ENTRY)) {
close(vfs);
return GEN_FAIL;
}
}
// ricordiamo che l'entry giusta deve essere trovata per forza, a
// causa del controllo all'inizio del listato
// la modifichiamo rendendo positivo il valore del campo inode
temp_dir_entry.i_node = - temp_dir_entry.i_node;
// ma esiste veramente o per caso e' stata fatta una purge?
if(lseek(vfs,temp_dir_entry.i_node,SEEK_SET) == GEN_FAIL) {
error_handler(VFS_INTERNAL_ERROR_MESSAGE, message);
close(vfs);
return GEN_FAIL;
}
if(read(vfs,&maybe_purged_inode,I_NODE_SIZE) \
< I_NODE_SIZE) {
close(vfs);
return GEN_FAIL;
}
if(maybe_purged_inode.block == 0) {
error_handler(INVALID_PATH_MESSAGE, message);
return GEN_FAIL;
}
if(lseek(vfs,((i-1)*sizeof(DIRECTORY_ENTRY))+ temp_inode.block, \
SEEK_SET) == GEN_FAIL) {
error_handler(VFS_INTERNAL_ERROR_MESSAGE, message);
close(vfs);
return GEN_FAIL;
}
// e la riscriviamo
if(write(vfs,&temp_dir_entry,sizeof(DIRECTORY_ENTRY)) \
< sizeof(DIRECTORY_ENTRY)) {
error_handler(VFS_INTERNAL_ERROR_MESSAGE, message);
close(vfs);
return GEN_FAIL;
}
// e vado a scrivere la modifica
if(lseek(vfs,temp_inode_offset,SEEK_SET) == GEN_FAIL) {
error_handler(VFS_INTERNAL_ERROR_MESSAGE, message);
close(vfs);
return GEN_FAIL;
}
if(write(vfs,&temp_inode,I_NODE_SIZE) < I_NODE_SIZE) {
error_handler(VFS_INTERNAL_ERROR_MESSAGE, message);
close(vfs);
return GEN_FAIL;
}
// chiudo il file
close(vfs);
// termino con successo
(*message)[0] = '0';
(*message)[1] = '\0';
return EXIT_SUCCESS;
}
/* fine file */
/* file sorgente vd.c
*
* sorgente del client
*
*/
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/time.h>
#include <stdlib.h>
#include "coderr.h"
#include "const.h"
int send_server(char *param[], int len);
int main(int argc, char *argv[]) {
// se non ci sono parametri restituisco l'usage
if(argc == 1) {
fprintf(stderr,"Usage: %s <comand>\n",argv[0]);
return -1;
}
// invio gli argomenti al server e stampo risposta/errore
if(send_server(argv,argc-1)==-1) {
return -1;
}
// se tutto e' andato bene restituisco 0
return 0;
}
// comunica al server il comando e gli argomenti da eseguire
// leggendoli carattere per carattere
int send_server(char *param[], int len) {
int sock; // descrittore del socket
int i,j; // variabili per cicli
char exit_code; // exit code
int num_el; // contatore per la risposta
char temp = '0'; // buffer da 1 carattere
char term = '&'; // terminatore
struct sockaddr_un name; // struttura per la connessione
struct timeval timeout; // timeout per la read
char *reply; // array dinamico per la risposta
// inserisco le informazioni nella struttura: tipo e path
name.sun_family = AF_UNIX;
strcpy(name.sun_path, SOCK_PATH);
// crea un socket anonimo con socket()
sock = socket(AF_UNIX, SOCK_STREAM, 0);
// collega il socket al server con connect()
if(connect(sock, (struct sockaddr *) &name, sizeof(name))==-1) {
perror("Error connecting to the server");
return -1;
}
// imposto il timeout in ricezione sul socket
// necessario impostare sia il valore dei secondi...
timeout.tv_sec = SOCKET_TIMEOUT_VAL;
// che dei millisecondi
timeout.tv_usec = 0;
setsockopt(sock,SOL_SOCKET,SO_RCVTIMEO,&timeout,sizeof(timeout));
// opera sul socket con write()
for(i = 1; i <= len; i++) {
temp='0';
j=0;
while(temp!='\0') {
// carica in temp un carattere del comando in input
temp=param[i][j];
// lo invia
if(write(sock,&temp,1)==-1) {
perror("Error connecting to the server");
return -1;
}
j++;
}
}
// invia il carattere di terminazione
if(write(sock,&term,1)==-1) {
perror("Error connecting to the server");
return -1;
}
// si pone in ascolto sul socket
// in attesa di risposta da parte del server
// la read qui puo' dare anche un errore di timeout
if(read(sock,&exit_code,1)!=1){
perror("Error/Timeout in receiving reply from server");
close(sock);
return -1;
}
// inizializzo l'array dinamico di char
reply = (char *)malloc(sizeof(char));
// inizializzo temp e i per il while
temp='0';
i = 0;
// num_el = 2 cosi' realloc crea un array di 2 elementi alla prima
// esecuzione del ciclo
num_el = 2;
while(temp != '\0'){
if(read(sock,&temp,1)!=1){
perror("Error in receiving reply from server");
close(sock);
return -1;
}
reply[i] = temp;
i++;
// rialloco l'array in memoria dinamica
reply = (char *)realloc(reply, num_el*sizeof(char));
num_el++;
}
if(strlen(reply) != 0) {
printf("%s\n",reply);
}
// chiude il socket
close(sock);
// ovviamo al problema che il primo carattere letto dalla socket
// non puo' essere negativo e restituiamo il risultato che il
// comando ha avuto nel server
if(exit_code=='1')
return -1;
// se e' andato tutto bene
return 0;
}
CFLAGS=-Wall -g all: vd server clean: rm *.o vd server server: create-vfs.o \ allocate-block.o \ deallocate-block.o \ get-i-node.o \ ls.o \ mkdir.o \ cp-fs2vd.o \ cp-vd2fs.o \ cp-vd2vd.o \ error-handler.o \ ln.o \ purge.o \ del.o \ undel.o \ base-functions.h vd: coderr.h \ const.h create-vfs.o: base-functions.h allocate-block.o: base-functions.h deallocate-block.o: base-functions.h get-i-node.o: base-functions.h mkdir.o: base-functions.h ls.o: base-functions.h cp-fs2vd.o: base-functions.h cp-vd2fs.o: base-functions.h cp-vd2vd.o: base-functions.h ln.o: base-functions.h purge.o: base-functions.h del.o: base-functions.h undel.o: base-functions.h install: script/install.sh uninstall: script/uninstall.sh