Esercizio 1, prova pratica 13/09/2013
Jump to navigation
Jump to search
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
#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] ;
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*/
}
int main( int argc, char* argv[]){
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*/
struct dirent *entry_i ; /*struttura di informazioni sulle entry di una directory*/
int fd1, fd2 ; /*descrittori di file*/
char *name ;
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( (dir1 = opendir( argv[1] )) == NULL ){
perror("opendir") ;
return 1 ;
}
if( (dir2 = 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_i = readdir(dir1) ) != NULL){ /*scorro le entry della directory*/
stat( entry_i->d_name , &s1 ) ;
if(!S_ISREG(s1.st_mode)) continue ; /*se la entry che sto considerando non è un file normale salta una iterazione */
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*/
perror("open") ;
exit(1) ;
}
//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*/
while( (entry_i = readdir(dir2) ) != NULL) { /*secondo ciclo*/
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*/
stat( entry_i->d_name , &s2 ) ;
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) ;
free( name ) ;
printf("\n") ;
}
return 0 ;
}