From 47e8322e1d6e9328835a46fcc4c87fad1242579e Mon Sep 17 00:00:00 2001 From: Thomas Pietrzak Date: Sun, 23 Sep 2018 16:14:09 +0200 Subject: [PATCH] init --- info | 23 + musique/auclairdelalune | 12 + musique/essainotes | 1 + musique/hardasarock | 16 + musique/musique.c | 289 +++++ musique/musique.exe | Bin 0 -> 172138 bytes musique/paradigmshift | 472 ++++++++ partie1/Dossier Utilisateur Pietrzak.doc | Bin 0 -> 89599 bytes partie1/sources/defines.h | 19 + partie1/sources/exc.c | 214 ++++ partie1/sources/exc.h | 28 + partie1/sources/exs.c | 873 ++++++++++++++ partie1/sources/exs.h | 43 + partie1/sources/makefilec | 8 + partie1/sources/makefiles | 17 + partie1/sources/mks | 2 + partie1/sources/serveurdedie.c | 389 +++++++ partie1/sources/serveurdedie.h | 35 + partie1/sources/tables.c | 1194 ++++++++++++++++++++ partie1/sources/tables.h | 77 ++ partie1/sources/verrou.c | 125 ++ partie1/sources/verrou.h | 36 + partie2/Dossier Utilisateur Pietrzak 2.doc | Bin 0 -> 118272 bytes sujet.htm | 60 + 24 files changed, 3933 insertions(+) create mode 100644 info create mode 100755 musique/auclairdelalune create mode 100755 musique/essainotes create mode 100755 musique/hardasarock create mode 100755 musique/musique.c create mode 100755 musique/musique.exe create mode 100755 musique/paradigmshift create mode 100644 partie1/Dossier Utilisateur Pietrzak.doc create mode 100644 partie1/sources/defines.h create mode 100644 partie1/sources/exc.c create mode 100644 partie1/sources/exc.h create mode 100644 partie1/sources/exs.c create mode 100644 partie1/sources/exs.h create mode 100644 partie1/sources/makefilec create mode 100644 partie1/sources/makefiles create mode 100644 partie1/sources/mks create mode 100644 partie1/sources/serveurdedie.c create mode 100644 partie1/sources/serveurdedie.h create mode 100644 partie1/sources/tables.c create mode 100644 partie1/sources/tables.h create mode 100644 partie1/sources/verrou.c create mode 100644 partie1/sources/verrou.h create mode 100644 partie2/Dossier Utilisateur Pietrzak 2.doc create mode 100644 sujet.htm diff --git a/info b/info new file mode 100644 index 0000000..53e391b --- /dev/null +++ b/info @@ -0,0 +1,23 @@ +Projet système +============== + +Partie 1 : +---------- +- sources +- dossier programmation +- dossier utilisateur + +Partie 2 : +---------- +- sources +- dossier programmation +- dossier utilisateur + +musique : +--------- +- programme lisant un fichier de musique sur le haut parleur du pc. Je n'ai pas pu l'inclure par manque de temps pour chercher un équivalent à la fonction beep, qui était obsolète sous linux à l'époque. + +Note : +------ + +Ceci n'est pas la version finale : il y a encore un petit bug dans la gestion des pages. Il manque une condition dans un for que j'avais bricolé à la dernière minute (remplacé un while + if en fait). Quand j'aurai le temps je corrigerai. diff --git a/musique/auclairdelalune b/musique/auclairdelalune new file mode 100755 index 0000000..77396c6 --- /dev/null +++ b/musique/auclairdelalune @@ -0,0 +1,12 @@ +100 +C3 C +C3 C +C3 C +D3 C +E3 N +D3 N +C3 C +E3 C +D3 C +D3 C +C3 B \ No newline at end of file diff --git a/musique/essainotes b/musique/essainotes new file mode 100755 index 0000000..a272dd1 --- /dev/null +++ b/musique/essainotes @@ -0,0 +1 @@ +100 C1 TC CD1 TC D1 TC DD1 TC E1 TC F1 TC FD1 TC G1 TC GD1 TC A1 TC AD1 TC B1 TC C2 TC CD2 TC D2 TC DD2 TC E2 TC F2 TC FD2 TC G2 TC GD2 TC A2 TC AD2 TC B2 TC C3 TC CD3 TC D3 TC DD3 TC E3 TC F3 TC FD3 TC G3 TC GD3 TC A3 TC AD3 TC B3 TC C4 TC CD4 TC D4 TC DD4 TC E4 TC F4 TC FD4 TC G4 TC GD4 TC A4 TC AD4 TC B4 TC C5 TC CD5 TC D5 TC DD5 TC E5 TC F5 TC FD5 TC G5 TC GD5 TC A5 TC AD5 TC B5 TC \ No newline at end of file diff --git a/musique/hardasarock b/musique/hardasarock new file mode 100755 index 0000000..3dcdf1a --- /dev/null +++ b/musique/hardasarock @@ -0,0 +1,16 @@ +120 +A3 C +B3 C +C4 N +B3 C +A3 C +G3 C +A3 C +B3 C +A3 B +P N +B3 C +G3 B +P N +B3 C +A3 B \ No newline at end of file diff --git a/musique/musique.c b/musique/musique.c new file mode 100755 index 0000000..dee05d4 --- /dev/null +++ b/musique/musique.c @@ -0,0 +1,289 @@ +#define DO1 65 +#define DOD1 69 +#define RE1 74 +#define RED1 78 +#define MI1 83 +#define FA1 87 +#define FAD1 92 +#define SOL1 98 +#define SOLD1 104 +#define LA1 110 +#define LAD1 117 +#define SI1 123 +#define DO2 131 +#define DOD2 139 +#define RE2 147 +#define RED2 156 +#define MI2 165 +#define FA2 175 +#define FAD2 185 +#define SOL2 196 +#define SOLD2 208 +#define LA2 220 +#define LAD2 233 +#define SI2 247 +#define DO3 262 +#define DOD3 277 +#define RE3 294 +#define RED3 311 +#define MI3 330 +#define FA3 349 +#define FAD3 370 +#define SOL3 392 +#define SOLD3 415 +#define LA3 440 +#define LAD3 466 +#define SI3 494 +#define DO4 523 +#define DOD4 554 +#define RE4 587 +#define RED4 622 +#define MI4 659 +#define FA4 698 +#define FAD4 740 +#define SOL4 784 +#define SOLD4 831 +#define LA4 880 +#define LAD4 932 +#define SI4 988 +#define DO5 1046 +#define DOD5 1109 +#define RE5 1175 +#define RED5 1244 +#define MI5 1318 +#define FA5 1397 +#define FAD5 1480 +#define SOL5 1568 +#define SOLD5 1661 +#define LA5 1760 +#define LAD5 1865 +#define SI5 1975 + +#include +#include +#include + +#define MS_PAR_MIN 60000 + +unsigned int freq_of_note (char *note) +{ + //Octave 1 + if (strcmp ("C1",note)==0) //DO + return DO1; + else if (strcmp ("CD1",note)==0) //DO # + return DOD1; + else if (strcmp ("D1",note)==0) //RE + return RE1; + else if (strcmp ("DD1",note)==0) //RE # + return RED1; + else if (strcmp ("E1",note)==0) //MI + return MI1; + else if (strcmp ("F1",note)==0) //FA + return FA1; + else if (strcmp ("FD1",note)==0) //FA # + return FAD1; + else if (strcmp ("G1",note)==0) //SOL + return SOL1; + else if (strcmp ("GD1",note)==0) //SOL # + return SOLD1; + else if (strcmp ("A1",note)==0) //LA + return LA1; + else if (strcmp ("AD1",note)==0) //LA # + return LAD1; + else if (strcmp ("B1",note)==0) //SI + return SI1; + //Octave 2 + else if (strcmp ("C2",note)==0) //DO + return DO2; + else if (strcmp ("CD2",note)==0) //DO # + return DOD2; + else if (strcmp ("D2",note)==0) //RE + return RE2; + else if (strcmp ("DD2",note)==0) //RE # + return RED2; + else if (strcmp ("E2",note)==0) //MI + return MI2; + else if (strcmp ("F2",note)==0) //FA + return FA2; + else if (strcmp ("FD2",note)==0) //FA # + return FAD2; + else if (strcmp ("G2",note)==0) //SOL + return SOL2; + else if (strcmp ("GD2",note)==0) //SOL # + return SOLD2; + else if (strcmp ("A2",note)==0) //LA + return LA2; + else if (strcmp ("AD2",note)==0) //LA # + return LAD2; + else if (strcmp ("B2",note)==0) //SI + return SI2; + //Octave 3 + else if (strcmp ("C3",note)==0) //DO + return DO3; + else if (strcmp ("CD3",note)==0) //DO # + return DOD3; + else if (strcmp ("D3",note)==0) //RE + return RE3; + else if (strcmp ("DD3",note)==0) //RE # + return RED3; + else if (strcmp ("E3",note)==0) //MI + return MI3; + else if (strcmp ("F3",note)==0) //FA + return FA3; + else if (strcmp ("FD3",note)==0) //FA # + return FAD3; + else if (strcmp ("G3",note)==0) //SOL + return SOL3; + else if (strcmp ("GD3",note)==0) //SOL # + return SOLD3; + else if (strcmp ("A3",note)==0) //LA + return LA3; + else if (strcmp ("AD3",note)==0) //LA # + return LAD3; + else if (strcmp ("B3",note)==0) //SI + return SI3; + //Octave 4 + else if (strcmp ("C4",note)==0) //DO + return DO4; + else if (strcmp ("CD4",note)==0) //DO # + return DOD4; + else if (strcmp ("D4",note)==0) //RE + return RE4; + else if (strcmp ("DD4",note)==0) //RE # + return RED4; + else if (strcmp ("E4",note)==0) //MI + return MI4; + else if (strcmp ("F4",note)==0) //FA + return FA4; + else if (strcmp ("FD4",note)==0) //FA # + return FAD4; + else if (strcmp ("G4",note)==0) //SOL + return SOL4; + else if (strcmp ("GD4",note)==0) //SOL # + return SOLD4; + else if (strcmp ("A4",note)==0) //LA + return LA4; + else if (strcmp ("AD4",note)==0) //LA # + return LAD4; + else if (strcmp ("B4",note)==0) //SI + return SI4; + //Octave 5 + else if (strcmp ("C5",note)==0) //DO + return DO5; + else if (strcmp ("CD5",note)==0) //DO # + return DOD5; + else if (strcmp ("D5",note)==0) //RE + return RE5; + else if (strcmp ("DD5",note)==0) //RE # + return RED5; + else if (strcmp ("E5",note)==0) //MI + return MI5; + else if (strcmp ("F5",note)==0) //FA + return FA5; + else if (strcmp ("FD5",note)==0) //FA # + return FAD5; + else if (strcmp ("G5",note)==0) //SOL + return SOL5; + else if (strcmp ("GD5",note)==0) //SOL # + return SOLD5; + else if (strcmp ("A5",note)==0) //LA + return LA5; + else if (strcmp ("AD5",note)==0) //LA # + return LAD5; + else if (strcmp ("B5",note)==0) //SI + return SI5; + else return 0; +} + +unsigned int duree_of_type (char *type, int temps_noire) +{ + if (strcmp(type,"N")==0) //noire + return temps_noire; + else if (strcmp(type,"NP")==0) //noire pointée + return (3*temps_noire)/2; + else if (strcmp(type,"B")==0) //blanche + return 2*temps_noire; + else if (strcmp(type,"BP")==0) //blanche pointée + return 3*temps_noire; + else if (strcmp(type,"R")==0) //ronde + return 4*temps_noire; + else if (strcmp(type,"RP")==0) //ronde pointée + return 6*temps_noire; + else if (strcmp(type,"C")==0) //croche + return temps_noire/2; + else if (strcmp(type,"CP")==0) //croche pointée + return (3*temps_noire)/4; + else if (strcmp(type,"DC")==0) //double croche + return temps_noire/4; + else if (strcmp(type,"DCP")==0) //double croche pointée + return (3*temps_noire)/8; + else if (strcmp(type,"TC")==0) //triple croche + return temps_noire/8; + else if (strcmp(type,"TCP")==0) //triple croche pointée + return (3*temps_noire)/16; + else if (strcmp(type,"C")==0) //quadruple croche + return temps_noire/16; + else if (strcmp(type,"C")==0) //quadruple croche pointée + return (3*temps_noire)/32; + else return 0; +} + + +void jouer (char *morceau) +{ + FILE *fichier; + int tempo; + char note[8]; + char type[8]; + int duree = 0; + int temps_noire = 0; + + //ouverture du fichier + if ((fichier = fopen(morceau, "r")) == NULL) + { + fprintf(stderr,"fichier inconnu\n"); + exit(1); + } + + //lecture du tempo + if (fscanf(fichier, "%d", &tempo) != 1) + { + perror("lecture du tempo"); + exit(1); + } + + //tempo = (int) *tp; + + //détermination de la durée d'une noire + temps_noire = MS_PAR_MIN / tempo; + + fprintf(stdout,"Tempo : %d à la noire\n", tempo); + + //lecture des notes + while (fscanf(fichier, "%s %s",note, type) == 2) + { + if (strcmp(note,"P")==0) + { + fprintf(stdout,"PAUSE duree=%d\n",duree_of_type(type, temps_noire)); + _sleep((unsigned long)duree_of_type(type, temps_noire)); + } + else + { + fprintf(stdout,"freq=%d duree=%d\n",freq_of_note(note),duree_of_type(type, temps_noire)); + _beep(freq_of_note(note),duree_of_type(type, temps_noire)); + } + } + +} + +int main (void) +{ + char morceau[128]; + + fprintf(stdout, "Entrez le nom du morceau :"); + + fscanf(stdin,"%s",morceau); + + jouer(morceau); + +} \ No newline at end of file diff --git a/musique/musique.exe b/musique/musique.exe new file mode 100755 index 0000000000000000000000000000000000000000..6030ce6f82ed1b83dad38e86cfcae4c24dce004d GIT binary patch literal 172138 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 literal 0 HcmV?d00001 diff --git a/musique/paradigmshift b/musique/paradigmshift new file mode 100755 index 0000000..581e7b4 --- /dev/null +++ b/musique/paradigmshift @@ -0,0 +1,472 @@ +210 +E4 DC +F4 DC +E4 DC +D4 DC +E4 DC +D4 DC +CD3 DC +D4 DC +E4 DC +D4 DC +CD3 DC +D4 DC +E4 DC +F4 DC +E4 DC +D4 DC +E4 DC +D4 DC +CD3 DC +D4 DC +E4 DC +D4 DC +CD3 DC +D4 DC +E4 DC +F4 DC +E4 DC +D4 DC +E4 DC +D4 DC +CD3 DC +D4 DC +E4 DC +D4 DC +CD3 DC +D4 DC +G4 DC +F4 DC +D4 DC +C3 DC +AD3 DC +G3 DC +AD3 DC +C3 DC +CD3 DC +C3 DC +AD3 DC +G3 DC +F3 DC +D3 DC +AD3 DC +G3 DC +F3 DC +D3 DC +C2 DC +AD2 DC +D3 DC +C2 DC +AD2 DC +G2 DC +P B +P C +G2 C +AD2 DC +G2 DC +G2 DC +AD2 DC +G2 DC +G2 DC +AD2 DC +G2 DC +G2 DC +AD2 DC +G2 DC +G2 DC +AD2 DC +G2 DC +C3 DC +G2 DC +AD2 DC +G2 DC +G2 DC +AD2 DC +G2 DC +G2 DC +AD2 DC +G2 DC +G2 DC +AD2 DC +G2 DC +G2 DC +F2 DC +D2 DC +F2 DC +D2 DC +AD2 DC +G2 DC +G2 DC +AD2 DC +G2 DC +G2 DC +AD2 DC +G2 DC +G2 DC +AD2 DC +G2 DC +G2 DC +AD2 DC +G2 DC +C3 DC +G2 DC +CD3 DC +G2 DC +C3 DC +G2 DC +AD2 DC +G2 DC +G2 DC +AD2 DC +G2 DC +G2 DC +D2 DC +D2 DC +G2 DC +D2 DC +F2 DC +D2 DC +AD2 DC +G2 DC +G2 DC +AD2 DC +G2 DC +G2 DC +AD2 DC +G2 DC +G2 DC +AD2 DC +G2 DC +G2 DC +AD2 DC +G2 DC +C3 DC +G2 DC +AD2 DC +G2 DC +G2 DC +AD2 DC +G2 DC +G2 DC +AD2 DC +G2 DC +G2 DC +AD2 DC +G2 DC +G2 DC +F2 DC +D2 DC +F2 DC +D2 DC +AD2 DC +G2 DC +G2 DC +AD2 DC +G2 DC +G2 DC +AD2 DC +G2 DC +G2 DC +AD2 DC +G2 DC +G2 DC +AD2 DC +G2 DC +C3 DC +G2 DC +G3 DC +D3 DC +F3 DC +C3 DC +AD2 DC +G2 DC +C3 DC +G2 DC +C3 DC +AD2 DC +G2 DC +F2 DC +D2 DC +C2 DC +AD1 DC +G1 DC + +F1 CP +G1 NP +G1 DC +F1 CP +G1 CP +AD1 NP +F1 CP +G1 NP +G1 DC +E1 B +F1 B +F1 CP +G1 NP +G1 DC +F1 CP +G1 CP +C2 NP +AD1 B +C2 B +DD B +FD B + + +F1 DC +G1 DC +G1 DC +G1 DC +G1 DC +G1 DC +G1 CP +G1 DC +P DC +G1 DC +G1 N + +F1 DC +G1 DC +G1 DC +G1 DC +G1 DC +G1 DC +AD1 N +B1 DC +B1 DC +C2 C +D2 C + +F1 DC +G1 DC +G1 DC +G1 DC +G1 DC +G1 DC +G1 CP +G1 DC +P DC +G1 DC +G1 N + +F1 DC +G1 DC +G1 DC +G1 DC +G1 DC +G1 DC +AD1 N +B1 DC +B1 DC +C2 C +AD1 C + +F1 DC +G1 DC +G1 DC +G1 DC +G1 DC +G1 DC +G1 CP +G1 DC +P DC +G1 DC +G1 N + +F1 DC +G1 DC +G1 DC +G1 DC +G1 DC +G1 DC +AD1 N +B1 DC +B1 DC +C2 C +D2 C + +F1 DC +G1 DC +G1 DC +G1 DC +G1 DC +G1 DC +G1 CP +G1 DC +P DC +G1 DC +G1 N + +F1 DC +G1 DC +G1 DC +G1 DC +G1 DC +G1 DC +AD1 N +B1 DC +B1 DC +C2 C +AD1 C + +F1 DC +G1 DC +G1 DC +G1 DC +G1 DC +G1 DC +AD1 N +B1 DC +B1 DC +C2 C +D2 C + +F1 DC +G1 DC +G1 DC +G1 DC +G1 DC +G1 DC +AD1 N +B1 DC +B1 DC +C2 C +D2 C + +F1 DC +G1 DC +G1 DC +G1 DC +G1 DC +G1 DC +AD1 N +B1 DC +B1 DC +C2 C +D2 C + +F1 DC +G1 DC +G1 DC +G1 DC +G1 DC +G1 DC +AD1 N +B1 DC +B1 DC +C2 C +D2 C + +F3 DC +G3 DC +G3 DC +G3 CP +AD3 CP +G3 DC +AD3 DC +G3 DC +C4 DC +G3 DC +D4 DC +G3 DC + +F3 DC +G3 DC +G3 DC +G3 CP +AD3 CP +G3 DC +C4 DC +G3 DC +AD3 DC +G3 DC +F3 DC +D3 DC + +F3 DC +G3 DC +G3 DC +G3 CP +AD3 CP +G3 DC +AD3 DC +G3 DC +C4 DC +G3 DC +D4 DC +G3 DC + +G4 DC +D4 DC +F4 DC +C4 DC +D4 DC +C4 DC +AD3 DC +C4 C +G3 DC +CD4 DC +G3 DC +C4 DC +AD3 DC +G3 DC +F3 DC + +F3 DC +G3 DC +G3 DC +G3 CP +AD3 CP +G3 DC +AD3 DC +G3 DC +C4 DC +G3 DC +D4 DC +G3 DC + +F3 DC +G3 DC +G3 DC +G3 CP +AD3 CP +G3 DC +C4 DC +G3 DC +AD3 DC +G3 DC +F3 DC +D3 DC + +D3 DC +G3 DC +G3 DC +G3 CP +AD3 CP +G3 DC +AD3 DC +G3 DC +C4 DC +G3 DC +D4 DC +C4 DC + +G4 DC +D4 DC +F4 DC +C4 DC +D4 DC +C4 C +AD3 DC +C4 DC +G3 DC +CD4 DC +G3 DC +C4 DC +AD3 DC +G3 DC +F3 DC + +F1 N +G1 R \ No newline at end of file diff --git a/partie1/Dossier Utilisateur Pietrzak.doc b/partie1/Dossier Utilisateur Pietrzak.doc new file mode 100644 index 0000000000000000000000000000000000000000..9f923830749b715435f3b14f554c8cefeb6ce315 GIT binary patch literal 89599 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 L$31g;OW=P2<0i(T literal 0 HcmV?d00001 diff --git a/partie1/sources/defines.h b/partie1/sources/defines.h new file mode 100644 index 0000000..6ab03a9 --- /dev/null +++ b/partie1/sources/defines.h @@ -0,0 +1,19 @@ +#ifndef _DEF_ + #define _DEF_ + + #define TAILLE_STR 128 + #define NB_LECT_MAX 3 + #define MAX_TABLES 20 + #define MAX_CHAMPS 7 + + #define CONNECTE 1 + #define DECONNECTE 0 + + #define TUBE_CONNEXION "TubeConnexion" + #define LISTE_PASS "pwl" + #define LOG_FILE "log" + + #define PROMPT "\n@xx}:::> " + #define CLE "e£$r*µ%t?" + #define MP_SERV "e£LlkQRhyFDuc" +#endif diff --git a/partie1/sources/exc.c b/partie1/sources/exc.c new file mode 100644 index 0000000..74da037 --- /dev/null +++ b/partie1/sources/exc.c @@ -0,0 +1,214 @@ +#include "exc.h" + +//********************************************************************************************* +//code +//********************************************************************************************* +int main (void) +{ + FILE * requete; + FILE * reponse; + + int fd; + + char tuberep[TAILLE_STR]; + char *tubereq; + char rep[TAILLE_STR]; + char login[TAILLE_STR]; + char mp[TAILLE_STR]; + char req[TAILLE_STR]; + + pthread_t aff_rep; + aff_rep_t params; + + //demande le login + fprintf (stdout, "Login : "); + if (fgets (login, TAILLE_STR, stdin) == NULL) + exit(0); + if (login [strlen (login) - 1] == '\n') + login [strlen (login) - 1] = '\0'; + + //demande le mot de passe + fprintf (stdout, "Mot de passe : "); + if (fgets (mp, TAILLE_STR, stdin) == NULL) + exit(0); + + //détermine le nom du tube de réponse + //c'est celui dans lequel il recevra la réponse de connexion et + //les réponses à ses requêtes + sprintf (tuberep, "Client.%u", getpid()); + + //crée le tube de réponse + if (mkfifo (tuberep, 0666) != 0) + { + fprintf (stderr, "Impossible de créer le tube\n"); + exit (1); + } + + //ouvre le tube de connexion en écriture + if ((fd = open (TUBE_CONNEXION, O_WRONLY)) < 0) + { + perror ("Impossible d'ouvrir le tube de connexion"); + unlink(tuberep); + exit (1); + } + requete = fdopen (fd, "w"); + + //envoie la demande de connexion + fprintf (requete, "%s\n%s\n%s", tuberep, login, mp); + //ferme le tube + fclose (requete); + + //ouvre le tube de réponse en lecture + if ((fd = open (tuberep, O_RDONLY)) < 0) + { + perror ("Impossible d'ouvrir le tube de réponse"); + exit (1); + } + reponse = fdopen (fd, "r"); + + //lit la réponse + if (fgets (rep, TAILLE_STR, reponse) == NULL) + { + perror ("fgets"); + fclose(reponse); + unlink(tuberep); + return(0); + } + //ferme le tube + fclose(reponse); + //enlève l'éventuel caractère le fin de ligne + if (rep [strlen (rep) - 1] == '\n') + rep [strlen (rep) - 1] = '\0'; + + //quitte si le mot de passe n'est pas bon + if (strcasecmp(rep,"non") == 0) + { + fprintf (stdout, "Login ou mot de passe incorrect\n"); + unlink(tuberep); + return(0); + } + + //si c'est bon, la réponse c'est le nom du tube de requêtes + //c'est le tube par lequel le client va envoyer les requêtes + tubereq = strdup(rep); + //connecté + + //Message Perso + fprintf(stdout,"\n********************************************************************************\n"); + fprintf(stdout,"Vous êtes connecté au serveur NSQL- de eXs\n"); + fprintf(stdout,"\n ______\n"); + fprintf(stdout," X X /||||||\\\n"); + fprintf(stdout," eee X X cccc /\\' \"\" '/\\\n"); + fprintf(stdout," e e X X c |\\-- --/|\n"); + fprintf(stdout," eeeeee X c F| o o |\n"); + fprintf(stdout," e X X c || | |\n"); + fprintf(stdout," eeee X X cccc L\\ _| /\\\n"); + fprintf(stdout," X X //|\\ --- /|\\\\\n"); + fprintf(stdout," ||||\\___/||||\n"); + fprintf(stdout,"Par TOM compilé le "); + fprintf(stdout, __DATE__); + fprintf(stdout, " à "); + fprintf(stdout, __TIME__); + fprintf(stdout,"********************************************************************************\n"); + + //lance la thread qui reçoit les résultats et les affiche + params.tube = strdup(tuberep); + params.login = strdup(login); + pthread_create(&aff_rep, NULL,affiche_reponses, (void *)¶ms); + + //boucle dans laquelle on lit la ligne de commande + while(1) + { + //affichage du prompt + fprintf(stdout,"%s =# ", login); + + //lecture de la requête à partir de l'entrée standard + if (fgets(req, TAILLE_STR, stdin) == NULL) + perror("Problème de lecture de la requête"); + + //ouverture du tube de requetes + if ((fd = open (tubereq, O_WRONLY)) < 0) + { + fprintf (stdout,"Le serveur est fermé\n Déconnexion...\n"); + break; + } + requete = fdopen (fd, "w"); + + //ecriture dans le tube de requetes + fprintf(requete, "%s", req); + //fermeture du tube + fclose(requete); + + if(strcmp(req,"DISCONNECT\n") == 0) + { + pthread_join(&aff_rep, NULL); + break; + } + + } + + //destruction du tube de reponses + unlink (tuberep); + //libération de la chaîne + free(tubereq); + return (0); +} + +void *affiche_reponses(void *tube) +{ + FILE *reponse; + + int fd; + + char *tuberep; + char *login; + char rep[TAILLE_STR]; + + //récupération du nom du tube et du login + tuberep = strdup(((aff_rep_t *) tube)->tube); + login = strdup(((aff_rep_t *) tube)->login); + + //ouverture du tube de reponsesen lecture/écriture + if ((fd = open (tuberep, O_RDWR)) < 0) + { + perror ("Impossible d'ouvrir le tube de réponse : déconnectez vous"); + pthread_exit ((void *)NULL); + } + reponse = fdopen (fd, "r"); + + //boucle dans laquelle on va regarder dans le tube de réponse + while(1) + { + //lecture de la réponse + if (fgets(rep, TAILLE_STR, reponse) == NULL) + { + perror("Impossible de lire dans le tube de réponse"); + break; + } + + //si la requête était DISCONNECT on quitte la thread + if(strcmp(rep,"FIN\n") == 0) + break; + + //affiche la réponse + fprintf(stdout, "%s", rep); + + //affichage du prompt + fprintf(stdout,"%s =# ", login); + //force l'affichage + fflush(stdout); + } + + //Confirme la déconnexion + fprintf(stdout,"Déconnecté\n"); + + //ferme le tube de réponse + fclose (reponse); + + //libère les pointeurs + free(login); + free(tuberep); + + //quitte -->la fonction main peut continuer après le pthread_join + pthread_exit((void *)NULL); +} diff --git a/partie1/sources/exc.h b/partie1/sources/exc.h new file mode 100644 index 0000000..ab3c51c --- /dev/null +++ b/partie1/sources/exc.h @@ -0,0 +1,28 @@ +//********************************************************************************************* +//includes +//********************************************************************************************* +#include +#include +#include +#include +#include +#include + +//********************************************************************************************* +//defines +//********************************************************************************************* +#define TAILLE_STR 128 +#define TUBE_CONNEXION "TubeConnexion" +//********************************************************************************************* +//types +//********************************************************************************************* +typedef struct + { + char *tube; + char *login; + }aff_rep_t; + +//********************************************************************************************* +//fonctions +//********************************************************************************************* +void *affiche_reponses(void *); diff --git a/partie1/sources/exs.c b/partie1/sources/exs.c new file mode 100644 index 0000000..199a895 --- /dev/null +++ b/partie1/sources/exs.c @@ -0,0 +1,873 @@ +#include "exs.h" + +//********************************************************************************************* +//Programme +//********************************************************************************************* + +//********************************************************************************************* +//fonction principale : Meta Serveur +//lance une thread qui va écouter le tube de connexion et gère la ligne de commande servant à +//gérer les mots de passe +//********************************************************************************************* +int main (void) +{ + FILE *deconnexion; //flux sur le tube de connexion + FILE *logs; //flus sur le fichier de logs (connexions) + int fd; //descripteur de fichiers + + char *ligne; + char *login; + char *mp; + char *vlogin; + char *crlogin; + char *crmp; + char *type_requete; + char *tube; + + int position; + + pthread_t ana_connect; + + //allocation des chaînes + if ((ligne = (char *) malloc (TAILLE_STR * sizeof(char))) == NULL) + { + fprintf (stderr,"Problème d'allocation mémoire\n"); + exit(1); + } + if ((login = (char *) malloc (TAILLE_STR * sizeof(char))) == NULL) + { + fprintf (stderr,"Problème d'allocation mémoire\n"); + exit(1); + } + if ((mp = (char *) malloc (TAILLE_STR * sizeof(char))) == NULL) + { + fprintf (stderr,"Problème d'allocation mémoire\n"); + exit(1); + } + if ((type_requete = (char *) malloc (TAILLE_STR * sizeof(char))) == NULL) + { + fprintf (stderr,"Problème d'allocation mémoire\n"); + exit(1); + } + if ((vlogin = (char *) malloc (TAILLE_STR * sizeof(char))) == NULL) + { + fprintf (stderr,"Problème d'allocation mémoire\n"); + exit(1); + } + if ((tube = (char *) malloc (TAILLE_STR * sizeof(char))) == NULL) + { + fprintf (stderr,"Problème d'allocation mémoire\n"); + exit(1); + } + + //lancement de la requête qui va écouter le tube de connexion + pthread_create (&ana_connect, NULL, ana_connexions, NULL); + + //Message Perso + fprintf(stdout,"\n********************************************************************************\n"); + fprintf(stdout,"eXs : Serveur NSQL- activé\n"); + fprintf(stdout,"\n ______\n"); + fprintf(stdout," X X /||||||\\\n"); + fprintf(stdout," eee X X ssss /\\' \"\" '/\\\n"); + fprintf(stdout," e e X X s |\\-- --/|\n"); + fprintf(stdout," eeeeee X s F| o o |\n"); + fprintf(stdout," e X X s || | |\n"); + fprintf(stdout," eeee X X ssss L\\ _| /\\\n"); + fprintf(stdout," X X //|\\ --- /|\\\\\n"); + fprintf(stdout," ||||\\___/||||\n"); + fprintf(stdout,"Par TOM compilé le "); + fprintf(stdout, __DATE__); + fprintf(stdout, " à "); + fprintf(stdout, __TIME__); + fprintf(stdout,"********************************************************************************\n"); + + //bocle dans laquelle on s'occupe de la ligne de commande + while(1) + { + //imprime le prompt + fprintf(stdout, PROMPT); + + //lit la ligne de commande + if ( fgets(ligne, TAILLE_STR, stdin) == NULL ) + { + //problème avec la ligne de commande + fprintf(stderr,"Impossible de lire la commande\n"); + continue; + } + + //cherche le type de requête + if (sscanf(ligne, "%s %n", type_requete, &position) !=1) + { + //aucune commande n'a été tapée + fprintf(stderr,"Tapez une commande SVP\n"); + continue; + } + + //si c'est un DISCONNECT + if (strcmp(type_requete,"DISCONNECT")==0) + { + //mise à jour de la valeur servok => le meta serveur sort de sa boucle + fprintf(stdout,"Déconnection\n"); + pthread_cancel(ana_connect); + break; + } + + //ajour d'un client + else if (strcmp(type_requete,"ADD")==0) + { + //analyse des arguments de la requête + if (sscanf(&(ligne[position]), "%s %s", login, mp) != 2) + { + fprintf(stderr,"Utilisation : ADD \n"); + continue; + } + //enlève les éventuels caractères de fin de ligne + if (login[strlen(login) - 1] == '\n') + login[strlen(login) - 1] = '\0'; + if (mp[strlen(mp) - 1] == '\n') + mp[strlen(mp) - 1] = '\0'; + + //crypte le login et le mot de passe + crlogin = strdup(crypt(login,CLE)); + crmp = strdup(crypt(mp,CLE)); + + //insertion du client + if (inserermp (crlogin, crmp, LISTE_PASS) == 1) + { + //crée le fichier de la liste des tables du client + sprintf(ligne,"%s.tables",login); + if (mknod(ligne,0666|S_IFREG,0) == -1) + fprintf(stderr,"Erreur lors de la création de la table des tables du client %s\n", login); + else + { + //crée le fichier contenant les tables du client + sprintf(ligne,"%s.data",ligne); + if (mknod(ligne,0666|S_IFREG,0) == -1) + fprintf(stderr,"Erreur lors de la création du fichier de données du client %s\n", login); + else + fprintf(stdout,"Client %s inséré\n", login); + } + } + else + fprintf(stderr,"Erreur lors de l'insertion du client %s\n", login); + } + + //supprime un client de la liste + else if (strcmp(type_requete,"SUPPR")==0) + { + //analyse des arguments de la requête + if (sscanf(&(ligne[position]), "%s", login) != 1) + { + fprintf(stderr,"Utilisation : SUPPR \n"); + continue; + } + //enlève les éventuels caractères de fin de ligne + if (login[strlen(login) - 1] == '\n') + login[strlen(login) - 1] = '\0'; + //crypte le login + crlogin = strdup(crypt(login,CLE)); + //suppression du client + if (supprimermp (crlogin, LISTE_PASS) == 1) + { + //supprime le fichier des tables du client + sprintf(ligne,"%s.tables",login); + unlink(ligne); + //supprime la liste des tables du client + sprintf(ligne,"%s.data",ligne); + unlink(ligne); + fprintf(stdout,"Client %s supprimé\n", login); + } + else + fprintf(stderr,"Erreur lors de la suppression du client %s (client probablement inexistant)\n", login); + } + + //Modification du mot de passe + else if (strcmp(type_requete,"CHPW")==0) + { + //lit le login et le mot de passe + if (sscanf(&(ligne[position]), "%s %s", login, mp) != 2) + { + fprintf(stderr,"Utilisation : CHPW \n"); + continue; + } + //enlève les éventuels caractères de fin de ligne + if (login[strlen(login) - 1] == '\n') + login[strlen(login) - 1] = '\0'; + if (mp[strlen(mp) - 1] == '\n') + mp[strlen(mp) - 1] = '\0'; + + //crypte le login et le mot de passe + crlogin = strdup(crypt(login,CLE)); + crmp = strdup(crypt(mp,CLE)); + + //suppression puis insertion du client --> modifie le mot de passe + if (supprimermp (crlogin, LISTE_PASS) == 1) + if (inserermp (crlogin, crmp, LISTE_PASS) == 1) + fprintf(stdout,"Changement du mot de passe du client %s\n", login); + else + fprintf(stderr,"Erreur lors de la modification du mot de passe du client %s\n", login); + else + fprintf(stderr,"Erreur lors de la modification du mot de passe du client %s (client probablement inexistant)\n", login); + } + + //Crypte la chaine en argument + //Pas important + else if (strcmp(type_requete,"CRYPT")==0) + { + if (sscanf(&(ligne[position]), "%s", login) != 1) + { + fprintf(stderr,"Utilisation : CRYPT \n"); + continue; + } + //enlève l'éventuel caractère de fin de ligne + if (login[strlen(login) - 1] == '\n') + login[strlen(login) - 1] = '\0'; + //suppression puis insertion du client + crlogin = strdup(crypt(login,CLE)); //duplication du login + fprintf(stderr,"%s\n", crlogin); + } + + //Bloque la ligne de commande tant que le mot de passe n'est pas bon + else if (strcmp(type_requete,"BLOCK") == 0) + { + fprintf(stdout,"Ligne de commande bloquée\n"); + //boucle + do + { + //demande le mot de passe + fprintf(stdout,"Mot de passe : "); + fflush(stdout); + if (fgets (mp, TAILLE_STR, stdin) == NULL) + exit(0); + //enlève l'éventuel caractère de fin de ligne + if (mp [strlen (login) - 1] == '\n') + mp [strlen (login) - 1] = '\0'; + + //crypte le motde passe + crmp = strdup(crypt(mp,CLE)); //duplication du login + }//boucle tant que le mot de passe n'est pas celui défini dans defines.h + while(strcmp(crmp, MP_SERV) != 0); + + //la ligne de commande est débloquée + fprintf(stdout,"Ligne de commande débloquée\n"); + } + + //Affiche le dernier log du client + //je l'ai juste fait à titre d'exercice sur les flux + //mais au niveau administrateur ça peut avoir une utilité + else if (strcmp(type_requete,"LAST") == 0) + { + if (sscanf(&(ligne[position]), "%s", login) != 1) + { + fprintf(stderr,"Utilisation : LAST \n"); + continue; + } + //enlève l'éventuel caractère de fin de ligne + if (login[strlen(login) - 1] == '\n') + login[strlen(login) - 1] = '\0'; + //ouvre le fichier de logs en lecture + if ((logs = fopen(LOG_FILE, "r")) == NULL) + { + fprintf (stderr,"Problème à l'ouverture du fichiers de login\n"); + exit(0); + } + //lit une ligne du fichier de logs + while (fgets(ligne, TAILLE_STR, logs) != NULL) + //on lit le premier mot de la ligne : c'est le login + if (sscanf(ligne, "%s %*n", vlogin) == 1) + { + //si le login correspond à celui du début dela ligneon le mémorise + if (strcmp(vlogin,login) == 0) + mp = strdup(ligne); + } + else break; + //affiche la dernière ligne dont le login ést celui qui étati passé en argument + fprintf(stdout, "%s", mp); + //fermeture du fichier de log + fclose (logs); + } + + //Affiche tous les logs du client + //il y a juste une petite modification par rapport à la précédente + else if (strcmp(type_requete,"LOGS") == 0) + { + if (sscanf(&(ligne[position]), "%s", login) != 1) + { + fprintf(stderr,"Utilisation : LOGS \n"); + continue; + } + //enlève les éventuels caractères de fin de ligne + if (login[strlen(login) - 1] == '\n') + login[strlen(login) - 1] = '\0'; + //ouvre le fichier de logs en lecture + if ((logs = fopen(LOG_FILE, "r")) == NULL) + { + fprintf (stderr,"Problème à l'ouverture du fichiers de login\n"); + exit(0); + } + //lit une ligne du fichier + while (fgets(ligne, TAILLE_STR, logs) != NULL) + //mémorise le login qui est en début de ligne + if (sscanf(ligne, "%s %*n", vlogin) == 1) + { + //si le login est celui en argument... + if (strcmp(vlogin,login) == 0) + //... on affiche la ligne + fprintf(stdout, "%s", ligne); + } + else break; + //fermeture du fichier de log + fclose (logs); + } + + //Déconnecte le client + //pas sur que ça marche + //c'est resté au stade expérimental. C'était pas une priorité, j'ai fait ça quand je + //me donnais une pause. pfiouuu c'est laborieux ... :-) + else if (strcmp(type_requete,"KILL") == 0) + { + if (sscanf(&(ligne[position]), "%s", login) != 1) + { + fprintf(stderr,"Utilisation : KILL \n"); + continue; + } + //enlève les éventuels caractères de fin de ligne + if (login[strlen(login) - 1] == '\n') + login[strlen(login) - 1] = '\0'; + //ouvre le fichier de logs en lecture + if ((logs = fopen(LOG_FILE, "r")) == NULL) + { + fprintf (stderr,"Problème à l'ouverture du fichiers de login\n"); + exit(0); + } + //cherche la dernière connexion du client + while (fgets(ligne, TAILLE_STR, logs) != NULL) + { + //prend le login et le nom du tube de requêtes du client à déconnecter + if (sscanf(ligne, "%s %*s %*s %*s %*s %s", vlogin, tube) == 2) + { + //si le login est le bon on mémorise le nom du tube + if (strcmp(vlogin,login) == 0) + mp = strdup(tube); + } + else break; + } + //fermeture du fichier de log + fclose (logs); + //envoie le message de déconnexion au serveur => celui ci va en théorie faire + //quitter le client. J'ai pas cherché à débugger ce truc. J'avais d'autres choses + //à faire dans ce programme ... + if (mp[strlen(mp) - 1] == '\n') + mp[strlen(mp) - 1] = '\0'; + if ((deconnexion = fopen(mp, "w")) == NULL) + fprintf (stdout,"Le client n'est plus connecté\n"); + else fprintf(deconnexion, "DISCONNECT\n"); + //Rq : quel feinteur ce Meta Serveur ... il se fait passer pour le client :-) + } + + //Aide + //ça sert pour le gars qui va copier le logiciel à la place de l'acheter. Au moins il saura s'en servir sans + //avoir la doc. + //d'un côté qui va acheter ça ? cça sera même pas en vente. + else if ((strcmp(type_requete,"?") == 0)||(strcmp(type_requete,"HELP") == 0)) + { + //affichage des commandes possibles + fprintf(stdout,"ADD : ajoute un client\nSUPPR : supprime un client\nCHPW : change le mot de passe\nCRYPT : crypte le mot et l'affiche\nLAST : affiche la dernière connexion du client\nLOGS : affiche toutes les connexions du client\nKILL : déconnecte un client\nDISCONNECT : déconnecte le serveur\n? ou HELP : affiche les commandes\n"); + } + + //L'utilisateur a tapé nimp + //on reste quand même gentil avec lui. Si j'avais eu le temps j'aurais pu + //mettre un truc sympa à ce niveau là. Genre un générateur de messages avec un tableau de messages + //et un tirage aléatoire du message à afficher. Mais bon... + else + { + fprintf(stderr,"Commande inconnue\n"); + continue; + } + + position = 0; + + } + + //ferme la thread d'analyse de connexion de façon à ce qu'elle finisse son travail + + //ouvre le tube de connexion + if ((fd = open (TUBE_CONNEXION, O_WRONLY)) < 0) + fprintf (stderr, "Tube déjà supprimé\n"); + else + { + if ((deconnexion = fdopen (fd, "w")) == NULL) + perror("Ouverture du tube de connexion"); + else + { + //envoi du message de fin à la requête d'analyse des demandes de connexions + fprintf (deconnexion, "FIN\nFIN\nFIN\n"); + //ferme le tube + fclose(deconnexion); + } + } + + //libération des chaînes (mais pas des esclaves :-( + //désolé mais je ne suis pas venu ici pour affranchir les esclaves + // Qui Gon Jinn (Star Wars Episode I : La Menace Fantôme) + free (ligne); + free (login); + free (mp); + free (type_requete); + + //destruction du tube de connection + unlink(tubeconnexion); + + return(0); +} + +//********************************************************************************************* +//vérification du mot de passe +//cette thread reçoit le login et le mot de passe crypté et va vérifier si le client peut se connecter +//********************************************************************************************* +void * verif (void * params) +{ + FILE *reponse; + int fd; + char tuberequetes[TAILLE_STR]; + + int rep; + + verif_pw_t * v_pw; + + if ((v_pw = (verif_pw_t *) malloc (sizeof(verif_pw_t))) == NULL) + { + fprintf (stderr,"Problème d'allocation mémoire\n"); + pthread_exit(NULL); + } + + //récupération des paramètres de la thread + v_pw = (verif_pw_t *)params; + + //vérifie le login et le mot de passe + rep = verifier ( strdup(crypt(v_pw->login, CLE)) , strdup(crypt(v_pw->mp, CLE)) ); + + //ouverture du tube de réponse + if ((fd = open (v_pw->tuberep, O_WRONLY)) < 0) + { + perror("Impossible d'ouvrir le rube de reponse"); + pthread_exit(NULL); + } + reponse = fdopen (fd, "w"); + + //si le client n'est pas autorisé à se connecter + if (rep == DECONNECTE) + { + //envoi du message négatif + fprintf(reponse, "non\n"); + //fermeture du tube de réponse + fclose (reponse); + } + else //rep == CONNECTE + { + //recopiage du nom du tube et création de celui-ci + sprintf( tuberequetes, "%s.R", v_pw->tuberep); + //creation du tube de requetes + if (mkfifo (tuberequetes, 0666) != 0) + { + fprintf (stderr, "Impossible de créer le tube\n"); + exit (1); + } + + //crée le serveur dédié + switch(fork()) + { + case -1 : //y'a eu un binz... merde + fprintf(stderr, "Erreur à la création du Serveur dédié\n"); + fprintf(reponse, "non\n"); //désolé mais y'a pas moyen + fclose(reponse); + unlink(tuberequetes); + case 0 : //tout va bien, ça roule Raoul + //lancement de la procédure du serveur dédié + serveurdedie(v_pw->tuberep, tuberequetes, v_pw->login); + //quitte la thread après avoir effectué le travail + pthread_exit(NULL); + } + } + //le processus père (la thread) peut finir tranquillement + pthread_exit(NULL); +} + +//********************************************************************************************* +//fonction qui vérifie le login et le mot de passe +//le login et le mot de passe sont cryptés, comme ceux dans la liste +//"liste" pasée dans la structure paramètre. +//********************************************************************************************* +int verifier (char * login, char * mp) +{ + FILE *liste; + + char *vl; //login de la liste \_ ceux auxquels on va comparer + char *vmp; //mot de passe de la liste / celui en paramètres + + int rep = DECONNECTE; //état du client + int filedes; + + //allocation des chaines de login, mp + if ((vl = (char *) malloc (TAILLE_STR * sizeof(char))) == NULL) + { fprintf (stderr,"Problème d'allocation mémoire\n"); + exit(1); + } + + if ((vmp = (char *) malloc (TAILLE_STR * sizeof(char))) == NULL) + { + fprintf (stderr,"Problème d'allocation mémoire\n"); + exit(1); + } + + //ouvre le fichier de mots de passe (cryptés) + if ((filedes = open(LISTE_PASS,O_RDONLY)) < 0) + { + fprintf (stderr,"Problème à l'ouverture du fichier de mots de passe\n"); + exit(0); + } + //ouverture du flux sur le fichier de mots de passe + if ((liste = fdopen(filedes, "r")) == NULL) + { + fprintf (stderr,"Problème à l'ouverture du descripteur de fichiers de mots de passe\n"); + close(filedes); + exit(0); + } + + //lecture du fichier des mots de passe ligne par ligne + while ( fscanf(liste, "%s %s",vl,vmp) == 2) + { + //si le login est bon il faut vérifier le mot de passe + if ( strcmp(login, vl) == 0 ) + //si le mot de passe est bon on marque le client comme connecté + if ( strcmp(mp, vmp) == 0) + { + fprintf (stdout,"Mot de passe OK\n"); + rep = CONNECTE; + break; + } + //sinon ça sert à rien de chercher dans la suite de la liste + else + { + rep = DECONNECTE; + break; + } + } + //fermeture du fichier de mots de passe + fclose (liste); + + //libère les pointeurs : ouaaaaaais + free(vl); + free(vmp); + + //on renvoie la réponse... ça peut servir ... + return (rep); +} + +//************************************************************************************** +//ANA_CONNECTION +//cette thread crée le tube de connexion et l'écoute en boucle jusqu'à ce que le Meta Serveur lui dit d'arrêter +//************************************************************************************* +void * ana_connexions (void * inutile) +{ + FILE * connexion; + int fd; + char tuberep[TAILLE_STR]; + char login[TAILLE_STR]; + char mp[TAILLE_STR]; + + pthread_t verif_pw; + verif_pw_t *v_pw; + //allocation de la mémoire pour les paramètres + if ((v_pw = (verif_pw_t *) malloc (sizeof(verif_pw_t))) == NULL) + { + fprintf (stderr,"Problème d'allocation mémoire\n"); + pthread_exit((void *)0); + } + + //supprime le tube de connexion au cas ou il existe déjà !!! + //ça arrive le plantage... Même si c'est pas censé tourner sur Windows + unlink(tubeconnexion); + + //crée le tube de connexion + if (mkfifo (tubeconnexion, 0666 |O_CREAT) != 0) + { + fprintf(stderr, "Impossible de créer le tube\n"); + exit(1); + } + + //ouvre le tube de connexion + fd = open (tubeconnexion, O_RDWR); + if ((connexion = fdopen(fd, "r")) == NULL) + { + perror("Erreur à l'ouverture du tube\n"); + close(fd); + unlink(tubeconnexion); + exit(1); + } + + //on analyse les demandes de connexion + while (1) + { + //récupère le nom du tube de réponse + if (fgets (tuberep, TAILLE_STR, connexion) == NULL) + { + perror("fgets"); + break; + } + //on enlève le caractère de fin de ligne qui fait chier + if (tuberep [strlen (tuberep) - 1] == '\n') + tuberep [strlen (tuberep) - 1] = '\0'; + + //récupère le login + if (fgets (login, TAILLE_STR, connexion) == NULL) + { + perror("fgets"); + break; + } + //on fait comme avant + if (login [strlen (login) - 1] == '\n') + login [strlen (login) - 1] = '\0'; + + //récupère le mot de passe + if (fgets (mp, TAILLE_STR, connexion) == NULL) + { + perror("fgets"); + break; + } + //toujours la même + if (mp [strlen (mp) - 1] == '\n') + mp [strlen (mp) - 1] = '\0'; + + //quitte si c'est le meta qui envoie un message d'explosion + if (strcasecmp (tuberep, "FIN") == 0) + { + fprintf(stdout, "quitte\n"); + break; + } + + //on enregistre les paramètres de la thread + v_pw->tuberep = strdup(tuberep); + v_pw->login = strdup (login); + v_pw->mp = strdup(mp); + + fprintf(stdout, "\nVérification du mot de passe de %s\n", login); + + //vérification du login et du mot de passe + pthread_create (&verif_pw, NULL, verif, (void *)v_pw); + } + //ferme le tube de de connexion + fclose(connexion); + + //on quitte la thread dans les règles + pthread_exit (NULL); +} + +//********************************************************************************************* +//chercher : cherche "login" dans la liste des mots de passe "liste" +//renvoie 1 si il y est et 0 sinon +//********************************************************************************************* +int cherchermp (const char * login, const char * liste) +{ + FILE *lmp; + + char *vlogin; //login de la table + char *ligne; //ligne de la table + + //ouverture du fichier + if ((lmp = fopen(liste, "r")) == NULL) //écriture + { + perror("ouverture du fichier de mots de passe"); + return(0); + } + + //allocation patati patata + if ((vlogin = (char *) malloc (TAILLE_STR * sizeof(char))) == NULL) + { + fprintf (stderr,"Problème d'allocation mémoire\n"); + return(0); + } + if ((ligne = (char *) malloc (TAILLE_STR * sizeof(char))) == NULL) + { + fprintf (stderr,"Problème d'allocation mémoire\n"); + return(0); + } + + //on lit une ligne du fichier de mots de passe + while (fgets(ligne, TAILLE_STR, lmp) != NULL) + //on enregistre le login qui s'y trouve + if (sscanf(ligne, "%s %*s",vlogin) == 1) + { + //on le compare avec celui qui est donné en argument + if (strcmp(vlogin,login) == 0) + { + //c'est le bon !!! + //la classe + + //libération de la chaîne allouée + free(vlogin); + free(ligne); + + //fermeture du fichier + fclose(lmp); + //on a trouvé + return (1); + } + } + else break; //il n'y a plus rien à lire d'intéressant + + //libération de la chaîne allouée + free(vlogin); + free(ligne); + + //fermeture du fichier + fclose(lmp); + return (0); +} + +//********************************************************************************************* +//inserer : insère "login" avec son mot de passe "mp" dans la liste +//de mots de passe "liste" +//renvoie 1 si le login a été inséré et 0 sinon +//********************************************************************************************* +int inserermp (const char * login, const char * mp, const char * liste) +{ + FILE *lmp; + char *ligne; //ligne de la table + + //allocation mémoire + if ((ligne = (char *) malloc (TAILLE_STR * sizeof(char))) == NULL) + { + fprintf (stderr,"Problème d'allocation mémoire\n"); + return(0); + } + + //ouverture du fichier des mots de passe en ajout + if ((lmp = fopen(liste, "a+")) == NULL) //écriture + { + perror("ouverture du fichier de mots de passe"); + return(0); + } + + //vérification que le login est unique + if (cherchermp(login, liste) == 1) + { + fprintf(stderr, "login déjà existant\n"); + + //et on ferme le fichier + fclose(lmp); + + return(0); + } + + //insertion du nouveau login + fprintf(lmp, "%s %s\n",login, mp); + //on s'assure que ça a été rajouté + fflush(lmp); + + //et on ferme le fichier + fclose(lmp); + + return (1); +} + +//********************************************************************************************* +//supprimer : supprime le login "login" ainsi que le mot de passe +//associé de la liste de mots de passe "liste" +//retourne 1 si il n'y a pas eu d'erreurs et 0 sinon +//********************************************************************************************* +int supprimermp (const char * login, const char * liste) +{ + FILE *lmp; //liste de mots de passe + FILE *tmpfile; //fichier temporaire + + char *tmp_login; //login temporaire + char *tmp_mp; //mot de passe temporaire + char *ligne; //ligne de la table + int c; //caractère temporaire pour la copie + + int retour = 0; + + //allocation mémoire + if ((ligne = (char *) malloc (TAILLE_STR * sizeof(char))) == NULL) + { + fprintf (stderr,"Problème d'allocation mémoire\n"); + return(0); + } + + //allocation des chaînes + if ((tmp_login = (char *) malloc (TAILLE_STR * sizeof(char))) == NULL) + { + fprintf (stderr,"Problème d'allocation mémoire\n"); + exit(1); + } + if ((tmp_mp = (char *) malloc (TAILLE_STR * sizeof(char))) == NULL) + { + fprintf (stderr,"Problème d'allocation mémoire\n"); + exit(1); + } + + //création du fichier temporaire + if ((tmpfile = fopen("tmpfile", "w")) == NULL) + { + perror("création du fichier temporaire"); + return(0); + } + + //ouverture de la liste des mots de passe lecture + if ((lmp = fopen(liste, "r")) == NULL) + { + perror("ouverture du fichier de mots de passe en lecture"); + return(0); + } + + //recherche du login a supprimer + while (fgets(ligne, TAILLE_STR, lmp) != NULL) + if (sscanf(ligne, "%s %s",tmp_login, tmp_mp) == 2) + { //Si ce n'est pas le bon login, rajouter la ligne au fichier temporaire + if (strcmp(tmp_login, login) != 0) + { + //insertion du login et du mot de passe dans le fichier temporaire + //car c'était pas celui à supprimer + fprintf(tmpfile, "%s %s\n",tmp_login, tmp_mp); + } + else + //sinon le login a supprimer y était on continue pour effacer les éventuels doublons + //cela peut arriver si quelqu'un modifie le fichier manuellement + retour = 1; + } + else break; + + //fermeture des flux + fclose(lmp); + fclose(tmpfile); + + //ouverture des flux pour la copie + if ((lmp = fopen(liste, "w")) == NULL) + { + perror("ouverture du fichier de mots de passe en écriture"); + return(0); + } + if ((tmpfile = fopen("tmpfile", "r")) == NULL) + { + perror("ouverture du fichier temporaire en lecture"); + return(0); + } + + //copie de tmpfile dans lmp + while ((c = getc(tmpfile)) != EOF) + putc(c, lmp); + + //libération des chaines + free(tmp_login); + free(tmp_mp); + + //fermeture des flux + fclose(lmp); + fclose(tmpfile); + + //suppression du fichier temporaire + unlink("tmpfile"); + + return retour; +} diff --git a/partie1/sources/exs.h b/partie1/sources/exs.h new file mode 100644 index 0000000..be56098 --- /dev/null +++ b/partie1/sources/exs.h @@ -0,0 +1,43 @@ +#ifndef _EXS_ + #define _EXS_ + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + + #include "serveurdedie.h" + #include "defines.h" + + + //********************************************************************************************* + //structures de données + //********************************************************************************************* + typedef struct verif_pw //pour 'verif' + { + char *login; //login crypté + char *mp; //mot de passe crypté + const char *tuberep; //tube de réponse du client + }verif_pw_t; + + //********************************************************************************************* + //fonctions + //********************************************************************************************* + void * ana_connexions (void *); + void * verif (void *); //verif_pw_t + int verifier (char *, char *); //login mp + int cherchermp (const char *, const char *); //login liste + int inserermp (const char *, const char *, const char *); //login mp liste + int supprimermp (const char *, const char *); //login liste + + //********************************************************************************************* + //Variables + //********************************************************************************************* + static char * tubeconnexion = TUBE_CONNEXION; + +#endif diff --git a/partie1/sources/makefilec b/partie1/sources/makefilec new file mode 100644 index 0000000..9508ad3 --- /dev/null +++ b/partie1/sources/makefilec @@ -0,0 +1,8 @@ +COMP = gcc +OBJ = exc.o + +eXc : $(OBJ) + $(COMP) -lpthread -lcrypt -o eXc $(OBJ) + +exc.o : + $(COMP) -c exc.c diff --git a/partie1/sources/makefiles b/partie1/sources/makefiles new file mode 100644 index 0000000..09a5fb3 --- /dev/null +++ b/partie1/sources/makefiles @@ -0,0 +1,17 @@ +COMP = gcc +RM = rm -f +OBJ = exs.o verrou.o tables.o serveurdedie.o + +eXs : $(OBJ) + $(COMP) -lpthread -lcrypt -Wall -o eXs $(OBJ) + +nettoyage : $(OBJ) + $(RM) $(OBJ) + +exs.o : defines.h + +serveurdedie.o : defines.h tables.c + +tables.o : verrou.c + +verrou.o : diff --git a/partie1/sources/mks b/partie1/sources/mks new file mode 100644 index 0000000..d89479a --- /dev/null +++ b/partie1/sources/mks @@ -0,0 +1,2 @@ +make -f makefiles +make -f makefilec diff --git a/partie1/sources/serveurdedie.c b/partie1/sources/serveurdedie.c new file mode 100644 index 0000000..aee6257 --- /dev/null +++ b/partie1/sources/serveurdedie.c @@ -0,0 +1,389 @@ +#include "serveurdedie.h" + +//********************************************************************************************* +//code du SERVEUR DEDIE +//********************************************************************************************* +void serveurdedie (const char *tuberep, const char *tubereq, const char *login) +{ + FILE *reponse; + FILE *requete; + FILE *logs; + + char ligne[TAILLE_STR]; + + int filedes; + + //variables pour les fonctions de temps + time_t temps; + struct tm *tm; + + //liste des tables chargées en mémoire + ls_table_t *liste_tb_ch = init_liste_tb_ch(); + + //variable des threads (analyse des requêtes) + pthread_t analyse; + ana_req_t *params; + + //allocation des paramètres de la thread + if ((params = (ana_req_t *) malloc (sizeof(ana_req_t))) == NULL) + { + fprintf (stderr,"Problème d'allocation mémoire\n"); + return((void)NULL); + } + if ((params->req = (char *) malloc (TAILLE_STR * sizeof(char))) == NULL) + { + fprintf (stderr,"Problème d'allocation mémoire\n"); + free(params); + return((void)NULL); + } + if ((params->tables = (char *) malloc (TAILLE_STR * sizeof(char))) == NULL) + { + fprintf (stderr,"Problème d'allocation mémoire\n"); + free(params); + free(params->req); + return((void)NULL); + } + + //ouverture du tube de réponse en écriture + if ((filedes = open (tuberep, O_WRONLY)) < 0) + { + perror ("Impossible d'ouvrir le tube de reponse"); + free(params->tables); + free(params->req); + free(params); + return ((void)NULL); + } + reponse = fdopen (filedes, "w"); + + //envoi du nom du tube de réponses : c'est la réponse à la demande de connexion du client + fprintf (reponse, "%s\n", tubereq); + //ferme le tube de réponse + fclose (reponse); + + //Ajoute les informations de la connection du client dans le fichier de logs + + //ouvre le fichier de logs + if ((logs = fopen(LOG_FILE, "a+")) == NULL) + { + fprintf (stderr,"Problème à l'ouverture du descripteur de fichiers de mots de passe\n"); + return((void)NULL); + } + time(&temps); + tm = localtime(&temps); + //ajoute jj/mm/aa XXh XXmin XXs + fprintf(logs, "%-10s %02d/%02d/%02d %02dh %02dmin %02ds %s\n", login, tm->tm_mday, tm->tm_mon+1, tm->tm_year %100, tm->tm_hour, tm->tm_min, tm->tm_sec, tubereq); + //fermeture du fichier de log + fclose (logs); + + //imprime un nouveau prompt sur la console du meta serveur + fprintf (stdout, PROMPT); + fflush(stdout); + + //ouvre le tube de requêtes en lecture + if ((filedes = open (tubereq, O_RDONLY)) < 0) + { + perror ("Impossible d'ouvrir le tube de requetes"); + return ((void)NULL); + } + requete = fdopen (filedes, "r"); + + //détermine les paramètres inchangeant de la thread + params->tuberep = strdup(tuberep); //nom du tube de réponse + params->liste = liste_tb_ch; //liste des tables chargées en mémoire + sprintf(params->tables,"%s.tables", login); //nom du fichier où se trouve la liste des tables + + //lit le tube de requêtes en boucle + while(1) + { + //lecture de la requête + if (fgets(ligne, TAILLE_STR, requete) != NULL) + { + //si c'est une requête de déconnexion, il s'en charge lui même + //ça sert à rien de créer une thread pour ça parce qu'il faudra + //la fermer etc et puis c'est la fin alors on fait le tout pour le tout + if (strcmp(ligne,"DISCONNECT\n") == 0) + { + //envoi du message de fin au client + + //ouvre le tube de réponse en écriture + if ((filedes = open (tuberep, O_WRONLY)) < 0) + break; + else + { + if ((reponse = fdopen (filedes, "w")) != NULL ) + { + //envoi du message de fin. + fprintf(reponse,"FIN\n"); + fclose(reponse); + } + } + break; + } + //détermine la ligne à analyser par la thread + sprintf(params->req, "%s", ligne); + + //lance la thread d'analyse + pthread_create(&analyse, NULL, analyser, (void *)params); + } + } + //enregistre les tables chargées en mémoire et les décharge + sprintf(ligne, "%s.tables.data", login); + decharger_tables (liste_tb_ch, ligne); + + //libère les pointeurs + free(params->tuberep); + free(params->tables); + free(params->req); + free(params); + + //ferme le tube de requêtes + fclose(requete); + + //détruit le tube : boum + //comme en Irak : on pète les pipelines ! + unlink(tubereq); + + //et on sort gentillement, les mains sur la tête + return ((void)NULL); +} + +//********************************************************************************************* +//analyse d'une requête +//dans un premier temps la thread lit le premier mot de la requête +//afin d'identifier son type (DISCONNECT, SELECT, CREATE, UPDATE, ...) +//DISCONNECT n'a aucun paramètre : il sert juste à dire que le client désire se déconnecter du système +//CREATE a un seul paramètre : le nom de la table à créer +//SELECT a quatre paramètres : le nom du champ et le nom de la table à afficher. Ainsi que le nom du champ et +//la valeur qu'il doit prendre pour que la ligne soit affichée +//UPDATE sert à modifier le champ d'une table. Il y a cinq arguments le nom de la table, le champ et la valeur +//à mettre là où champ2 = valeur2 +//********************************************************************************************* +void *analyser (void *params) +{ + FILE *reponse; + + char tuberep[TAILLE_STR]; //tube de réponse + char ligne[TAILLE_STR]; //ligne lue + char table[TAILLE_STR]; //paramètre table dans la requête + char champ[TAILLE_STR]; //paramètre champ dans la requête + char champ2[TAILLE_STR]; //paramètre 2e champ dans la requête + char valeur[TAILLE_STR]; //paramètre valeur dans la requête + char valeur2[TAILLE_STR]; //paramètre 2e valeur dans la requête + char type_requete[TAILLE_STR]; //type de requête effectuée + + char c[1]; + + int position,position1, position2; //"curseurs" de lecture sur la ligne de la requête + int filedes; //descripteur de fichier + int tableok = 0; //booléen définissant si la table est correctement définie (pour CREATE) + + table_t *tb; //table résultat + + //on récupère le nom du tube de réponse et la requête + sprintf(tuberep,"%s",((ana_req_t *)params)->tuberep); + sprintf(ligne,"%s",((ana_req_t *)params)->req); + + //ouverture du tube de reponse en écriture + if ( (filedes = open(tuberep, O_WRONLY)) < 0 ) + { + fprintf (stderr,"Impossible d'écrire dans le tube de réponse %s\n", tuberep); + pthread_exit((void *)NULL); + } + reponse = fdopen(filedes, "w"); + + //Détermination du type de la requête en analysant le premier mot + if (sscanf(ligne, "%s %n", type_requete, &position) !=1) + { + //Aucun mot n'a été tapé + fprintf(reponse,"Tapez une commande SVP\n"); + } + + //CREATE + else if (strcmp(type_requete,"CREATE") == 0) + { + //vérification des paramètres de la commande CREATE + if ((sscanf(&(ligne[position]), "%s %s %n", table, c, &position1) != 2)) + //le nombre d'arguments n'est pas bon + fprintf(reponse,"Utilisation : CREATE ( , ... , )\n"); + else + { + //vérifie que l'utilisateur n'a pas oublié la parenthèse avant la liste des noms de champs + if (strcmp( c, "(") != 0) + //le nombre d'arguments n'est pas bon + fprintf(reponse,"N'oubliez pas ( avant la liste des champs\n"); + else + { + //calcule la position du "curseur" de lecture de la chaine + position1 += position; + + //alloue la mémoire de la nouvelle table + if ((tb = allouer_table (table)) == NULL) + fprintf(stderr,"Impossible d'allouer la table\n"); + else + + //boucle qui va lire les champs + while(1) + { + //lecture d'un nom de champ + if (sscanf(&(ligne[position1]), "%s %n", champ, &position2) != 1) + { + //le nombre d'arguments n'est pas bon + fprintf(reponse,"Tapez un nom de champ\n"); + desallouer_table (tb); + break; + } + else + { + //calcule la position du "curseur" de lecture de la chaine + position2 += position1; + + //lecture du type de champ (et la virgule ou la parenthèse fermante) + if (sscanf(&(ligne[position2]), "%s %s %n", valeur, c, &position1) != 2) + { + //le nombre d'arguments n'est pas bon + fprintf(reponse,"Tapez un nom de type\n"); + desallouer_table (tb); + break; + } + else + { + //calcule la position du "curseur" de lecture de la chaine + position1 += position2; + //vérification du type + if ((strcmp(valeur,"INT") != 0 ) && (strcmp(valeur,"CHAR") != 0)) //vérifie si le type est bon + { + //le type n'est ni INT ni CHAR + fprintf(reponse,"Type inconnu : %s\n", valeur); + desallouer_table (tb); + break; + } + else + { + inserer_champ(tb, champ, valeur); + if (strcmp(c,")") == 0) //c'est la fin de la table + { + tableok = 1; + break; + } + else if (strcmp(c,",") != 0) //vérifie que le champ suivant vient après une virgule ! + { + //le champ ne se termine pas apr une virgule + fprintf(reponse,"Séparez les champs par une virgule et n'oubliez pas les espaces\n"); + desallouer_table (tb); + break; + } + } + } + } + } + //affiche un message si la table a bien été créée + if (tableok == 1) + { + //regarde si la table est en mémoire principale (l'index dans la table sera > 0 dans ce cas) + if (ch_table_dans_tables (tb->nom, ((ana_req_t *)params)->liste) >= 0) + { + fprintf(reponse,"la table %s existe déjà (ch)\n",table); //elle est même en mémoire ! + desallouer_table(tb); + } + else //la table n'est pas en mémoire principale + { + //cherche la table dans la liste des tables (si elle y est la fonction retourne le nom du fichier dans lequel + //elle se trouve. Donc si elle existe déjà, le résultat n'est pas NULL + if (ch_table_dans_liste (tb->nom, ((ana_req_t *)params)->tables) != NULL) + { + fprintf(reponse,"la table %s existe déjà(fich)\n",table); //elle n'est pas chargée mais c'est pas une raison + desallouer_table(tb); + } + else //la table n'existe pas ==> on peut l'ajouter + { + //ajoute la table dans la table des tables chargées en mémoire + if (ajouter_table_ds_tables (tb,((ana_req_t *)params)->liste, ((ana_req_t *)params)->tables) == -1) + fprintf(reponse,"impossible de charger la table %s en mémoire\n",table); + else + { + //inserer la table dans la liste des tables du client + sprintf(valeur2, "%s.data", ((ana_req_t *)params)->tables); + ins_table_dans_liste (strdup(tb->nom),((ana_req_t *)params)->tables, valeur2); + //envoie un message de confirmation de création + fprintf(reponse,"table %s créée\n",table); + } + } + } + } + } + } + } + + //SELECT + else if (strcmp(type_requete,"SELECT")==0) + { + //vérification du nombre d'arguments + if (sscanf(&(ligne[position]), "%s FROM %s WHERE %s = %s", champ, table, champ2, valeur) != 4) + //le nombre d'arguments n'est pas bon + fprintf(reponse,"Utilisation : SELECT FROM
WHERE = \n"); + else + { + //traitement de la requête + if ((tb = sel_champs(table, champ, champ2, valeur, ((ana_req_t *)params)->tables, ((ana_req_t *)params)->liste)) != NULL) + { + //affiche la table sur le tube de sortie + afficher_table (tb, reponse); + //désalloue la réponse + desallouer_table(tb); + } + else //le pointeur retourné est NULL ==> au moins un des paramètres est erroné + fprintf(reponse,"Paramètres erronés\n"); + } + } + + //UPDATE + else if (strcmp(type_requete,"UPDATE") == 0) + { + //vérification du nombre d'arguments + if (sscanf(&(ligne[position]), "%s SET %s = %s WHERE %s = %s", table, champ, valeur, champ2, valeur2) != 5) + //le nombre d'arguments n'est pas bon + fprintf(reponse,"Utilisation : UPDATE
SET = WHERE = \n"); + else + { + //traitement de la requête + if ((update_table(table, champ, champ2, valeur, valeur2, ((ana_req_t *)params)->tables, ((ana_req_t *)params)->liste)) == 1) + //envoie une confirmation sur le tube de réponse + fprintf(reponse,"Table %s mise à jour\n", table); + else + fprintf(reponse,"Paramètres erronés vérifiez les types des valeurs à changer\n"); + } + } + + //Aide + else if ((strcmp(type_requete,"?") == 0)||(strcmp(type_requete,"HELP") == 0)) + { + //vérification du nombre d'arguments + if (sscanf(&(ligne[position]), "%s", champ) == 1) + { + if (strcmp(champ,"CREATE") == 0) + fprintf(reponse,"CREATE
( , ... , ) : crée une table\n"); + else if (strcmp(champ,"SELECT") == 0) + fprintf(reponse,"SELECT FROM
WHERE = : affiche les champs d'une table sous certaines conditions\n"); + else if (strcmp(champ,"UPDATE") == 0) + fprintf(reponse,"UPDATE
SET = : modifie le champ n° d'une table\n"); + else if (strcmp(champ,"DISCONNECT") == 0) + fprintf(reponse,"DISCONNECT : se déconnecter du système\n"); + else + //les arguments sont pas les bons + fprintf(reponse,"Utilisation : HELP (ou ?) avec commande :\n- CREATE\n- SELECT\n- UPDATE\n- DISCONNECT\n"); + } + else + //le nombre d'arguments n'est pas bon + fprintf(reponse,"Utilisation : HELP (ou ?) avec commande :\n- CREATE\n- SELECT\n- UPDATE\n- DISCONNECT\n"); + } + + //L'utilisateur a tapé nimp + else + fprintf(reponse,"Commande inconnue\n"); + + //fermeture du tube de réponse + fclose(reponse); + + //Au revoir + pthread_exit((void *)NULL); +} diff --git a/partie1/sources/serveurdedie.h b/partie1/sources/serveurdedie.h new file mode 100644 index 0000000..f9828c1 --- /dev/null +++ b/partie1/sources/serveurdedie.h @@ -0,0 +1,35 @@ +#ifndef _SERDED_ + #define _SERDED_ + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + + #include "tables.h" + #include "defines.h" + + //********************************************************************************************* + //structures de données + //********************************************************************************************* + typedef struct //pour 'analyser' + { + char *req; //requete + char *tuberep; //tube de réponse + ls_table_t *liste; //liste des tables du client chargées en mémoire + char *tables; //nom de la liste des tables du client + }ana_req_t; + + + //********************************************************************************************* + //fonctions + //********************************************************************************************* + void *analyser (void *); //ana_req_t + void serveurdedie (const char *, const char *, const char *);//tuberep tubereq login + +#endif diff --git a/partie1/sources/tables.c b/partie1/sources/tables.c new file mode 100644 index 0000000..e89b5d8 --- /dev/null +++ b/partie1/sources/tables.c @@ -0,0 +1,1194 @@ +#include "tables.h" + +//***************************************************************************************** +//Code +//***************************************************************************************** + +//********************************************************************************************* +//Alloue une table +//prend en paramètre un nom de table et retourne un pointeur sur une table vide (sans champs et sans n-uplets) +//********************************************************************************************* +table_t * allouer_table (const char * tb) +{ + table_t * table; + //alloue la structure + if ( (table = (table_t *) malloc (sizeof (table_t))) == NULL) + { + fprintf(stderr, "erreur d'allocation de la table\n"); + return NULL; + } + //copie le nom + table->nom = strdup(tb); + //initialise le nombre de champs et le nombre de n-uplets + table->nbchamps = 0; + table->nbnuplets = 0; + + //initialise le verrou + init_verrou(&table->verrou); + + //retourne le pointeur sur la table + return (table); +} + +//********************************************************************************************* +//Désalloue une table +//prend en argument un pointeur sur la table à désallouer +//********************************************************************************************* +void desallouer_table (table_t * tb) +{ + int i,j; + + //bloque l'accès à la table + DownEcriture(&tb->verrou); + + //libère le nom de la table + free(tb->nom); + + //libération des champs + for (i=0 ; i < tb->nbchamps ; i++) + { + //libère le nom du champ + free(tb->champ[i].nom); + //libère le type du champ + free(tb->champ[i].type); + } + + //libération des n-uplets + for (i=0 ; i < tb->nbnuplets ; i++) + { + //pour chaque ligne supprime chaque champ + for (j=0 ; j < tb->nbchamps ; j++) + free(tb->ligne[i].donnees[j]); + + //détruit le verrou du n-uplet + detruire_verrou(&tb->ligne[i].verrou); + } + + //si il y avait des n-uplets, libère le pointeur sur le tableau de n-uplets + if (tb->nbnuplets > 0) + free(tb->ligne); + + //déverouille le verrou + Up(&tb->verrou); + + //détruit le verrou + detruire_verrou(&tb->verrou); + + //libère la structure + free(tb); +} + +//********************************************************************************************* +//Insère un champ dans une table +//prend en argument un pointeur sur une table, un nom et un type de champ +//renvoie un pointeur sur la table +//********************************************************************************************* +table_t * inserer_champ (table_t * table, char * champ, char * type) +{ + //verrouille la table + DownEcriture(&table->verrou); + + //incrémente le nombre de champs + table->nbchamps++; + + //vérifie si on ne dépasse pas le nombre max de champs + if (table->nbchamps > MAX_CHAMPS) + { + fprintf(stderr, "Trop de champs\n"); + + //remet le nombre de champs en place + table->nbchamps++; + + //déverrouille la table + Up(&table->verrou); + return NULL; + } + + //Met le nom et le type du champ dans le nouveau champ + table->champ[table->nbchamps -1].nom = strdup(champ); + table->champ[table->nbchamps -1].type = strdup(type); + + //déverouille la table + Up(&table->verrou); + + //retourne un pointeur vers la table + return table; +} + +//********************************************************************************************* +//Insère un n-uplet dans une table +//prend en argument un pointeur sur une table et une ligne +//renvoie 0 si le n-uplet n'a pas pu être ajouté et 1 sinon +//********************************************************************************************* +int inserer_nuplet(table_t * table, char * ligne) +{ + int i, j; + int position = 0; + int position2 = 0; + int valeur; + char champ[TAILLE_STR]; + char intvaleur[TAILLE_STR]; + + //vérouille la table + DownEcriture(&table->verrou); + + //incrémente le nombre de n-uplets + table->nbnuplets++; + + //si c'est le premier n-uplet il faut allouer un n-uplet + if (table->nbnuplets == 1) + if ((table->ligne = (nuplet_t *) malloc(sizeof(nuplet_t))) == NULL) + { + fprintf(stderr,"erreur à l'allocation d'un n-uplet\n"); + free(champ); + free(intvaleur); + //remet le nombre de n-uplets comme il était + table->nbnuplets--; + //déverouille la table + Up(&table->verrou); + return 0; + } + else + if ((table->ligne = (nuplet_t *) realloc(table->ligne, table->nbnuplets * sizeof(nuplet_t))) == NULL) + { + fprintf(stderr,"erreur à l'allocation d'un n-uplet\n"); + free(champ); + free(intvaleur); + //remet le nombre de n-uplets comme il était + table->nbnuplets--; + //déverouille la table + Up(&table->verrou); + return 0; + } + + //initialise le verrou du n-uplet + init_verrou(&table->ligne[table->nbnuplets - 1].verrou); + + //lecture des champs + for (i=0 ; i< table->nbchamps ; i++) + { + //si le champ suivant est un INT + if (strcmp(table->champ[i].type,"INT") == 0) + { + //lit un int + if (sscanf (&ligne[position],"%d %n", &valeur, &position2) !=1) + { + //c'était pas un INT + fprintf(stderr,"erreur à l'insertion d'un n-uplet\n"); + //libère les champs ajoutés + for (j=0 ; jligne[table->nbnuplets - 1].donnees[j]); + + //décrémente le nombre de n-uplets + table->nbnuplets--; + + free(champ); + free(intvaleur); + + //déverouille la table + Up(&table->verrou); + return 0; + } + //avance le "curseur" + position += position2; + + //ajoute la valeur dans le n-uplet + sprintf(intvaleur,"%d",valeur); + table->ligne[table->nbnuplets - 1].donnees[i] = strdup(intvaleur); + } + //si le champ suivant est un CHAR + else if (strcmp(table->champ[i].type,"CHAR") == 0) + { + //lit un champ + if (sscanf (&ligne[position],"%s %n", champ, &position2) !=1) + { + fprintf(stderr,"erreur à l'insertion d'un n-uplet\n"); + //libère les champs ajoutés + for (j=0 ; jligne[table->nbnuplets - 1].donnees[j]); + + //décrémente le nombre de n-uplet + table->nbnuplets--; + + free(champ); + free(intvaleur); + + //déverouille la table + Up(&table->verrou); + return 0; + } + + //avance le "curseur" + position += position2; + + //ajout de la donnée + table->ligne[table->nbnuplets - 1].donnees[i] = strdup(champ); + } + else //y'a une erreur de type dans la table elle même. Ca c'est pas bien + { + fprintf(stderr,"erreur de type\n"); + + //décrémente le nombre de n-uplets + table->nbnuplets--; + + free(champ); + free(intvaleur); + + //déverouille la table + Up(&table->verrou); + return 0; + } + } + + //déverouille la table + Up(&table->verrou); + + //retourne une réponse positive + return 1; +} + +//********************************************************************************************* +//Cherche la table passée en paramètre dans la liste des tables de l'utilisateur passée en argument +//retourne le nom du fichier contenant la table +//********************************************************************************************* +char *ch_table_dans_liste (const char * table, const char * liste) +{ + FILE *ls; + + char *vt; //nom de table lu dans le fichier + char *fichier; //nom du fichier où se trouve la table + char *ligne; //ligne de la table + + //ouverture de la liste des tables en lecture + if ((ls = fopen(liste, "r")) == NULL) + { + perror("ouverture du fichier de mots de passe"); + return NULL; + } + + //allocations + if ((vt = (char *) malloc (TAILLE_STR * sizeof(char))) == NULL) + { + fprintf (stderr,"Problème d'allocation mémoire\n"); + return NULL; + } + if ((ligne = (char *) malloc (TAILLE_STR * sizeof(char))) == NULL) + { + fprintf (stderr,"Problème d'allocation mémoire\n"); + return NULL; + } + if ((fichier = (char *) malloc (TAILLE_STR * sizeof(char))) == NULL) + { + fprintf (stderr,"Problème d'allocation mémoire\n"); + return NULL; + } + + //lit une ligne dans la liste + while (fgets(ligne, TAILLE_STR, ls) != NULL) + { + //enlève l'éventuel caractère de fin de ligne + if (ligne[strlen(ligne) - 1] == '\n') + ligne[strlen(ligne) - 1] = '\0'; + + //enregistre le nom de table et le nom de fichier + if (sscanf(ligne, "%s %s",vt, fichier) >= 0) + { + //compare les noms de tables + if (strcmp(vt,table) == 0) + { + //libération de la chaîne allouée + free(vt); + free(ligne); + + //fermeture du fichier + fclose(ls); + + //on retourne le nom du fichier contenant la table + return (fichier); + } + } + else break; //plus rien d'intéresssant à lire + } + + //libération de la chaîne allouée + free(vt); + free(ligne); + + //fermeture du fichier + fclose(ls); + + //retourne NULL : on n'a pas trouvé la table + return NULL; +} + +//********************************************************************************************* +//Cherche la table passée en paramètre dans les tables chargées en mémoire (pointées dans +//la table des tables passée en paramètre +//retourne -1 si la talbe n'est pas trouvée et son index sinon +//********************************************************************************************* +int ch_table_dans_tables (const char * table, ls_table_t * liste_tab) +{ + int i; + + //On pose le verrou en lecture sur la table + DownLecture (&liste_tab->verrou); + + //Section critique + for (i=0 ; i < liste_tab->nbtables ; i++) + { //si la table n'a pas été déchargée (ça arrive qu'elle soit déchargée avec decharger_tables) + if ( liste_tab->table[i] != NULL) + { + //si c'est la bonne table + if (strcmp( liste_tab->table[i]->nom, table) == 0) + { + //on relache le verrou + Up(&liste_tab->verrou); + + //on a trouvé : on retourne l'index de la table dans la liste des tables chargées + return(i); + } + } + } + + //on relache le verrou + Up(&liste_tab->verrou); + + //on a pas trouvé + return(-1); +} + +//********************************************************************************************* +//Ajoute la table dans la table des tables chargées en mémoire +//prend en argument un pointeur sur une table, une liste de tables et le nom du fichier contenant la table +//********************************************************************************************* +int ajouter_table_ds_tables (table_t * table, ls_table_t * liste_tab, const char * fichier) +{ + + //protection le la liste des tables en lecture pour lire le nombre de tables chargées + DownLecture(&liste_tab->verrou); + + //Si il y a trop de tables chargées, on en décharge une + if ( (liste_tab->nbtables + 1) > MAX_TABLES) + { + + //on relache le mutex sur la liste sinon le déchargement va bloquer + Up(&liste_tab->verrou); + + //on décharge une table + if (decharger_une_table (liste_tab, fichier) == 0) + return (-1); + + //on pose le verrou en écriture cette fois + DownEcriture(&liste_tab->verrou); + } + else + { + + //on relache le mutex de lecture + Up(&liste_tab->verrou); + + //et on le pose en écriture + DownEcriture(&liste_tab->verrou); + } + + //incrémentation du nombre de tables + liste_tab->nbtables++; + + //on fait pointer la nouvelle table de la liste sur la structure passée en param + liste_tab->table[liste_tab->nbtables - 1] = table; + + //déverouillage de la table + Up(&liste_tab->verrou); + + //on retourne l'index de la table dans la liste + return (liste_tab->nbtables - 1); + +} + +//********************************************************************************************* +//initialise une liste de tables +//retourne un pointeur sur une liste de tables +//********************************************************************************************* +ls_table_t * init_liste_tb_ch(void) +{ + ls_table_t * liste; + + //alloue la liste + if ((liste = (ls_table_t *)malloc(sizeof(ls_table_t))) == NULL) + { + fprintf(stderr, "erreur d'allocation mémoire\n"); + return NULL; + } + + //initialise le nombre de tables + liste->nbtables = 0; + + //initialise le verrou + init_verrou(&liste->verrou); + + //retourne un pointeur sur la liste + return (liste); +} + +//********************************************************************************************* +//Charge une table en mémoire. Retourne l'index de la table dans la liste des tables chargées en mémoire. +//retourne -1 si la table n'a pas pu être chargée +//********************************************************************************************* +int charger_table (const char * table, const char * liste, ls_table_t * tb) +{ + FILE *flux; + char *fichier; + int index; + + table_t * a_inserer; + + //allocation + if ((fichier = (char *) malloc (TAILLE_STR * sizeof(char))) == NULL) + { + fprintf (stderr,"Problème d'allocation mémoire\n"); + return (-1); + } + + //cherche le fichier dans lequel se trouve la table + if ((fichier = ch_table_dans_liste(table, liste)) == NULL) + { + //la table n'est pas dans la liste : on ne peut pas la charger + return (-1); + } + //recherche la table dans la liste des tables chargées en mémoire + if ((index = ch_table_dans_tables(table, tb)) != -1) + //retourne l'index où la table est déjà chargée + return (index); + + //ouverture du flux sur le fichier contenant la table + flux = fopen(fichier,"r"); + //recherche les tables les unes après les autres dans le fichier + while(1) + { + //charge la première table du flux + //on lit séquentiellement les tables dans le flux + if ((a_inserer = fichier2table (flux)) == NULL) + { + desallouer_table(a_inserer); + //fermeture du flux + fclose(flux); + return (0); + } + //si c'est la bonne table, on sort de la boucle + if (strcmp(a_inserer->nom,table) != 0) + break; + //sinon on désalloue et on recommence + else + desallouer_table(a_inserer); + } + + //fermeture du flux + fclose(flux); + + //a_inserer contient la table que nous voulons + //--> on l'ajoute dans la table des tables chargées en mémoire + if ((index = ajouter_table_ds_tables (a_inserer, tb, liste)) == -1) + { + fprintf(stderr, "erreur au chargement de la table %s\n",a_inserer->nom); + return(-1); + } + + //retourne la place de la table dans la table des tables + return (index); +} + +//********************************************************************************************* +//Lit la première table trouvée dans le flux et construit une structure contenant la table et renvoie un pointeur sur +//cette structure +//********************************************************************************************* +table_t * fichier2table (FILE * fichier) +{ + table_t * table; + char *nom; + char *ligne; + char *champ; + char *type; + int nbchamps, nbnuplets, i; + + //alloue les pointeurs + if ((nom = (char *) malloc (TAILLE_STR * sizeof(char))) == NULL) + { + fprintf (stderr,"Problème d'allocation mémoire\n"); + return ((table_t *)NULL); + } + if ((champ = (char *) malloc (TAILLE_STR * sizeof(char))) == NULL) + { + fprintf (stderr,"Problème d'allocation mémoire\n"); + free(nom); + return ((table_t *)NULL); + } + if ((type = (char *) malloc (TAILLE_STR * sizeof(char))) == NULL) + { + fprintf (stderr,"Problème d'allocation mémoire\n"); + free(nom); + free(champ); + return ((table_t *)NULL); + } + if ((ligne = (char *) malloc (TAILLE_STR * sizeof(char))) == NULL) + { + fprintf (stderr,"Problème d'allocation mémoire\n"); + free(nom); + free(champ); + free(type); + return ((table_t *)NULL); + } + + //lecture de la première ligne du flux + if (fgets(ligne,TAILLE_STR,fichier) == NULL) + { + free(nom); + free(champ); + free(type); + free(ligne); + return ((table_t *)NULL); + } + + //Lecture du nom de la table, du nombre de champs et de n-uplets + if (sscanf(ligne, "%s %d %d\n", nom, &nbchamps, &nbnuplets) !=3) + { + free(nom); + free(champ); + free(type); + free(ligne); + return ((table_t *)NULL); + } + + //allocation de la table + if ((table = allouer_table(nom)) == NULL) + { + fprintf (stderr,"Problème d'allocation de la table\n"); + free(nom); + free(champ); + free(type); + free(ligne); + return ((table_t *)NULL); + } + + //lit les champs + for (i=0 ; i < nbchamps ; i++) + { + //lecture du nom du champ et du type + if (fscanf(fichier, "%s %s\n", champ, type) !=2) + { + fprintf(stderr,"erreur à la lecture des champs\n"); + desallouer_table (table); + free(nom); + free(champ); + free(type); + free(ligne); + return ((table_t *)NULL); + } + //insère le champ + if (inserer_champ (table, champ, type) == 0) + { + fprintf(stderr,"erreur à l'insertion des champs\n"); + desallouer_table (table); + free(nom); + free(champ); + free(type); + free(ligne); + return ((table_t *)NULL); + } + } + + //lit les n-uplets + for (i = 0 ; i < nbnuplets ; i++) + { + //lecture d'un n-uplet + if (fgets(ligne, TAILLE_STR, fichier) == NULL) + { + fprintf(stderr,"erreur à la lecture des n-uplets\n"); + desallouer_table (table); + free(nom); + free(champ); + free(type); + free(ligne); + return ((table_t *)NULL); + } + //tradition oblige : on enlève l'éventuel caractère de fin de ligne + if (ligne[strlen(ligne) - 1] == '\n') + ligne[strlen(ligne) - 1] = '\0'; + + //insertion du nuplet dans la table + if (inserer_nuplet(table,ligne) == 0) + { + fprintf(stderr,"erreur à l'insertion des n-uplets\n"); + desallouer_table (table); + free(nom); + free(champ); + free(type); + free(ligne); + return ((table_t *)NULL); + } + } + + //libération ... + free(nom); + free(champ); + free(type); + free(ligne); + + //retourneun pointeru sur la table + return table; +} + +//********************************************************************************************* +//écrit les données de la table (y compris le nom, les champs etc..) dans le flux passé en paramètre +//********************************************************************************************* +int table2fichier (table_t * table, FILE * fichier) +{ + int i, j; + + //pose le verrou de la table en lecture + DownLecture(&table->verrou); + + //Enregistrement du nom de la table, du nombre de champs et de n-uplets + fprintf(fichier, "%s %d %d\n", table->nom, table->nbchamps, table->nbnuplets); + + //Enregistrement des champs et de leur type + for (i=0 ; i < table->nbchamps ; i++) + fprintf(fichier, "%s %s\n", table->champ[i].nom, table->champ[i].type); + + //enregistrement des n-uplets... + for (i = 0 ; i < table->nbnuplets ; i++) + { + //...champ par champ + for (j = 0 ; j < table->nbchamps ; j++) + { + //verouille le n-uplet en lecture + DownLecture(&table->ligne[i].verrou); + + //écriture de la donnée + fprintf (fichier, "%s ", table->ligne[i].donnees[j]); + + //déverouille le n-uplet + Up(&table->ligne[i].verrou); + } + //passe à la ligne à la fin du n-uplet + fprintf (fichier, "\n"); + } + + //relache le verrou sur la table + Up(&table->verrou); + + //retourne une réponse positive + return 1; +} + +//********************************************************************************************* +//Renvoie un pointeur sur une table issue de celle passée en paramètre. Le champ est le premier passé en paramètre +//et les n-uplets doivent satisfaire l'égalité champ2 = valeur dans la table d'origine pour figurer dans celle ci +//c'est le résultat de la requête : SELECT champ1 FROM table WHERE champ2 = valeur +//********************************************************************************************* +table_t * sel_champs(const char * table, const char * champ1, const char * champ2, const char * valeur, const char * liste, ls_table_t * tb) +{ + int index, i = 0; + int c1 = -1; + int c2 = -1; + char *ligne; + + //allocation (pas de chômage en tout cas parce qu'il va travailler le gaillard !) + if ((ligne = (char *) malloc (TAILLE_STR * sizeof(char))) == NULL) + { + fprintf (stderr,"Problème d'allocation mémoire\n"); + return NULL; + } + + //table contenant le résultat de la requête + table_t * table_resultat; + + //allocation de table résultat + table_resultat = allouer_table("resultat"); + + //recherche de la table + if ((index = charger_table (table, liste, tb)) == -1) + { + //la table n'existe pas + free(ligne); + //on libère la table de résultat + desallouer_table(table_resultat); + + //retourne un pointeur nul + return NULL; + } + + //recherche des indices des champs en paramètre + for (i=0 ; i < tb->table[index]->nbchamps ; i++) + { + //est-ce le champ1 ? + if (strcmp(tb->table[index]->champ[i].nom,champ1) == 0) + c1 = i; + //est-ce le champ2 ? + if (strcmp(tb->table[index]->champ[i].nom,champ2) == 0) + c2 = i; + } + + //si au moins l'un des deux n'existe pas... + if ((c1 == -1) || (c2 == -1)) + { + //...on libère tout + free(ligne); + desallouer_table(table_resultat); + //on reourne un pointeur nul + return NULL; + } + + //ajout du champ1 dans la table + if ((table_resultat = inserer_champ (table_resultat, strdup(champ1),tb->table[index]->champ[c1].type)) == NULL) + { + fprintf(stderr, "erreur à l'insertion du champ1\n"); + free(ligne); + desallouer_table(table_resultat); + } + + //recherche des enregistrement tels que "champ2 = valeur" + + //on parcourt tous les nuplets de la table + for (i=0 ; i < tb->table[index]->nbnuplets ; i++) + { + //on compare les données du champ2 avec valeur + if (strcmp(tb->table[index]->ligne[i].donnees[c2], valeur) == 0) + { + //si c'estbon, on ajoute le nuplet à la table + sprintf(ligne,"%s %s",tb->table[index]->ligne[i].donnees[c1], tb->table[index]->champ[c1].type); + if (inserer_nuplet(table_resultat, ligne) == 0) + fprintf(stderr,"erreur à l'insertion du n-uplet\n"); + } + } + + //on libère la ligne + free (ligne); + + //on retourne un pointeur vers la table de résultat + return table_resultat; +} + +//********************************************************************************************* +//Met à "valeur1" les champs "champ1" de la table "table" pous lesquels le champ "champ2" vaut "valeur2" +//retourne 1 si ça se passe bien et 0 sinon +//********************************************************************************************* +int update_table(const char * table, const char * champ1, const char * champ2, const char * valeur1, const char * valeur2, const char * liste, ls_table_t * tb) +{ + int index, i = 0; + int c1 = -1; + int c2 = -1; + + //recherche de la table + if ((index = charger_table (table, liste, tb)) == -1) + { + //la table n'existe pas + return 0; + } + + //recherche des indices des champs en paramètre + for (i=0 ; i < tb->table[index]->nbchamps ; i++) + { + //est-ce le champ1 ? + if (strcmp(tb->table[index]->champ[i].nom,champ1) == 0) + c1 = i; + //est-ce le champ2 ? + if (strcmp(tb->table[index]->champ[i].nom,champ2) == 0) + c2 = i; + } + + //si au moins un des champs n'existe pas + if ((c1 == -1) || (c2 == -1)) + //on repart la tête basse + return 0; + + //recherche des enregistrement tels que "champ2 = valeur2" + + //on parcourt les n-uplets + for (i=0 ; i < tb->table[index]->nbnuplets ; i++) + { + //on compare la valeur de champ2 avec valeur2 + if (strcmp(tb->table[index]->ligne[i].donnees[c2], valeur2) == 0) + { + //on regarde le type + //si c'est un INT + if (strcmp(tb->table[index]->champ[c1].type,"INT") == 0) + { + //on bloque la ligne en écriture + DownEcriture(&tb->table[index]->ligne[i].verrou); + + //on s'assure que le champ sera un INT, et on copie + sprintf(tb->table[index]->ligne[i].donnees[c1],"%d",atoi(valeur1)); + + //on relache le verrou + Up(&tb->table[index]->ligne[i].verrou); + } + else + { + //on bloque la ligne en écriture + DownEcriture(&tb->table[index]->ligne[i].verrou); + + //on recopie la donnée + sprintf(tb->table[index]->ligne[i].donnees[c1],"%s",valeur1); + + //on relache le verrou + Up(&tb->table[index]->ligne[i].verrou); + } + } + } + + //on renvoit une bonne nouvelle + return 1; +} + +//********************************************************************************************* +//Insère la table passée en paramètre dans la liste des tables de l'utilisateur passée en argument +//fichier désigne le fichier où est placée la table +//********************************************************************************************* +int ins_table_dans_liste (const char * table, const char * liste, const char * fichier) +{ + FILE *ls; + + char *vt; //nom de table lu dans le fichier + char *ligne; //ligne de la table + + //allocation + if ((vt = (char *) malloc (TAILLE_STR * sizeof(char))) == NULL) + { + fprintf (stderr,"Problème d'allocation mémoire\n"); + return 0; + } + if ((ligne = (char *) malloc (TAILLE_STR * sizeof(char))) == NULL) + { + fprintf (stderr,"Problème d'allocation mémoire\n"); + return 0; + } + + //ouverture de la liste en lecture / écriture + if ((ls = fopen(liste, "r+")) == NULL) + { + perror("ouverture du fichier des tables"); + return 0; + } + + //lit une ligne + while (fgets(ligne, TAILLE_STR, ls) != NULL) + //enregistre le nom de la table + if (sscanf(ligne, "%s %*s",vt) == 1) + { + //compare le nom de la table et celui du nom trouvé dans le fichier + if (strcmp(vt,table) == 0) + { + //fermeture du fichier + fclose(ls); + //libération de la chaîne allouée + free(vt); + free(ligne); + + //la table était déjà dans la liste --> on ne l'ajoute pas + return 0; + } + } + else break; + + //la table n'y est pas déjà -> on l'ajoute + fprintf(ls,"%s %s\n",table, fichier); + + //fermeture du fichier + fclose(ls); + + //libération de la chaîne allouée + free(vt); + free(ligne); + + //et on signale que la table a été ajoutée + return 1; +} + +//********************************************************************************************* +//affiche un table passée en paramètre sur le flux désigné +//********************************************************************************************* +void afficher_table (table_t * table, FILE * sortie) +{ + int i,j; + + //pose le verrou de la table en lecture + DownLecture(&table->verrou); + + //affiche le nom de la table + fprintf(sortie,"\nTable %s\n",table->nom); + + //affiche le haut du tableau + for (i=0 ; inbchamps ; i++) + fprintf(sortie, "_____________"); + fprintf(sortie,"_\n"); + + //affiche les noms des champs + for (i=0 ; inbchamps ; i++) + fprintf(sortie, "| %10s ",table->champ[i]); + fprintf(sortie,"|\n"); + + //affiche le milieu du tableau + for (i=0 ; inbchamps ; i++) + fprintf(sortie, "|------------"); + fprintf(sortie,"|\n"); + + //affiche les n-uplets + for (i=0 ; inbnuplets ; i++) + { + //verouille le n-uplet en lecture + DownLecture(&table->ligne[i].verrou); + + //affiche n-uplet par n-uplet + for (j=0 ; jnbchamps ; j++) + fprintf(sortie, "| %10s ",table->ligne[i].donnees[j]); + fprintf(sortie,"|\n"); + + //déverouille le n-uplet + Up(&table->ligne[i].verrou); + } + + //affiche le bas du tableau + for (i=0 ; inbchamps ; i++) + fprintf(sortie, "|------------"); + fprintf(sortie,"|\n"); + + //déverouille la table + Up(&table->verrou); +} + +//********************************************************************************************* +//décharge les tables de la liste passée en argument et les enregistre dans le fichier indiqué +//********************************************************************************************* +int decharger_tables (ls_table_t * tables, const char * fichier) +{ + FILE *fich_temp; + FILE *liste; + + table_t * table_temp; + + int index, i, test; + + char c; + + //lit les tables du fichier et regarde si elles sont chargées en mémoire. Si elles y sont on enregistre la version + //en mémoire sionon on enregistre la version qui était déjà dans le fichier + + //ouvre la liste en lecture + if ((liste = fopen(fichier,"r")) == NULL) + { + perror("lecture des données"); + return 0; + } + + //ouvre (et crée un fichier temporaire) en écriture + if ((fich_temp = fopen("fich_temp","w")) == NULL) + { + perror("lecture des données"); + fclose(liste); + return 0; + } + + //charge les tables du fichier + while ((table_temp = fichier2table (liste)) != NULL) + { + //si la table n'est pas chargée + if ((index = ch_table_dans_tables(table_temp->nom, tables)) == -1) + { + //on l'enregistre dans le fichier + if ((test = table2fichier(table_temp, fich_temp)) == 0) + { + perror("écriture de la table"); + fclose(liste); + fclose(fich_temp); + return 0; + } + } + else //la table est la table No index dans la liste des tables + { + //enregistrement de la table qui est en mémoire principale + //(écrasement de la table qui se trouvait dans le fichier) + if ((test = table2fichier(tables->table[index], fich_temp)) == 0) + { + perror("écriture de la table"); + fclose(liste); + fclose(fich_temp); + return 0; + } + //désallocation de la table + desallouer_table(tables->table[index]); + //met le pointeur à NULL + //pour éviter de la réenregistrer dans la phase suivante + tables->table[index] = NULL; + } + desallouer_table(table_temp); + } + + //enregistrement des nouvelles tables (elles sont juste en mémoire et pas dans un fichier) + for (i=0 ; i < tables->nbtables ; i++) + { + //si la table n'a pas été déchargée + if (tables->table[i] != NULL) + { + //enregistrement de la table + if ((test = table2fichier(tables->table[i], fich_temp)) == 0) + { + perror("écriture de la table"); + fclose(liste); + fclose(fich_temp); + return 0; + } + //désallocation de la table + desallouer_table(tables->table[i]); + //marque la table comme déchargée + tables->table[i] = NULL; + } + } + + //ferme les flux + fclose(liste); + fclose(fich_temp); + + //ouverture des flux pour la copie + if ((liste = fopen(fichier, "w")) == NULL) + { + perror("ouverture du fichier de mots de passe en écriture"); + return 0; + } + if ((fich_temp = fopen("fich_temp", "r")) == NULL) + { + perror("ouverture du fichier temporaire en lecture"); + fclose(liste); + return 0; + } + + //copie de fich_tmp dans liste + while ((c = getc(fich_temp)) != EOF) + { + putc(c, liste); + } + + //ferme les flux + fclose(liste); + fclose(fich_temp); + + //supprime le fichier temporaire + unlink ("fich_temp"); + + //retourne la réponse + return 1; +} + +//********************************************************************************************* +//décharge une table. L'algorithme utilisé enlève tout simplement la première table chargée +//puis décale les autres dans la table +//********************************************************************************************* +int decharger_une_table (ls_table_t * tables, const char * fichier) +{ + FILE *fich_temp; + FILE *liste; + + table_t * table_temp; + + int index, i, test; + + char c; + + //ouvre le fichier contenant les tables en lecture + if ((liste = fopen(fichier,"r")) == NULL) + { + perror("lecture des données"); + return 0; + } + + //ouvre (et crée) un fichier temporaire + if ((fich_temp = fopen("fich_temp","w")) == NULL) + { + perror("lecture des données"); + fclose(liste); + return 0; + } + + //charge les tables + while ((table_temp = fichier2table (liste)) != NULL) + { + //si la table n'est pas chargée + if ((index = ch_table_dans_tables(table_temp->nom, tables)) == -1) + { + //on la remet dans le fichier (en passant par le fichier temporaire) + if ((test = table2fichier(table_temp, fich_temp)) == 0) + { + perror("écriture de la table"); + fclose(liste); + fclose(fich_temp); + //Up(&tables->verrou); + return 0; + } + } + else //la table est la table No index dans la liste des tables + { + //si c'est la première table + if (index == 0) + { + //enregistrement de la table qui est en mémoire + if ((test = table2fichier(tables->table[index], fich_temp)) == 0) + { + perror("écriture de la table"); + fclose(liste); + fclose(fich_temp); + //Up(&tables->verrou); + return 0; + } + } + //désallocation de la table + desallouer_table(tables->table[index]); + //marque la table comme déchargée + tables->table[index] = NULL; + } + //désallocation de la table qui vient d'être chargée + desallouer_table(table_temp); + } + + //verrouille la liste des tables + DownEcriture(&tables->verrou); + + //décalage des tables dans la liste + for (i=0 ; i < tables->nbtables - 1; i++) + tables->table[i] = tables->table[i + 1]; + + //marque comme non lue la dernière table + tables->table[tables->nbtables - 1] = NULL; + tables->nbtables--; + + //on déverouille la liste + Up(&tables->verrou); + + //ferme les flux + fclose(liste); + fclose(fich_temp); + + //ouverture des flux pour la copie + if ((liste = fopen(fichier, "w")) == NULL) + { + perror("ouverture du fichier de mots de passe en écriture"); + return 0; + } + if ((fich_temp = fopen("fich_temp", "r")) == NULL) + { + perror("ouverture du fichier temporaire en lecture"); + fclose(liste); + return 0; + } + //copie de fich_tmp dans liste + while ((c = getc(fich_temp)) != EOF) + putc(c, liste); + + //ferme les flux + fclose(liste); + fclose(fich_temp); + + //supprime le fichier temporaire + unlink ("fich_temp"); + + //et donne une bonne réponse + return 1; +} diff --git a/partie1/sources/tables.h b/partie1/sources/tables.h new file mode 100644 index 0000000..3302713 --- /dev/null +++ b/partie1/sources/tables.h @@ -0,0 +1,77 @@ +//***************************************************************************************** +//Includes +//***************************************************************************************** + +#ifndef _TABL_ + #define _TABL_ + #include + #include + #include + #include + + #include "defines.h" + #include "verrou.h" + + #define TAILLE_STR 128 + #define TAILLE_INT sizeof(int) + #define TAILLE_CHAR (10*sizeof(char)) + + //***************************************************************************************** + //Types + //***************************************************************************************** + typedef struct champ + { + char *nom; //nom du champ + char *type; //type de la donnée (restreint à INT et CHAR) + }champ_t; + + typedef struct nuplet + { + verrou_t verrou; //verrou protégeant l'accès à la ressource + char *donnees[MAX_CHAMPS]; //données de l'enregistrement + }nuplet_t; + + typedef struct table + { + char *nom; //nom de la table + int nbchamps; //nombre de champs dans la table (colonnes) + int nbnuplets; //nombres de N-uplets de la table (lignes) + verrou_t verrou; //verrou protégeant l'accès à la table + champ_t champ[MAX_CHAMPS]; //définition des champs + nuplet_t * ligne; //enregistrements + }table_t; + + typedef struct ls_table + { + int nbtables; //nombre de tables chargées en mémoire + verrou_t verrou; //verrous protégeant l'accès à la table + table_t * table[MAX_TABLES]; //pointeurs sur les tables chargées en mémoire + }ls_table_t; + + //***************************************************************************************** + //fonctions + ///**************************************************************************************** + + table_t * allouer_table (const char *); //nom de la table //alloue la structure d'une table + void desallouer_table (table_t *); //table //désalloue une table, les champs ... + table_t * inserer_champ (table_t *, char *, char *); //Table, Champ, Type //Insère un champ dans une table + int inserer_nuplet(table_t *, char *); //Table, ligne //Insère un n-uplet dans une table + + ls_table_t * init_liste_tb_ch(void); //initialise et alloue une liste de tables + + char * ch_table_dans_liste (const char *, const char *); //nom table, liste //Cherche une table dans une liste de tables + int ch_table_dans_tables (const char *, ls_table_t *); //nom table, table tables //Cherche une table dans les tables chargées + int ajouter_table_ds_tables (table_t *, ls_table_t *, const char * ); //table, liste, tables //ajoute une table dans la table des tables chargées + int charger_table (const char *, const char *, ls_table_t *); //table, liste, tab de tab //charge une table en mémoire + + table_t * fichier2table (FILE *); //flux //prend la première table du flux et la met dans une structure + int table2fichier (table_t *, FILE *); //table, fichier //met la talbe dans le flux + + table_t * sel_champs(const char *, const char *, const char *, const char *, const char *, ls_table_t *); //voir fichier .c + + int ins_table_dans_liste (const char *, const char *, const char *); //table, liste, fichier //insère la table dans la liste + + void afficher_table (table_t *, FILE *); //table, flux //affiche la table sur le flux + int decharger_tables (ls_table_t *, const char *); //liste, tables //décharge et enregistre les tables du client + int decharger_une_table (ls_table_t *, const char *); //liste, tables //décharge et enregistre la première table du client +#endif diff --git a/partie1/sources/verrou.c b/partie1/sources/verrou.c new file mode 100644 index 0000000..37e2728 --- /dev/null +++ b/partie1/sources/verrou.c @@ -0,0 +1,125 @@ +#include "verrou.h" + +//********************************************************************************************* +//DownLecture(&verrrou) : pose le verrou en lecture (NB_LECT_MAX lecteurs permis en même temps) +//********************************************************************************************* +void DownLecture (verrou_t* verrou) +{ + //bloque l'accès à la structure + pthread_mutex_lock(&verrou->mutex); + + //tant qu'il y a un écrivain en SC ou 3 lecteurs (NB_LECT_MAX) ou qu'il y a des ecrivains + //en attente d'écriture + while (verrou->verouilles < 0 || verrou->verouilles >= NB_LECT_MAX || verrou->ecrivains > 0) + { + //incrémente le nombre de lecteurs en attente de lecture + verrou->lecteurs++; + //relache le mutex en attente de cond_r + pthread_cond_wait(&verrou->cond_r, &verrou->mutex); + //décrémente le nombre de lecteurs en attente de lecture + verrou->lecteurs--; + } + //incrémente le nombre de lecteurs en section critique + verrou->verouilles++; + //relache le mutex ==> un autre processus pourra tenter d'entrer + pthread_mutex_unlock(&verrou->mutex); +} + +//********************************************************************************************* +//DownEcriture(&verrrou) : pose le verrou en écriture (aucun lecteur ou autre écrivain n'est permis) +//********************************************************************************************* +void DownEcriture (verrou_t* verrou) +{ + //bloque l'accès à la structure + pthread_mutex_lock(&verrou->mutex); + //tant qu'il y a un écrivain ou des lecteurs en SC + while (verrou->verouilles != 0) + { + //incrémente le nombre d'écrivains en attente de lecture + verrou->ecrivains++; //permet de privilégier les écrivains + //relache le mutex en attente de cond_w + pthread_cond_wait(&verrou->cond_r, &verrou->mutex); + //décrémente le nombre d'écriture en attente de lecture + verrou->ecrivains--; + } + //signifie qu'il y a un écrivain en section critique + verrou->verouilles = -1; + //relache le mutex ==> un autre processus pourra tenter d'entrer + pthread_mutex_unlock(&verrou->mutex); +} + +//********************************************************************************************* +//Up(&verrrou) : relache un verrou +//********************************************************************************************* +void Up (verrou_t* verrou) +{ + //permet d'éviter de réveiller plus de 3 lecteurs + //on stocke le min de verrou->lecteurs et NB_LECT_MAX + int i; + if (verrou->lecteurs >= NB_LECT_MAX) + i = NB_LECT_MAX; + else i = verrou->lecteurs; + + //bloque l'accès à la structure + pthread_mutex_lock(&verrou->mutex); + //Si c'est un écrivain qui déverouille + if (verrou->verouilles < 0) + { + //signifie qu'il n'y a plus personne en SC + verrou->verouilles = 0; + //réveille un écrivain si il y en a en attente + if (verrou->ecrivains > 0) + pthread_cond_signal(&verrou->cond_w); + //sinon réveille les lecteurs + else + while (i>0) + { + pthread_cond_signal(&verrou->cond_r); + i--; + } + } + //si c'est un lecteur qui déverouille + else + { + //décrémente le nombr de lecteurs en section critique + verrou->verouilles --; + //si il y avait 1 seul lecteur + if (verrou->verouilles == 0) + //si il y a un ou des écrivains en attente d'écriture : réveille un écrivain + //NB : il ne pouvait pas y avoir de lecteurs vu qu'ils pouvaient rentrer en SC + if (verrou->ecrivains > 0) + pthread_cond_signal(&verrou->cond_w); + //Si il y avait 3 lecteurs (NB_LECT_MAX) on peut réveiller un lecteur si il y en a en attente + else if ((verrou->verouilles == NB_LECT_MAX - 1) && (verrou->lecteurs > 0)) + pthread_cond_signal(&verrou->cond_r); + } + //relache le mutex + pthread_mutex_unlock(&verrou->mutex); +} + +//********************************************************************************************* +//Détruit un verrou +//********************************************************************************************* +void detruire_verrou (verrou_t *verrou) +{ + //détruit le mutex et les variables conditionnelles + pthread_mutex_destroy(&verrou->mutex); + pthread_cond_destroy(&verrou->cond_r); + pthread_cond_destroy(&verrou->cond_w); +} + +//********************************************************************************************* +//initialise un verrou +//********************************************************************************************* +void init_verrou(verrou_t *verrou) +{ + //initialise le mutex + pthread_mutex_init(&verrou->mutex, NULL); + //initialise les variables + verrou->verouilles = 0; + verrou->lecteurs = 0; + verrou->ecrivains = 0; + //initialise les variables conditionnelles + pthread_cond_init (&verrou->cond_r, NULL); + pthread_cond_init (&verrou->cond_w, NULL); +} diff --git a/partie1/sources/verrou.h b/partie1/sources/verrou.h new file mode 100644 index 0000000..90bd438 --- /dev/null +++ b/partie1/sources/verrou.h @@ -0,0 +1,36 @@ +//***************************************************************************************** +//Includes +//***************************************************************************************** + +#ifndef _VERROU_ + #define _VERROU_ + #include + #include + #include + + #include "defines.h" + + //***************************************************************************************** + //Types + //***************************************************************************************** + typedef struct + { + pthread_mutex_t mutex; //bloque l'accès aux variables de condition + int verouilles; //nombre de lecteurs en section critique (-1 si il y a un écrivain) + int lecteurs; //nombre de lecteurs en attente d'écriture + int ecrivains; //nombre d'écrivains en attente d'écriture + pthread_cond_t cond_r; //attente de lecture + pthread_cond_t cond_w; //attente d'écriture + }verrou_t; + + //***************************************************************************************** + //fonctions + ///**************************************************************************************** + + void DownLecture (verrou_t*); //Pose le verrou en LECTURE + void DownEcriture (verrou_t*); //Pose le verrou en ECRITURE + void Up (verrou_t*); //Relache le verrou + void init_verrou(verrou_t *); //initialise et alloue un verrou + void detruire_verrou(verrou_t *); //détruit un verrou + +#endif diff --git a/partie2/Dossier Utilisateur Pietrzak 2.doc b/partie2/Dossier Utilisateur Pietrzak 2.doc new file mode 100644 index 0000000000000000000000000000000000000000..c6aec26461dfee7eb4d90180e9cf07d5918423f1 GIT binary patch literal 118272 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 z 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 literal 0 HcmV?d00001 diff --git a/sujet.htm b/sujet.htm new file mode 100644 index 0000000..731f9b8 --- /dev/null +++ b/sujet.htm @@ -0,0 +1,60 @@ + + +ProJet OS, un SGBD le retour + + + + + + +

Projet système
Licence Informatique

La deuxième partie du projet concerne la gestion de la +mémoire principale. +

Seul le stockage en mémoire des tables utiles pour répondre aux requêtes nous +intéresse dans le cadre de la simulation. Autrement dit les processus ne sont +représentés que par les tables qu'ils manipulent. +

Je vous laisse choisir la taille de la mémoire. Mais veillez à ce +qu'elle correspondent aux besoins des simulations que l'on va détailler. Il faut +en effet que cette mémoire soit suffisamment grande pour contenir plusieurs +tables (qui sont implicitement associées aux processus prêts) tout en s'assurant +qu'elle ne soit pas trop grande afin de ne pas avoir toutes les tables +nécessaires en mémoire. Il faut bien que l'ordannanceur de haut niveau +est du travail! +

Le partitionnement sera votre premier cadre d'étude de cette mémoire. +Puis vous étudirez cette dernière sous l'angle merveilleux et passionnant de la +pagination. +

Vous devez maintenant utiliser obligatoirement l'instruction INSERT aussi +bien dans le cas du partitionnement que dans le cas de la pagination. +

I Partionnement

L'ordonnaceur de haut niveau, ou swapper, utilise +l'algorithme du PAPS intelligent avec des partitions variables. +

Remarque : le partionnement ne fait intervenir le swapper que dans sa +fonction swap in! +

II Pagination

Dans cette deuxième partie, le système doit permettre +d'expérienter la fonction swap out du swapper. +

Le swap out est déclenché quand les processus sont découpés en pages de +taille fixe. Lors de l'execution sur l'UCT d'une page celle-ci peut faire appel +à une référence se trouvant sur une autre page. Dans ce cas la page est +recherchée dans la table des pages du processus. Si celle-ci est marquée +invalide il faut alors aller la chercher en mémoire secondaire :défaut +de page. Si de plus au moment de ce défaut de pages tous les cadres sont +occupés alors il y a une demande de page. Le swap out va alors rapatrier +en mémoire secondaire (il faut contrôler le bit de modification) une page +occupant un cadre pour pouvoir charger la page faisant défaut. Le swap out +fonctionne suivant l'algorithme de la seconde chance. +

Remarques : +

    +
  1. Encore une fois je ne fixe pas de taile de mémoire. Mais vous l'avez déjà + sûrement compris, toutes les pages ne doivent pas se trouver en mémoire en + même temps. Et ce afin de permettre la mise en œuvre du swap out !!! +
  2. Je rappelle que les pages ne contiennent que les entités des tables. Ainsi + les défauts de page surviendront uniquement lors d'une concultation, + modification ou création d'une table.
+

III Plus qu'une conclusion

Ce qui est obligatoire c'est évidemment le +partionnement, son binding et sa représentation +physique que je vous laisse, encore une fois, choisir. +

Je suis conscient que la charge de travail est imposante. Aussi je considère +que la pagination doit être faite que si vous avez franchi toutes les étapes +précédentes avec succès et de manière élégante. Autrement dit, si vous me +présentez un projet avec une implantation de la pagination mais un +partitionnement boiteux cela vous désservira!

-- 2.30.2