Quand on dit que sous Linux, tout est un fichier, c'est vraiment vrai. La plupart des opérations que nous pouvons effectuer sur les fichiers peuvent être effectuées sur d'autres entités telles que socket, pipe, répertoires, etc.
Il existe certaines situations dans lesquelles un utilitaire logiciel peut avoir à parcourir des répertoires dans le système Linux pour trouver ou faire correspondre quelque chose. C'est le cas d'utilisation où le programmeur de cet utilitaire doit gérer la programmation de répertoires. Ainsi, dans cet article, nous couvrirons les bases suivantes de la programmation d'annuaires avec un exemple.
- Créer des répertoires.
- Lire des répertoires.
- Suppression de répertoires.
- Fermer le répertoire.
- Obtenir le répertoire de travail actuel.
Nous passerons en revue les fonctions utilisées pour chaque étape ci-dessus, puis nous verrons enfin un exemple qui résumera toutes les opérations sur les répertoires.
1. Création de répertoires
Le système Linux fournit l'appel système suivant pour créer des répertoires :
#include <sys/stat.h> #include <sys/types.h> int mkdir(const char *pathname, mode_t mode);
L'argument 'pathname' est utilisé pour le nom du répertoire.
Depuis la page de manuel :
Le mode d'argument spécifie les autorisations à utiliser. Il est modifié par le processus umask de la manière habituelle :les permissions du répertoire créé sont (mode &~umask &0777). Les autres bits de mode du répertoire créé dépendent du système d'exploitation. Pour Linux, voir ci-dessous.
Le répertoire nouvellement créé appartiendra à l'ID utilisateur effectif du processus. Si le répertoire contenant le fichier a le bit set-group-ID défini, ou si le système de fichiers est monté avec la sémantique du groupe BSD (mount -o bsdgroups ou, synonyme mount -o grpid), le nouveau répertoire héritera de la propriété du groupe de son parent ; sinon, il appartiendra à l'ID de groupe effectif du processus. Si le répertoire parent a le bit set-group-ID défini, il en sera de même pour le répertoire nouvellement créé.
2. Répertoires de lecture
Une famille de fonctions permet de lire le contenu du répertoire.
1. Tout d'abord, un flux de répertoire doit être ouvert. Cela se fait par l'appel système suivant :
#include <sys/types.h> #include <dirent.h> DIR *opendir(const char *name);
Depuis la page de manuel :
La fonction opendir() ouvre un flux de répertoire correspondant au nom du répertoire et renvoie un pointeur vers le flux de répertoire. Le flux est positionné à la première entrée du répertoire.
2. Ensuite, pour lire les entrées du répertoire, le flux ouvert ci-dessus est utilisé par l'appel système suivant :
#include struct dirent *readdir(DIR *dirp);
Depuis la page de manuel :
La fonction readdir() renvoie un pointeur vers une structure dirent représentant la prochaine entrée de répertoire dans le flux de répertoire pointé par dirp. Il renvoie NULL lorsqu'il atteint la fin du flux de répertoire ou si une erreur s'est produite.
Sous Linux, la structure dirent est définie comme suit :
struct dirent { ino_t d_ino; /* inode number */ off_t d_off; /* offset to the next dirent */ unsigned short d_reclen; /* length of this record */ unsigned char d_type; /* type of file; not supported by all file system types */ char d_name[256]; /* filename */ };
3. Suppression de répertoires
Le système Linux fournit l'appel système suivant pour supprimer les répertoires :
#include <unistd.h> int rmdir(const char *pathname);
Depuis la page de manuel :
rmdir() supprime le répertoire représenté par 'pathname' s'il est vide. SI le répertoire n'est pas vide alors cette fonction ne réussira pas.
4. Fermeture des répertoires
Le système Linux fournit l'appel système suivant pour fermer les répertoires :
#include <sys/types.h> #include <dirent.h> int closedir(DIR *dirp);
Depuis la page de manuel :
La fonction closedir() ferme le flux de répertoire associé à dirp. Un appel réussi à closedir() ferme également le descripteur de fichier sous-jacent associé à dirp. Le descripteur de flux de répertoire dirp n'est pas disponible après cet appel.
5. Obtenir le répertoire de travail actuel
Le système Linux fournit l'appel système suivant pour obtenir le CWD :
#include <unistd.h> char *getcwd(char *buf, size_t size);
Depuis la page de manuel :
La fonction getcwd() copie un nom de chemin absolu du répertoire de travail actuel dans le tableau pointé par buf, qui est de longueur size. Cette fonction renvoie une chaîne terminée par un caractère nul contenant un nom de chemin absolu qui est le répertoire de travail actuel du processus d'appel. Le nom du chemin est renvoyé comme résultat de la fonction et via l'argument buf, s'il est présent. Si la longueur du nom de chemin absolu du répertoire de travail actuel, y compris l'octet nul de fin, dépasse size octets, NULL est renvoyé et errno est défini sur ERANGE; une application doit vérifier cette erreur et allouer un tampon plus grand si nécessaire.
6. Un exemple
#include<stdio.h> #include<stdlib.h> #include<string.h> #include<dirent.h> #include <sys/stat.h> #include <sys/types.h> #include <unistd.h> int main (int argc, char *argv[]) { if(2 != argc) { printf("\n Please pass in the directory name \n"); return 1; } DIR *dp = NULL; struct dirent *dptr = NULL; // Buffer for storing the directory path char buff[128]; memset(buff,0,sizeof(buff)); //copy the path set by the user strcpy(buff,argv[1]); // Open the directory stream if(NULL == (dp = opendir(argv[1])) ) { printf("\n Cannot open Input directory [%s]\n",argv[1]); exit(1); } else { // Check if user supplied '/' at the end of directory name. // Based on it create a buffer containing path to new directory name 'newDir' if(buff[strlen(buff)-1]=='/') { strncpy(buff+strlen(buff),"newDir/",7); } else { strncpy(buff+strlen(buff),"/newDir/",8); } printf("\n Creating a new directory [%s]\n",buff); // create a new directory mkdir(buff,S_IRWXU|S_IRWXG|S_IRWXO); printf("\n The contents of directory [%s] are as follows \n",argv[1]); // Read the directory contents while(NULL != (dptr = readdir(dp)) ) { printf(" [%s] ",dptr->d_name); } // Close the directory stream closedir(dp); // Remove the new directory created by us rmdir(buff); printf("\n"); } return 0; }
L'exemple ci-dessus devrait maintenant être explicite.
La sortie de l'exemple ci-dessus est :
# ./direntry /home/himanshu/practice/linux Creating a new directory [/home/himanshu/practice/linux/newDir/] The contents of directory [/home/himanshu/practice/linux] are as follows [redhat] [newDir] [linuxKernel] [..] [ubuntu] [.]