#include #include #include #include #include #include #include #include #include "ajout-serveur.corrige.h" #define TAILLEMAXBUFFER 4096 shm_t *shm; /* Procédures P et V pour manipulation du sémaphore #0 des objets sémaphores */ void P(int semId){ struct sembuf aBuf = {0, -1, 0}; int retour; retour = semop(semId, &aBuf, 1); assert(retour != -1); } void V(int semId){ struct sembuf aBuf = {0, +1, 0}; int retour; retour = semop(semId, &aBuf, 1); assert(retour != -1); } /* Ajout Effectif du mEtMme fourni en parametre au fichier mEtMme.txt (voir le commentaire de ajoutDansFic pour comprendre la difference entre ajoutEffectifDansFic et ajoutDansFic */ void ajoutEffectifDansFic(char *mEtMme){ FILE *f; char ligne[256]; char buffer[TAILLEMAXBUFFER]; int positionPremierOctetADecaler; int tailleADecaler; /* Valeur de mEtMme avec un '\n' a la fin pour qu'il s'insere */ /* joliment dans le fichier */ char mEtMmeAvecNL[512]; /* offset ou il faudra stocke le mEtMme dans le fichier mEtMme.txt */ int offsetMEtMme = 0; /**************************/ /* Calcul de mEtMmeAvecNL */ /**************************/ strncpy(mEtMmeAvecNL, mEtMme, sizeof(mEtMmeAvecNL)); mEtMmeAvecNL[strlen(mEtMmeAvecNL)+1] = '\0'; mEtMmeAvecNL[strlen(mEtMmeAvecNL)] = '\n'; /*************************************/ /* Ouverture du fichier de M. et Mme */ /*************************************/ f = fopen("mEtMme.txt", "r+"); assert(f != NULL); /**************************/ /* Calcul de offsetMEtMme */ /**************************/ /* On cherche la premiere ligne de mEtMme.txt qui soit apres */ /* (au sens lexicographique) la ligne qu'on veut inserer, */ /* l'objectif etant de memoriser son offset */ rewind(f); while (feof(f) == 0) { if (fgets(ligne, sizeof(ligne), f) != NULL) { if (strcmp(mEtMme, ligne) <= 0){ break; } } offsetMEtMme = ftell(f); assert(offsetMEtMme >= 0); } /**************************/ /* Decalage des octets */ /**************************/ /* Dans le fichier mEtMme.txt, il faut maintenant faire de la place */ /* pour stocker le nouveau mEtMme. On decale les octets a partir de */ /* la fin du fichier */ assert(fseek (f, 0, SEEK_END) == 0); positionPremierOctetADecaler = ftell(f); assert(positionPremierOctetADecaler >= 0); while (positionPremierOctetADecaler > offsetMEtMme){ if (positionPremierOctetADecaler - offsetMEtMme > TAILLEMAXBUFFER){ tailleADecaler = TAILLEMAXBUFFER; }else{ tailleADecaler = positionPremierOctetADecaler - offsetMEtMme; } positionPremierOctetADecaler -= tailleADecaler; assert(fseek(f, positionPremierOctetADecaler, SEEK_SET) == 0); assert(fread(buffer, tailleADecaler, 1, f) == 1); assert(fseek(f, positionPremierOctetADecaler+strlen(mEtMmeAvecNL), SEEK_SET) == 0); assert(fwrite (buffer, tailleADecaler, 1, f) == 1); assert(fflush(f) == 0); } /**********************/ /* Ecriture de mEtMme */ /**********************/ assert(fseek(f, offsetMEtMme, SEEK_SET) >= 0); assert(fputs(mEtMmeAvecNL,f) >= 0); /*************************************/ /* Fermeture du fichier de M. et Mme */ /*************************************/ assert(fclose(f) == 0); /********************************************************************/ /* On signale a tous les enfants de serveur que le fichier a change */ /********************************************************************/ shm->numVersionFichier += 1; if (shm->numVersionFichier == 0){ /* On evite la valeur 0 qui permet aux enfants de serveur de */ /* s'initialiser */ shm->numVersionFichier = 1; } } /* Ajout du mEtMme fourni en parametre au fichier mEtMme.txt Cette procedure s'occupe de la synchronisation avec les enfants. Elle appelle ajoutEffectifDansFic quand elle est sure qu'ajout a pris le controle (dans le paradigme lecteur/redacteur) */ void ajoutDansFic(char *mEtMme){ key_t key; int shmid; int fifo; int mutexG; printf("La fonction ajoutDansFic ajoute le M. et Mme \"%s\"\n", mEtMme); /**************************************************************/ /* Initialisations liees a la concurrence d'acces entre ajout */ /* et les enfants */ /**************************************************************/ /* Recuperation pointeur sur la mémoire partagee (crees par imprime6s) */ key = ftok(NOMFIC,NOMPROJPOURSHM); assert( key != -1); shmid = shmget(key, sizeof(shm_t), 0600); assert( shmid != -1); shm = (shm_t*) shmat(shmid, NULL, 0); assert(shm != (shm_t*)-1); /* Recuperation des semaphores (crees par imprime6s) */ key = ftok(NOMFIC,NOMPROJPOURFIFO); assert( key != -1); fifo = semget(key, 1, 0600); assert(fifo != -1); key = ftok(NOMFIC,NOMPROJPOURMUTEXG); assert( key != -1); mutexG = semget(key, 1, 0600); assert(mutexG != -1); /**********************************************************/ /* Synchronisation entre ajout et enfants selon paradigme */ /* lecteur (les enfants)/redacteur (ajout) */ /**********************************************************/ P(fifo); P(mutexG); V(fifo); /**********************************/ /* Ajout effectif dans le fichier */ /**********************************/ ajoutEffectifDansFic(mEtMme); /**********************************************************/ /* Fin de synchronisation entre ajout et enfants selon */ /* paradigme lecteur (les enfants)/redacteur (ajout) */ /**********************************************************/ V(mutexG); printf("Fin ajout\n"); } int main(int argc, char *argv[]) { if (argc != 2) { printf("Usage = ajout nouveauMEtMme\n"); printf("Par exemple :\n"); printf(" ajout 'ADESSIN ont une fille : Blanche'\n"); printf("(noter l'utilisation des simples quotes pour garantir que le shell \n"); printf("n'interprete pas les espaces)\n"); exit(EXIT_FAILURE); } ajoutDansFic(argv[1]); return EXIT_SUCCESS; }