Programmation Avancée en C


annuaire_mmap.c

00001 #include <errno.h>
00002 #include <fcntl.h>
00003 #include <stdint.h>
00004 #include <stdio.h>
00005 #include <stdlib.h>
00006 #include <string.h>
00007 #include <unistd.h>
00008 
00009 inline void error(char * msg) { // Affichage d'un message d'erreur et sortie.
00010         fprintf(stderr, "[Erreur] %s: %s\n", msg, strerror(errno));
00011         exit(EXIT_FAILURE);
00012 }
00013 
00014 #include <sys/mman.h>
00015 #include <sys/types.h>
00016 #include <sys/uio.h>
00017 
00018 #define STR_SIZE 20             // Taille maximale d'une chaine de caractères.
00019 #define MAX_PERS 100            // Taille maximale de l'annuaire.
00020 #define ANNUAIRE "annuaire.txt" // Le nom du fichier qui contient l'annuaire.
00021 
00022 struct personne {
00023         char nom[STR_SIZE], prenom[STR_SIZE], tel[STR_SIZE];
00024         int8_t age;
00025         char align[3]; /* Pour l'alignement. */
00026 };
00027 
00028 int main()
00029 {
00030         int err = 0;
00031         struct personne tab[MAX_PERS] = {
00032                 {"Varrette", "Sébastien", "+33 (0)0 11 22 33 44", 26},
00033                 {"Bernard",  "Nicolas",   "+33 (0)0 55 66 77 88", 25},
00034                 {"", "", "", -1} // Entrée spéciale (indique la fin de l'annuaire).
00035         };
00036 
00037         /* Sauvegarde de l'annuaire. */
00038         int fd = open(ANNUAIRE, O_CREAT | O_RDWR, 0600);
00039         if (fd == -1) error("open (write)");
00040         uint16_t i = 0;
00041         while (strlen(tab[i].nom) > 0) i++; // Calcul du nombre d'entrées.
00042         err = write(fd, &i, 2); // Écriture du nombre d'entrées au début du fichier.
00043         if (err != 2) error("write (1)");
00044 
00045         /* On s'assure que le fichier est assez grand avant d'utiliser mmap. */
00046         err = lseek(fd, i * sizeof(struct personne) + 2, SEEK_SET);
00047         if (err == -1) error("lseek");
00048         err = write(fd, &i, 2);
00049         if (err != 2) error("write (2)");
00050 
00051         char *fic = mmap(NULL, i * sizeof(struct personne) + 8,// 8: alignement.
00052                           PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
00053         if (fic == MAP_FAILED) error("mmap (write)");
00054         struct personne* fich = (struct personne*) (fic + 8);
00055 
00056         for (int j = 0; j <= i; j++)  /* Écriture des entrées. */
00057                 fich[j] = tab[j];
00058 
00059         err = munmap(fic, i * sizeof(struct personne) + 8);
00060         if (err) error("munmap (1)");
00061         fic = NULL; fich = NULL;
00062 
00063         err = close(fd);
00064         if (err) error("close (1)");
00065 
00066         /* Récupération des données sauvegardées. */
00067         uint16_t nb_pers = 0; // Nombre de personnes dans l'annuaire.
00068         fd = open(ANNUAIRE, O_RDONLY);
00069         if (fd == -1) error("open (write)");
00070 
00071         err = read(fd, &nb_pers, 2);
00072         if (err != 2) error("read");
00073 
00074         fic = mmap(NULL, nb_pers * sizeof(struct personne) + 8, PROT_READ,
00075                    MAP_SHARED, fd, 0);
00076         fich = (struct personne*) (fic + 8);
00077         err = close(fd);
00078         if (err) error("close (2)");
00079         if (fich == MAP_FAILED) error("mmap (read)");
00080 
00081         for (int j = 0; j < nb_pers; j++) /* Affichage des entrées. */
00082                 printf("Entrée %d\n\t %s %s (age: %d) -->  %s\n", j + 1,
00083                        fich[j].nom, fich[j].prenom, fich[j].age, fich[j].tel);
00084 
00085         err = munmap(fic, nb_pers * sizeof(struct personne) + 8);
00086         if (err) error("munmap (2)");
00087         return 0;
00088 }