File:  [local] / rpl / src / gestion_fichiers.c
Revision 1.33: download - view: text, annotated - select for diffs - revision graph
Mon Jul 25 07:44:54 2011 UTC (12 years, 9 months ago) by bertrand
Branches: MAIN
CVS tags: rpl-4_1_2, HEAD
En route pour la 4.1.2.

    1: /*
    2: ================================================================================
    3:   RPL/2 (R) version 4.1.2
    4:   Copyright (C) 1989-2011 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, "RPL-%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:             (*s_etat_processus).erreur_systeme = d_es_allocation_memoire;
  430:             return(d_erreur);
  431:         }
  432: 
  433:         if (sqlite3_prepare_v2(sqlite, commande, strlen(commande), &ppStmt,
  434:                 &queue) != SQLITE_OK)
  435:         {
  436:             free(commande);
  437:             (*s_etat_processus).erreur_systeme = d_es_erreur_fichier;
  438:             return(d_erreur);
  439:         }
  440: 
  441:         if (sqlite3_step(ppStmt) != SQLITE_DONE)
  442:         {
  443:             free(commande);
  444:             (*s_etat_processus).erreur_systeme = d_es_erreur_fichier;
  445:             return(d_erreur);
  446:         }
  447: 
  448:         if (sqlite3_finalize(ppStmt) != SQLITE_OK)
  449:         {
  450:             free(commande);
  451:             (*s_etat_processus).erreur_systeme = d_es_erreur_fichier;
  452:             return(d_erreur);
  453:         }
  454: 
  455:         free(commande);
  456:     }
  457: 
  458:     return(d_absence_erreur);
  459: }
  460: 
  461: logical1
  462: initialisation_fichier_acces_indexe(struct_processus *s_etat_processus,
  463:         sqlite3 *sqlite, integer8 position_clef, logical1 binaire)
  464: {
  465:     const char              commande1[] =
  466:             "create table data(id integer primary key asc, key_id integer, "
  467:             "data text, sequence integer)";
  468:     const char              commande10[] =
  469:             "create table key(id integer primary key asc, key text)";
  470:     const char              commande2[] =
  471:             "create table data(id integer primary key asc, key_id integer, "
  472:             "data blob, sequence integer)";
  473:     const char              commande20[] =
  474:             "create table key(id integer primary key asc, key blob)";
  475:     const char              commande3[] =
  476:             "create index data_idx on data(key_id)";
  477:     const char              commande4[] =
  478:             "create index key_idx on key(key)";
  479:     const char              *queue;
  480: 
  481:     sqlite3_stmt            *ppStmt;
  482: 
  483:     if (initialisation_controle(s_etat_processus, sqlite, position_clef, d_vrai)
  484:             != d_absence_erreur)
  485:     {
  486:         return(d_erreur);
  487:     }
  488: 
  489:     if (binaire == d_faux)
  490:     {
  491:         if (sqlite3_prepare_v2(sqlite, commande1, strlen(commande1), &ppStmt,
  492:                 &queue) != SQLITE_OK)
  493:         {
  494:             (*s_etat_processus).erreur_systeme = d_es_erreur_fichier;
  495:             return(d_erreur);
  496:         }
  497: 
  498:         if (sqlite3_step(ppStmt) != SQLITE_DONE)
  499:         {
  500:             (*s_etat_processus).erreur_systeme = d_es_erreur_fichier;
  501:             return(d_erreur);
  502:         }
  503: 
  504:         if (sqlite3_finalize(ppStmt) != SQLITE_OK)
  505:         {
  506:             (*s_etat_processus).erreur_systeme = d_es_erreur_fichier;
  507:             return(d_erreur);
  508:         }
  509: 
  510:         if (sqlite3_prepare_v2(sqlite, commande10, strlen(commande10), &ppStmt,
  511:                 &queue) != SQLITE_OK)
  512:         {
  513:             (*s_etat_processus).erreur_systeme = d_es_erreur_fichier;
  514:             return(d_erreur);
  515:         }
  516: 
  517:         if (sqlite3_step(ppStmt) != SQLITE_DONE)
  518:         {
  519:             (*s_etat_processus).erreur_systeme = d_es_erreur_fichier;
  520:             return(d_erreur);
  521:         }
  522: 
  523:         if (sqlite3_finalize(ppStmt) != SQLITE_OK)
  524:         {
  525:             (*s_etat_processus).erreur_systeme = d_es_erreur_fichier;
  526:             return(d_erreur);
  527:         }
  528:     }
  529:     else
  530:     {
  531:         if (sqlite3_prepare_v2(sqlite, commande2, strlen(commande2), &ppStmt,
  532:                 &queue) != SQLITE_OK)
  533:         {
  534:             (*s_etat_processus).erreur_systeme = d_es_erreur_fichier;
  535:             return(d_erreur);
  536:         }
  537: 
  538:         if (sqlite3_step(ppStmt) != SQLITE_DONE)
  539:         {
  540:             (*s_etat_processus).erreur_systeme = d_es_erreur_fichier;
  541:             return(d_erreur);
  542:         }
  543: 
  544:         if (sqlite3_finalize(ppStmt) != SQLITE_OK)
  545:         {
  546:             (*s_etat_processus).erreur_systeme = d_es_erreur_fichier;
  547:             return(d_erreur);
  548:         }
  549: 
  550:         if (sqlite3_prepare_v2(sqlite, commande20, strlen(commande20), &ppStmt,
  551:                 &queue) != SQLITE_OK)
  552:         {
  553:             (*s_etat_processus).erreur_systeme = d_es_erreur_fichier;
  554:             return(d_erreur);
  555:         }
  556: 
  557:         if (sqlite3_step(ppStmt) != SQLITE_DONE)
  558:         {
  559:             (*s_etat_processus).erreur_systeme = d_es_erreur_fichier;
  560:             return(d_erreur);
  561:         }
  562: 
  563:         if (sqlite3_finalize(ppStmt) != SQLITE_OK)
  564:         {
  565:             (*s_etat_processus).erreur_systeme = d_es_erreur_fichier;
  566:             return(d_erreur);
  567:         }
  568:     }
  569: 
  570:     if (sqlite3_prepare_v2(sqlite, commande3, strlen(commande3), &ppStmt,
  571:             &queue) != SQLITE_OK)
  572:     {
  573:         (*s_etat_processus).erreur_systeme = d_es_erreur_fichier;
  574:         return(d_erreur);
  575:     }
  576: 
  577:     if (sqlite3_step(ppStmt) != SQLITE_DONE)
  578:     {
  579:         (*s_etat_processus).erreur_systeme = d_es_erreur_fichier;
  580:         return(d_erreur);
  581:     }
  582: 
  583:     if (sqlite3_finalize(ppStmt) != SQLITE_OK)
  584:     {
  585:         (*s_etat_processus).erreur_systeme = d_es_erreur_fichier;
  586:         return(d_erreur);
  587:     }
  588: 
  589:     if (sqlite3_prepare_v2(sqlite, commande4, strlen(commande4), &ppStmt,
  590:             &queue) != SQLITE_OK)
  591:     {
  592:         (*s_etat_processus).erreur_systeme = d_es_erreur_fichier;
  593:         return(d_erreur);
  594:     }
  595: 
  596:     if (sqlite3_step(ppStmt) != SQLITE_DONE)
  597:     {
  598:         (*s_etat_processus).erreur_systeme = d_es_erreur_fichier;
  599:         return(d_erreur);
  600:     }
  601: 
  602:     if (sqlite3_finalize(ppStmt) != SQLITE_OK)
  603:     {
  604:         (*s_etat_processus).erreur_systeme = d_es_erreur_fichier;
  605:         return(d_erreur);
  606:     }
  607: 
  608:     return(d_absence_erreur);
  609: }
  610: 
  611: logical1
  612: initialisation_fichier_acces_direct(struct_processus *s_etat_processus,
  613:         sqlite3 *sqlite, logical1 binaire)
  614: {
  615:     const char              commande1[] =
  616:             "create table data(id integer primary key asc, data text)";
  617:     const char              commande2[] =
  618:             "create table data(id integer primary key asc, data blob)";
  619:     const char              commande3[] =
  620:             "create index data_idx on data(id)";
  621:     const char              *queue;
  622: 
  623:     sqlite3_stmt            *ppStmt;
  624: 
  625:     if (initialisation_controle(s_etat_processus, sqlite, (integer8) 0, d_faux)
  626:             != d_absence_erreur)
  627:     {
  628:         return(d_erreur);
  629:     }
  630: 
  631:     if (binaire == d_faux)
  632:     {
  633:         if (sqlite3_prepare_v2(sqlite, commande1, strlen(commande1), &ppStmt,
  634:                 &queue) != SQLITE_OK)
  635:         {
  636:             (*s_etat_processus).erreur_systeme = d_es_erreur_fichier;
  637:             return(d_erreur);
  638:         }
  639: 
  640:         if (sqlite3_step(ppStmt) != SQLITE_DONE)
  641:         {
  642:             (*s_etat_processus).erreur_systeme = d_es_erreur_fichier;
  643:             return(d_erreur);
  644:         }
  645: 
  646:         if (sqlite3_finalize(ppStmt) != SQLITE_OK)
  647:         {
  648:             (*s_etat_processus).erreur_systeme = d_es_erreur_fichier;
  649:             return(d_erreur);
  650:         }
  651:     }
  652:     else
  653:     {
  654:         if (sqlite3_prepare_v2(sqlite, commande2, strlen(commande2), &ppStmt,
  655:                 &queue) != SQLITE_OK)
  656:         {
  657:             (*s_etat_processus).erreur_systeme = d_es_erreur_fichier;
  658:             return(d_erreur);
  659:         }
  660: 
  661:         if (sqlite3_step(ppStmt) != SQLITE_DONE)
  662:         {
  663:             (*s_etat_processus).erreur_systeme = d_es_erreur_fichier;
  664:             return(d_erreur);
  665:         }
  666: 
  667:         if (sqlite3_finalize(ppStmt) != SQLITE_OK)
  668:         {
  669:             (*s_etat_processus).erreur_systeme = d_es_erreur_fichier;
  670:             return(d_erreur);
  671:         }
  672:     }
  673: 
  674:     if (sqlite3_prepare_v2(sqlite, commande3, strlen(commande3), &ppStmt,
  675:             &queue) != SQLITE_OK)
  676:     {
  677:         (*s_etat_processus).erreur_systeme = d_es_erreur_fichier;
  678:         return(d_erreur);
  679:     }
  680: 
  681:     if (sqlite3_step(ppStmt) != SQLITE_DONE)
  682:     {
  683:         (*s_etat_processus).erreur_systeme = d_es_erreur_fichier;
  684:         return(d_erreur);
  685:     }
  686: 
  687:     if (sqlite3_finalize(ppStmt) != SQLITE_OK)
  688:     {
  689:         (*s_etat_processus).erreur_systeme = d_es_erreur_fichier;
  690:         return(d_erreur);
  691:     }
  692: 
  693:     return(d_absence_erreur);
  694: }
  695: 
  696: // vim: ts=4

CVSweb interface <joel.bertrand@systella.fr>