1: /*
2: ================================================================================
3: RPL/2 (R) version 4.1.36
4: Copyright (C) 1989-2025 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-%llu-%llu-%lu", (unsigned long long) getpid(),
81: (unsigned long 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(chemins[i] + 1);
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 if (errno == EACCES)
352: {
353: // Le répertoire n'est pas accessible en écriture. On tente
354: // l'ouverture du fichier.
355:
356: if ((descripteur = open(nom, O_RDONLY, S_IRUSR | S_IWUSR)) == -1)
357: {
358: // Le fichier n'existe pas.
359: close(descripteur);
360: erreur = d_absence_erreur;
361: }
362: else
363: {
364: erreur = d_absence_erreur;
365: (*existence) = d_vrai;
366:
367: // On chercher à savoir si le fichier est ouvert.
368: // S'il est ouvert, on renvoie son unité de rattachement.
369:
370: l_element_courant = (*s_etat_processus).s_fichiers;
371:
372: while(l_element_courant != NULL)
373: {
374: if (strcmp((*((struct_descripteur_fichier *)
375: (*l_element_courant).donnee)).nom, nom) == 0)
376: {
377: if (((*((struct_descripteur_fichier *)
378: (*l_element_courant).donnee)).pid == getpid())
379: && (pthread_equal(
380: (*((struct_descripteur_fichier *)
381: (*l_element_courant).donnee)).tid,
382: pthread_self()) != 0))
383: {
384: (*ouverture) = d_vrai;
385:
386: (*unite) = (unsigned long)
387: fileno((*((struct_descripteur_fichier *)
388: (*l_element_courant).donnee))
389: .descripteur_c);
390: break;
391: }
392: }
393:
394: l_element_courant = (*l_element_courant).suivant;
395: }
396: }
397: }
398: else
399: {
400: erreur = d_erreur;
401: }
402: }
403: else
404: {
405: close(descripteur);
406: unlink(nom);
407: erreur = d_absence_erreur;
408: }
409:
410: return(erreur);
411: }
412:
413:
414: /*
415: ================================================================================
416: Routines d'initialisation des fichiers à accès direct et indexé
417: ================================================================================
418: Entrées : pointeur sur le fichier SQLITE
419: --------------------------------------------------------------------------------
420: Sorties : drapeau d'erreur
421: --------------------------------------------------------------------------------
422: Effets de bord : néant
423: ================================================================================
424: */
425:
426: /*
427: * Un fichier à accès direct se compose d'une seule table :
428: * 1: identifiant (entier sur 64 bits) -> enregistrement
429: *
430: * Un fichier à accès indexé comporte trois tables :
431: * 1 : contrôle
432: * 2 : clef (unique) -> identifiant (entier sur 64 bits)
433: * 3 : identifiant -> collection d'enregistrements
434: *
435: * La table de contrôle contient
436: * 1/ la position de la clef pour les fichiers à accès indexés
437: */
438:
439: static logical1
440: initialisation_controle(struct_processus *s_etat_processus, sqlite3 *sqlite,
441: integer8 position_clef, logical1 fichier_indexe)
442: {
443: const char commande1[] =
444: "create table control(id integer primary key asc, key integer)";
445: const char commande2[] =
446: "insert into control (id, key) values (1, %lld)";
447: const char *queue;
448:
449: sqlite3_stmt *ppStmt;
450:
451: unsigned char *commande;
452:
453: if (sqlite3_prepare_v2(sqlite, commande1, (int) strlen(commande1), &ppStmt,
454: &queue) != SQLITE_OK)
455: {
456: (*s_etat_processus).erreur_systeme = d_es_erreur_fichier;
457: return(d_erreur);
458: }
459:
460: if (sqlite3_step(ppStmt) != SQLITE_DONE)
461: {
462: (*s_etat_processus).erreur_systeme = d_es_erreur_fichier;
463: return(d_erreur);
464: }
465:
466: if (sqlite3_finalize(ppStmt) != SQLITE_OK)
467: {
468: (*s_etat_processus).erreur_systeme = d_es_erreur_fichier;
469: return(d_erreur);
470: }
471:
472: if (fichier_indexe == d_vrai)
473: {
474: if (alsprintf(s_etat_processus, &commande, commande2, position_clef)
475: < 0)
476: {
477: (*s_etat_processus).erreur_systeme = d_es_allocation_memoire;
478: return(d_erreur);
479: }
480:
481: if (sqlite3_prepare_v2(sqlite, commande, (int) strlen(commande),
482: &ppStmt, &queue) != SQLITE_OK)
483: {
484: free(commande);
485: (*s_etat_processus).erreur_systeme = d_es_erreur_fichier;
486: return(d_erreur);
487: }
488:
489: if (sqlite3_step(ppStmt) != SQLITE_DONE)
490: {
491: free(commande);
492: (*s_etat_processus).erreur_systeme = d_es_erreur_fichier;
493: return(d_erreur);
494: }
495:
496: if (sqlite3_finalize(ppStmt) != SQLITE_OK)
497: {
498: free(commande);
499: (*s_etat_processus).erreur_systeme = d_es_erreur_fichier;
500: return(d_erreur);
501: }
502:
503: free(commande);
504: }
505:
506: return(d_absence_erreur);
507: }
508:
509: logical1
510: initialisation_fichier_acces_indexe(struct_processus *s_etat_processus,
511: sqlite3 *sqlite, integer8 position_clef, logical1 binaire)
512: {
513: const char commande1[] =
514: "create table data(id integer primary key asc, key_id integer, "
515: "data text, sequence integer)";
516: const char commande10[] =
517: "create table key(id integer primary key asc, key text)";
518: const char commande2[] =
519: "create table data(id integer primary key asc, key_id integer, "
520: "data blob, sequence integer)";
521: const char commande20[] =
522: "create table key(id integer primary key asc, key blob)";
523: const char commande3[] =
524: "create index data_idx on data(key_id)";
525: const char commande4[] =
526: "create index key_idx on key(key)";
527: const char *queue;
528:
529: sqlite3_stmt *ppStmt;
530:
531: if (initialisation_controle(s_etat_processus, sqlite, position_clef, d_vrai)
532: != d_absence_erreur)
533: {
534: return(d_erreur);
535: }
536:
537: if (binaire == d_faux)
538: {
539: if (sqlite3_prepare_v2(sqlite, commande1, (int) strlen(commande1),
540: &ppStmt, &queue) != SQLITE_OK)
541: {
542: (*s_etat_processus).erreur_systeme = d_es_erreur_fichier;
543: return(d_erreur);
544: }
545:
546: if (sqlite3_step(ppStmt) != SQLITE_DONE)
547: {
548: (*s_etat_processus).erreur_systeme = d_es_erreur_fichier;
549: return(d_erreur);
550: }
551:
552: if (sqlite3_finalize(ppStmt) != SQLITE_OK)
553: {
554: (*s_etat_processus).erreur_systeme = d_es_erreur_fichier;
555: return(d_erreur);
556: }
557:
558: if (sqlite3_prepare_v2(sqlite, commande10, (int) strlen(commande10),
559: &ppStmt, &queue) != SQLITE_OK)
560: {
561: (*s_etat_processus).erreur_systeme = d_es_erreur_fichier;
562: return(d_erreur);
563: }
564:
565: if (sqlite3_step(ppStmt) != SQLITE_DONE)
566: {
567: (*s_etat_processus).erreur_systeme = d_es_erreur_fichier;
568: return(d_erreur);
569: }
570:
571: if (sqlite3_finalize(ppStmt) != SQLITE_OK)
572: {
573: (*s_etat_processus).erreur_systeme = d_es_erreur_fichier;
574: return(d_erreur);
575: }
576: }
577: else
578: {
579: if (sqlite3_prepare_v2(sqlite, commande2, (int) strlen(commande2),
580: &ppStmt, &queue) != SQLITE_OK)
581: {
582: (*s_etat_processus).erreur_systeme = d_es_erreur_fichier;
583: return(d_erreur);
584: }
585:
586: if (sqlite3_step(ppStmt) != SQLITE_DONE)
587: {
588: (*s_etat_processus).erreur_systeme = d_es_erreur_fichier;
589: return(d_erreur);
590: }
591:
592: if (sqlite3_finalize(ppStmt) != SQLITE_OK)
593: {
594: (*s_etat_processus).erreur_systeme = d_es_erreur_fichier;
595: return(d_erreur);
596: }
597:
598: if (sqlite3_prepare_v2(sqlite, commande20, (int) strlen(commande20),
599: &ppStmt, &queue) != SQLITE_OK)
600: {
601: (*s_etat_processus).erreur_systeme = d_es_erreur_fichier;
602: return(d_erreur);
603: }
604:
605: if (sqlite3_step(ppStmt) != SQLITE_DONE)
606: {
607: (*s_etat_processus).erreur_systeme = d_es_erreur_fichier;
608: return(d_erreur);
609: }
610:
611: if (sqlite3_finalize(ppStmt) != SQLITE_OK)
612: {
613: (*s_etat_processus).erreur_systeme = d_es_erreur_fichier;
614: return(d_erreur);
615: }
616: }
617:
618: if (sqlite3_prepare_v2(sqlite, commande3, (int) strlen(commande3), &ppStmt,
619: &queue) != SQLITE_OK)
620: {
621: (*s_etat_processus).erreur_systeme = d_es_erreur_fichier;
622: return(d_erreur);
623: }
624:
625: if (sqlite3_step(ppStmt) != SQLITE_DONE)
626: {
627: (*s_etat_processus).erreur_systeme = d_es_erreur_fichier;
628: return(d_erreur);
629: }
630:
631: if (sqlite3_finalize(ppStmt) != SQLITE_OK)
632: {
633: (*s_etat_processus).erreur_systeme = d_es_erreur_fichier;
634: return(d_erreur);
635: }
636:
637: if (sqlite3_prepare_v2(sqlite, commande4, (int) strlen(commande4), &ppStmt,
638: &queue) != SQLITE_OK)
639: {
640: (*s_etat_processus).erreur_systeme = d_es_erreur_fichier;
641: return(d_erreur);
642: }
643:
644: if (sqlite3_step(ppStmt) != SQLITE_DONE)
645: {
646: (*s_etat_processus).erreur_systeme = d_es_erreur_fichier;
647: return(d_erreur);
648: }
649:
650: if (sqlite3_finalize(ppStmt) != SQLITE_OK)
651: {
652: (*s_etat_processus).erreur_systeme = d_es_erreur_fichier;
653: return(d_erreur);
654: }
655:
656: return(d_absence_erreur);
657: }
658:
659: logical1
660: initialisation_fichier_acces_direct(struct_processus *s_etat_processus,
661: sqlite3 *sqlite, logical1 binaire)
662: {
663: const char commande1[] =
664: "create table data(id integer primary key asc, data text)";
665: const char commande2[] =
666: "create table data(id integer primary key asc, data blob)";
667: const char commande3[] =
668: "create index data_idx on data(id)";
669: const char *queue;
670:
671: sqlite3_stmt *ppStmt;
672:
673: if (initialisation_controle(s_etat_processus, sqlite, (integer8) 0, d_faux)
674: != d_absence_erreur)
675: {
676: return(d_erreur);
677: }
678:
679: if (binaire == d_faux)
680: {
681: if (sqlite3_prepare_v2(sqlite, commande1, (int) strlen(commande1),
682: &ppStmt, &queue) != SQLITE_OK)
683: {
684: (*s_etat_processus).erreur_systeme = d_es_erreur_fichier;
685: return(d_erreur);
686: }
687:
688: if (sqlite3_step(ppStmt) != SQLITE_DONE)
689: {
690: (*s_etat_processus).erreur_systeme = d_es_erreur_fichier;
691: return(d_erreur);
692: }
693:
694: if (sqlite3_finalize(ppStmt) != SQLITE_OK)
695: {
696: (*s_etat_processus).erreur_systeme = d_es_erreur_fichier;
697: return(d_erreur);
698: }
699: }
700: else
701: {
702: if (sqlite3_prepare_v2(sqlite, commande2, (int) strlen(commande2),
703: &ppStmt, &queue) != SQLITE_OK)
704: {
705: (*s_etat_processus).erreur_systeme = d_es_erreur_fichier;
706: return(d_erreur);
707: }
708:
709: if (sqlite3_step(ppStmt) != SQLITE_DONE)
710: {
711: (*s_etat_processus).erreur_systeme = d_es_erreur_fichier;
712: return(d_erreur);
713: }
714:
715: if (sqlite3_finalize(ppStmt) != SQLITE_OK)
716: {
717: (*s_etat_processus).erreur_systeme = d_es_erreur_fichier;
718: return(d_erreur);
719: }
720: }
721:
722: if (sqlite3_prepare_v2(sqlite, commande3, (int) strlen(commande3), &ppStmt,
723: &queue) != SQLITE_OK)
724: {
725: (*s_etat_processus).erreur_systeme = d_es_erreur_fichier;
726: return(d_erreur);
727: }
728:
729: if (sqlite3_step(ppStmt) != SQLITE_DONE)
730: {
731: (*s_etat_processus).erreur_systeme = d_es_erreur_fichier;
732: return(d_erreur);
733: }
734:
735: if (sqlite3_finalize(ppStmt) != SQLITE_OK)
736: {
737: (*s_etat_processus).erreur_systeme = d_es_erreur_fichier;
738: return(d_erreur);
739: }
740:
741: return(d_absence_erreur);
742: }
743:
744: // vim: ts=4
CVSweb interface <joel.bertrand@systella.fr>