File:  [local] / rpl / src / gestion_fichiers.c
Revision 1.8: download - view: text, annotated - select for diffs - revision graph
Mon Mar 8 14:28:20 2010 UTC (14 years, 2 months ago) by bertrand
Branches: MAIN
CVS tags: HEAD
Écriture des fichiers formatés à accès indexé.

    1: /*
    2: ================================================================================
    3:   RPL/2 (R) version 4.0.12
    4:   Copyright (C) 1989-2010 Dr. BERTRAND Joël
    5: 
    6:   This file is part of RPL/2.
    7: 
    8:   RPL/2 is free software; you can redistribute it and/or modify it
    9:   under the terms of the CeCILL V2 License as published by the french
   10:   CEA, CNRS and INRIA.
   11:  
   12:   RPL/2 is distributed in the hope that it will be useful, but WITHOUT
   13:   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   14:   FITNESS FOR A PARTICULAR PURPOSE.  See the CeCILL V2 License
   15:   for more details.
   16:  
   17:   You should have received a copy of the CeCILL License
   18:   along with RPL/2. If not, write to info@cecill.info.
   19: ================================================================================
   20: */
   21: 
   22: 
   23: #include "rpl.conv.h"
   24: 
   25: 
   26: /*
   27: ================================================================================
   28:   Routines de gestion des fichiers
   29: ================================================================================
   30:   Entrées : nom du fichier
   31: --------------------------------------------------------------------------------
   32:   Sorties : 0, le fichier n'existe pas, -1, il existe.
   33: --------------------------------------------------------------------------------
   34:   Effets de bord : néant
   35: ================================================================================
   36: */
   37: 
   38: /*
   39:  * Génère un nom de fichier
   40:  */
   41: 
   42: unsigned char *
   43: creation_nom_fichier(struct_processus *s_etat_processus,
   44:         unsigned char *chemin)
   45: {
   46:     /*
   47:      * Le nom du fichier est créé à l'aide du pid du processus et
   48:      * d'un numéro d'ordre pour ce processus.
   49:      */
   50: 
   51:     logical1                        erreur;
   52: 
   53:     logical1                        existence;
   54:     logical1                        ouverture;
   55: 
   56:     pthread_mutex_t                 exclusion = PTHREAD_MUTEX_INITIALIZER;
   57: 
   58:     unsigned char                   *nom;
   59:     unsigned char                   tampon[256 + 1];
   60: 
   61:     unsigned long                   ordre_initial;
   62:     unsigned long                   unite;
   63: 
   64:     static unsigned long            ordre = 0;
   65: 
   66:     if (pthread_mutex_lock(&exclusion) != 0)
   67:     {
   68:         return(NULL);
   69:     }
   70: 
   71:     ordre_initial = ordre;
   72: 
   73:     if (pthread_mutex_unlock(&exclusion) != 0)
   74:     {
   75:         return(NULL);
   76:     }
   77: 
   78:     do
   79:     {
   80:         sprintf(tampon, "RPL2-%lu-%lu-%lu", (unsigned long) getpid(),
   81:                 (unsigned long) pthread_self(), ordre);
   82: 
   83:         if (chemin == NULL)
   84:         {
   85:             if ((nom = malloc((strlen(tampon) + 1) *
   86:                     sizeof(unsigned char))) == NULL)
   87:             {
   88:                 return(NULL);
   89:             }
   90: 
   91:             strcpy(nom, tampon);
   92:         }
   93:         else
   94:         {
   95:             if ((nom = malloc((strlen(chemin) + strlen(tampon) + 2) *
   96:                     sizeof(unsigned char))) == NULL)
   97:             {
   98:                 return(NULL);
   99:             }
  100: 
  101:             sprintf(nom, "%s/%s", chemin, tampon);
  102:         }
  103: 
  104:         if (pthread_mutex_lock(&exclusion) != 0)
  105:         {
  106:             return(NULL);
  107:         }
  108: 
  109:         ordre++;
  110: 
  111:         if (pthread_mutex_unlock(&exclusion) != 0)
  112:         {
  113:             return(NULL);
  114:         }
  115: 
  116:         if (ordre == ordre_initial)
  117:         {
  118:             // Il n'existe plus aucun nom de fichier disponible...
  119: 
  120:             free(nom);
  121:             return(NULL);
  122:         }
  123: 
  124:         erreur = caracteristiques_fichier(s_etat_processus,
  125:                 nom, &existence, &ouverture, &unite);
  126: 
  127:         if (erreur != 0)
  128:         {
  129:             free(nom);
  130:             return(NULL);
  131:         }
  132: 
  133:         if (existence == d_vrai)
  134:         {
  135:             free(nom);
  136:         }
  137:     } while(existence == d_vrai);
  138: 
  139:     return(nom);
  140: }
  141: 
  142: /*
  143:  * Efface un fichier
  144:  */
  145: 
  146: logical1
  147: destruction_fichier(unsigned char *nom_fichier)
  148: {
  149:     return((unlink(nom_fichier) == 0) ? d_absence_erreur : d_erreur);
  150: }
  151: 
  152: /*
  153:  * Renvoie le descripteur en fonction de la structure de contrôle du fichier
  154:  */
  155: 
  156: struct_descripteur_fichier *
  157: descripteur_fichier(struct_processus *s_etat_processus,
  158:         struct_fichier *s_fichier)
  159: {
  160:     logical1                    concordance_descripteurs;
  161: 
  162:     struct_liste_chainee        *l_element_courant;
  163: 
  164:     l_element_courant = (*s_etat_processus).s_fichiers;
  165:     concordance_descripteurs = d_faux;
  166: 
  167:     while(l_element_courant != NULL)
  168:     {
  169:         if ((*((struct_descripteur_fichier *) (*l_element_courant).donnee))
  170:                 .identifiant == (*s_fichier).descripteur)
  171:         {
  172:             if (((*((struct_descripteur_fichier *) (*l_element_courant).donnee))
  173:                     .pid == (*s_fichier).pid) && (pthread_equal(
  174:                     (*((struct_descripteur_fichier *) (*l_element_courant)
  175:                     .donnee)).tid, pthread_self()) != 0))
  176:             {
  177:                 return((struct_descripteur_fichier *)
  178:                         (*l_element_courant).donnee);
  179:             }
  180:             else
  181:             {
  182:                 concordance_descripteurs = d_vrai;
  183:             }
  184:         }
  185: 
  186:         l_element_courant = (*l_element_courant).suivant;
  187:     }
  188: 
  189:     if (concordance_descripteurs == d_vrai)
  190:     {
  191:         (*s_etat_processus).erreur_execution = d_ex_fichier_hors_contexte;
  192:     }
  193:     else
  194:     {
  195:         (*s_etat_processus).erreur_systeme = d_es_erreur_fichier;
  196:     }
  197: 
  198:     return(NULL);
  199: }
  200: 
  201: /*
  202:  * Recherche un chemin pour les fichiers temporaires
  203:  */
  204: 
  205: unsigned char *
  206: recherche_chemin_fichiers_temporaires(struct_processus *s_etat_processus)
  207: {
  208:     file                *fichier;
  209: 
  210:     unsigned char       *candidat;
  211:     unsigned char       *chemin;
  212:     unsigned char       *chemins[] = { "$RPL_TMP_PATH",
  213:                                 "/tmp", "/var/tmp", NULL };
  214:     unsigned char       *nom_candidat;
  215: 
  216:     unsigned long int   i;
  217: 
  218:     i = 0;
  219:     chemin = NULL;
  220: 
  221:     while(chemin == NULL)
  222:     {
  223:         if (chemins[i][0] == '$')
  224:         {
  225:             candidat = getenv("RPL_TMP_PATH");
  226: 
  227:             if (candidat != NULL)
  228:             {
  229:                 if ((nom_candidat = creation_nom_fichier(s_etat_processus,
  230:                         candidat)) == NULL)
  231:                 {
  232:                     return NULL;
  233:                 }
  234: 
  235:                 if ((fichier = fopen(nom_candidat, "w+")) != NULL)
  236:                 {
  237:                     fclose(fichier);
  238:                     unlink(nom_candidat);
  239:                     free(nom_candidat);
  240: 
  241:                     if ((chemin = malloc((strlen(candidat) + 1)
  242:                             * sizeof(unsigned char))) != NULL)
  243:                     {
  244:                         strcpy(chemin, candidat);
  245:                     }
  246:                     else
  247:                     {
  248:                         return NULL;
  249:                     }
  250:                 }
  251:                 else
  252:                 {
  253:                     free(nom_candidat);
  254:                 }
  255:             }
  256:         }
  257:         else
  258:         {
  259:             if ((nom_candidat = creation_nom_fichier(s_etat_processus,
  260:                     chemins[i])) == NULL)
  261:             {
  262:                 return NULL;
  263:             }
  264: 
  265:             if ((fichier = fopen(nom_candidat, "w+")) != NULL)
  266:             {
  267:                 fclose(fichier);
  268:                 unlink(nom_candidat);
  269:                 free(nom_candidat);
  270: 
  271:                 if ((chemin = malloc((strlen(chemins[i]) + 1)
  272:                         * sizeof(unsigned char))) != NULL)
  273:                 {
  274:                     strcpy(chemin, chemins[i]);
  275:                 }
  276:                 else
  277:                 {
  278:                     return NULL;
  279:                 }
  280:             }
  281:             else
  282:             {
  283:                 free(nom_candidat);
  284:             }
  285:         }
  286: 
  287:         i++;
  288:     }
  289: 
  290:     return chemin;
  291: }
  292: 
  293: 
  294: /*
  295:  * Fonction d'interrogation du fichier
  296:  */
  297: 
  298: logical1
  299: caracteristiques_fichier(struct_processus *s_etat_processus,
  300:         unsigned char *nom, logical1 *existence, logical1 *ouverture,
  301:         unsigned long *unite)
  302: {
  303:     int                             descripteur;
  304: 
  305:     logical1                        erreur;
  306: 
  307:     struct_liste_chainee            *l_element_courant;
  308: 
  309:     (*unite) = 0;
  310:     (*ouverture) = d_faux;
  311:     (*existence) = d_faux;
  312: 
  313:     if ((descripteur = open(nom, O_CREAT | O_EXCL, S_IRUSR | S_IWUSR)) == -1)
  314:     {
  315:         if (errno == EEXIST)
  316:         {
  317:             // Le fichier préexiste.
  318: 
  319:             erreur = d_absence_erreur;
  320:             (*existence) = d_vrai;
  321: 
  322:             // On chercher à savoir si le fichier est ouvert. S'il est ouvert,
  323:             // on renvoie son unité de rattachement.
  324: 
  325:             l_element_courant = (*s_etat_processus).s_fichiers;
  326: 
  327:             while(l_element_courant != NULL)
  328:             {
  329:                 if (strcmp((*((struct_descripteur_fichier *)
  330:                         (*l_element_courant).donnee)).nom, nom) == 0)
  331:                 {
  332:                     if (((*((struct_descripteur_fichier *) (*l_element_courant)
  333:                             .donnee)).pid == getpid()) &&
  334:                             (pthread_equal((*((struct_descripteur_fichier *)
  335:                             (*l_element_courant).donnee)).tid, pthread_self())
  336:                             != 0))
  337:                     {
  338:                         (*ouverture) = d_vrai;
  339: 
  340:                         (*unite) = (unsigned long)
  341:                                 fileno((*((struct_descripteur_fichier *)
  342:                                 (*l_element_courant).donnee))
  343:                                 .descripteur_c);
  344:                         break;
  345:                     }
  346:                 }
  347: 
  348:                 l_element_courant = (*l_element_courant).suivant;
  349:             }
  350:         }
  351:         else
  352:         {
  353:             erreur = d_erreur;
  354:         }
  355:     }
  356:     else
  357:     {
  358:         close(descripteur);
  359:         unlink(nom);
  360:         erreur = d_absence_erreur;
  361:     }
  362: 
  363:     return(erreur);
  364: }
  365: 
  366: 
  367: /*
  368: ================================================================================
  369:   Routines d'initialisation des fichiers à accès direct et indexé
  370: ================================================================================
  371:   Entrées : pointeur sur le fichier SQLITE
  372: --------------------------------------------------------------------------------
  373:   Sorties : drapeau d'erreur
  374: --------------------------------------------------------------------------------
  375:   Effets de bord : néant
  376: ================================================================================
  377: */
  378: 
  379: /*
  380:  * Un fichier à accès direct se compose d'une seule table :
  381:  * 1: identifiant (entier sur 64 bits) -> enregistrement
  382:  *
  383:  * Un fichier à accès indexé comporte trois tables :
  384:  * 1 : contrôle
  385:  * 2 : clef (unique) -> identifiant (entier sur 64 bits)
  386:  * 3 : identifiant -> collection d'enregistrements
  387:  *
  388:  * La table de contrôle contient
  389:  * 1/ la position de la clef pour les fichiers à accès indexés
  390:  */
  391: 
  392: static logical1
  393: initialisation_controle(struct_processus *s_etat_processus, sqlite3 *sqlite,
  394:         integer8 position_clef, logical1 fichier_indexe)
  395: {
  396:     const char              commande1[] =
  397:             "create table control(id integer primary key asc, key integer)";
  398:     const char              commande2[] =
  399:             "insert into control (id, key) values (1, %lld)";
  400:     const char              *queue;
  401: 
  402:     sqlite3_stmt            *ppStmt;
  403: 
  404:     unsigned char           *commande;
  405: 
  406:     if (sqlite3_prepare_v2(sqlite, commande1, strlen(commande1), &ppStmt,
  407:             &queue) != SQLITE_OK)
  408:     {
  409:         (*s_etat_processus).erreur_systeme = d_es_erreur_fichier;
  410:         return(d_erreur);
  411:     }
  412: 
  413:     if (sqlite3_step(ppStmt) != SQLITE_DONE)
  414:     {
  415:         (*s_etat_processus).erreur_systeme = d_es_erreur_fichier;
  416:         return(d_erreur);
  417:     }
  418: 
  419:     if (sqlite3_finalize(ppStmt) != SQLITE_OK)
  420:     {
  421:         (*s_etat_processus).erreur_systeme = d_es_erreur_fichier;
  422:         return(d_erreur);
  423:     }
  424: 
  425:     if (fichier_indexe == d_vrai)
  426:     {
  427:         if (alsprintf(&commande, commande2, position_clef) < 0)
  428:         {
  429:             return(d_erreur);
  430:         }
  431: 
  432:         if (sqlite3_prepare_v2(sqlite, commande, strlen(commande), &ppStmt,
  433:                 &queue) != SQLITE_OK)
  434:         {
  435:             free(commande);
  436:             (*s_etat_processus).erreur_systeme = d_es_erreur_fichier;
  437:             return(d_erreur);
  438:         }
  439: 
  440:         if (sqlite3_step(ppStmt) != SQLITE_DONE)
  441:         {
  442:             free(commande);
  443:             (*s_etat_processus).erreur_systeme = d_es_erreur_fichier;
  444:             return(d_erreur);
  445:         }
  446: 
  447:         if (sqlite3_finalize(ppStmt) != SQLITE_OK)
  448:         {
  449:             free(commande);
  450:             (*s_etat_processus).erreur_systeme = d_es_erreur_fichier;
  451:             return(d_erreur);
  452:         }
  453: 
  454:         free(commande);
  455:     }
  456: 
  457:     return(d_absence_erreur);
  458: }
  459: 
  460: logical1
  461: initialisation_fichier_acces_indexe(struct_processus *s_etat_processus,
  462:         sqlite3 *sqlite, integer8 position_clef, logical1 binaire)
  463: {
  464:     const char              commande1[] =
  465:             "create table data(id integer primary key asc, key_id integer, "
  466:             "data text, sequence integer)";
  467:     const char              commande10[] =
  468:             "create table key(id integer primary key asc, key text)";
  469:     const char              commande2[] =
  470:             "create table data(id integer primary key asc, key_id integer, "
  471:             "data blob, sequence integer)";
  472:     const char              commande20[] =
  473:             "create table key(id integer primary key asc, key blob)";
  474:     const char              commande3[] =
  475:             "create index data_idx on data(key_id)";
  476:     const char              commande4[] =
  477:             "create index key_idx on key(key)";
  478:     const char              *queue;
  479: 
  480:     sqlite3_stmt            *ppStmt;
  481: 
  482:     if (initialisation_controle(s_etat_processus, sqlite, position_clef, d_vrai)
  483:             != d_absence_erreur)
  484:     {
  485:         return(d_erreur);
  486:     }
  487: 
  488:     if (binaire == d_faux)
  489:     {
  490:         if (sqlite3_prepare_v2(sqlite, commande1, strlen(commande1), &ppStmt,
  491:                 &queue) != SQLITE_OK)
  492:         {
  493:             (*s_etat_processus).erreur_systeme = d_es_erreur_fichier;
  494:             return(d_erreur);
  495:         }
  496: 
  497:         if (sqlite3_step(ppStmt) != SQLITE_DONE)
  498:         {
  499:             (*s_etat_processus).erreur_systeme = d_es_erreur_fichier;
  500:             return(d_erreur);
  501:         }
  502: 
  503:         if (sqlite3_finalize(ppStmt) != SQLITE_OK)
  504:         {
  505:             (*s_etat_processus).erreur_systeme = d_es_erreur_fichier;
  506:             return(d_erreur);
  507:         }
  508: 
  509:         if (sqlite3_prepare_v2(sqlite, commande10, strlen(commande10), &ppStmt,
  510:                 &queue) != SQLITE_OK)
  511:         {
  512:             (*s_etat_processus).erreur_systeme = d_es_erreur_fichier;
  513:             return(d_erreur);
  514:         }
  515: 
  516:         if (sqlite3_step(ppStmt) != SQLITE_DONE)
  517:         {
  518:             (*s_etat_processus).erreur_systeme = d_es_erreur_fichier;
  519:             return(d_erreur);
  520:         }
  521: 
  522:         if (sqlite3_finalize(ppStmt) != SQLITE_OK)
  523:         {
  524:             (*s_etat_processus).erreur_systeme = d_es_erreur_fichier;
  525:             return(d_erreur);
  526:         }
  527:     }
  528:     else
  529:     {
  530:         if (sqlite3_prepare_v2(sqlite, commande2, strlen(commande2), &ppStmt,
  531:                 &queue) != SQLITE_OK)
  532:         {
  533:             (*s_etat_processus).erreur_systeme = d_es_erreur_fichier;
  534:             return(d_erreur);
  535:         }
  536: 
  537:         if (sqlite3_step(ppStmt) != SQLITE_DONE)
  538:         {
  539:             (*s_etat_processus).erreur_systeme = d_es_erreur_fichier;
  540:             return(d_erreur);
  541:         }
  542: 
  543:         if (sqlite3_finalize(ppStmt) != SQLITE_OK)
  544:         {
  545:             (*s_etat_processus).erreur_systeme = d_es_erreur_fichier;
  546:             return(d_erreur);
  547:         }
  548: 
  549:         if (sqlite3_prepare_v2(sqlite, commande20, strlen(commande20), &ppStmt,
  550:                 &queue) != SQLITE_OK)
  551:         {
  552:             (*s_etat_processus).erreur_systeme = d_es_erreur_fichier;
  553:             return(d_erreur);
  554:         }
  555: 
  556:         if (sqlite3_step(ppStmt) != SQLITE_DONE)
  557:         {
  558:             (*s_etat_processus).erreur_systeme = d_es_erreur_fichier;
  559:             return(d_erreur);
  560:         }
  561: 
  562:         if (sqlite3_finalize(ppStmt) != SQLITE_OK)
  563:         {
  564:             (*s_etat_processus).erreur_systeme = d_es_erreur_fichier;
  565:             return(d_erreur);
  566:         }
  567:     }
  568: 
  569:     if (sqlite3_prepare_v2(sqlite, commande3, strlen(commande3), &ppStmt,
  570:             &queue) != SQLITE_OK)
  571:     {
  572:         (*s_etat_processus).erreur_systeme = d_es_erreur_fichier;
  573:         return(d_erreur);
  574:     }
  575: 
  576:     if (sqlite3_step(ppStmt) != SQLITE_DONE)
  577:     {
  578:         (*s_etat_processus).erreur_systeme = d_es_erreur_fichier;
  579:         return(d_erreur);
  580:     }
  581: 
  582:     if (sqlite3_finalize(ppStmt) != SQLITE_OK)
  583:     {
  584:         (*s_etat_processus).erreur_systeme = d_es_erreur_fichier;
  585:         return(d_erreur);
  586:     }
  587: 
  588:     if (sqlite3_prepare_v2(sqlite, commande4, strlen(commande4), &ppStmt,
  589:             &queue) != SQLITE_OK)
  590:     {
  591:         (*s_etat_processus).erreur_systeme = d_es_erreur_fichier;
  592:         return(d_erreur);
  593:     }
  594: 
  595:     if (sqlite3_step(ppStmt) != SQLITE_DONE)
  596:     {
  597:         (*s_etat_processus).erreur_systeme = d_es_erreur_fichier;
  598:         return(d_erreur);
  599:     }
  600: 
  601:     if (sqlite3_finalize(ppStmt) != SQLITE_OK)
  602:     {
  603:         (*s_etat_processus).erreur_systeme = d_es_erreur_fichier;
  604:         return(d_erreur);
  605:     }
  606: 
  607:     return(d_absence_erreur);
  608: }
  609: 
  610: logical1
  611: initialisation_fichier_acces_direct(struct_processus *s_etat_processus,
  612:         sqlite3 *sqlite, logical1 binaire)
  613: {
  614:     const char              commande1[] =
  615:             "create table data(id integer primary key asc, data text)";
  616:     const char              commande2[] =
  617:             "create table data(id integer primary key asc, data blob)";
  618:     const char              commande3[] =
  619:             "create index data_idx on data(id)";
  620:     const char              *queue;
  621: 
  622:     sqlite3_stmt            *ppStmt;
  623: 
  624:     if (initialisation_controle(s_etat_processus, sqlite, (integer8) 0, d_faux)
  625:             != d_absence_erreur)
  626:     {
  627:         return(d_erreur);
  628:     }
  629: 
  630:     if (binaire == d_faux)
  631:     {
  632:         if (sqlite3_prepare_v2(sqlite, commande1, strlen(commande1), &ppStmt,
  633:                 &queue) != SQLITE_OK)
  634:         {
  635:             (*s_etat_processus).erreur_systeme = d_es_erreur_fichier;
  636:             return(d_erreur);
  637:         }
  638: 
  639:         if (sqlite3_step(ppStmt) != SQLITE_DONE)
  640:         {
  641:             (*s_etat_processus).erreur_systeme = d_es_erreur_fichier;
  642:             return(d_erreur);
  643:         }
  644: 
  645:         if (sqlite3_finalize(ppStmt) != SQLITE_OK)
  646:         {
  647:             (*s_etat_processus).erreur_systeme = d_es_erreur_fichier;
  648:             return(d_erreur);
  649:         }
  650:     }
  651:     else
  652:     {
  653:         if (sqlite3_prepare_v2(sqlite, commande2, strlen(commande2), &ppStmt,
  654:                 &queue) != SQLITE_OK)
  655:         {
  656:             (*s_etat_processus).erreur_systeme = d_es_erreur_fichier;
  657:             return(d_erreur);
  658:         }
  659: 
  660:         if (sqlite3_step(ppStmt) != SQLITE_DONE)
  661:         {
  662:             (*s_etat_processus).erreur_systeme = d_es_erreur_fichier;
  663:             return(d_erreur);
  664:         }
  665: 
  666:         if (sqlite3_finalize(ppStmt) != SQLITE_OK)
  667:         {
  668:             (*s_etat_processus).erreur_systeme = d_es_erreur_fichier;
  669:             return(d_erreur);
  670:         }
  671:     }
  672: 
  673:     if (sqlite3_prepare_v2(sqlite, commande3, strlen(commande3), &ppStmt,
  674:             &queue) != SQLITE_OK)
  675:     {
  676:         (*s_etat_processus).erreur_systeme = d_es_erreur_fichier;
  677:         return(d_erreur);
  678:     }
  679: 
  680:     if (sqlite3_step(ppStmt) != SQLITE_DONE)
  681:     {
  682:         (*s_etat_processus).erreur_systeme = d_es_erreur_fichier;
  683:         return(d_erreur);
  684:     }
  685: 
  686:     if (sqlite3_finalize(ppStmt) != SQLITE_OK)
  687:     {
  688:         (*s_etat_processus).erreur_systeme = d_es_erreur_fichier;
  689:         return(d_erreur);
  690:     }
  691: 
  692:     return(d_absence_erreur);
  693: }
  694: 
  695: // vim: ts=4

CVSweb interface <joel.bertrand@systella.fr>