使用锁(POSIX)在C中读写

时间:2014-12-21 13:40:37

标签: c locking posix

你好,我是信息学的学生,我尝试做一个锁定/解锁文件夹的程序。

我把完整的程序给你试试。我可以编译并运行它,但我总是被阻止。 我不知道如何阅读文件(我总是有一个带有读取的返回-1。)

我不会要求我们更正所有代码,只是为了告诉我POSIX的错误

这里我的问题与read(返回-1), 我希望我的程序创建文件,如果不存在但我不知道是否可能 如何验证文件是否打开?我找不到办法。 此函数在文件" PATH_FILE_OWNER"中添加一个struc所有者。在添加锁之前,请验证OWNER是否已具有与新ID相同的ID,如果没有将新的所有者添加到文件中。

void addOwner()
{
    proprietaire* proprio = (proprietaire*)malloc(sizeof(proprietaire));
    if(proprio == NULL){
        perror("L'allocation n'a pu etre réalisee\n");
        exit(1);
    }

    int fd=open(PATH_FILE_OWNER, O_RDWR|O_CREAT, S_IRUSR|S_IWUSR);
    struct flock verrou;
    verrou.l_type=F_WRLCK;
    verrou.l_whence=verrou.l_start=verrou.l_len=0;



    while((fcntl(fd, F_SETLK, &verrou) )== -1 && (errno == EACCES || errno == EAGAIN)){
        sleep(5);
        printf("Verrouiller\n");
    }


    int idDispo = FALSE,
        id;
    while(idDispo == FALSE)
    {
    cleanBuffer();
    printf("Entrez un identifiant non utilise\n");
    scanf("%d", &id);
    printf("id:  %d\n", id);


        // verifie si l'id est utilisé
        int trouve = FALSE, temp;
        while((temp = read(fd, proprio, sizeof(proprietaire))) != 0 && trouve == FALSE)
        {
            // I have add this for verify the error, it is right ? (if yes I ll do every where :)
            if(temp < 0){
                printf("Boucle %d\n", temp); 
                perror("erreur");
                printf("errno=%d\n", errno);
                exit(1);
            }

            if(proprio->identifiant == id){
                trouve = TRUE;
            }
        }

        // si l'id est utilisé redemande un autre id et refait une recherche,
        // sinon sort de la boucle et continue
        if(trouve == TRUE){
            printf("Identifiant deja utilise\n");
        } else {
            idDispo = TRUE;
        }
    }

    // demande le reste des info et initialise la structure
    proprio->identifiant = id;
    printf("Entrez son nom:\n");
    scanf("%s",proprio->nom);
    printf("Entrez son prenom:\n");
    scanf("%s",proprio->prenom);
    printf("Entrez son adresse:\n");
    scanf("%s",proprio->adresse);
    proprio->nbVoiture = 0;

       // test affichage
    printf("Id : %d\n", proprio->identifiant);
    printf("Nom: %s\n", proprio->nom);
    printf("Prenom: %s\n", proprio->prenom);
    printf("Adresse: %s\n", proprio->adresse);
    printf("Nombre de voiture posseder: %d\n\n", proprio->nbVoiture);

    // j'enregistrer le proprietaire
    lseek(fd,0,SEEK_END);
    write(fd, proprio , sizeof(proprio));

    // je deverrouille
    verrou.l_type = F_UNLCK;
    if (fcntl(fd, F_SETLK, &verrou) == -1){
        perror("Impossible de deverouiller le record");
        exit(1);
    }
    close(fd);
    free(proprio);
}

这里是完整的代码:

#if defined(linux) || defined(__linux__) || defined(unix) || defined (__unix__) || defined (__APPLE__)
    #define mrpropre system("clear")
    #else
    #define mrpropre system("cls")
    #endif

    #include <stdio.h>
    #include <stdlib.h>
    #include <time.h>
    #include <unistd.h>
    #include <sys/types.h>
    #include <stdio.h>
    #include <sys/stat.h>
    #include <errno.h>
    #include <string.h>
    #include <fcntl.h>


    #define TAILLE_NOM_MARQUE 20
    #define TAILLE_NOM_MODELE 10
    #define TAILLE_NOM_COULEUR 10
    #define TAILLE_NOM_PLAQUE 7

    #define TAILLE_NOM_PROPRIETAIRE 20
    #define TAILLE_PRENOM_PROPRIETAIRE 20
    #define TAILLE_ADRESSE_PROPRIETAIRE 40


    #define FALSE 0
    #define TRUE  1

    #define PATH_FILE_OWNER "fichProprio.bin"
    #define PATH_FILE_CAR   "fichVoiture.bin"


    typedef struct voiture
    {
        char nomMarque[TAILLE_NOM_MARQUE];
        char nomModele[TAILLE_NOM_MODELE];
        char couleur[TAILLE_NOM_COULEUR];
        char plaque[TAILLE_NOM_PLAQUE];
        int idProprietaire;

    } voiture;

    typedef struct proprietaire
    {
        int identifiant;
        char nom[TAILLE_NOM_PROPRIETAIRE];
        char prenom[TAILLE_PRENOM_PROPRIETAIRE];
        char adresse[TAILLE_ADRESSE_PROPRIETAIRE];
        int nbVoiture;

    } proprietaire;

    char menu();

    void showOwnerWithCar();

    void addOwner();

    void addCar();

    void updateOwner();

    void updateCar();

    void deleteOwner();

    void deleteCarID(int);

    void deleteCar();

    int addCarToOwner(int, int);

    void cleanBuffer();
    int main(void)
    {
        int fin=0;
        while(fin == 0)
        {
            mrpropre;
        cleanBuffer();
            char choixMenu = menu();
            switch(choixMenu)
            {
            case '0': // Quitter
                fin = 1;
                break;
            case '1':
                showOwnerWithCar();
                break;
            case '2':
                addOwner();
                break;
            case '3':
                addCar();
                break;
            case '4':
                updateOwner();
                break;
            case '5':
                updateCar();
                break;
            case '6':
                deleteOwner();
                break;
            case '7':
                deleteCar();
                break;
            default:
                printf("Erreur, aucun choix \n");
                getchar();
                break;

            }

        }
        return 0;
    }


    char menu()
    {
        printf("\nQue voulez-vous faire ?\n-------------------\n\n");
        printf("\t 1) Afficher un proprietaire et ces voiture\n");
        printf("\t 2) Ajouter un proprietaire\n");
        printf("\t 3) Ajouter une voiture (elle devra etre liee a un proprietaire)\n");
        printf("\t 4) Mise a jour des informations d'un proprietaire\n");
        printf("\t 5) Mise a jour des informations d'une voiture\n");
        printf("\t 6) Supprimer un proprietaire et ces voitures\n");
        printf("\t 7) Supprimer une voiture\n");
        printf("\t 0) Quitter le programme\n");
        return getchar();
    }


    void showOwnerWithCar(){

        // on cherche le propriétaire
        printf("Entrez l'identifiant du proprietaire\n");
        int idChercher; 
        scanf("%d", &idChercher);

        proprietaire* proprio = (proprietaire*)malloc(sizeof(proprietaire));
        if(proprio == NULL){
            perror("L'allocation n'a pu etre réalisee\n");
            exit(1);
        }

        int fdOwner = open(PATH_FILE_OWNER, O_RDONLY|O_CREAT, S_IRUSR);
        int trouve = FALSE;

        while(read(trouve == FALSE && fdOwner, proprio, sizeof(proprietaire)) != 0)
        {
        printf("ici1\t");
            if(proprio->identifiant == idChercher)
            {
                trouve = TRUE;
            }
        }
        close(fdOwner);
        printf("ici2\t");
        voiture * car = (voiture*)malloc(sizeof(voiture));
        voiture * tabVoiture = malloc(proprio->nbVoiture * sizeof(voiture));
        int fdCar = open(PATH_FILE_CAR, O_RDONLY);

        // ensuite on cherche ces voitures
        int nbVoitureTrouver = 0;
        while(read(fdCar, car, sizeof(voiture)) != 0 && nbVoitureTrouver < proprio->nbVoiture)
        {
            if(proprio->identifiant == idChercher)
            {
                tabVoiture[nbVoitureTrouver] = *car;
                nbVoitureTrouver++;
            }
        }
        close(fdCar);
        free(car);


        // on affiche le propriétaire
        printf("Id : %d\n", proprio->identifiant);
        printf("Nom: %s\n", proprio->nom);
        printf("Prenom: %s\n", proprio->prenom);
        printf("Adresse: %s\n", proprio->adresse);
        printf("Nombre de voiture posseder: %d\n\n", proprio->nbVoiture);

        // ensuite ces voitures
        int nbCar;
        for(nbCar=0;nbCar<proprio->nbVoiture;nbCar++){
            printf("Marque : %s\n", tabVoiture[nbCar].nomMarque);
            printf("Modele : %s\n", tabVoiture[nbCar].nomModele);
            printf("Couleur : %s\n",tabVoiture[nbCar].couleur);
            printf("Plaque : %s\n", tabVoiture[nbCar].plaque);
        }

        // on vide la mémoire
        free(proprio);
        for(nbCar=0;nbCar<proprio->nbVoiture;nbCar++){
            free(tabVoiture + nbCar);
        }

    }



    void addOwner()
    {
        proprietaire* proprio = (proprietaire*)malloc(sizeof(proprietaire));
        if(proprio == NULL){
            perror("L'allocation n'a pu etre réalisee\n");
            exit(1);
        }

        int fd=open(PATH_FILE_OWNER, O_RDWR|O_CREAT, S_IRUSR|S_IWUSR);
        struct flock verrou;
        verrou.l_type=F_WRLCK;
        verrou.l_whence=verrou.l_start=verrou.l_len=0;



        while((fcntl(fd, F_SETLK, &verrou) )== -1 && (errno == EACCES || errno == EAGAIN)){
            sleep(5);
            printf("Verrouiller\n");
        }


        int idDispo = FALSE,
            id;
        while(idDispo == FALSE)
        {
        cleanBuffer();
        printf("Entrez un identifiant non utilise\n");
        scanf("%d", &id);
        printf("id:  %d\n", id);


            // verifie si l'id est utilisé
            int trouve = FALSE, temp;
            while((temp = read(fd, proprio, sizeof(proprietaire))) != 0 && trouve == FALSE)
            {
                // I have add this for verify the error, it is right ? (if yes I ll do every where :)
                if(temp < 0){
                    printf("Boucle %d\n", temp); 
                    perror("erreur");
                    printf("errno=%d\n", errno);
                    exit(1);
                }

                if(proprio->identifiant == id){
                    trouve = TRUE;
                }
            }

            // si l'id est utilisé redemande un autre id et refait une recherche,
            // sinon sort de la boucle et continue
            if(trouve == TRUE){
                printf("Identifiant deja utilise\n");
            } else {
                idDispo = TRUE;
            }
        }

        // demande le reste des info et initialise la structure
        proprio->identifiant = id;
        printf("Entrez son nom:\n");
        scanf("%s",proprio->nom);
        printf("Entrez son prenom:\n");
        scanf("%s",proprio->prenom);
        printf("Entrez son adresse:\n");
        scanf("%s",proprio->adresse);
        proprio->nbVoiture = 0;

           // test affichage
        printf("Id : %d\n", proprio->identifiant);
        printf("Nom: %s\n", proprio->nom);
        printf("Prenom: %s\n", proprio->prenom);
        printf("Adresse: %s\n", proprio->adresse);
        printf("Nombre de voiture posseder: %d\n\n", proprio->nbVoiture);

        // j'enregistrer le proprietaire
        lseek(fd,0,SEEK_END);
        write(fd, proprio , sizeof(proprio));

        // je deverrouille
        verrou.l_type = F_UNLCK;
        if (fcntl(fd, F_SETLK, &verrou) == -1){
            perror("Impossible de deverouiller le record");
            exit(1);
        }
        close(fd);
        free(proprio);
    }


    void addCar()
    {
        voiture* car = (voiture*)malloc(sizeof(voiture));
        if(car == NULL){
            perror("L'allocation n'a pu etre réalisee\n");
            exit(1);
        }

        int fd=open(PATH_FILE_CAR, O_APPEND|O_CREAT, S_IRUSR|S_IWUSR);
        struct flock verrou;
        verrou.l_type=F_WRLCK;
        verrou.l_whence=verrou.l_start=verrou.l_len=0;


        int res, id;
        while( res == 0 )
        {
            printf("Entrer l'identifiant du proprietaire\n");
            scanf("%d", &id);
            res = addCarToOwner(1, id);
        }

        if(res == 1)
        {
            printf("Id valide\n");
            car->idProprietaire = id;
            printf("Entrez sa marque:\n");
            scanf("%s",car->nomMarque);
            printf("Entrez son modele:\n");
            scanf("%s",car->nomModele);
            printf("Entrez sa couleur:\n");
            scanf("%s",car->couleur);
            printf("Entrez son numero de plaque:\n");
            scanf("%s",car->plaque);


            // je verrouille le fichier
            while ( (fcntl(fd, F_SETLK, &verrou) )== -1 && (errno == EACCES  || errno == EAGAIN) ){
                sleep(5);
            }

            // j'enregistre la voiture
            lseek(fd,0,SEEK_END);
            write(fd , car, sizeof(car));

            // je deverrouille le fichier
            verrou.l_type = F_UNLCK;
            if (fcntl(fd, F_SETLK, &verrou) == -1){
                perror("Impossible de deverouiller le record");
                exit(1);
            }
        }
        free(car);
        close(fd);
    }


    void updateOwner()
    {
        proprietaire* proprio = (proprietaire*)malloc(sizeof(proprietaire));
        if(proprio == NULL){
            perror("L'allocation n'a pu etre réalisee\n");
            exit(1);
        }

        int fd=open(PATH_FILE_OWNER, O_RDWR|O_CREAT, S_IRUSR|S_IWUSR);
        struct flock verrou;
        verrou.l_type=F_WRLCK;
        verrou.l_whence=verrou.l_start=verrou.l_len=0;

        printf("Id du proprietaire: \n");
        int id; scanf("%d",&id);

        while((fcntl(fd, F_SETLK, &verrou) )== -1 && (errno == EACCES || errno == EAGAIN)){
            sleep(5);
        }

        // je cherche la personne concerner et la modifie si elle existe
        int trouve = FALSE;
        while(read(fd, proprio, sizeof(proprietaire)) != 0 && trouve == FALSE){
            if(proprio->identifiant == id){
                trouve = TRUE;
                printf(" L'adresse est %s\n Entrez la nouvelle adresse:\n", proprio->adresse);
                scanf("%s", proprio->adresse);
                lseek(fd, -sizeof(proprio) , SEEK_CUR);
                write(fd, proprio , sizeof(proprio));
                }
        }

        if(trouve == FALSE) printf("ID invalide\n");

        // je deverrouille le fichier
        verrou.l_type = F_UNLCK;
        if (fcntl(fd, F_SETLK, &verrou) == -1)
            perror("Impossible de deverouiller le record");

        close(fd);
        free(proprio);
    }



    void updateCar()
    {
        voiture* car = (voiture*)malloc(sizeof(voiture));
        if(car == NULL){
            perror("L'allocation n'a pu etre réalisee\n");
            exit(1);
        }

        int fd=open(PATH_FILE_OWNER, O_RDWR|O_CREAT, S_IRUSR|S_IWUSR);
        struct flock verrou;
        verrou.l_type=F_WRLCK;
        verrou.l_whence=verrou.l_start=verrou.l_len=0;

        char numPlaque[TAILLE_NOM_PLAQUE];
        printf("Entrez la plaque d'immatriculation du véhicule");
        scanf("%s", numPlaque);

        // je verouille
        while((fcntl(fd, F_SETLK, &verrou) )== -1 && (errno == EACCES || errno == EAGAIN)){
            sleep(5);
        }

        // je recherche la voiture portant ce numero de plaque
        int trouve = FALSE;
        while(read(fd, car, sizeof(voiture)) != 0 && trouve == FALSE){
            // si je la trouve je modifie sa couleur
            if(strcmp(numPlaque, car->plaque) == 0){
                trouve = TRUE;
                printf("Entrez la nouvelle couleur");
                scanf("%s", car->couleur);
                lseek(fd, -sizeof(car) , SEEK_CUR);
                write(fd , car , sizeof(car));
            }
        }

            // je deverrouille le fichier
            verrou.l_type = F_UNLCK;
            if (fcntl(fd, F_SETLK, &verrou) == -1){
                perror("Impossible de deverouiller le record");
                exit(1);
            }

            if(trouve == FALSE){
                printf("Voiture inconnue");
            }

            free(car);
    }

    void deleteOwner(){
        proprietaire* proprio = (proprietaire*)malloc(sizeof(proprietaire));
        if(proprio == NULL){
            perror("L'allocation n'a pu etre réalisee\n");
            exit(1);
        }

        int fd=open(PATH_FILE_OWNER, O_RDONLY|O_CREAT, S_IRUSR);
        int fdNew=open("tempOwner.dat", O_WRONLY|O_CREAT, S_IWUSR);

        int id;
        printf("Entrez l'identifiant du proprietaire a supprimer\n");
        scanf("%d", &id);


        int trouve = FALSE;
        while(read(fd, proprio, sizeof(proprietaire)) != 0)
        {
            if(proprio->identifiant == id){
                trouve = TRUE;
            } else {
                write( fdNew, proprio, sizeof(proprietaire));
            }
        }

        if(trouve == TRUE){
            rename("tempOwner.dat", PATH_FILE_OWNER);
            deleteCarID(id);
            printf("Supression du proprietaire\n");
        } else {
            printf("id invalide");
        }
        free(proprio);
    }

    void deleteCarID(int id){
        voiture* car = (voiture*)malloc(sizeof(voiture));
        if(car == NULL){
            perror("L'allocation n'a pu etre réalisee\n");
            exit(1);
        }

        int fd=open(PATH_FILE_CAR, O_RDONLY|O_CREAT, S_IRUSR);
        int fdNew=open("tempCar.dat", O_WRONLY|O_CREAT, S_IWUSR);
        int trouve = FALSE;
        while(read(fd, car, sizeof(voiture)) != 0)
        {
            if(!car->idProprietaire == id){
                trouve = TRUE;
                write( fdNew, car, sizeof(proprietaire));
            }
        }

        if(trouve == TRUE){
            rename("tempCar.dat", PATH_FILE_CAR);
            printf("Supression des voitures\n");
        }
        free(car);
    }

    void deleteCar(){

        voiture* car = (voiture*)malloc(sizeof(voiture));
        if(car == NULL){
            perror("L'allocation n'a pu etre réalisee\n");
            exit(1);
        }

        char numPlaque[TAILLE_NOM_PLAQUE];
        printf("Entrez le numero de plaque de la voiture a supprimer\n");
        scanf("%s", numPlaque);

        int fd=open(PATH_FILE_CAR, O_RDONLY|O_CREAT, S_IRUSR);
        int fdNew=open("tempCar.dat", O_WRONLY|O_CREAT, S_IWUSR);
        int trouve = FALSE;
        while(read(fd, car, sizeof(voiture)) != 0)
        {
            if(strcmp(numPlaque, car->plaque) == 0){
                trouve = TRUE;
            } else {
                write(fdNew, car, sizeof(proprietaire));
            }
        }

        if(trouve == TRUE){
            rename("tempCar.dat", PATH_FILE_CAR);
            printf("Supression des voitures\n");
            addCarToOwner(-1, car->idProprietaire);
        }
        free(car);
    }

    // -1 pas de fichier
    // 0 id correspond pas
    // 1 ok
    int addCarToOwner(int nb, int id){
        proprietaire* proprio = (proprietaire*)malloc(sizeof(proprietaire));
        if(proprio == NULL){
            perror("L'allocation n'a pu etre réalisee\n");
            exit(1);
        }

        int fd=open(PATH_FILE_OWNER, O_RDWR|O_CREAT, S_IRUSR|S_IWUSR);
        struct flock verrou;
        verrou.l_type=F_WRLCK;
        verrou.l_whence=verrou.l_start=verrou.l_len=0;

        int res = 0,
            trouve = FALSE;

        res = 0;


        // je verrouille le fichier des proprietaires
       while((fcntl(fd, F_SETLK, &verrou) )== -1 && (errno == EACCES || errno == EAGAIN)){
            sleep(5);
        }

        // je cherche le proprietaire dans le fichier
        while(read(fd, proprio, sizeof(proprietaire)) != 0 && trouve == FALSE){
            if(proprio->identifiant == id){
                trouve = TRUE;
                res = 1;

                if(nb>0){
                    proprio->nbVoiture++;
                } else {
                    if(proprio->nbVoiture>0){
                        proprio->nbVoiture--;
                    }
                }
                lseek(fd, -sizeof(proprio) , SEEK_CUR);
                write(fd, proprio , sizeof(proprio));
            }
        }

        // je deverrouille le fichier
        verrou.l_type = F_UNLCK;
        if (fcntl(fd, F_SETLK, &verrou) == -1){
            perror("Impossible de deverouiller le record");
            exit(1);
        }
        close(fd);
        free(proprio);
        return res;
    }

    void cleanBuffer(){
        while( getchar() != '\n');
    }

P.S我的借口是我的英语,并且没有尊重我的问题的语法。我下次会尝试做得更好。我实际上只是要求函数addOwner();在您的帮助下,如果可能的话,我会尝试调试我的所有程序。

对你所有人来说,这很好。)

2 个答案:

答案 0 :(得分:2)

像这样打开文件:

fd = open(PATH_FILE_OWNER, O_RDWR|O_CREAT, S_IRUSR|S_IWUSR);

请注意,您仍需要指定访问模式(O_RDWR),并且新创建的文件需要文件模式标志。这应该可以解决你的问题。

此外,您应该为open()以及之前的malloc()添加错误检查。

修改

您在编写数据时遇到了进一步的问题。写入不完整的记录是因为您只写sizeof(proprio)个字节。 proprio被声明为结构的指针,因此它的大小是指针的大小(64位机器上的8个字节)。将您的写入更改为:

ssize_t n = write(fd, proprio , sizeof(proprietaire));

这样您就可以编写struct proprietaire所需的字节数(64位机器为88字节)。检查write()的返回值以确保写入正确的字节数或检查错误非常重要。

答案 1 :(得分:1)

您需要检查open()的返回码。如果您的文件尚未存在,则打开将失败,然后您的read()调用将因EBADF而失败。

听起来您想要在open()调用中添加O_CREAT标志,以便在文件不存在的情况下创建该文件。

此时,我不认为你的锁与你的问题有任何关系。