Librairie Apr : tutoriels : 6 et 7
6. Les verrous sur les fichiers
Lorsqu’on veut verrouiller des fichiers entre processus, il faut utiliser apr_file_lock(). Historiquement, des confusions se sont installées concernant le verouillage sur Unix. C’est pourquoi le fait de n’avoir que deux fonctions simples grâce à la librairie libapr est très appréciable.
/* extrait de apr_file_io.h */ APR_DECLARE(apr_status_t) apr_file_lock(apr_file_t *thefile, int type); APR_DECLARE(apr_status_t) apr_file_unlock(apr_file_t *thefile);
apr_file_lock() demande deux arguments. Le premier est un objet apr_file_t. Le second est un drapeau (“flag”), qui sert à spécifier les blocages qu’on veut imposer (“lock type”). Il peut être soit APR_FLOCK_SHARED, soit APR_FLOCK_EXCLUSIVE. We can use the former as a readable lock, and the latter as a writable lock. Pour déverrouiller le fichier, il suffit d’appeler apr_file_unlock(). Ou bien le fait d’appeler apr_file_close() le déverrouille implicitement. Regardez flock-sample.c pour savoir comment faire.
De plus, il est possible d’utiliser un paramètre composé de drapeaux (“bitwised-or flag”) en précisant APR_FLOCK_NONBLOCK. Sans le flag APR_FLOCK_NONBLOCK, apr_file_lock() est bloquant. Avec ce flag, APR_FLOCK_NONBLOCK, si apr_file_lock() ne peut pas verouiller un fichier, il ne bloque pas et renvoie immédiatement un code erreur : APR_EAGAIN.
Il faut toujours s’assurer que la valeur de retour de apr_file_lock() est APR_SUCCESS. Si c’est le cas, le fichier a été verouillé avec succès. Sinon, il n’a pas pu être verouillé.
7. Gestion des répertoires dans le système de fichiers
Quand on veut faire quelque chose avec des répertoires, il faut toujours appeler d’abord apr_dir_open(). Après cet appel, on a un objet apr_dir_t. La seule chose que l’on puisse faire avec un objet apr_dir_t est de parcourir le répertoire. La fonction à utiliser est apr_dir_read(). A la fin on appelle apr_dir_close() pour fermer le répertoire. Ci-suivent les déclarations de la librairie :
/* extrait de apr_file_info.h */ APR_DECLARE(apr_status_t) apr_dir_open(apr_dir_t **new_dir, const char *dirname, apr_pool_t *pool); APR_DECLARE(apr_status_t) apr_dir_read(apr_finfo_t *finfo, apr_int32_t wanted, apr_dir_t *thedir); APR_DECLARE(apr_status_t) apr_dir_close(apr_dir_t *thedir);
Le premier argument de apr_dir_open() est un argument résultat. C’est grâce à lui qu’on récupère l’objet apr_dir_t qui est crée. Le second argument est le nom du répertoire. Le troisième est le nom du pool mémoire à utiliser.
Le premier arguement de apr_dir_read() est un argument résultat. Comme mentionné précédemment, apr_finfo_t est un type complet. Donc il faut l’allouer explicitement. apr_dir_read() renvoie une entrée du répertoire apr_finfo_t. L’entrée est soit un fichier soit un répertoire. Le second argument est une aggrégation de drapeaux (“bit-wised flag”). Ces drapeaux sont définis dans apr_file_info.h. Ils ont tous le préfixe APR_FINFO_, par exemple APR_FINFO_SIZE, APR_FINFO_TYPE et APR_FINFO_NAME. Le troisième argument est l’objet apr_dir_t à parcourir.
Voici un code d’exemple :
/* pseudo code expliquant apr_dir_read() */ /* no error checks */ apr_pool_t *mp; apr_pool_create(&mp, NULL); /* répertoire à scanner */ const char *dirpath = "/home"; apr_dir_t *dir; /* créer l'objet apr_dir_t */ apr_dir_open(&dir, dirpath, mp); apr_finfo_t dirent; /* remplir l'objet apr_finfo_t */ apr_dir_read(&dirent, APR_FINFO_DIRENT, dir); /* dirent est la première entrée du répertoire. * Cette entrée est soit un fichier soit un répertoire. */ apr_dir_close(dir);
Dans l’exemple au-dessus, on appelle apr_dir_read() une seule fois, mais habituellement on le fait en boucle pour énumérer tous les fichiers d’un répertoire. Pour ce faire, il suffit juste d’appeler apr_dir_read() tant qu’il renvoie APR_SUCCESS. Regardez l’exemple qui est plus parlant : dir-sample.c.
/* pseudo code sur la boucle apr_dir_read(). Vérif. des erreurs omise */ /* Boucle typique de apr_dir_read() */ apr_dir_open(&dir, dirpath, mp); while ((apr_dir_read(&dirent, APR_FINFO_NAME, dir)) == APR_SUCCESS) { printf("Le nom est %s\n", dirent.name); } apr_dir_close(dir);
Comme vous pouvez l’imaginer, la position courante du répertoire est stockée dans l’objet apr_dir_t. Le fait d’appeler apr_dir_read() fait avancer la position d’un cran. On peut reculer cette potision (qui est interne) en appelant apr_dir_rewind(). Les seules opération que l’on peut faire avec la position sont ces deux là : aller en avant et aller en arrière.
Comme vous pouvez le voir dans dir-sample.c, si vous scannez un répertoire de manière récursive, vous devez appeler apr_dir_open() de manière récursive, ici aussi.
REMARQUE : Sur Unix, apr_dir_read() renvoie un objet apr_finfo_t dont la propriété apr_file_t::fname est NULL.