find
:
#!/bin/sh # findsequentiel.sh <rep> <nom> doit fonctionner comme find <rep> -name <nom> findname() { # $1: rep $2: motif for f in $1/*; do case `basename "$f"` in $2) echo "$f";; esac if test -d "$f"; then findname "$f" "$2" fi done } findname "$1" "$2"
Question: modifier le script shell de façon à ce qu'un processus soit créé pour explorer chaque répertoire rencontré.
stat(2)
permet d'avoir accès aux caractéristiques du fichier dont le
chemin d'accès est passé en paramètre.
#include <sys/types.h> #include <sys/stat.h> #include <unistd.h> int stat(const char *file_name, struct stat *buf); struct stat { dev_t st_dev; /* Périphérique */ ino_t st_ino; /* Numéro i-noeud */ mode_t st_mode; /* Protection */ nlink_t st_nlink; /* Nb liens matériels */ uid_t st_uid; /* UID propriétaire */ gid_t st_gid; /* GID propriétaire */ dev_t st_rdev; /* Type périphérique */ off_t st_size; /* Taille totale en octets */ blksize_t st_blksize; /* Taille de bloc pour E/S */ blkcnt_t st_blocks; /* Nombre de blocs alloués */ time_t st_atime; /* Heure dernier accès */ time_t st_mtime; /* Heure dernière modification */ time_t st_ctime; /* Heure dernier changement */ };Les attributs suivants correspondent au champ
st\_mode
qui code
outre les droits d'accès rwx
sur 9 bits et les droits spéciaux «
set-UID, set-GID, sticky bit » sur 3 bits, le type de fichier sur 4 bits (soit
16 bits en tout) :
S_IFMT | 00170000 | masque du type de fichier |
S_IFSOCK | 0140000 | socket |
S_IFLNK | 0120000 | lien symbolique |
S_IFREG | 0100000 | fichier régulier |
S_IFBLK | 0060000 | périphérique blocs |
S_IFDIR | 0040000 | répertoire |
S_IFCHR | 0020000 | périphérique caractères |
S_IFIFO | 0010000 | fifo |
S_ISUID | 0004000 | bit Set-UID |
S_ISGID | 0002000 | bit Set-Gid |
S_ISVTX | 0001000 | bit "sticky" |
S_IRWXU | 00700 | lecture/écriture/exécution du propriétaire |
S_IRUSR | 00400 | le propriétaire a le droit de lecture |
S_IWUSR | 00200 | le propriétaire a le droit d'écriture |
S_IXUSR | 00100 | le propriétaire a le droit d'exécution |
S_IRWXG | 00070 | lecture/écriture/exécution du groupe |
S_IRGRP | 00040 | le groupe a le droit de lecture |
S_IWGRP | 00020 | le groupe a le droit d'écriture |
S_IXGRP | 00010 | le groupe a le droit d'exécution |
S_IRWXO | 00007 | lecture/écriture/exécution des autres |
S_IROTH | 00004 | les autres ont le droit de lecture |
S_IWOTH | 00002 | les autres ont le droit d'écriture |
S_IXOTH | 00001 | les autres ont le droit d'exécution |
S_ISREG(m) | un fichier régulier ? |
S_ISDIR(m) | un répertoire ? |
S_ISCHR(m) | un péripherique en mode caractère ? |
S_ISBLK(m) | un périphérique en mode bloc ? |
S_ISFIFO(m) | une FIFO ? |
S_ISLNK(m) | est-ce un lien symbolique ? (Pas dans POSIX.1-1996). |
S_ISSOCK(m) | une socket ? (Pas dans POSIX.1-1996). |
opendir
, readdir
et
closedir
:
#include <sys/types.h> #include <dirent.h> DIR *opendir(const char *name); int closedir(DIR *dir); struct dirent *readdir(DIR *dir); struct dirent { #if defined _FILE_OFFSET_BITS && _FILE_OFFSET_BITS == 64 ino64_t d_ino; /* inode number */ off64_t d_off; /* offset to the next dirent */ #else ino_t d_ino; /* inode number */ off_t d_off; /* offset to the next dirent */ #endif unsigned short int d_reclen; /* length of this record */ unsigned char d_type; /* type of file */ char d_name[256]; /* filename */ };On peut ainsi faire une version simpliste de
ls
qui ne prend pas
d'argument sur la ligne de contrôle :
// palels.c -- alexis.lechervy@info.unicaen.fr -- oct 2014 // une pale version de ls(1) #include <stdio.h> // pour perror #include <sys/types.h> #include <sys/stat.h> #include <unistd.h> #include <dirent.h> #define true 1 #define false 0 void usage(const char* nom) { fprintf(stderr,"%s noms...\n",nom); } /** teste si nom est un répertoire * renvoie : -1 si erreur (fichier inexistant, * absence des droits de lecture, ... * 1 si c'est un fichier de type répertoire * 0 sinon. */ int isDir(const char * nom) { struct stat bufstat; if (stat(nom, &bufstat) != 0) { perror(nom); return -1; } return S_ISDIR(bufstat.st_mode) ? 1 : 0; } /** Liste le contenu d'un répertoire */ void listerep(const char* nom) { DIR* dir = opendir(nom); if (dir == NULL) { perror(nom); return; } struct dirent* ent; while((ent = readdir(dir)) != NULL) { printf("%s\n",ent->d_name); } closedir(dir); } short ls(const char* nom) { short ret = true; switch (isDir(nom)) { case -1: // erreur ret = false; break; case 1: // c'est un répertoire listerep(nom); break; case 0: // juste un simple fichier printf("%s\n",nom); } return ret; } int main(int argc, char *argv[]) { if (argc <= 1) { usage(argv[0]); return 1; // ou exit(1) } short ret = true; for(int i = 1; i < argc; i++) ret = ret && ls(argv[i]); return ret ? 0 : 1; // 0 si OK }Vous pouvez accéder au source de palels.c et le compiler avec :
gcc -Wall -o palels palels.c
Question : écrire en C ou C++, le find multiprocessus
.
et ..
.
int l = strlen(chaine1); if (strncmp(chaine1, chaine2, l) == 0) // les 2 chaînes sont égales
/
:
// on alloue un tableau de la bonne longueur // +1 pour le / et +1 pour le \0 final char tampon[strlen(repertoire)+1+strlen(nom)+1]; // on écrit dans tampon le repertoire, le /, et le nom // strncat et strncpy sont inutiles car on a vérifié les longueurs // et on peut faire strcat(strcat(strcpy(tampon, repertoire), "/"),nom); // au lieu de : // strncat(strcat(strncpy(tampon, repertoire, strlen(repertoire)+1), "/"),nom, strlen(nom)+1); // on pourrait aussi faire : // sprintf(tampon, "%s/%s", repertoire, nom);
include
suivante pour utiliser
les fonctions de bibliothèques préfixées par str
:
#include <strings.h>