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

From Sistemi Operativi
Jump to navigation Jump to search
(Created page with "Consegna: <source lang="text"> 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 c...")
 
Line 1: Line 1:
Consegna:
+
Consegna([http://www.cs.unibo.it/~renzo/so/pratiche/2013.09.13.pdf]):
 
<source lang="text">
 
<source lang="text">
 
Lo scopo del programma che dovrete scrivere e' di confrontare fra loro i file di una directory, se ne trovate due (o piu') che
 
Lo scopo del programma che dovrete scrivere e' di confrontare fra loro i file di una directory, se ne trovate due (o piu') che

Revision as of 19:31, 1 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

#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <limits.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <fcntl.h>
#include <string.h>
#include <stdlib.h>
 
#define SIZE 1024
 
char buff1[SIZE] ;  /*buffer usati per leggere i file*/
char buff2[SIZE] ;
 
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 ) ;
        buff1[n1] = '\0' ;  /*per evitare che vengano letti anche residui di read precedenti, pongo lo 0 terminatore dove finiscono i caratteri letti in questa iterazione del ciclo*/
        buff2[n2] = '\0' ;
        if( strcmp(buff1 , buff2 )!= 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 ;
}

Il mio programma funziona correttamente finchè si tratta di gestire file di testo. Ho provato a creare copie di immagini (.png), ma le considera come file dal contenuto differente... Non riesco a capire se è normale così o se sto sbagliando qualcosa. Inoltre, mi sembra di aver impiegato una quantità di tempo ( e codice ) spropositata considerando che si tratta solo del primo esercizio di una prova pratica; ci sono metodi più brevi per farlo?