]> git.llucax.com Git - z.facultad/75.06/emufs.git/blob - emufs/emufs.c
9f7917cfd52bedcf359325a09944875325ec7746
[z.facultad/75.06/emufs.git] / emufs / emufs.c
1 /* vim: set noexpandtab tabstop=4 shiftwidth=4:
2  *----------------------------------------------------------------------------
3  *                                  emufs
4  *----------------------------------------------------------------------------
5  * This file is part of emufs.
6  *
7  * emufs is free software; you can redistribute it and/or modify it under the
8  * terms of the GNU General Public License as published by the Free Software
9  * Foundation; either version 2 of the License, or (at your option) any later
10  * version.
11  *
12  * emufs is distributed in the hope that it will be useful, but WITHOUT ANY
13  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14  * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
15  * details.
16  *
17  * You should have received a copy of the GNU General Public License along
18  * with emufs; if not, write to the Free Software Foundation, Inc., 59 Temple
19  * Place, Suite 330, Boston, MA  02111-1307  USA
20  *----------------------------------------------------------------------------
21  * Creado:  mié mar 31 17:26:46 ART 2004
22  * Autores: Nicolás Dimov <sagardua@uolsinectis.com.ar>
23  *          Ricardo Markiewicz <rmarkie@fi.uba.ar>
24  *          Leandro Lucarella <llucare@fi.uba.ar>
25  *----------------------------------------------------------------------------
26  *
27  * $Id$
28  *
29  */
30
31 /** \file
32  *
33  * Estructura general de un archivo <em>abstracto</em> de emufs.
34  * 
35  * Implementación de la estructura abstracta que representa cualquiera de los
36  * tipos de archivo implementados. Se incluyen funciones tipo <em>factory</em>
37  * para crear un archivo, abrirlo y destruirlo.
38  *
39  */
40
41 #include "emufs.h"
42 #include "common.h"
43 #include "tipo1.h"
44 #include "tipo2.h"
45 #include "tipo3.h"
46 #include "did.h"
47 #include "fsc.h"
48 #include "idx.h"
49
50 typedef struct _data_indices_ {
51         char nombre[50];
52         INDICE_FUNCION funcion;
53         INDICE_TIPO tipo;
54         INDICE_TIPO_DATO tipo_dato;
55         unsigned int offset;
56         unsigned int tam_bloque;
57         int str_offset;
58 } t_Indice;
59
60 int guardar_indice(EMUFS *emu, char *nombre, INDICE_FUNCION funcion, INDICE_TIPO tipo, INDICE_TIPO_DATO tipo_dato,  unsigned int offset, unsigned int tam_bloque, int str_offset);
61 int cargar_indices(EMUFS *emu);
62
63 char *str_dup(const char *s);
64
65 char *str_dup(const char *s)
66 {
67         char *tmp;
68         if (s == NULL) return NULL;
69         tmp = (char *)malloc(sizeof(char)*(strlen(s)+1));
70         strcpy(tmp, s);
71         return tmp;
72 }
73
74 int emufs_crear_archivo_auxiliar(const char* name, const char* ext)
75 {
76         FILE* f;
77         char* filename;
78
79         filename = (char*) malloc(sizeof(char) * (strlen(name) + strlen(ext) + 1));
80         if (filename == NULL) {
81                 /* TODO Manejo de errores */
82                 return -1;
83         }
84         strcpy(filename, name);
85         strcat(filename, ext);
86         f = fopen(filename, "w");
87         free(filename);
88         if (f == NULL) {
89                 /* TODO Manejo de errores */
90                 return -1;
91         }
92         fclose(f);
93         return 0;
94 }
95
96 EMUFS *emufs_crear(const char *filename, EMUFS_Tipo tipo, EMUFS_BLOCK_SIZE tam_bloque, EMUFS_REG_SIZE tam_reg)
97 {
98         char name[255], otroname[255];
99         FILE *fp;
100         EMUFS *efs;
101         int err = 0;
102
103         /* Si no es un tipo conocido, sale. */
104         if ((tipo != T1) && (tipo != T2) && (tipo != T3) && (tipo != T4) && (tipo != T5)) {
105                 return NULL;
106         }
107
108         /* Inicializa parámetros comunes. */
109         efs = (EMUFS*) malloc(sizeof(EMUFS));
110         if (efs == NULL) {
111                 return NULL;
112         }
113         efs->tipo = tipo;
114         efs->tam_bloque = tam_bloque;
115         efs->tam_reg = tam_reg;
116         efs->nombre = str_dup(filename);
117         efs->indices = NULL;
118
119         sprintf(otroname, "%s.info", efs->nombre);
120         fp = fopen(otroname, "w");
121         if (fp == NULL) {
122                 PERR("CARAJO!, NO PUEDO CREAR INFO");
123         } else {
124                 err = 0;
125                 fwrite(&err, 1, sizeof(int), fp);
126                 fclose(fp);
127         }
128
129         /* Abre archivo de datos. */
130         strcpy(name, filename);
131         strcat(name, ".dat");
132         fp = fopen(name, "w");
133         if (fp == NULL) {
134                 /* TODO ERROR */
135                 free(efs->nombre);
136                 free(efs);
137                 return NULL;
138         }
139
140         /* Guarda cabecera común. */
141         fwrite(&tipo, sizeof(EMUFS_Tipo), 1, fp);
142
143         /* Crea archivo de índice. */
144         if (emufs_idx_crear(efs)) {
145                 /* TODO ERROR */
146                 fclose(fp);
147                 free(efs->nombre);
148                 free(efs);
149                 return NULL;
150         }
151
152         /* Crea archivo de control de espacio libre. */
153         if (emufs_fsc_crear(efs)) {
154                 /* TODO ERROR */
155                 fclose(fp);
156                 free(efs->nombre);
157                 free(efs);
158                 return NULL;
159         }
160
161         /* Crea archivo de identificadores borrados (recuperables). */
162         if (emufs_did_crear(efs)) {
163                 /* TODO ERROR */
164                 fclose(fp);
165                 free(efs->nombre);
166                 free(efs);
167                 return NULL;
168         }
169
170         /* Termina de realizar el trabajo según el tipo de archivo. */
171         switch (tipo) {
172
173                 case T1:
174                         /* Asigna punteros a funciones. */
175                         if ((err = emufs_tipo1_inicializar(efs))) {
176                                 /* TODO ERROR */
177                                 PERR("No se pudo inicializar el EMUFS de tipo1");
178                                 fclose(fp);
179                                 free(efs->nombre);
180                                 free(efs);
181                                 return NULL;
182                         }
183
184                         /* Guarda cabeceras propias. */
185                         fwrite(&tam_bloque, sizeof(EMUFS_BLOCK_SIZE), 1, fp);
186
187                         break;
188
189                 case T2:
190                         /* Asigna punteros a funciones. */
191                         emufs_tipo2_inicializar(efs);
192                         break;
193
194                 case T3:
195                         /* Asigna punteros a funciones. */
196                         if ((err = emufs_tipo3_inicializar(efs))) {
197                                 /* TODO ERROR */
198                                 PERR("No se pudo inicializar el EMUFS de tipo3");
199                                 fclose(fp);
200                                 free(efs->nombre);
201                                 free(efs);
202                                 return NULL;
203                         }
204                         /* Guarda cabeceras propias. */
205                         fwrite(&tam_bloque, sizeof(EMUFS_BLOCK_SIZE), 1, fp);
206                         fwrite(&tam_reg, sizeof(EMUFS_REG_SIZE), 1, fp);                        
207                         break;
208                 
209                 case T4:
210                         /* Asigna punteros a funciones. */
211                         if ((err = emufs_tipo4_inicializar(efs))) {
212                                 /* TODO ERROR */
213                                 PERR("No se pudo inicializar el EMUFS de tipo4");
214                                 fclose(fp);
215                                 free(efs->nombre);
216                                 free(efs);
217                                 return NULL;
218                         }
219                         /* Guarda cabeceras propias. */
220                         fwrite(&tam_bloque, sizeof(EMUFS_BLOCK_SIZE), 1, fp);
221                         break;
222                 
223                 case T5:
224                         /* Asigna punteros a funciones. */
225                         if ((err = emufs_tipo5_inicializar(efs))) {
226                                 /* TODO ERROR */
227                                 PERR("No se pudo inicializar el EMUFS de tipo5");
228                                 fclose(fp);
229                                 free(efs->nombre);
230                                 free(efs);
231                                 return NULL;
232                         }
233                         /* Guarda cabeceras propias. */                 
234                         fwrite(&tam_bloque, sizeof(EMUFS_BLOCK_SIZE), 1, fp);
235                         fwrite(&tam_reg, sizeof(EMUFS_REG_SIZE), 1, fp);                        
236                         break;
237         }
238
239         fclose(fp);
240         return efs;
241 }
242
243 EMUFS *emufs_abrir(const char *filename)
244 {
245         EMUFS *efs;
246         char name[255];
247         char tipo;
248         FILE *fp;
249         int err = 0;
250
251         strcpy(name, filename);
252         strcat(name, ".dat");
253
254         /* Trato de determinar el tipo de archivo */
255         fp = fopen(name, "r");
256         if (fp == NULL) return NULL;
257         fread(&tipo, sizeof(EMUFS_Tipo), 1, fp);
258
259         /* Si no es un tipo conocido, sale. */
260         if ((tipo != T1) && (tipo != T2) && (tipo != T3) && (tipo != T4) && (tipo != T5)) {
261                 fclose(fp);
262                 return NULL;
263         }
264         
265         /* Inicializa parámetros comunes. */
266         efs = (EMUFS*) malloc(sizeof(EMUFS));
267         if (efs == NULL) {
268                 fclose(fp);
269                 return NULL;
270         }
271         efs->tipo = tipo;
272         efs->nombre = str_dup(filename);
273         
274         switch (tipo) {
275                 case T1:
276                         /* Lee cabeceras propias. */
277                         if (!fread(&(efs->tam_bloque), sizeof(EMUFS_BLOCK_SIZE), 1, fp)) {
278                                 PERR("ERROR Tipo1 no se pudo leer cabecera");
279                                 free(efs->nombre);
280                                 free(efs);
281                                 fclose(fp);
282                                 return NULL;
283                         }
284                         /* Asigna punteros a funciones. */
285                         if ((err = emufs_tipo1_inicializar(efs))) {
286                                 PERR("No se pudo inicializar el EMUFS de tipo1");
287                                 fclose(fp);
288                                 return NULL;
289                         }
290                         break;
291                 case T2:
292                         /* Asigna punteros a funciones. */
293                         emufs_tipo2_inicializar(efs);                   
294                         break;
295                 case T3:
296                         if ((!fread(&(efs->tam_bloque), sizeof(EMUFS_BLOCK_SIZE), 1, fp)) ||
297                            (!fread(&(efs->tam_reg), sizeof(EMUFS_REG_SIZE), 1, fp)))
298                                 {
299                                 PERR("ERROR Tipo3 no se pudo leer header");
300                                 free(efs->nombre);
301                                 free(efs);
302                                 fclose(fp);
303                                 return NULL;
304                         }                       
305                         /* Asigna punteros a funciones. */                      
306                         emufs_tipo3_inicializar(efs);
307                         break;
308         
309                 case T4:
310                         /* Lee cabeceras propias. */
311                         if (!fread(&(efs->tam_bloque), sizeof(EMUFS_BLOCK_SIZE), 1, fp)) {
312                                 free(efs->nombre);
313                                 free(efs);
314                                 fclose(fp);
315                                 return NULL;
316                         }
317                         emufs_tipo4_inicializar(efs);
318                         break;
319
320                 case T5:
321                         if ((!fread(&(efs->tam_bloque), sizeof(EMUFS_BLOCK_SIZE), 1, fp)) ||
322                            (!fread(&(efs->tam_reg), sizeof(EMUFS_REG_SIZE), 1, fp)))
323                                 {
324                                 free(efs->nombre);
325                                 free(efs);
326                                 fclose(fp);
327                                 return NULL;
328                         }                       
329                         /* Asigna punteros a funciones. */
330                         emufs_tipo5_inicializar(efs);
331                 default:
332                         PERR("EMUFS TIPO NO SOPORTADO");
333         }       
334
335         /* finalmente cargo la data de los indices */
336         cargar_indices(efs);
337         fclose(fp);
338         return efs;
339 }
340
341 int emufs_destruir(EMUFS *e)
342 {
343         INDICE *del, *cur;
344
345         if (e == NULL) return 1;
346
347         /* libero indices */
348         cur = e->indices;
349         while (cur) {
350                 del = cur;
351                 fprintf(stderr, "INDICE A ELIMINAR = %s\n", del->nombre);
352                 cur = cur->sig;
353                 emufs_indice_destruir(e, del);
354         }
355
356         free(e->nombre);
357         free(e);
358         return 0;
359 }
360
361 int ver_archivo_FS(EMUFS *emu)
362 {
363         FILE *f_block_free;
364         EMUFS_FSC reg;
365         char name_f_block_free[255];
366         
367         strcpy(name_f_block_free,emu->nombre);
368         strcat(name_f_block_free,".fsc");
369
370         if ( (f_block_free = fopen(name_f_block_free,"r"))==NULL ){
371                 fprintf(stderr, "no pude abrir el archivo %s\n",name_f_block_free);
372                 return -1;
373         }
374         fprintf(stderr,"BOQUES Y ESPACIO LIBRE\n");
375         fread(&reg,sizeof(reg),1,f_block_free);
376         while ( !feof(f_block_free) ){
377                 fprintf(stderr, "Bloque = %li   Espacio libre = %li\n",reg.marker, reg.freespace);
378                 fread(&reg,sizeof(reg),1,f_block_free);
379         }
380         
381         fclose(f_block_free);
382
383         /* Imprimo la lista de bloques/registros */
384         fprintf(stderr, "BLOQUES Y REGISTROS\n");
385         strcpy(name_f_block_free,emu->nombre);
386         strcat(name_f_block_free,".idx");
387         f_block_free = fopen(name_f_block_free, "r");
388         {
389                 EMUFS_IDX r;
390                 while (!feof(f_block_free)) {
391                         if (fread(&r, sizeof(EMUFS_IDX), 1, f_block_free) != 1) continue;
392                         fprintf(stderr, "ID %li en bloque %li\n", r.id_reg, r.location);
393                 }
394         }
395         fclose(f_block_free);
396         
397         return 0;
398 }
399
400 int debug_ver_estadisticas(EMUFS* efs)
401 {
402         EMUFS_Estadisticas s = efs->leer_estadisticas(efs);
403
404         printf("ESTADISTICAS:\n");
405         printf("=============\n");
406         printf("Tamaño del archivo: %lu bytes\n", s.tam_archivo);
407         printf("Tamaño de datos (incluye espacio libre): %lu bytes (%.2f %%)\n",
408                         s.tam_archivo - s.tam_info_control_dat,
409                         (s.tam_archivo - s.tam_info_control_dat) * 100.0
410                                 / (float) s.tam_archivo);
411         printf("Tamaño de info de control total: %lu bytes (%.2f %%)\n",
412                         s.tam_info_control_dat + s.tam_archivos_aux,
413                         (s.tam_info_control_dat + s.tam_archivos_aux) * 100.0
414                                 / (float) s.tam_archivo);
415         printf("Tamaño de los archivos auxiliares: %lu bytes\n",
416                         s.tam_archivos_aux);
417         printf("Tamaño de la información de control en el .dat: %lu bytes\n",
418                         s.tam_info_control_dat);
419         printf("Total de espacio libre: %lu bytes\n", s.total_fs);
420         printf("Máximo espacio libre en bloque: %lu bytes\n", s.max_fs);
421         printf("Mínimo espacio libre en bloque: %lu bytes\n", s.min_fs);
422         printf("Media del espacio libre por bloque: %lu bytes\n", s.media_fs);
423         printf("Cantidad de registros: %lu\n", s.cant_registros);
424         printf("Cantidad de bloques: %lu\n", s.cant_bloques);
425         return 0;
426 }
427
428 int emufs_agregar_indice(EMUFS *emu, char *nombre, INDICE_FUNCION funcion, INDICE_TIPO tipo, INDICE_TIPO_DATO tipo_dato,  unsigned int offset, unsigned int tam_bloque, int str_offset)
429 {
430         INDICE *tmp;
431         int error=0;
432
433         /* Verifico que no existe un indice con el mismo nombre */
434         /* y que no exista un indice primario */
435         PERR("Agregando indice");
436         tmp = emu->indices;
437         while (tmp) {
438                 if (strcmp(tmp->nombre, nombre)==0) {
439                         error = 1;
440                         break;
441                 }
442                 if ((funcion == IND_PRIMARIO) && (tmp->funcion == funcion)) {
443                         error = 2;
444                         break;
445                 }
446                 tmp = tmp->sig;
447         }
448
449         if (tmp != NULL) {
450                 switch (error) {
451                         case 1:
452                                 PERR("Ya existe un indice con el mismo nombre!");
453                         break;
454                         case 2:
455                                 PERR("EMUFS ya tiene indice primario!!");
456                 }
457                 return 0;
458         }
459
460         /* Creo el nuevo indice */
461         PERR("Creando indice\n");
462         tmp = emufs_indice_crear(emu, nombre, funcion, tipo, tipo_dato, offset, tam_bloque, str_offset);
463
464         /* Guardo la info del indice para poder abrir despues el archivo */
465         guardar_indice(emu, nombre, funcion, tipo, tipo_dato, offset, tam_bloque, str_offset);
466
467         if (tmp == NULL) {
468                 PERR("NO SE PUDO CREAR INDICE!!!");
469                 return 0;
470         }
471
472         tmp->sig = NULL;
473         if (emu->indices==NULL)
474                 emu->indices = tmp;
475         else {
476                 tmp->sig = emu->indices;
477                 emu->indices = tmp;
478         }
479         return 1;
480 }
481
482 INDICE_DATO *emufs_buscar_registros(EMUFS *emu, char *indice, char *data, int *cant)
483 {
484         CLAVE k;
485         INDICE *tmp;
486
487         tmp = emu->indices;
488         while (tmp) {
489                 if (strcmp(tmp->nombre, indice) == 0) break;
490                 tmp = tmp->sig;
491         }
492
493         if (tmp == NULL) {
494                 PERR("NO EXISTE EL INDICE");
495                 cant = 0;
496                 return NULL;
497         }
498
499         PERR("GENERANDO CLAVE")
500         PERR(data);
501         k = emufs_indice_generar_clave_desde_valor(tmp, data);
502         PERR("DONE");
503         return tmp->buscar_entradas(tmp, k, cant);
504 }
505
506 int guardar_indice(EMUFS *emu, char *nombre, INDICE_FUNCION funcion, INDICE_TIPO tipo, INDICE_TIPO_DATO tipo_dato,  unsigned int offset, unsigned int tam_bloque, int str_offset)
507 {
508         char filename[100];
509         FILE *fp;
510         int cant; /* cantidad de indices hasta el momento */
511         t_Indice *indices;
512
513         sprintf(filename, "%s.info", emu->nombre);
514         fp = fopen(filename, "r+");
515         PERR("Abri info");
516         PERR(filename);
517         if (fp == NULL) {
518                 PERR("No se pudo");
519                 return 0;
520         }
521
522         fread(&cant, 1, sizeof(int), fp);
523         indices = malloc((cant+1)*sizeof(t_Indice));
524         fread(indices, cant, sizeof(t_Indice), fp);
525         memset(indices[cant].nombre, 0, 50); 
526         strcpy(indices[cant].nombre, nombre);
527         indices[cant].funcion = funcion;
528         indices[cant].tipo = tipo;
529         indices[cant].tipo_dato = tipo_dato;
530         indices[cant].offset = offset;
531         indices[cant].tam_bloque = tam_bloque;
532         indices[cant].str_offset = str_offset;
533
534         fseek(fp, SEEK_SET, 0);
535         cant++;
536         fwrite(&cant, 1, sizeof(int), fp);
537         fwrite(indices, cant, sizeof(t_Indice), fp);
538         fclose(fp);
539         free(indices);
540         return 1;
541 }
542
543 int cargar_indices(EMUFS *emu)
544 {
545         char filename[100];
546         FILE *fp;
547         int cant, i; /* cantidad de indices hasta el momento */
548         t_Indice *indices;
549
550         sprintf(filename, "%s.info", emu->nombre);
551         fp = fopen(filename, "r");
552         PERR("Abri info");
553         PERR(filename);
554         if (fp == NULL) {
555                 PERR("No se pudo");
556                 return 0;
557         }
558
559         emu->indices = NULL;
560         fread(&cant, 1, sizeof(int), fp);
561         if (cant == 0) {
562                 PERR("NO HAY INDICES EN ESTE ARCHIVO");
563                 return 1;
564         }
565         indices = malloc(cant*sizeof(t_Indice));
566         fread(indices, cant, sizeof(t_Indice), fp);
567         fclose(fp);
568         
569         /* Leo  */
570         for(i=0; i<cant; i++) {
571                 INDICE *tmp;
572                 tmp = emufs_indice_abrir(emu,
573                                 indices[i].nombre,
574                                 indices[i].funcion,
575                                 indices[i].tipo,
576                                 indices[i].tipo_dato,
577                                 indices[i].offset,
578                                 indices[i].tam_bloque,
579                                 indices[i].str_offset
580                         );
581                 PERR(indices[i].nombre);
582                 if (emu->indices==NULL)
583                         emu->indices = tmp;
584                 else {
585                         tmp->sig = emu->indices;
586                         emu->indices = tmp;
587                 }
588         }
589         
590         free(indices);
591         return 1;
592 }
593
594 /*crea un bloque y devuelve en numero del mismo*/
595 EMUFS_BLOCK_ID emufs_create_new_block(EMUFS *emu)
596 {
597         FILE *fp;
598         char name[255];
599         char *dummy;
600         EMUFS_BLOCK_ID num;
601         
602         /* obtengo nombre del archivo */
603         strcpy(name, emu->nombre);
604         strcat(name,".dat");
605         
606         if ( (fp=fopen(name,"a+")) == NULL ){
607                 PERR("NO SE PUDO ABRIR EL ARCHIVO");
608                 return -1;
609         }
610
611         dummy = (char*)malloc(emu->tam_bloque);
612         memset(dummy, 0, emu->tam_bloque);
613         fwrite(dummy, emu->tam_bloque, 1, fp);
614         switch(emu->tipo){
615                 case T4: num = (ftell(fp)-sizeof(EMUFS_Tipo)-sizeof(EMUFS_BLOCK_SIZE))/emu->tam_bloque;
616                         break;
617                 case T5: num = (ftell(fp)-sizeof(EMUFS_Tipo)-sizeof(EMUFS_BLOCK_SIZE)-sizeof(EMUFS_REG_SIZE))/emu->tam_bloque;
618                         break;
619                 default: num = 0;               
620         }
621         fclose(fp);
622         free(dummy);
623         return num-1;
624 }
625
626 /*devuelve un numero de bloque siguiente al ultimo*/
627 EMUFS_BLOCK_ID emufs_get_new_block_number(EMUFS *emu)
628 {
629         FILE *fp;
630         char name[255];
631         EMUFS_BLOCK_ID num=0;
632         
633         /* obtengo nombre del archivo */
634         strcpy(name, emu->nombre);
635         strcat(name,".dat");
636         if ( (fp=fopen(name,"r")) == NULL ){
637                 PERR("NO SE PUDO ABRIR EL ARCHIVO");
638                 return -1;
639         }
640         if ( fseek(fp, 0, SEEK_END)!=0 ){
641                 PERR("NO PUDE HACER EL SEEK");
642                 return -1;
643         }
644         switch(emu->tipo){
645                 case T4: num = (ftell(fp)-sizeof(EMUFS_Tipo)-sizeof(EMUFS_BLOCK_SIZE))/emu->tam_bloque;
646                         if (ftell(fp) ==  sizeof(EMUFS_Tipo)+sizeof(EMUFS_BLOCK_SIZE)) num = 0;
647                         break;
648                 case T5: num = (ftell(fp)-sizeof(EMUFS_Tipo)-sizeof(EMUFS_BLOCK_SIZE)-sizeof(EMUFS_REG_SIZE))/emu->tam_bloque;
649                         if (ftell(fp) ==  sizeof(EMUFS_Tipo)+sizeof(EMUFS_BLOCK_SIZE)+sizeof(EMUFS_REG_SIZE)) num = 0;
650                         break;
651                 default: num = 0;
652         }
653         fclose(fp);
654         return num;
655 }
656
657 INDICE *emufs_buscar_indice_por_nombre(EMUFS *emu, const char *nombre)
658 {
659         INDICE *tmp;
660
661         tmp = emu->indices;
662         while (tmp) {
663                 if (strcmp(tmp->nombre, nombre) == 0) break;
664                 tmp = tmp->sig;
665         }
666         return tmp;
667 }