/* (c) Yann Guidon 2000 (whygee@f-cpu.org) fichier créé le 21 octobre 2000 gdups4.c : ajout de l'option -x (exclude) pour eviter de balayer des repertoires specifies. ajout de -v pour afficher ou non les messages a l'ecran. gdups3.c : portage pour SunOS du 30/11/2000, reparation d'une petite erreur et passage de la taille d'un fichier vers off_t. Maintenant, ca a l'air assez stable. gdups2.c : version préliminaire de GDUPS sans le rapport final. Le nom est la contractions de "GNU DUPlicates", il cherche des fichiers en double en explorant récursivement les sous-répertoires du répertoire courant. Il dispose aussi d'une liste de répertoires à ignorer. Ce fichier est une inclusion des fichiers signature.c, arbres3.c et explore5.c dans un seul source monolithique plus simple. Pour compiler (mode autonome) : gcc -o gdups gdups4.c (options -g, -ansi, -Wall et -Ox à volonté) Utilisation : $ gdups > dups.txt (pour ne pas mélanger le rapport avec les messages) options : -v : "verbose" -x path/ : exclue path/ de la recherche Pour plus d'informations : voir les fichiers sources du répertoire "exemples" This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /************************************ Définitions des types et tailles : * ************************************/ #define MAXPATHSIZE 255 /* taille maximale du nom d'un fichier */ #define CRC_BUFFER_CHUNK_SIZE 65536 /* peut être changé */ #define TAILLE_BLOC 524288 /* 512KO devraient suffire pour avoir peu de blocs si on scanne tout un disque dur. Réduire ou augmenter si nécessaire. */ /*************************************** * inclusion des librairies standard : * ***************************************/ #include /* pour printf, fprintf, fopen, fread, fclose */ #include /* pour readdir, opendir */ #include #include /* pour ctime */ /* #include : enlevé pour SunOS */ #include /* pour lstat */ #include #include /* pour strcmp, memcpy */ #include /* pour malloc */ /* Remarque : Les variables et constantes globales sont souvent réunies et classées par ordre décroissant de taille pour favoriser l'alignement des données. */ /************************************ * Variables globales pour le CRC : * ************************************/ unsigned long int CRC32tab[256] = { /* table CRC32 de poly=0x04C11DB7*/ 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d }; unsigned long int CRC_val, CRCSeed = 0xffffffff; unsigned char *CRC_buffer=NULL; /********************************** * Variables globales générales : * **********************************/ char *avancement[]={ "-%c", "\%c", "|%c", "/%c" }; int rotation=0; int verbose=0; char *CRCstring[]={ "c%c", "C%c" }; int crc_avancement=0; #define NB_FIXED_PATHS 5 char *const_chemins_interdits[NB_FIXED_PATHS]= { "/dev/", "/proc/", "/tmp/", "/usr/tmp/", "/var/tmp/" }; char **chemins_interdits=const_chemins_interdits; int max_profondeur_chemins_interdits=3, nb_chemins_interdits=NB_FIXED_PATHS; /* Les données suivantes sont globales pour réduire l'occupation de la pile et éviter des opérations redondantes */ char chemin[MAXPATHSIZE]; struct stat state; int taille_chemin, max_imbrication=MAXPATHSIZE; /* il ne peut y avoir plus de répertoires que de caractères dans le chemin... */ /************************************************** * Variables globales pour le wrapper de malloc : * **************************************************/ int nb_blocs=0, nb_elements=0; /* nombre de blocs alloués et d'appels à mon_malloc */ char * bloc_courant; /* pointe sur le dernier bloc alloué */ int index_bloc_courant=TAILLE_BLOC; /* nombre d'octets occupés dans le bloc, initialisé afin de déclencher l'allocation dès le premier appel à mon_malloc() */ /*********************************************** * Structures de données et variables globales * ***********************************************/ /* description d'un chemin */ struct noeud_chemin { /* Il sera possible d'ajouter des données à cet endroit. */ unsigned char nom[0]; /* chaine de type Pascal : le caractère 0 est la taille de la chaine en ASCIIZ. La chaine commence donc au caractère #1 et se termine par un zéro. Il faut toujours placer cette partie à taille variable à la fin de la structure. Un avantage important est que cela accélère la comparaison avec strcmp() ! */ }; /* description d'un fichier : */ struct noeud_fic { /* propriétés/caractéristiques du fichier : */ off_t taille; /* taille du fichier en octets */ time_t date; /* long int, défini par et */ long int CRC; /* signature, ignorée si arbre_taille_pareil==NULL */ struct noeud_chemin *chemin; /* pointeur vers le nom du chemin */ /* arbres entrelacés : */ struct noeud_fic *arbre_taille_prec, *arbre_taille_pareil, *arbre_taille_suiv, *arbre_nom_prec, *arbre_nom_pareil, *arbre_nom_suiv; /* Il sera possible d'ajouter des données à cet endroit. */ /* partie à taille variable du noeud, située à la fin : */ unsigned char nom[0]; /* nom du fichier, voir plus haut pour le format */ }; /* arbre du descripteur pour l'arbre de fichiers identiques : */ struct noeud_arbre_id { /* arbres d'arbres d'arbres entrelacés : */ struct noeud_arbre_id *arbre_prec, *arbre_suiv; struct noeud_fic *noeud; }; /**************************************** * Variables globales pour les arbres : * ****************************************/ /* arbre de tri des tailles et des noms */ struct noeud_fic * racine_arbre_nom[MAXPATHSIZE], /* pré-hachage */ * racine_arbre_taille=NULL; /* arbre des descripteurs identiques */ struct noeud_arbre_id * racine_taille_id=NULL, * racine_nom_id=NULL; /*************************** * CRC32, version inline : * ***************************/ /* algorithme de base en Pascal : vCRC32 := CRCSeed; For P := 1 to Size DO vCRC32 :=CRC32tab[Byte(vCRC32 xor LongInt(Bytes[P]))] xor ((vCRC32 shr 8) and 0x00ffffff); vCRC32 := vCRC32 xor CRCSeed; (on peut oublier la dernière ligne, ça change la signature mais deux fichiers identiques auront quand même une signature identique) */ void calcule_CRC(char *nom_fic){ unsigned char *c; unsigned int i,taille; FILE *in; if (CRC_buffer==NULL) { /* initialisation du buffer */ CRC_buffer=malloc(CRC_BUFFER_CHUNK_SIZE); if (CRC_buffer==NULL) { fprintf(stderr,"\nerreur de malloc() dans calcule_CRC\n"); exit(6); } } CRC_val=CRCSeed; in=fopen(nom_fic,"rb"); if (in==NULL) { printf("CRC impossible, lecture de %s refusée\n",nom_fic); return; } if (verbose) fprintf(stderr,"CRCing %s %c",nom_fic,0xD); while ((taille=fread(CRC_buffer,1,CRC_BUFFER_CHUNK_SIZE,in))!=0) { fprintf(stderr,CRCstring[crc_avancement],0xD); fflush(stderr); crc_avancement^=1; c=CRC_buffer; while (taille--) { i=(CRC_val&255)^(*c++); CRC_val=CRC32tab[i]^(CRC_val>>8); } } fclose(in); if (verbose) { fprintf(stderr," %c",0xD); } else { fprintf(stderr,avancement[rotation],0xD); rotation=(rotation+1)&3; } fflush(stderr); } /***************************************************************** * Gestion fine de l'allocation de la mémoire (sans libération) * *****************************************************************/ void * mon_malloc(int taille) { void *temporaire; nb_elements++; taille=(taille+7) & -8; /* arrondit la taille aux 8 octets supérieurs afin d'éviter des fautes de pointeurs sur les architectures 64 bits */ /* ce type d'erreur ne devrait jamais arriver mais on ne sait jamais... */ if (taille > TAILLE_BLOC) { fprintf(stderr,"\n erreur : bloc trop gros\n"); exit(4); } index_bloc_courant+=taille; if (index_bloc_courant > TAILLE_BLOC) { bloc_courant=malloc(TAILLE_BLOC); if (bloc_courant == NULL) { fprintf(stderr,"\n erreur de malloc\n"); exit(5); } nb_blocs++; index_bloc_courant=0; } temporaire=bloc_courant+index_bloc_courant; index_bloc_courant+=taille; return temporaire; } /**************************************** * Création en mémoire des descripteurs * ****************************************/ struct noeud_chemin * cree_noeud_chemin( char * nom_fic, int taille_nom) { struct noeud_chemin * chemin_courant =mon_malloc(sizeof(struct noeud_chemin)+taille_nom+2); /* il ne faut pas oublier les caractères de début et de fin du nom */ /* initialisation des données du noeud : */ chemin_courant->nom[0]=taille_nom; memcpy((chemin_courant->nom)+1,nom_fic,taille_nom+1); return chemin_courant; } struct noeud_fic * cree_noeud_fic(char * nom_fic, int taille_nom, off_t taille_fic, struct noeud_chemin * chemin_courant) { struct noeud_fic * fichier_courant =mon_malloc(sizeof(struct noeud_fic)+taille_nom+2); /* il ne faut pas oublier les caractères de début et de fin du nom */ /* initialisation des données du noeud : */ memset(fichier_courant,0,sizeof (*fichier_courant)); fichier_courant->taille=taille_fic; /* taille du fichier en octets */ fichier_courant->date=state.st_mtime; /* date de dernière modification du fichier */ fichier_courant->chemin=chemin_courant; /* pointeur vers le nom du chemin */ fichier_courant->nom[0]=taille_nom; memcpy((fichier_courant->nom)+1,nom_fic,taille_nom+1); return fichier_courant; } /* arbre des descriptions de fichiers identiques : */ struct noeud_arbre_id * cree_noeud_id (struct noeud_fic *noeud) { struct noeud_arbre_id *id_courant =mon_malloc(sizeof(struct noeud_arbre_id)); id_courant->arbre_prec=NULL; id_courant->arbre_suiv=NULL; id_courant->noeud=noeud; return id_courant; }; /************************************************** * crée l'arbre des fichiers de taille identique: * **************************************************/ void tri_taille_id(struct noeud_fic *noeud) { struct noeud_arbre_id *temp, *p=racine_taille_id, *id_courant=cree_noeud_id (noeud); long long int taille=noeud->taille; /* nous allons ici, en plus, calculer le CRC du fichier */ char chemin2[MAXPATHSIZE]; struct noeud_chemin *chemin3=noeud->chemin; int i=chemin3->nom[0]; /* reconstitution du chemin */ memcpy(chemin2,&(chemin3->nom[1]),i); memcpy(&(chemin2[i]),&(noeud->nom[1]),noeud->nom[0]+1); /* vérification du CRC : */ calcule_CRC(chemin2); noeud->CRC=CRC_val; /* vérifie la racine : */ if (p==NULL) { racine_taille_id=id_courant; return; } do { /* procédure de recherche itérative dans l'arbre : */ /* pas besoin de test d'égalité (la fonction est appelée à chaque fois qu'une nouvelle taille apparait) */ if (taille<(p->noeud)->taille) { /* branche inférieure : */ temp=p->arbre_prec; if (temp==NULL) { p->arbre_prec=id_courant; return; } } else { /* branche supérieure : */ temp=p->arbre_suiv; if (temp==NULL) { p->arbre_suiv=id_courant; return; } } p=temp; } while (1); } /********************************* * tri des fichiers par taille : * ********************************* (appelé chaque fois qu'un fichier est scanné dans la fonction récursive principale) */ void tri_taille(struct noeud_fic *noeud) { long long int taille=noeud->taille; struct noeud_fic * temp, * noeud_courant=racine_arbre_taille; /* vérifie la racine : */ if (noeud_courant==NULL) { racine_arbre_taille=noeud; return; } do { /* procédure de recherche itérative dans l'arbre : */ if (taille==noeud_courant->taille) { /* vérification du CRC : */ calcule_CRC(chemin); /* pour simplifier, on utilise la variable globale, mais on ne peut plus faire de mode de test autonome. */ noeud->CRC=CRC_val; /* vérifie si c'est le seul élément de la liste chainée : */ if (noeud_courant->arbre_taille_pareil==NULL) tri_taille_id(noeud_courant); else { /* cherche la fin de la liste chainée */ /* à remplacer par un arbre de tri/CRC */ do noeud_courant=noeud_courant->arbre_taille_pareil; while (noeud_courant->arbre_taille_pareil!=NULL); } noeud_courant->arbre_taille_pareil=noeud; return; } else { /* sélection du chemin dans l'arbre : */ if (tailletaille) { /* branche inférieure : */ temp=noeud_courant->arbre_taille_prec; if (temp==NULL) { noeud_courant->arbre_taille_prec=noeud; return; } } else { /* branche supérieure : */ temp=noeud_courant->arbre_taille_suiv; if (temp==NULL) { noeud_courant->arbre_taille_suiv=noeud; return; } } noeud_courant=temp; } } while (1); } /************************************************* * crée l'arbre des fichiers de noms identiques: * ************************************************* (dérivé de tri_taille_id()) */ void tri_nom_id(struct noeud_fic *noeud) { struct noeud_arbre_id *temp, *p=racine_nom_id, *id_courant=cree_noeud_id (noeud); /* vérifie la racine : */ if (p==NULL) { racine_nom_id=id_courant; return; } do { /* procédure de recherche itérative dans l'arbre : */ /* pas besoin de test d'égalité (la fonction est appelée à chaque fois qu'une nouvelle taille apparait) */ /* remarquer ici l'astuce qui permet de trier d'abord par la taille du nom puis sa valeur */ if (strncmp(noeud->nom,p->noeud->nom,MAXPATHSIZE)<0) { /* branche inférieure : */ temp=p->arbre_prec; if (temp==NULL) { p->arbre_prec=id_courant; return; } } else { /* branche supérieure : */ temp=p->arbre_suiv; if (temp==NULL) { p->arbre_suiv=id_courant; return; } } p=temp; } while (1); } /****************** * Tri par noms : * ****************** (dérivé de tri_taille()) - remarquer que strncmp() n'est pas utilisé afin de pouvoir reprendre la comparaison au dernier endroit où les noms divergent. - remarquer aussi que nous utilisons un tableau de racines, afin de ne traiter que des chaines de caractères de même longueur. C'est un premier filtrage assez efficace. */ void tri_nom(struct noeud_fic *noeud) { int taille, /* taille du nom */ index; /* début de la chaine de caractères */ struct noeud_fic * temp, * noeud_courant; char *s1,*s2; /* variables temporaires pour comparer les noms */ taille=noeud->nom[0]; index=1; noeud_courant=racine_arbre_nom[taille]; /* vérifie la racine : */ if (noeud_courant==NULL) { racine_arbre_nom[taille]=noeud; return; } s1=noeud->nom; do { /* procédure de recherche itérative dans l'arbre : */ s2=noeud_courant->nom; /* compare, caractère par caractère, le nom des fichiers : */ while (s1[index]==s2[index]) { index++; if (index>taille) { /* nom identique */ /* à cete endroit, on pourrait trier par la date ou le chemin. */ /* La date serait mieux. Le chemin est déterminé par l'ordre de balayage. */ /* vérifie si c'est le seul élément de la liste chainée : */ if (noeud_courant->arbre_nom_pareil==NULL) /* crée un nouvel élément à la liste chainée d'éléments identiques */ tri_nom_id(noeud_courant); else { /* cherche la fin de la liste chainée */ /* à remplacer par un arbre de tri/date */ do noeud_courant=noeud_courant->arbre_nom_pareil; while (noeud_courant->arbre_nom_pareil!=NULL); } noeud_courant->arbre_nom_pareil=noeud; return; } } /* sélection du chemin dans l'arbre : */ if (s1[index]>s2[index]) { /* branche de gauche */ temp=noeud_courant->arbre_nom_prec; if (temp==NULL) { noeud_courant->arbre_nom_prec=noeud; return; } } /* le cas de l'égalité est déjà traité plus haut */ else { /* branche de droite */ temp=noeud_courant->arbre_nom_suiv; if (temp==NULL) { noeud_courant->arbre_nom_suiv=noeud; return; } } noeud_courant=temp; } while (1); } /*************************************** * Fonctions d'impression du rapport : * ***************************************/ /* exploration récursive de l'arbre des tailles identiques */ void imprime_rapport_taille (struct noeud_arbre_id *noeud_taille) { struct noeud_fic *t=noeud_taille->noeud; char *date; /* branche de gauche */ if (noeud_taille->arbre_prec != NULL) imprime_rapport_taille (noeud_taille->arbre_prec); /* milieu : imprime la liste */ printf(" * taille : %Ld\n",t->taille); do { date=ctime(&(t->date)); date[strlen(date)-1]=0; /* enlève le \n */ printf(date); if (t->CRC==0) /* CRC non calculé */ printf(" | "); else printf(" | CRC: %08lX",t->CRC); printf(" | %s%s\n",&(t->chemin->nom[1]),&(t->nom[1])); t=t->arbre_taille_pareil; } while (t != NULL); printf("\n"); /* branche de droite */ if (noeud_taille->arbre_suiv != NULL) imprime_rapport_taille (noeud_taille->arbre_suiv); } /* exploration récursive de l'arbre des noms identiques */ void imprime_rapport_noms (struct noeud_arbre_id *noeud_nom) { struct noeud_fic *t=noeud_nom->noeud; char *date; /* branche de gauche */ if (noeud_nom->arbre_prec != NULL) imprime_rapport_noms (noeud_nom->arbre_prec); /* milieu : imprime la liste */ printf(" * nom : %s\n",&(t->nom[1])); do { date=ctime(&(t->date)); date[strlen(date)-1]=0; /* enlève le \n */ printf(date); if (t->CRC==0) /* CRC non calculé */ printf(" | "); else printf(" | CRC: %08lX",t->CRC); printf(" | chemin : %s\n",&(t->chemin->nom[1])); t=t->arbre_nom_pareil; } while (t != NULL); printf("\n"); /* branche de droite */ if (noeud_nom->arbre_suiv != NULL) imprime_rapport_noms (noeud_nom->arbre_suiv); } /* procédure principale du rapport : */ void imprime_rapport () { printf ("\n rapport d'analyse\n\n"); /* 1 : arbre des tailles identiques : */ if (racine_taille_id!=NULL) { printf ("*** fichiers de tailles identiques : ***\n\n"); imprime_rapport_taille (racine_taille_id); } else printf ("*** pas de fichiers de tailles identiques ***\n\n"); /* 2 : arbre des noms identiques : */ if (racine_nom_id!=NULL) { printf ("*** fichiers aux noms identiques : ***\n\n"); imprime_rapport_noms (racine_nom_id); } else printf ("*** pas de fichiers aux noms identiques ***\n\n"); } /*************************************************** * Fonctions principale de balayage des fichiers : * ***************************************************/ void explore_recursif(int imbrication) { /* variables locales : elles sont allouées à chaque appel et elles peuvent donc exister en de multiples exemplaires */ int temp_taille_chemin, taille_nom,i,inc_slash=0; DIR *dir; char *nom_local; struct dirent *file; /* erreur ici, "direct" au lieu de "dirent" */ struct noeud_chemin *chemin_local; struct noeud_fic *fichier_local; if (imbrication>max_imbrication) /* profondeur admise */ return; if (verbose) { fprintf(stderr,"scanning %s %c",chemin,0xD); } else { fprintf(stderr,avancement[rotation],0xD); rotation=(rotation+1)&3; } fflush(stderr); temp_taille_chemin=taille_chemin; /* sauvegarde */ if (taille_chemin!=1) { /* si on est déjà dans la racine, ne pas ajouter le '/' */ chemin[taille_chemin++]='/'; chemin[taille_chemin]=0; inc_slash=1; } /* vérification du chemin pour éviter les tests inutiles ou interdits */ if (imbrication <= max_profondeur_chemins_interdits) { /* degré d'imbrication maximal concerné par les chemins interdits */ i=0; do { if (strcmp(chemins_interdits[i],chemin)==0) { printf("%s ignoré\n",chemin); return; } i++; } while (id_name; /* renommage */ /* filtre "." et ".." */ if ((nom_local[0] == '.') && ((nom_local[1] == 0) /* "." */ || ((nom_local[1] == '.') &&(nom_local[2] == 0)))) { /* ".." */ /* ne rien faire */ } else { /* concaténation, placée avant le stat() pour pouvoir interroger n'importe quel fichier hors du répertoire courant */ taille_nom=strlen(nom_local); taille_chemin=temp_taille_chemin+taille_nom+inc_slash; if (taille_chemin > MAXPATHSIZE) { fprintf(stderr,"\n erreur : chemin trop long :\n%s\n",chemin); exit(3); } memcpy(&chemin[temp_taille_chemin+inc_slash],nom_local,taille_nom+1); if (lstat(chemin,&state)==0) { /* déterminer le type de fichier */ if (S_ISREG(state.st_mode)) { /* fichier normal */ fichier_local=cree_noeud_fic(nom_local,taille_nom,state.st_size,chemin_local); tri_taille(fichier_local); tri_nom(fichier_local); } else { if (S_ISDIR(state.st_mode)) /* répertoire */ explore_recursif(imbrication+1); /* appel récursif */ } } else { printf("lstat impossible sur %s\n",chemin); } } } closedir(dir); taille_chemin=temp_taille_chemin; /* restaure */ chemin[taille_chemin]=0; /* nettoie le chemin */ } /********** * MAIN : * **********/ int main(int argc, char **argv) { int i=0, j,k, nb_slash=0; /* lit le chemin courant */ if (getcwd(chemin,MAXPATHSIZE)==NULL) return 1; printf(" GDUPS v0.1 beta (C) Yann Guidon 2000\n"); /* initialise la variable globale */ taille_chemin=strlen(chemin); while (i1){ i=1; do { if (strncmp(argv[i],"-v",3)==0) { verbose=1; } else { if (strncmp(argv[i],"-x",3)==0) { i++; if (chemins_interdits==const_chemins_interdits) { /* premier chemin de la ligne de commande : on doit changer le pointeur. */ chemins_interdits=malloc(sizeof(const_chemins_interdits[0])*64); /* ca devrait suffire... */ if (chemins_interdits==NULL){ fprintf(stderr,"\nmalloc failed.\n"); return -1; } /* copie la liste des chemins interdits */ k=0; do { chemins_interdits[k]=const_chemins_interdits[k]; k++; } while (k64) { fprintf(stderr,"\ntoo many '-x' arguments.\n"); return -1; } chemins_interdits[nb_chemins_interdits]=argv[i]; } /* dans tous les cas : */ nb_chemins_interdits++; /* compte le nombre de '/' */ j=0; k=0; while (argv[i][k]) { if (argv[i][k++]=='/') j++; } if (argv[i][k-1] !='/') { fprintf(stderr,"\nsorry, '-x' arguments need a '/' at the end of the path.\n"); return -1; } if (j>max_profondeur_chemins_interdits) max_profondeur_chemins_interdits=j; } } i++; } while (i