paquet.c (13863B)
1 #include <assert.h> 2 #include <fcntl.h> 3 #include <stdint.h> 4 #include <sys/stat.h> 5 #include <time.h> 6 #include <unistd.h> 7 8 #include <stdio.h> 9 #include <stdlib.h> 10 11 #include "paquet.h" 12 #include "sm2.h" 13 14 #define PQ_VERSION 0 15 16 #define PQ_ENTETE_LG 32 17 #define PQ_FICHE_LG 12 18 19 #define DEC_ENTETE_VERSION 0 20 #define DEC_ENTETE_DRAPS 1 21 #define DEC_ENTETE_DEB_S 2 22 #define DEC_ENTETE_DEB_N 5 23 #define DEC_ENTETE_NB 8 24 #define DEC_ENTETE_PINS 11 25 #define DEC_ENTETE_PIPI 12 26 #define DEC_ENTETE_PNPI 14 27 #define DEC_ENTETE_FI 16 28 #define DEC_ENTETE_DATE 17 29 #define DEC_ENTETE_NFS 24 30 31 #define DEC_FICHE_PRCH 0 32 #define DEC_FICHE_DERN 3 33 #define DEC_FICHE_ID 6 34 #define DEC_FICHE_FAC 9 35 #define DEC_FICHE_NSUCC 10 36 37 #define PQ_PINS_DEF 3 38 #define PQ_PIPI_DEF 1 39 #define PQ_PNPI_DEF 377 40 #define PQ_FI_DEF 120 41 #define PQ_NFS_DEF 20 42 43 #define TAMPON_TLL (4096 - (4096 % PQ_FICHE_LG)) 44 #define TAMPON_FICHES (TAMPON_TLL / PQ_FICHE_LG) 45 46 #define LIRE_1(tp) \ 47 (((uint8_t) *(tp))) 48 #define LIRE_2(tp) \ 49 (((uint16_t) *(tp) << 8) \ 50 + ((uint16_t) *((tp) + 1))) 51 #define LIRE_3(tp) \ 52 (((uint32_t) *(tp) << 16) \ 53 + ((uint32_t) *((tp) + 1) << 8) \ 54 + ((uint32_t) *((tp) + 2))) 55 #define LIRE_7(tp) \ 56 (((uint64_t) *(tp) << 48) \ 57 + ((uint64_t) *((tp) + 1) << 40) \ 58 + ((uint64_t) *((tp) + 2) << 32) \ 59 + ((uint64_t) *((tp) + 3) << 24) \ 60 + ((uint64_t) *((tp) + 4) << 16) \ 61 + ((uint64_t) *((tp) + 5) << 8) \ 62 + ((uint64_t) *((tp) + 6))) 63 64 #define PARENT(pos) ((pos) / 2) 65 #define ENFANT1(pos) ((pos) * 2 + 1) 66 #define ENFANT2(pos) ((pos) * 2 + 2) 67 68 static int pq_fiche_copier(struct paquet *, uint32_t, uint8_t *); 69 static int pq_fiche_coller(struct paquet *, uint32_t, uint8_t *); 70 static int pq_fiches_echanger(struct paquet *, uint32_t, uint32_t); 71 static int pq_fiche_monter(struct paquet *, uint32_t, uint8_t *); 72 static int pq_fiche_descendre(struct paquet *, uint32_t, uint8_t *); 73 74 extern char *nom_prog; 75 76 /* Créer la base de données au chemin et écrire les valeurs par défaut. 77 * Ne créer la base de données que s'il n'y a pas de paquet à chemin */ 78 int 79 pq_init(char *chemin) 80 { 81 struct paquet pq; 82 83 assert(chemin != NULL); 84 assert(PQ_ENTETE_LG + 1 < (1 << 8)); 85 86 if ((pq.fd = open(chemin, O_WRONLY | O_CREAT | O_EXCL, 87 S_IRUSR | S_IWUSR)) < 0) { 88 perror(chemin); 89 return -1; 90 } 91 92 pq.nom = chemin; 93 pq.entete.version = 0; 94 pq.entete.draps = 0; 95 pq.entete.deb_s = 0; 96 pq.entete.deb_n = 0; 97 pq.entete.nb = 0; 98 pq.entete.pins = PQ_PINS_DEF; 99 pq.entete.pipi = PQ_PIPI_DEF; 100 pq.entete.pnpi = PQ_PNPI_DEF; 101 pq.entete.fi = PQ_FI_DEF; 102 pq.entete.date = (uint64_t) time(NULL) >> 8; 103 pq.entete.nfs = PQ_NFS_DEF; 104 105 if (pq_entete_maj(&pq) < 0) 106 return -1; 107 108 if (close(pq.fd) < 0) { 109 perror(chemin); 110 return -1; 111 } 112 113 return 0; 114 } 115 116 /* ouvrir le paquet pointé par chemin, en lire l'entête et remplir un struct 117 * paquet */ 118 int 119 pq_ouvrir(char *chemin, struct paquet *pq) 120 { 121 uint8_t tp[PQ_ENTETE_LG]; 122 123 assert(chemin != NULL); 124 assert(pq != NULL); 125 126 if ((pq->fd = open(chemin, O_RDWR)) < 0) { 127 perror(chemin); 128 return -1; 129 } 130 131 if (read(pq->fd, tp, PQ_ENTETE_LG) != PQ_ENTETE_LG) { 132 fprintf(stderr, "%s: paquet corrompu\n", chemin); 133 return -1; 134 } 135 136 pq->nom = chemin; 137 138 if ((pq->entete.version = LIRE_1(tp + DEC_ENTETE_VERSION)) != 0) { 139 fprintf(stderr, "%d: version incompatible\n", 140 pq->entete.version); 141 return -1; 142 } 143 144 pq->entete.draps = LIRE_1(tp + DEC_ENTETE_DRAPS); 145 pq->entete.deb_s = LIRE_3(tp + DEC_ENTETE_DEB_S); 146 pq->entete.deb_n = LIRE_3(tp + DEC_ENTETE_DEB_N); 147 pq->entete.nb = LIRE_3(tp + DEC_ENTETE_NB); 148 pq->entete.pins = LIRE_1(tp + DEC_ENTETE_PINS); 149 pq->entete.pipi = LIRE_2(tp + DEC_ENTETE_PIPI); 150 pq->entete.pnpi = LIRE_2(tp + DEC_ENTETE_PNPI); 151 pq->entete.fi = LIRE_1(tp + DEC_ENTETE_FI); 152 pq->entete.date = LIRE_7(tp + DEC_ENTETE_DATE); 153 pq->entete.nfs = LIRE_2(tp + DEC_ENTETE_NFS); 154 155 return 0; 156 } 157 158 /* ajouter n entrées à la base de données 159 * les entrées sont ajoutées dans la section « nouveaux » */ 160 int 161 pq_ajouter(struct paquet *pq, unsigned int n) 162 { 163 uint32_t id; 164 uint8_t tp[TAMPON_TLL] = { 0 }; 165 uint8_t *ptr; 166 int min; 167 int reste; 168 169 assert(pq != NULL); 170 171 id = pq->entete.nb ; 172 173 if (lseek(pq->fd, PQ_ENTETE_LG + id * PQ_FICHE_LG, SEEK_SET) < 0) { 174 perror(pq->nom); 175 return -1; 176 } 177 178 while (n != 0) { 179 assert(n > 0); 180 reste = min = n < TAMPON_FICHES ? n : TAMPON_FICHES; 181 for (ptr = tp; reste > 0; reste--, ptr += PQ_FICHE_LG) { 182 ptr[6] = (uint8_t) (id >> 16); 183 ptr[7] = (uint8_t) (id >> 8); 184 ptr[8] = (uint8_t) (id); 185 ptr[9] = (uint8_t) (pq->entete.fi); 186 id++; 187 } 188 reste = min * PQ_FICHE_LG; 189 if (write(pq->fd, tp, reste) != reste) { 190 perror(pq->nom); 191 return -1; 192 } 193 pq->entete.nb += min; 194 n -= min; 195 } 196 197 if (pq_entete_maj(pq) < 0) 198 return -1; 199 200 return 0; 201 } 202 203 /* retourner l'identifiant de la prochaine fiche à réviser */ 204 int 205 pq_prochain(struct paquet *pq, int opts) 206 { 207 uint8_t fiche[PQ_FICHE_LG]; 208 uint32_t indice; 209 210 assert(pq != NULL); 211 212 if (pq->entete.draps & PQ_DRAP_QST) { 213 if (pq->entete.draps & PQ_DRAP_MNC) 214 indice = 0; 215 else 216 indice = pq->entete.deb_n; 217 } else { 218 if (pq->entete.nb - pq->entete.deb_n > 0 219 && (pq->entete.nfs > 0 220 || !(pq->entete.draps & PQ_DRAP_NOUV) 221 || opts & PQ_OPT_PRCH_NOUV) 222 && !(opts & PQ_OPT_PRCH_VIEU)) { 223 pq->entete.draps &= ~PQ_DRAP_MNC; 224 if (pq->entete.draps & PQ_DRAP_ALEA) { 225 srand(time(NULL)); 226 indice = rand() 227 % (pq->entete.nb - pq->entete.deb_n) 228 + pq->entete.deb_n; 229 if (pq_fiches_echanger(pq, indice, pq->entete.deb_n) < 0) 230 return -1; 231 } 232 indice = pq->entete.deb_n; 233 } else if (pq->entete.deb_s > 0) { 234 pq->entete.draps |= PQ_DRAP_MNC; 235 indice = 0; 236 } else { 237 fprintf(stderr, 238 "%s: le paquet %s ne contient aucune fiche\n", 239 nom_prog, pq->nom); 240 return -1; 241 } 242 } 243 244 if (pq_fiche_copier(pq, indice, fiche) < 0) 245 return -1; 246 247 indice = LIRE_3(fiche + DEC_FICHE_PRCH); 248 if (pq->entete.draps & PQ_DRAP_GRAC 249 && indice - LIRE_3(fiche + DEC_FICHE_DERN) < pq->entete.pnpi) 250 ; 251 else if (((uint64_t) time(NULL) >> 8) < indice + pq->entete.date) 252 goto rien; 253 254 if (!(pq->entete.draps & PQ_DRAP_QST)) { 255 pq->entete.draps |= PQ_DRAP_QST; 256 if (pq_entete_maj(pq) < 0) 257 return -1; 258 } 259 260 return LIRE_3(fiche + DEC_FICHE_ID); 261 262 rien: 263 fprintf(stderr, "%s: aucune fiche à réviser\n", nom_prog); 264 return -1; 265 } 266 267 static int 268 pq_fiches_echanger(struct paquet *pq, uint32_t pos1, uint32_t pos2) { 269 if (pos1 != pos2) { 270 uint8_t fiche1[PQ_FICHE_LG]; 271 uint8_t fiche2[PQ_FICHE_LG]; 272 if (pq_fiche_copier(pq, pos1, fiche1) < 0) 273 return -1; 274 if (pq_fiche_copier(pq, pos2, fiche2) < 0) 275 return -1; 276 if (pq_fiche_coller(pq, pos1, fiche2) < 0) 277 return -1; 278 if (pq_fiche_coller(pq, pos2, fiche1) < 0) 279 return -1; 280 } 281 282 return 0; 283 } 284 285 int 286 pq_reponse(struct paquet *pq, int rep) 287 { 288 struct fiche f; 289 int pos; 290 uint8_t fiche[PQ_FICHE_LG]; 291 292 assert(rep >= 0 && rep <= 5); 293 294 if (!(pq->entete.draps & PQ_DRAP_QST)) { 295 fprintf(stderr, "%s: veuillez d'abord exécuter la commande q\n", 296 nom_prog); 297 return -1; 298 } 299 300 if (pq->entete.draps & PQ_DRAP_MNC) 301 pos = 0; 302 else 303 pos = pq->entete.deb_n; 304 305 pq->entete.draps &= ~PQ_DRAP_QST; 306 307 if (pq_fiche_copier(pq, pos, fiche) < 0) 308 return -1; 309 310 f.prch = LIRE_3(fiche + DEC_FICHE_PRCH); 311 f.dern = LIRE_3(fiche + DEC_FICHE_DERN); 312 f.id = LIRE_3(fiche + DEC_FICHE_ID); 313 f.fac = LIRE_1(fiche + DEC_FICHE_FAC); 314 f.nsucc = LIRE_2(fiche + DEC_FICHE_NSUCC); 315 316 sm2(&f, rep, pq->entete.pins, pq->entete.pipi, pq->entete.pnpi, pq->entete.date); 317 318 fiche[0] = (uint8_t) (f.prch >> 16); 319 fiche[1] = (uint8_t) (f.prch >> 8); 320 fiche[2] = (uint8_t) (f.prch); 321 fiche[3] = (uint8_t) (f.dern >> 16); 322 fiche[4] = (uint8_t) (f.dern >> 8); 323 fiche[5] = (uint8_t) (f.dern); 324 fiche[6] = (uint8_t) (f.id >> 16); 325 fiche[7] = (uint8_t) (f.id >> 8); 326 fiche[8] = (uint8_t) (f.id); 327 fiche[9] = (uint8_t) (f.fac); 328 fiche[10] = (uint8_t) (f.nsucc >> 8); 329 fiche[11] = (uint8_t) (f.nsucc); 330 331 if (pos == 0 && pq->entete.deb_s > 0) { 332 if (pq_fiche_coller(pq, 0, fiche) < 0) 333 return -1; 334 if (pq_fiche_descendre(pq, 0, fiche) < 0) 335 return -1; 336 } else { 337 if (pq->entete.deb_n != pq->entete.deb_s) { 338 uint8_t fiche2[PQ_FICHE_LG]; 339 if (pq_fiche_copier(pq, pq->entete.deb_s, fiche2) < 0) 340 return -1; 341 if (pq_fiche_coller(pq, pq->entete.deb_n, fiche2) < 0) 342 return -1; 343 } 344 if (pq_fiche_coller(pq, pq->entete.deb_s, fiche) < 0) 345 return -1; 346 pq->entete.deb_s++; 347 pq->entete.deb_n++; 348 if (pq->entete.draps & PQ_DRAP_NOUV) 349 pq->entete.nfs--; 350 assert(pq->entete.nfs >= 0); 351 if (pq_fiche_monter(pq, pos, fiche) < 0) 352 return -1; 353 } 354 355 if (pq_entete_maj(pq) < 0) 356 return -1; 357 358 return 0; 359 } 360 361 int 362 pq_entete_maj(struct paquet *pq) 363 { 364 uint8_t texte[] = { 365 pq->entete.version, 366 pq->entete.draps, 367 (uint8_t) (pq->entete.deb_s >> 16), 368 (uint8_t) (pq->entete.deb_s >> 8), 369 (uint8_t) (pq->entete.deb_s), 370 (uint8_t) (pq->entete.deb_n >> 16), 371 (uint8_t) (pq->entete.deb_n >> 8), 372 (uint8_t) (pq->entete.deb_n), 373 (uint8_t) (pq->entete.nb >> 16), 374 (uint8_t) (pq->entete.nb >> 8), 375 (uint8_t) (pq->entete.nb), 376 pq->entete.pins, 377 (uint8_t) (pq->entete.pipi >> 8), 378 (uint8_t) (pq->entete.pipi), 379 (uint8_t) (pq->entete.pnpi >> 8), 380 (uint8_t) (pq->entete.pnpi), 381 pq->entete.fi, 382 (uint8_t) (pq->entete.date >> 48), 383 (uint8_t) (pq->entete.date >> 40), 384 (uint8_t) (pq->entete.date >> 32), 385 (uint8_t) (pq->entete.date >> 24), 386 (uint8_t) (pq->entete.date >> 16), 387 (uint8_t) (pq->entete.date >> 8), 388 (uint8_t) (pq->entete.date), 389 (uint8_t) (pq->entete.nfs >> 8), 390 (uint8_t) (pq->entete.nfs), 391 (uint8_t) (0), 392 (uint8_t) (0), 393 (uint8_t) (0), 394 (uint8_t) (0), 395 (uint8_t) (0), 396 (uint8_t) (0) }; 397 398 assert(pq != NULL); 399 assert(sizeof(texte) == PQ_ENTETE_LG); 400 401 if (lseek(pq->fd, 0, SEEK_SET) < 0) { 402 perror(pq->nom); 403 return -1; 404 } 405 406 if (write(pq->fd, texte, PQ_ENTETE_LG) != PQ_ENTETE_LG) { 407 perror(pq->nom); 408 return -1; 409 } 410 411 return 0; 412 } 413 414 static int 415 pq_fiche_copier(struct paquet *pq, uint32_t pos, uint8_t *tp) 416 { 417 if (lseek(pq->fd, PQ_ENTETE_LG + pos * PQ_FICHE_LG, SEEK_SET) < 0) { 418 perror(pq->nom); 419 return -1; 420 } 421 422 if (read(pq->fd, tp, PQ_FICHE_LG) != PQ_FICHE_LG) { 423 perror(pq->nom); 424 return -1; 425 } 426 427 return 0; 428 } 429 430 static int 431 pq_fiche_coller(struct paquet *pq, uint32_t pos, uint8_t *tp) 432 { 433 if (lseek(pq->fd, PQ_ENTETE_LG + pos * PQ_FICHE_LG, SEEK_SET) < 0) { 434 perror(pq->nom); 435 } 436 437 if (write(pq->fd, tp, PQ_FICHE_LG) != PQ_FICHE_LG) { 438 perror(pq->nom); 439 return -1; 440 } 441 442 return 0; 443 } 444 445 /* faire monter une fiche dans le monceau */ 446 static int 447 pq_fiche_monter(struct paquet *pq, uint32_t pos, uint8_t *tp) 448 { 449 uint8_t tp_parent[PQ_FICHE_LG]; 450 uint32_t date; 451 uint32_t pos_orig; 452 453 assert(pq != NULL); 454 assert(tp != NULL); 455 assert(pq->entete.deb_s > pos); /* l'entrée doit être dans le monceau */ 456 457 date = LIRE_3(tp + DEC_FICHE_PRCH); 458 for (pos_orig = pos; pos != 0; pos = PARENT(pos)) { 459 /* copier le parent */ 460 if (pq_fiche_copier(pq, PARENT(pos), tp_parent) < 0) 461 return -1; 462 463 if (date >= LIRE_3(tp_parent + DEC_FICHE_PRCH)) 464 break; 465 466 /* descendre le parent */ 467 if (pq_fiche_coller(pq, pos, tp_parent) < 0) 468 return -1; 469 } 470 471 /* ne coller l'entrée que si l'enfant doit être déplacé */ 472 if (pos != pos_orig) 473 if (pq_fiche_coller(pq, pos, tp) < 0) 474 return -1; 475 476 return 0; 477 } 478 479 /* faire descendre une entrée dans le monceau */ 480 static int 481 pq_fiche_descendre(struct paquet *pq, uint32_t pos, uint8_t *tp) 482 { 483 uint8_t tp_enfants[PQ_FICHE_LG * 2]; 484 uint32_t date_parent; 485 uint32_t date_enfants[2]; 486 int inf; /* sert à sélectionner l'enfant inférieur */ 487 uint32_t pos_orig; 488 489 assert(pq != NULL); 490 assert(pq->entete.deb_s > pos); /* l'entrée doit être dans le monceau */ 491 492 date_parent = LIRE_3(tp + DEC_FICHE_PRCH); 493 for (pos_orig = pos; ENFANT1(pos) < pq->entete.deb_s; pos = ENFANT1(pos) + inf) { 494 if (pq_fiche_copier(pq, ENFANT1(pos), tp_enfants) < 0) 495 return -1; 496 497 date_enfants[0] = LIRE_3(tp_enfants + DEC_FICHE_PRCH); 498 inf = 0; 499 500 if (ENFANT2(pos) < pq->entete.deb_s) { 501 if (pq_fiche_copier(pq, ENFANT2(pos), 502 tp_enfants + PQ_FICHE_LG) < 0) 503 return -1; 504 date_enfants[1] = LIRE_3(tp_enfants 505 + PQ_FICHE_LG 506 + DEC_FICHE_PRCH); 507 if (date_enfants[1] < date_enfants[0]) { 508 date_enfants[0] = date_enfants[1]; 509 inf = 1; 510 } 511 } 512 513 /* monter l'enfant */ 514 if (date_enfants[inf] <= date_parent) { 515 if (pq_fiche_coller(pq, pos, tp_enfants 516 + PQ_FICHE_LG * inf) < 0) 517 return -1; 518 } else { 519 break; 520 } 521 } 522 523 524 /* ne coller l'entrée que si le parent doit être déplacé */ 525 if (pos != pos_orig) 526 if (pq_fiche_coller(pq, pos, tp) < 0) 527 return -1; 528 529 return 0; 530 } 531 532 int 533 pq_fiches_afficher(struct paquet *pq) 534 { 535 uint8_t *tp; 536 int n; 537 int ncar; 538 539 ncar = pq->entete.nb * PQ_FICHE_LG; 540 541 if ((tp = malloc(ncar)) == NULL) { 542 perror(NULL); 543 return -1; 544 } 545 546 if (read(pq->fd, tp, ncar) != ncar) { 547 perror(pq->nom); 548 return -1; 549 } 550 551 printf("# MONCEAU\n"); 552 for (n = pq->entete.deb_s; n > 0; n--, tp += PQ_FICHE_LG) 553 printf("%u\t%u\t%u\t%u\t%u\n", 554 LIRE_3(tp + DEC_FICHE_PRCH), 555 LIRE_3(tp + DEC_FICHE_DERN), 556 LIRE_3(tp + DEC_FICHE_ID), 557 LIRE_1(tp + DEC_FICHE_FAC), 558 LIRE_2(tp + DEC_FICHE_NSUCC)); 559 560 printf("# CIMETIÈRE\n"); 561 for (n = pq->entete.deb_n - pq->entete.deb_s; n > 0; n--, tp += PQ_FICHE_LG) 562 printf("%u\t%u\t%u\t%u\t%u\n", 563 LIRE_3(tp + DEC_FICHE_PRCH), 564 LIRE_3(tp + DEC_FICHE_DERN), 565 LIRE_3(tp + DEC_FICHE_ID), 566 LIRE_1(tp + DEC_FICHE_FAC), 567 LIRE_2(tp + DEC_FICHE_NSUCC)); 568 569 printf("# NOUVEAUX\n"); 570 for (n = pq->entete.nb - pq->entete.deb_n; n > 0; n--, tp += PQ_FICHE_LG) 571 printf("%u\t%u\t%u\t%u\t%u\n", 572 LIRE_3(tp + DEC_FICHE_PRCH), 573 LIRE_3(tp + DEC_FICHE_DERN), 574 LIRE_3(tp + DEC_FICHE_ID), 575 LIRE_1(tp + DEC_FICHE_FAC), 576 LIRE_2(tp + DEC_FICHE_NSUCC)); 577 578 return 0; 579 }