/* ================================================================================ RPL/2 (R) version 4.1.32 Copyright (C) 1989-2020 Dr. BERTRAND Joël This file is part of RPL/2. RPL/2 is free software; you can redistribute it and/or modify it under the terms of the CeCILL V2 License as published by the french CEA, CNRS and INRIA. RPL/2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the CeCILL V2 License for more details. You should have received a copy of the CeCILL License along with RPL/2. If not, write to info@cecill.info. ================================================================================ */ #include "rpl-conv.h" /* ================================================================================ Routines de gestion des fichiers ================================================================================ Entrées : nom du fichier -------------------------------------------------------------------------------- Sorties : 0, le fichier n'existe pas, -1, il existe. -------------------------------------------------------------------------------- Effets de bord : néant ================================================================================ */ /* * Génère un nom de fichier */ unsigned char * creation_nom_fichier(struct_processus *s_etat_processus, unsigned char *chemin) { /* * Le nom du fichier est créé à l'aide du pid du processus et * d'un numéro d'ordre pour ce processus. */ logical1 erreur; logical1 existence; logical1 ouverture; pthread_mutex_t exclusion = PTHREAD_MUTEX_INITIALIZER; unsigned char *nom; unsigned char tampon[256 + 1]; unsigned long ordre_initial; unsigned long unite; static unsigned long ordre = 0; if (pthread_mutex_lock(&exclusion) != 0) { return(NULL); } ordre_initial = ordre; if (pthread_mutex_unlock(&exclusion) != 0) { return(NULL); } do { sprintf(tampon, "RPL-%llu-%llu-%lu", (unsigned long long) getpid(), (unsigned long long) pthread_self(), ordre); if (chemin == NULL) { if ((nom = malloc((strlen(tampon) + 1) * sizeof(unsigned char))) == NULL) { return(NULL); } strcpy(nom, tampon); } else { if ((nom = malloc((strlen(chemin) + strlen(tampon) + 2) * sizeof(unsigned char))) == NULL) { return(NULL); } sprintf(nom, "%s/%s", chemin, tampon); } if (pthread_mutex_lock(&exclusion) != 0) { return(NULL); } ordre++; if (pthread_mutex_unlock(&exclusion) != 0) { return(NULL); } if (ordre == ordre_initial) { // Il n'existe plus aucun nom de fichier disponible... free(nom); return(NULL); } erreur = caracteristiques_fichier(s_etat_processus, nom, &existence, &ouverture, &unite); if (erreur != 0) { free(nom); return(NULL); } if (existence == d_vrai) { free(nom); } } while(existence == d_vrai); return(nom); } /* * Efface un fichier */ logical1 destruction_fichier(unsigned char *nom_fichier) { return((unlink(nom_fichier) == 0) ? d_absence_erreur : d_erreur); } /* * Renvoie le descripteur en fonction de la structure de contrôle du fichier */ struct_descripteur_fichier * descripteur_fichier(struct_processus *s_etat_processus, struct_fichier *s_fichier) { logical1 concordance_descripteurs; struct_liste_chainee *l_element_courant; l_element_courant = (*s_etat_processus).s_fichiers; concordance_descripteurs = d_faux; while(l_element_courant != NULL) { if ((*((struct_descripteur_fichier *) (*l_element_courant).donnee)) .identifiant == (*s_fichier).descripteur) { if (((*((struct_descripteur_fichier *) (*l_element_courant).donnee)) .pid == (*s_fichier).pid) && (pthread_equal( (*((struct_descripteur_fichier *) (*l_element_courant) .donnee)).tid, pthread_self()) != 0)) { return((struct_descripteur_fichier *) (*l_element_courant).donnee); } else { concordance_descripteurs = d_vrai; } } l_element_courant = (*l_element_courant).suivant; } if (concordance_descripteurs == d_vrai) { (*s_etat_processus).erreur_execution = d_ex_fichier_hors_contexte; } else { (*s_etat_processus).erreur_systeme = d_es_erreur_fichier; } return(NULL); } /* * Recherche un chemin pour les fichiers temporaires */ unsigned char * recherche_chemin_fichiers_temporaires(struct_processus *s_etat_processus) { file *fichier; unsigned char *candidat; unsigned char *chemin; unsigned char *chemins[] = { "$RPL_TMP_PATH", "/tmp", "/var/tmp", NULL }; unsigned char *nom_candidat; unsigned long int i; i = 0; chemin = NULL; while(chemin == NULL) { if (chemins[i][0] == '$') { candidat = getenv(chemins[i] + 1); if (candidat != NULL) { if ((nom_candidat = creation_nom_fichier(s_etat_processus, candidat)) == NULL) { return(NULL); } if ((fichier = fopen(nom_candidat, "w+")) != NULL) { fclose(fichier); unlink(nom_candidat); free(nom_candidat); if ((chemin = malloc((strlen(candidat) + 1) * sizeof(unsigned char))) != NULL) { strcpy(chemin, candidat); } else { return(NULL); } } else { free(nom_candidat); } } } else { if ((nom_candidat = creation_nom_fichier(s_etat_processus, chemins[i])) == NULL) { return(NULL); } if ((fichier = fopen(nom_candidat, "w+")) != NULL) { fclose(fichier); unlink(nom_candidat); free(nom_candidat); if ((chemin = malloc((strlen(chemins[i]) + 1) * sizeof(unsigned char))) != NULL) { strcpy(chemin, chemins[i]); } else { return(NULL); } } else { free(nom_candidat); } } i++; } return(chemin); } /* * Fonction d'interrogation du fichier */ logical1 caracteristiques_fichier(struct_processus *s_etat_processus, unsigned char *nom, logical1 *existence, logical1 *ouverture, unsigned long *unite) { int descripteur; logical1 erreur; struct_liste_chainee *l_element_courant; (*unite) = 0; (*ouverture) = d_faux; (*existence) = d_faux; if ((descripteur = open(nom, O_CREAT | O_EXCL, S_IRUSR | S_IWUSR)) == -1) { if (errno == EEXIST) { // Le fichier préexiste. erreur = d_absence_erreur; (*existence) = d_vrai; // On chercher à savoir si le fichier est ouvert. S'il est ouvert, // on renvoie son unité de rattachement. l_element_courant = (*s_etat_processus).s_fichiers; while(l_element_courant != NULL) { if (strcmp((*((struct_descripteur_fichier *) (*l_element_courant).donnee)).nom, nom) == 0) { if (((*((struct_descripteur_fichier *) (*l_element_courant) .donnee)).pid == getpid()) && (pthread_equal((*((struct_descripteur_fichier *) (*l_element_courant).donnee)).tid, pthread_self()) != 0)) { (*ouverture) = d_vrai; (*unite) = (unsigned long) fileno((*((struct_descripteur_fichier *) (*l_element_courant).donnee)) .descripteur_c); break; } } l_element_courant = (*l_element_courant).suivant; } } else if (errno == EACCES) { // Le répertoire n'est pas accessible en écriture. On tente // l'ouverture du fichier. if ((descripteur = open(nom, O_RDONLY, S_IRUSR | S_IWUSR)) == -1) { // Le fichier n'existe pas. close(descripteur); erreur = d_absence_erreur; } else { erreur = d_absence_erreur; (*existence) = d_vrai; // On chercher à savoir si le fichier est ouvert. // S'il est ouvert, on renvoie son unité de rattachement. l_element_courant = (*s_etat_processus).s_fichiers; while(l_element_courant != NULL) { if (strcmp((*((struct_descripteur_fichier *) (*l_element_courant).donnee)).nom, nom) == 0) { if (((*((struct_descripteur_fichier *) (*l_element_courant).donnee)).pid == getpid()) && (pthread_equal( (*((struct_descripteur_fichier *) (*l_element_courant).donnee)).tid, pthread_self()) != 0)) { (*ouverture) = d_vrai; (*unite) = (unsigned long) fileno((*((struct_descripteur_fichier *) (*l_element_courant).donnee)) .descripteur_c); break; } } l_element_courant = (*l_element_courant).suivant; } } } else { erreur = d_erreur; } } else { close(descripteur); unlink(nom); erreur = d_absence_erreur; } return(erreur); } /* ================================================================================ Routines d'initialisation des fichiers à accès direct et indexé ================================================================================ Entrées : pointeur sur le fichier SQLITE -------------------------------------------------------------------------------- Sorties : drapeau d'erreur -------------------------------------------------------------------------------- Effets de bord : néant ================================================================================ */ /* * Un fichier à accès direct se compose d'une seule table : * 1: identifiant (entier sur 64 bits) -> enregistrement * * Un fichier à accès indexé comporte trois tables : * 1 : contrôle * 2 : clef (unique) -> identifiant (entier sur 64 bits) * 3 : identifiant -> collection d'enregistrements * * La table de contrôle contient * 1/ la position de la clef pour les fichiers à accès indexés */ static logical1 initialisation_controle(struct_processus *s_etat_processus, sqlite3 *sqlite, integer8 position_clef, logical1 fichier_indexe) { const char commande1[] = "create table control(id integer primary key asc, key integer)"; const char commande2[] = "insert into control (id, key) values (1, %lld)"; const char *queue; sqlite3_stmt *ppStmt; unsigned char *commande; if (sqlite3_prepare_v2(sqlite, commande1, (int) strlen(commande1), &ppStmt, &queue) != SQLITE_OK) { (*s_etat_processus).erreur_systeme = d_es_erreur_fichier; return(d_erreur); } if (sqlite3_step(ppStmt) != SQLITE_DONE) { (*s_etat_processus).erreur_systeme = d_es_erreur_fichier; return(d_erreur); } if (sqlite3_finalize(ppStmt) != SQLITE_OK) { (*s_etat_processus).erreur_systeme = d_es_erreur_fichier; return(d_erreur); } if (fichier_indexe == d_vrai) { if (alsprintf(s_etat_processus, &commande, commande2, position_clef) < 0) { (*s_etat_processus).erreur_systeme = d_es_allocation_memoire; return(d_erreur); } if (sqlite3_prepare_v2(sqlite, commande, (int) strlen(commande), &ppStmt, &queue) != SQLITE_OK) { free(commande); (*s_etat_processus).erreur_systeme = d_es_erreur_fichier; return(d_erreur); } if (sqlite3_step(ppStmt) != SQLITE_DONE) { free(commande); (*s_etat_processus).erreur_systeme = d_es_erreur_fichier; return(d_erreur); } if (sqlite3_finalize(ppStmt) != SQLITE_OK) { free(commande); (*s_etat_processus).erreur_systeme = d_es_erreur_fichier; return(d_erreur); } free(commande); } return(d_absence_erreur); } logical1 initialisation_fichier_acces_indexe(struct_processus *s_etat_processus, sqlite3 *sqlite, integer8 position_clef, logical1 binaire) { const char commande1[] = "create table data(id integer primary key asc, key_id integer, " "data text, sequence integer)"; const char commande10[] = "create table key(id integer primary key asc, key text)"; const char commande2[] = "create table data(id integer primary key asc, key_id integer, " "data blob, sequence integer)"; const char commande20[] = "create table key(id integer primary key asc, key blob)"; const char commande3[] = "create index data_idx on data(key_id)"; const char commande4[] = "create index key_idx on key(key)"; const char *queue; sqlite3_stmt *ppStmt; if (initialisation_controle(s_etat_processus, sqlite, position_clef, d_vrai) != d_absence_erreur) { return(d_erreur); } if (binaire == d_faux) { if (sqlite3_prepare_v2(sqlite, commande1, (int) strlen(commande1), &ppStmt, &queue) != SQLITE_OK) { (*s_etat_processus).erreur_systeme = d_es_erreur_fichier; return(d_erreur); } if (sqlite3_step(ppStmt) != SQLITE_DONE) { (*s_etat_processus).erreur_systeme = d_es_erreur_fichier; return(d_erreur); } if (sqlite3_finalize(ppStmt) != SQLITE_OK) { (*s_etat_processus).erreur_systeme = d_es_erreur_fichier; return(d_erreur); } if (sqlite3_prepare_v2(sqlite, commande10, (int) strlen(commande10), &ppStmt, &queue) != SQLITE_OK) { (*s_etat_processus).erreur_systeme = d_es_erreur_fichier; return(d_erreur); } if (sqlite3_step(ppStmt) != SQLITE_DONE) { (*s_etat_processus).erreur_systeme = d_es_erreur_fichier; return(d_erreur); } if (sqlite3_finalize(ppStmt) != SQLITE_OK) { (*s_etat_processus).erreur_systeme = d_es_erreur_fichier; return(d_erreur); } } else { if (sqlite3_prepare_v2(sqlite, commande2, (int) strlen(commande2), &ppStmt, &queue) != SQLITE_OK) { (*s_etat_processus).erreur_systeme = d_es_erreur_fichier; return(d_erreur); } if (sqlite3_step(ppStmt) != SQLITE_DONE) { (*s_etat_processus).erreur_systeme = d_es_erreur_fichier; return(d_erreur); } if (sqlite3_finalize(ppStmt) != SQLITE_OK) { (*s_etat_processus).erreur_systeme = d_es_erreur_fichier; return(d_erreur); } if (sqlite3_prepare_v2(sqlite, commande20, (int) strlen(commande20), &ppStmt, &queue) != SQLITE_OK) { (*s_etat_processus).erreur_systeme = d_es_erreur_fichier; return(d_erreur); } if (sqlite3_step(ppStmt) != SQLITE_DONE) { (*s_etat_processus).erreur_systeme = d_es_erreur_fichier; return(d_erreur); } if (sqlite3_finalize(ppStmt) != SQLITE_OK) { (*s_etat_processus).erreur_systeme = d_es_erreur_fichier; return(d_erreur); } } if (sqlite3_prepare_v2(sqlite, commande3, (int) strlen(commande3), &ppStmt, &queue) != SQLITE_OK) { (*s_etat_processus).erreur_systeme = d_es_erreur_fichier; return(d_erreur); } if (sqlite3_step(ppStmt) != SQLITE_DONE) { (*s_etat_processus).erreur_systeme = d_es_erreur_fichier; return(d_erreur); } if (sqlite3_finalize(ppStmt) != SQLITE_OK) { (*s_etat_processus).erreur_systeme = d_es_erreur_fichier; return(d_erreur); } if (sqlite3_prepare_v2(sqlite, commande4, (int) strlen(commande4), &ppStmt, &queue) != SQLITE_OK) { (*s_etat_processus).erreur_systeme = d_es_erreur_fichier; return(d_erreur); } if (sqlite3_step(ppStmt) != SQLITE_DONE) { (*s_etat_processus).erreur_systeme = d_es_erreur_fichier; return(d_erreur); } if (sqlite3_finalize(ppStmt) != SQLITE_OK) { (*s_etat_processus).erreur_systeme = d_es_erreur_fichier; return(d_erreur); } return(d_absence_erreur); } logical1 initialisation_fichier_acces_direct(struct_processus *s_etat_processus, sqlite3 *sqlite, logical1 binaire) { const char commande1[] = "create table data(id integer primary key asc, data text)"; const char commande2[] = "create table data(id integer primary key asc, data blob)"; const char commande3[] = "create index data_idx on data(id)"; const char *queue; sqlite3_stmt *ppStmt; if (initialisation_controle(s_etat_processus, sqlite, (integer8) 0, d_faux) != d_absence_erreur) { return(d_erreur); } if (binaire == d_faux) { if (sqlite3_prepare_v2(sqlite, commande1, (int) strlen(commande1), &ppStmt, &queue) != SQLITE_OK) { (*s_etat_processus).erreur_systeme = d_es_erreur_fichier; return(d_erreur); } if (sqlite3_step(ppStmt) != SQLITE_DONE) { (*s_etat_processus).erreur_systeme = d_es_erreur_fichier; return(d_erreur); } if (sqlite3_finalize(ppStmt) != SQLITE_OK) { (*s_etat_processus).erreur_systeme = d_es_erreur_fichier; return(d_erreur); } } else { if (sqlite3_prepare_v2(sqlite, commande2, (int) strlen(commande2), &ppStmt, &queue) != SQLITE_OK) { (*s_etat_processus).erreur_systeme = d_es_erreur_fichier; return(d_erreur); } if (sqlite3_step(ppStmt) != SQLITE_DONE) { (*s_etat_processus).erreur_systeme = d_es_erreur_fichier; return(d_erreur); } if (sqlite3_finalize(ppStmt) != SQLITE_OK) { (*s_etat_processus).erreur_systeme = d_es_erreur_fichier; return(d_erreur); } } if (sqlite3_prepare_v2(sqlite, commande3, (int) strlen(commande3), &ppStmt, &queue) != SQLITE_OK) { (*s_etat_processus).erreur_systeme = d_es_erreur_fichier; return(d_erreur); } if (sqlite3_step(ppStmt) != SQLITE_DONE) { (*s_etat_processus).erreur_systeme = d_es_erreur_fichier; return(d_erreur); } if (sqlite3_finalize(ppStmt) != SQLITE_OK) { (*s_etat_processus).erreur_systeme = d_es_erreur_fichier; return(d_erreur); } return(d_absence_erreur); } // vim: ts=4