Difference between revisions of "Esercizio 1, prova pratica 13/09/2013"

From Sistemi Operativi
Jump to navigation Jump to search
 
(2 intermediate revisions by the same user not shown)
Line 7: Line 7:
 
</source>
 
</source>
  
==Soluzione di Maldus==
+
==Soluzione di Maldus (ora con tabella hash!)==
 
<source lang="c">
 
<source lang="c">
 
#include <stdio.h>
 
#include <stdio.h>
 
#include <unistd.h>
 
#include <unistd.h>
 
#include <errno.h>
 
#include <errno.h>
#include <limits.h>
 
 
#include <sys/types.h>
 
#include <sys/types.h>
 
#include <sys/stat.h>
 
#include <sys/stat.h>
Line 23: Line 22:
 
char BUFF1[SIZE] ; /*buffer usati per leggere i file*/
 
char BUFF1[SIZE] ; /*buffer usati per leggere i file*/
 
char BUFF2[SIZE] ;
 
char BUFF2[SIZE] ;
 +
 +
struct list{ /*struttura che uso per implementare la lista di file che hanno uguale somma crittografica*/
 +
struct dirent* ent ;
 +
struct list *next ;
 +
struct list *prev ;
 +
};
 +
 +
 +
inline void del(struct list* p){ /*rimuove p dalla lista in cui si trova*/
 +
(p->next)->prev = p->prev ;
 +
(p->prev)->next = p->next ;
 +
free(p) ;
 +
}
 +
 +
 +
int critsum( int f ){ /*somma crittografica per la tabella hash*/
 +
int i , n ;
 +
int x = 0 ;
 +
while(( n = read( f , BUFF1 , SIZE ) )> 0 ){
 +
for( i = 0 ; i < n ; i++ ){
 +
x += ((int) BUFF1[i])*((i%8)+1) ; /*aggiungo ogni volta il valore numerico corrispondente al byte letto moltiplicato per un numero da 1 a 8*/
 +
}
 +
}
 +
if( x < 0) return -x ;/*restituisco sempre un valore positivo, perchè possa essere usato come indice di un vettore*/
 +
else return x ;
 +
}
 +
  
 
int buffcmp( char* buf1 , char* buf2 , int s1 , int s2 ){/*funzione che compara due buffer*/
 
int buffcmp( char* buf1 , char* buf2 , int s1 , int s2 ){/*funzione che compara due buffer*/
Line 32: Line 58:
 
return 0 ;
 
return 0 ;
 
}
 
}
 +
  
 
int filecmp( int f1 , int f2 ){ /*funzione ausiliaria che confronta due file. Si comporta come strcmp*/
 
int filecmp( int f1 , int f2 ){ /*funzione ausiliaria che confronta due file. Si comporta come strcmp*/
Line 40: Line 67:
 
}
 
}
 
return 0 ; /*ritorna 0 se sono uguali*/
 
return 0 ; /*ritorna 0 se sono uguali*/
}  
+
}
 +
 
 +
 
 +
void del_clones( struct list* p ){ /*cerca nella lista il cui primo elemento è p tutti i file con lo stesso contenuto*/
 +
struct list *aux1 , *aux2 , *tmp;
 +
int fd1, fd2 ;
 +
struct stat s1 , s2 ;
 +
aux1 = p ;
 +
aux2 = aux1->next ;
 +
while( aux1->next != p ){
 +
printf( "%s:\n" , (aux1->ent)->d_name ) ;
 +
if( stat( (aux1->ent)->d_name , &s1 ) != 0 ){
 +
perror("stat") ;
 +
exit(1) ;
 +
}
 +
if ( (fd1 = open((aux1->ent)->d_name, O_RDONLY ) ) == -1){ /*apro la entry*/
 +
perror("open") ;
 +
exit(1) ;
 +
}
 +
 +
while( (aux2->next) != p && (aux2 != p) ){
 +
tmp = aux2->next ;
 +
if( stat( (aux2->ent)->d_name , &s2 ) != 0 ){
 +
perror("stat") ;
 +
exit(1) ;
 +
}
 +
if ( (fd2 = open((aux2->ent)->d_name, O_RDONLY ) ) == -1){ /*apro la entry*/
 +
perror("open") ;
 +
exit(1) ;
 +
}
 +
printf("\t%s" , (aux2->ent)->d_name) ;
 +
if( s1.st_ino != s2.st_ino){
 +
if( filecmp( fd1 , fd2 ) == 0 ){ /*controllo se i due file hanno lo stesso contenuto*/
 +
printf("<-uguale\t") ;
 +
unlink((aux2->ent)->d_name) ; /*rimuovo il file uguale*/
 +
if( link( (aux1->ent)->d_name , (aux2->ent)->d_name) == -1 ){ /*creo un link fisico*/
 +
perror("link") ;
 +
exit(1) ;
 +
}
 +
del(aux2) ;
 +
}
 +
}
 +
else del(aux2) ; /*se hanno lo stesso i-node toglili dalla lista*/
 +
aux2 = tmp; /*tmp = aux2->next. Lo salvo in precedenza nel caso in cui aux2 sia stato cancellato*/
 +
close(fd2) ;
 +
}
 +
printf("\n") ;
 +
close(fd1) ;
 +
aux1 = aux1->next ;
 +
 +
}
 +
}
  
 
int main( int argc, char* argv[]){
 
int main( int argc, char* argv[]){
 
struct stat s1 , s2; /*struttura di informazioni su un file*/
 
struct stat s1 , s2; /*struttura di informazioni su un file*/
DIR *dir1 , *dir2 ; /*puntatori a directory; con dir1 scorro le entry, e con dir2 le scorro di nuovo controllando se ci sono dei file con il contenuto uguale*/
+
DIR *dir  ; /*puntatore a directory*/
struct dirent *entry_i ; /*struttura di informazioni sulle entry di una directory*/
+
struct dirent *entry ; /*struttura di informazioni sulle entry di una directory*/
int fd1, fd2 ; /*descrittori di file*/
+
int fd1; /*descrittore di file*/
 
char *name ;
 
char *name ;
 +
int n = 0 ; /*contatore di file all'interno della directory*/
 +
int cs , i ; /*cs è somma crittografica del file*/
 +
struct list *hash ;
 +
struct list *tmp ;
 
if( stat( argv[1] , &s1 ) != 0 ){
 
if( stat( argv[1] , &s1 ) != 0 ){
 
perror("stat") ;
 
perror("stat") ;
Line 56: Line 138:
 
return 0 ;
 
return 0 ;
 
}
 
}
if( (dir1 = opendir( argv[1] )) == NULL ){
+
if( (dir = opendir( argv[1] )) == NULL ){
perror("opendir") ;
 
return 1 ;
 
}
 
if( (dir2 = opendir( argv[1] )) == NULL ){
 
 
perror("opendir") ;
 
perror("opendir") ;
 
return 1 ;
 
return 1 ;
Line 68: Line 146:
 
return 1 ;
 
return 1 ;
 
}
 
}
while( (entry_i = readdir(dir1) ) != NULL){ /*scorro le entry della directory*/
+
while( (entry = readdir(dir) ) != NULL){ /*conto i file contenuti nella directory*/
stat( entry_i->d_name , &s1 ) ;
+
stat( entry->d_name , &s1 ) ;
if(!S_ISREG(s1.st_mode)) continue ; /*se la entry che sto considerando non è un file normale salta una iterazione */
+
if( S_ISREG(s1.st_mode) ) n++ ; /*se si tratta di un file normale contalo*/
asprintf( &name , "%s" , entry_i->d_name ) ; /*salvo il nome della entry che sto considerando in name*/
+
}
if ( (fd1 = open(name, O_RDONLY ) ) == -1){ /*apro la entry*/
+
printf("La directory contiene %i file\n" , n ) ;
perror("open") ;
+
n = 2*n ; /*da questo momento n è il numero di indici nella mia hashtable*/
exit(1) ;
+
hash = (struct list*) malloc( sizeof(struct list)*n) ; /*alloco una hash table con n = 2n indici*/
 +
rewinddir(dir) ;
 +
for( i = 0 ; i < n ; i++ ){ /*inizializzo le liste*/
 +
hash[i].next = &hash[i] ;
 +
hash[i].prev = &hash[i] ;
 +
hash[i].ent = NULL ;
 +
}
 +
while( (entry = readdir(dir) ) != NULL){ /*con questo ciclo riempo la hashtable*/
 +
stat( entry->d_name , &s1 ) ;
 +
if( S_ISREG(s1.st_mode) ){ /*se si tratta di un file normale consideralo*/
 +
if ( (fd1 = open(entry->d_name, O_RDONLY ) ) == -1){ /*apro la entry*/
 +
perror("open") ;
 +
exit(1) ;
 +
}
 +
cs = critsum( fd1 ) ;
 +
tmp = (struct list*) malloc( sizeof(struct list) ) ;
 +
tmp->ent = entry ;
 +
(hash[cs%n].next)->prev = tmp ; /*inserisco il file in testa alla lista di indice cs%n*/
 +
tmp->prev = &hash[cs%n] ;
 +
tmp->next = hash[cs%n].next ;
 +
hash[cs%n].next = tmp ;
 +
close(fd1) ;
 
}
 
}
printf("1)%s %i\n" , name , (int) s1.st_ino ) ;
+
}
rewinddir( dir2 ) ; /*ogni volta devo ricontrollare tutte le entry della directory (complessità quadratica), quindi il puntatore del ciclo più interno deve ripartire dall'inizio ogni volta*/
+
for( i = 0 ; i < n ; i++ ){ /*con questo ciclo cancello effettivamente i file uguali*/
while( (entry_i = readdir(dir2) ) != NULL) { /*secondo ciclo*/
+
printf("%i: " , i ) ;
lseek( fd1 , 0 , SEEK_SET ) ; /*per poter indagare il contenuto della entry che sto considerando nel ciclo più esterno, faccio ripartire l'offset dall'inizio a ogni iterazione*/
+
if( hash[i].next != &hash[i] ){
stat( entry_i->d_name , &s2 ) ;
+
del_clones( hash[i].next ) ;
if(!S_ISREG(s2.st_mode)) continue ; /*come sopra*/
 
if( s1.st_ino != s2.st_ino){ /*se non si tratta di link fisici dello stesso file procedi*/
 
printf("2)%s %i\t" , entry_i->d_name , (int)s2.st_ino) ;
 
if( ( fd2 = open( entry_i->d_name, O_RDONLY ) ) == -1 ){
 
perror("open");
 
exit(1) ;
 
}
 
if(S_ISREG(s2.st_mode)){
 
if( filecmp( fd1 , fd2 ) == 0 ){ /*controllo se i due file hanno lo stesso contenuto*/
 
printf("<-uguali\n") ;
 
unlink(entry_i->d_name) ; /*rimuovo il file uguale*/
 
if( link( name , entry_i->d_name) == -1 ){ /*creo un link fisico*/
 
perror("link") ;
 
return 1 ;
 
}
 
}
 
}
 
close(fd2) ;
 
}
 
 
}
 
}
close(fd1) ;
+
else printf("\n") ;
free( name ) ;
 
printf("\n") ;
 
 
}
 
}
 
 
return 0 ;
 
return 0 ;
 
}
 
}
 
</source>
 
</source>

Latest revision as of 21:55, 4 March 2015

Consegna([1]):

Lo scopo del programma che dovrete scrivere e' di confrontare fra loro i file di una directory, se ne trovate due (o piu') che
hanno lo stesso contenuto dovete unificarli. Alla fine del processo l'elenco dei file della directory deve rimanere invariato ma
i nomi dei file che avevano lo stesso contenuto devono essere link fisici che indicano lo stesso file.
In questo esercizio si richiede che l'intero contenuto dei file venga confrontato.

Soluzione di Maldus (ora con tabella hash!)

#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <fcntl.h>
#include <stdlib.h>

#define SIZE 1024 

char BUFF1[SIZE] ;	/*buffer usati per leggere i file*/
char BUFF2[SIZE] ;

struct list{	/*struttura che uso per implementare la lista di file che hanno uguale somma crittografica*/
	struct dirent* ent ;
	struct list *next ;
	struct list *prev ;
};


inline void del(struct list* p){	/*rimuove p dalla lista in cui si trova*/
	(p->next)->prev = p->prev ;
	(p->prev)->next = p->next ;
	free(p) ;
}


int critsum( int f ){	/*somma crittografica per la tabella hash*/
	int i , n ;
	int x = 0 ;
	while(( n = read( f , BUFF1 , SIZE ) )> 0 ){
		for( i = 0 ; i < n ; i++ ){
			x += ((int) BUFF1[i])*((i%8)+1) ;	/*aggiungo ogni volta il valore numerico corrispondente al byte letto moltiplicato per un numero da 1 a 8*/
		}
	}
	if( x < 0) return -x ;/*restituisco sempre un valore positivo, perchè possa essere usato come indice di un vettore*/
	else return x ;
}
		

int buffcmp( char* buf1 , char* buf2 , int s1 , int s2 ){/*funzione che compara due buffer*/
	int i ;
	if( s1 != s2 ) return 1 ; /*se hanno lunghezza diversa sono diversi*/
	for( i = 0 ; i < s1 ; i++ ){
		if( buf1[i] != buf2[i] ) return 1 ;
	}
	return 0 ;
}


int filecmp( int f1 , int f2 ){	/*funzione ausiliaria che confronta due file. Si comporta come strcmp*/
	int n1 , n2 ;
	while(( n1 = read( f1 , BUFF1 , SIZE ) )> 0 ){	/*ho provato a inserire entrambe le read nel controllo del while con un &&; mi creava dei problemi, come se la seconda read venisse eseguita nel giro seguente del ciclo*/
		n2 = read( f2 , BUFF2 , SIZE ) ;
		if( buffcmp( BUFF1 , BUFF2 , n1 , n2 ) != 0 ) return 1 ;	/*ritorna 1 se i due file sono diversi*/
	}
	return 0 ;	/*ritorna 0 se sono uguali*/
}


void del_clones( struct list* p ){	/*cerca nella lista il cui primo elemento è p tutti i file con lo stesso contenuto*/
	struct list *aux1 , *aux2 , *tmp;
	int fd1, fd2 ;
	struct stat s1 , s2 ;
	aux1 = p ;
	aux2 = aux1->next ;
	while( aux1->next != p ){
		printf( "%s:\n" , (aux1->ent)->d_name ) ;
		if( stat( (aux1->ent)->d_name , &s1 ) != 0 ){
			perror("stat") ;
			exit(1) ;
		}
		if ( (fd1 = open((aux1->ent)->d_name, O_RDONLY ) ) == -1){	/*apro la entry*/
			perror("open") ;
			exit(1) ;
		}
		
		while( (aux2->next) != p && (aux2 != p) ){
			tmp = aux2->next ;
			if( stat( (aux2->ent)->d_name , &s2 ) != 0 ){
				perror("stat") ;
				exit(1) ;
			}
			if ( (fd2 = open((aux2->ent)->d_name, O_RDONLY ) ) == -1){	/*apro la entry*/
				perror("open") ;
				exit(1) ;
			}
			printf("\t%s" , (aux2->ent)->d_name) ;
			if( s1.st_ino != s2.st_ino){
				if( filecmp( fd1 , fd2 ) == 0 ){	/*controllo se i due file hanno lo stesso contenuto*/
						printf("<-uguale\t") ;
						unlink((aux2->ent)->d_name) ;	/*rimuovo il file uguale*/
						if( link( (aux1->ent)->d_name , (aux2->ent)->d_name) == -1 ){	/*creo un link fisico*/
							perror("link") ;
							exit(1) ;
						}
						del(aux2) ;
					}
			}
			else del(aux2) ;	/*se hanno lo stesso i-node toglili dalla lista*/
			aux2 = tmp;	/*tmp = aux2->next. Lo salvo in precedenza nel caso in cui aux2 sia stato cancellato*/
			close(fd2) ;
		}
		printf("\n") ;
		close(fd1) ;
		aux1 = aux1->next ;
		
	} 
}

int main( int argc, char* argv[]){
	struct stat s1 , s2;	/*struttura di informazioni su un file*/
	DIR *dir  ;	/*puntatore a directory*/
	struct dirent *entry ;	/*struttura di informazioni sulle entry di una directory*/
	int fd1;	/*descrittore di file*/
	char *name ;
	int n = 0 ; /*contatore di file all'interno della directory*/
	int cs , i ; /*cs è somma crittografica del file*/
	struct list *hash ;
	struct list *tmp ;
	if( stat( argv[1] , &s1 ) != 0 ){
		perror("stat") ;
		return 1 ;
	}
	if( !S_ISDIR(s1.st_mode) ){
		printf( "argument is not a valid directory\n" ) ;
		return 0 ;
	}
	if( (dir = opendir( argv[1] )) == NULL ){
		perror("opendir") ;
		return 1 ;
	}
	if( chdir( argv[1] ) == -1 ){	/*sposto la directory corrente in quella di esecuzione per poter aprire i file*/
		perror("chdir") ;
		return 1 ;
	}
	while( (entry = readdir(dir) ) != NULL){	/*conto i file contenuti nella directory*/
		stat( entry->d_name , &s1 ) ;
		if( S_ISREG(s1.st_mode) ) n++ ;	/*se si tratta di un file normale contalo*/
	}
	printf("La directory contiene %i file\n" , n ) ;
	n = 2*n ;	/*da questo momento n è il numero di indici nella mia hashtable*/
	hash = (struct list*) malloc( sizeof(struct list)*n) ;	/*alloco una hash table con n = 2n indici*/
	rewinddir(dir) ;
	for( i = 0 ; i < n ; i++ ){	/*inizializzo le liste*/
		hash[i].next = &hash[i] ;
		hash[i].prev = &hash[i] ;
		hash[i].ent = NULL ;
	}
	while( (entry = readdir(dir) ) != NULL){	/*con questo ciclo riempo la hashtable*/
		stat( entry->d_name , &s1 ) ;
		if( S_ISREG(s1.st_mode) ){	/*se si tratta di un file normale consideralo*/
			if ( (fd1 = open(entry->d_name, O_RDONLY ) ) == -1){	/*apro la entry*/
				perror("open") ;
				exit(1) ;
			}
			cs = critsum( fd1 ) ;
			tmp = (struct list*) malloc( sizeof(struct list) ) ;
			tmp->ent = entry ;
			(hash[cs%n].next)->prev = tmp ;	/*inserisco il file in testa alla lista di indice cs%n*/
			tmp->prev = &hash[cs%n] ;
			tmp->next = hash[cs%n].next ;
			hash[cs%n].next = tmp ;
			close(fd1) ;
		}
	}
	for( i = 0 ; i < n ; i++ ){	/*con questo ciclo cancello effettivamente i file uguali*/
		printf("%i: " , i ) ;
		if( hash[i].next != &hash[i] ){
			del_clones( hash[i].next ) ;
		}
		else printf("\n") ;
	}
	return 0 ;
}