]> git.llucax.com Git - z.facultad/75.06/emufs.git/blob - emufs/emufs.c
Se amplia MERGEFILE para poder usarlo de salida tambien (al crear los chunks).
[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 } t_Indice;
58
59 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);
60
61 char *str_dup(const char *s);
62
63 char *str_dup(const char *s)
64 {
65         char *tmp;
66         if (s == NULL) return NULL;
67         tmp = (char *)malloc(sizeof(char)*(strlen(s)+1));
68         strcpy(tmp, s);
69         return tmp;
70 }
71
72 int emufs_crear_archivo_auxiliar(const char* name, const char* ext)
73 {
74         FILE* f;
75         char* filename;
76
77         filename = (char*) malloc(sizeof(char) * (strlen(name) + strlen(ext) + 1));
78         if (filename == NULL) {
79                 /* TODO Manejo de errores */
80                 return -1;
81         }
82         strcpy(filename, name);
83         strcat(filename, ext);
84         f = fopen(filename, "w");
85         free(filename);
86         if (f == NULL) {
87                 /* TODO Manejo de errores */
88                 return -1;
89         }
90         fclose(f);
91         return 0;
92 }
93
94 EMUFS *emufs_crear(const char *filename, EMUFS_Tipo tipo, EMUFS_BLOCK_SIZE tam_bloque, EMUFS_REG_SIZE tam_reg)
95 {
96         char name[255], otroname[255];
97         FILE *fp;
98         EMUFS *efs;
99         int err = 0;
100
101         /* Si no es un tipo conocido, sale. */
102         if ((tipo != T1) && (tipo != T2) && (tipo != T3) && (tipo != T4) && (tipo != T5)) {
103                 return NULL;
104         }
105
106         /* Inicializa parámetros comunes. */
107         efs = (EMUFS*) malloc(sizeof(EMUFS));
108         if (efs == NULL) {
109                 return NULL;
110         }
111         efs->tipo = tipo;
112         efs->tam_bloque = tam_bloque;
113         efs->tam_reg = tam_reg;
114         efs->nombre = str_dup(filename);
115         efs->indices = NULL;
116
117         sprintf(otroname, "%s.info", efs->nombre);
118         fp = fopen(otroname, "w");
119         if (fp == NULL) {
120                 PERR("CARAJO!, NO PUEDO CREAR INFO");
121         } else {
122                 err = 0;
123                 fwrite(&err, 1, sizeof(int), fp);
124                 fclose(fp);
125         }
126
127         /* Abre archivo de datos. */
128         strcpy(name, filename);
129         strcat(name, ".dat");
130         fp = fopen(name, "w");
131         if (fp == NULL) {
132                 /* TODO ERROR */
133                 free(efs->nombre);
134                 free(efs);
135                 return NULL;
136         }
137
138         /* Guarda cabecera común. */
139         fwrite(&tipo, sizeof(EMUFS_Tipo), 1, fp);
140
141         /* Crea archivo de índice. */
142         if (emufs_idx_crear(efs)) {
143                 /* TODO ERROR */
144                 fclose(fp);
145                 free(efs->nombre);
146                 free(efs);
147                 return NULL;
148         }
149
150         /* Crea archivo de control de espacio libre. */
151         if (emufs_fsc_crear(efs)) {
152                 /* TODO ERROR */
153                 fclose(fp);
154                 free(efs->nombre);
155                 free(efs);
156                 return NULL;
157         }
158
159         /* Crea archivo de identificadores borrados (recuperables). */
160         if (emufs_did_crear(efs)) {
161                 /* TODO ERROR */
162                 fclose(fp);
163                 free(efs->nombre);
164                 free(efs);
165                 return NULL;
166         }
167
168         /* Termina de realizar el trabajo según el tipo de archivo. */
169         switch (tipo) {
170
171                 case T1:
172                         /* Asigna punteros a funciones. */
173                         if ((err = emufs_tipo1_inicializar(efs))) {
174                                 /* TODO ERROR */
175                                 PERR("No se pudo inicializar el EMUFS de tipo1");
176                                 fclose(fp);
177                                 free(efs->nombre);
178                                 free(efs);
179                                 return NULL;
180                         }
181
182                         /* Guarda cabeceras propias. */
183                         fwrite(&tam_bloque, sizeof(EMUFS_BLOCK_SIZE), 1, fp);
184
185                         break;
186
187                 case T2:
188                         /* Asigna punteros a funciones. */
189                         emufs_tipo2_inicializar(efs);
190                         break;
191
192                 case T3:
193                         /* Asigna punteros a funciones. */
194                         if ((err = emufs_tipo3_inicializar(efs))) {
195                                 /* TODO ERROR */
196                                 PERR("No se pudo inicializar el EMUFS de tipo3");
197                                 fclose(fp);
198                                 free(efs->nombre);
199                                 free(efs);
200                                 return NULL;
201                         }
202                         /* Guarda cabeceras propias. */
203                         fwrite(&tam_bloque, sizeof(EMUFS_BLOCK_SIZE), 1, fp);
204                         fwrite(&tam_reg, sizeof(EMUFS_REG_SIZE), 1, fp);                        
205                         break;
206                 
207                 case T4:
208                         /* Asigna punteros a funciones. */
209                         if ((err = emufs_tipo4_inicializar(efs))) {
210                                 /* TODO ERROR */
211                                 PERR("No se pudo inicializar el EMUFS de tipo4");
212                                 fclose(fp);
213                                 free(efs->nombre);
214                                 free(efs);
215                                 return NULL;
216                         }
217                         /* Guarda cabeceras propias. */
218                         fwrite(&tam_bloque, sizeof(EMUFS_BLOCK_SIZE), 1, fp);
219                         break;
220                 
221                 case T5:
222                         /* Asigna punteros a funciones. */
223                         if ((err = emufs_tipo5_inicializar(efs))) {
224                                 /* TODO ERROR */
225                                 PERR("No se pudo inicializar el EMUFS de tipo5");
226                                 fclose(fp);
227                                 free(efs->nombre);
228                                 free(efs);
229                                 return NULL;
230                         }
231                         /* Guarda cabeceras propias. */                 
232                         fwrite(&tam_bloque, sizeof(EMUFS_BLOCK_SIZE), 1, fp);
233                         fwrite(&tam_reg, sizeof(EMUFS_REG_SIZE), 1, fp);                        
234                         break;
235         }
236
237         fclose(fp);
238         return efs;
239 }
240
241 EMUFS *emufs_abrir(const char *filename)
242 {
243         EMUFS *efs;
244         char name[255];
245         char tipo;
246         FILE *fp;
247         int err = 0;
248
249         strcpy(name, filename);
250         strcat(name, ".dat");
251
252         /* Trato de determinar el tipo de archivo */
253         fp = fopen(name, "r");
254         if (fp == NULL) return NULL;
255         fread(&tipo, sizeof(EMUFS_Tipo), 1, fp);
256
257         /* Si no es un tipo conocido, sale. */
258         if ((tipo != T1) && (tipo != T2) && (tipo != T3)) {
259                 fclose(fp);
260                 return NULL;
261         }
262         
263         /* Inicializa parámetros comunes. */
264         efs = (EMUFS*) malloc(sizeof(EMUFS));
265         if (efs == NULL) {
266                 fclose(fp);
267                 return NULL;
268         }
269         efs->tipo = tipo;
270         efs->nombre = str_dup(filename);
271         
272         switch (tipo) {
273                 case T1:
274                         /* Lee cabeceras propias. */
275                         if (!fread(&(efs->tam_bloque), sizeof(EMUFS_BLOCK_SIZE), 1, fp)) {
276                                 free(efs->nombre);
277                                 free(efs);
278                                 fclose(fp);
279                                 return NULL;
280                         }
281                         /* Asigna punteros a funciones. */
282                         if ((err = emufs_tipo1_inicializar(efs))) {
283                                 PERR("No se pudo inicializar el EMUFS de tipo1");
284                                 fclose(fp);
285                                 return NULL;
286                         }
287                         break;
288                 case T2:
289                         /* Asigna punteros a funciones. */
290                         emufs_tipo2_inicializar(efs);                   
291                         break;
292                 case T3:
293                         if ((!fread(&(efs->tam_bloque), sizeof(EMUFS_BLOCK_SIZE), 1, fp)) ||
294                            (!fread(&(efs->tam_reg), sizeof(EMUFS_REG_SIZE), 1, fp)))
295                                 {
296                                 free(efs->nombre);
297                                 free(efs);
298                                 fclose(fp);
299                                 return NULL;
300                         }                       
301                         /* Asigna punteros a funciones. */                      
302                         emufs_tipo3_inicializar(efs);
303                         break;
304         
305                 case T4:
306                         /* Lee cabeceras propias. */
307                         if (!fread(&(efs->tam_bloque), sizeof(EMUFS_BLOCK_SIZE), 1, fp)) {
308                                 free(efs->nombre);
309                                 free(efs);
310                                 fclose(fp);
311                                 return NULL;
312                         }
313                         emufs_tipo4_inicializar(efs);
314                         break;
315
316                 case T5:
317                         if ((!fread(&(efs->tam_bloque), sizeof(EMUFS_BLOCK_SIZE), 1, fp)) ||
318                            (!fread(&(efs->tam_reg), sizeof(EMUFS_REG_SIZE), 1, fp)))
319                                 {
320                                 free(efs->nombre);
321                                 free(efs);
322                                 fclose(fp);
323                                 return NULL;
324                         }                       
325                         /* Asigna punteros a funciones. */
326                         emufs_tipo5_inicializar(efs);
327         }       
328
329         fclose(fp);
330         return efs;
331 }
332
333 int emufs_destruir(EMUFS *e)
334 {
335         INDICE *del, *cur;
336
337         if (e == NULL) return 1;
338
339         /* libero indices */
340         cur = e->indices;
341         while (cur) {
342                 del = cur;
343                 cur = cur->sig;
344                 emufs_indice_destruir(e, cur);
345         }
346
347         free(e->nombre);
348         free(e);
349         return 0;
350 }
351
352 int ver_archivo_FS(EMUFS *emu)
353 {
354         FILE *f_block_free;
355         EMUFS_FSC reg;
356         char name_f_block_free[255];
357         
358         strcpy(name_f_block_free,emu->nombre);
359         strcat(name_f_block_free,".fsc");
360
361         if ( (f_block_free = fopen(name_f_block_free,"r"))==NULL ){
362                 fprintf(stderr, "no pude abrir el archivo %s\n",name_f_block_free);
363                 return -1;
364         }
365         fprintf(stderr,"BOQUES Y ESPACIO LIBRE\n");
366         fread(&reg,sizeof(reg),1,f_block_free);
367         while ( !feof(f_block_free) ){
368                 fprintf(stderr, "Bloque = %li   Espacio libre = %li\n",reg.marker, reg.freespace);
369                 fread(&reg,sizeof(reg),1,f_block_free);
370         }
371         
372         fclose(f_block_free);
373
374         /* Imprimo la lista de bloques/registros */
375         fprintf(stderr, "BLOQUES Y REGISTROS\n");
376         strcpy(name_f_block_free,emu->nombre);
377         strcat(name_f_block_free,".idx");
378         f_block_free = fopen(name_f_block_free, "r");
379         {
380                 EMUFS_IDX r;
381                 while (!feof(f_block_free)) {
382                         if (fread(&r, sizeof(EMUFS_IDX), 1, f_block_free) != 1) continue;
383                         fprintf(stderr, "ID %li en bloque %li\n", r.id_reg, r.location);
384                 }
385         }
386         fclose(f_block_free);
387         
388         return 0;
389 }
390
391 int debug_ver_estadisticas(EMUFS* efs)
392 {
393         EMUFS_Estadisticas s = efs->leer_estadisticas(efs);
394
395         printf("ESTADISTICAS:\n");
396         printf("=============\n");
397         printf("Tamaño del archivo: %lu bytes\n", s.tam_archivo);
398         printf("Tamaño de datos (incluye espacio libre): %lu bytes (%.2f %%)\n",
399                         s.tam_archivo - s.tam_info_control_dat,
400                         (s.tam_archivo - s.tam_info_control_dat) * 100.0
401                                 / (float) s.tam_archivo);
402         printf("Tamaño de info de control total: %lu bytes (%.2f %%)\n",
403                         s.tam_info_control_dat + s.tam_archivos_aux,
404                         (s.tam_info_control_dat + s.tam_archivos_aux) * 100.0
405                                 / (float) s.tam_archivo);
406         printf("Tamaño de los archivos auxiliares: %lu bytes\n",
407                         s.tam_archivos_aux);
408         printf("Tamaño de la información de control en el .dat: %lu bytes\n",
409                         s.tam_info_control_dat);
410         printf("Total de espacio libre: %lu bytes\n", s.total_fs);
411         printf("Máximo espacio libre en bloque: %lu bytes\n", s.max_fs);
412         printf("Mínimo espacio libre en bloque: %lu bytes\n", s.min_fs);
413         printf("Media del espacio libre por bloque: %lu bytes\n", s.media_fs);
414         printf("Cantidad de registros: %lu\n", s.cant_registros);
415         printf("Cantidad de bloques: %lu\n", s.cant_bloques);
416         return 0;
417 }
418
419 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)
420 {
421         INDICE *tmp;
422         int error=0;
423
424         /* Verifico que no existe un indice con el mismo nombre */
425         /* y que no exista un indice primario */
426         PERR("Agregando indice");
427         tmp = emu->indices;
428         while (tmp) {
429                 if (strcmp(tmp->nombre, nombre)==0) {
430                         error = 1;
431                         break;
432                 }
433                 if ((funcion == IND_PRIMARIO) && (tmp->funcion == funcion)) {
434                         error = 2;
435                         break;
436                 }
437                 tmp = tmp->sig;
438         }
439
440         if (tmp != NULL) {
441                 switch (error) {
442                         case 1:
443                                 PERR("Ya existe un indice con el mismo nombre!");
444                         break;
445                         case 2:
446                                 PERR("EMUFS ya tiene indice primario!!");
447                 }
448                 return 0;
449         }
450
451         /* Creo el nuevo indice */
452         PERR("Creando indice\n");
453         tmp = emufs_indice_crear(emu, nombre, funcion, tipo, tipo_dato, offset, tam_bloque, str_offset);
454
455         /* Guardo la info del indice para poder abrir despues el archivo */
456         guardar_indice(emu, nombre, funcion, tipo, tipo_dato, offset, tam_bloque);
457
458         if (tmp == NULL) {
459                 PERR("NO SE PUDO CREAR INDICE!!!");
460                 return 0;
461         }
462
463         if (emu->indices==NULL)
464                 emu->indices = tmp;
465         else {
466                 tmp->sig = emu->indices;
467                 emu->indices = tmp;
468         }
469         return 1;
470 }
471
472 INDICE_DATO *emufs_buscar_registros(EMUFS *emu, char *indice, char *data, int *cant)
473 {
474         CLAVE k;
475         INDICE *tmp;
476
477         tmp = emu->indices;
478         while (tmp) {
479                 if (strcmp(tmp->nombre, indice) == 0) break;
480                 tmp = tmp->sig;
481         }
482
483         if (tmp == NULL) {
484                 PERR("NO EXISTE EL INDICE");
485                 cant = 0;
486                 return NULL;
487         }
488
489         PERR("GENERANDO CLAVE")
490         PERR(data);
491         k = emufs_indice_generar_clave_desde_valor(tmp, data);
492         PERR("DONE");
493         return tmp->buscar_entradas(tmp, k, cant);
494 }
495
496 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)
497 {
498         char filename[100];
499         FILE *fp;
500         int cant; /* cantidad de indices hasta el momento */
501         t_Indice *indices;
502
503         sprintf(filename, "%s.info", emu->nombre);
504         fp = fopen(filename, "r+");
505         PERR("Abri info");
506         PERR(filename);
507         if (fp == NULL) {
508                 PERR("No se pudo");
509                 return 0;
510         }
511
512         fread(&cant, 1, sizeof(int), fp);
513         indices = malloc((cant+1)*sizeof(t_Indice));
514         fread(indices, cant, sizeof(t_Indice), fp);
515         memset(indices[cant].nombre, 0, 50); 
516         strcpy(indices[cant].nombre, nombre);
517         indices[cant].funcion = funcion;
518         indices[cant].tipo = tipo;
519         indices[cant].tipo_dato = tipo_dato;
520         indices[cant].offset = offset;
521         indices[cant].tam_bloque = tam_bloque;
522
523         fseek(fp, SEEK_SET, 0);
524         cant++;
525         fwrite(&cant, 1, sizeof(int), fp);
526         fwrite(indices, cant, sizeof(t_Indice), fp);
527         fclose(fp);
528         free(indices);
529         return 1;
530 }
531
532 /*crea un bloque y devuelve en numero del mismo*/
533 EMUFS_BLOCK_ID emufs_create_new_block(EMUFS *emu)
534 {
535         FILE *fp;
536         char name[255];
537         char *dummy;
538         EMUFS_BLOCK_ID num;
539         
540         /* obtengo nombre del archivo */
541         strcpy(name, emu->nombre);
542         strcat(name,".dat");
543         
544         if ( (fp=fopen(name,"a+")) == NULL ){
545                 PERR("NO SE PUDO ABRIR EL ARCHIVO");
546                 return -1;
547         }
548
549         dummy = (char*)malloc(emu->tam_bloque);
550         memset(dummy, 0, emu->tam_bloque);
551         fwrite(dummy, emu->tam_bloque, 1, fp);
552         switch(emu->tipo){
553                 case T4: num = (ftell(fp)-sizeof(EMUFS_Tipo)-sizeof(EMUFS_BLOCK_SIZE))/emu->tam_bloque;
554                         break;
555                 case T5: num = (ftell(fp)-sizeof(EMUFS_Tipo)-sizeof(EMUFS_BLOCK_SIZE)-sizeof(EMUFS_REG_SIZE))/emu->tam_bloque;
556                         break;
557                 default: num = 0;               
558         }
559         fclose(fp);
560         free(dummy);
561         return num-1;
562 }
563
564 /*devuelve un numero de bloque siguiente al ultimo*/
565 EMUFS_BLOCK_ID emufs_get_new_block_number(EMUFS *emu)
566 {
567         FILE *fp;
568         char name[255];
569         EMUFS_BLOCK_ID num=0;
570         
571         /* obtengo nombre del archivo */
572         strcpy(name, emu->nombre);
573         strcat(name,".dat");
574         if ( (fp=fopen(name,"r")) == NULL ){
575                 PERR("NO SE PUDO ABRIR EL ARCHIVO");
576                 return -1;
577         }
578         if ( fseek(fp, 0, SEEK_END)!=0 ){
579                 PERR("NO PUDE HACER EL SEEK");
580                 return -1;
581         }
582         switch(emu->tipo){
583                 case T4: num = (ftell(fp)-sizeof(EMUFS_Tipo)-sizeof(EMUFS_BLOCK_SIZE))/emu->tam_bloque;
584                         if (ftell(fp) ==  sizeof(EMUFS_Tipo)+sizeof(EMUFS_BLOCK_SIZE)) num = 0;
585                         break;
586                 case T5: num = (ftell(fp)-sizeof(EMUFS_Tipo)-sizeof(EMUFS_BLOCK_SIZE)-sizeof(EMUFS_REG_SIZE))/emu->tam_bloque;
587                         if (ftell(fp) ==  sizeof(EMUFS_Tipo)+sizeof(EMUFS_BLOCK_SIZE)+sizeof(EMUFS_REG_SIZE)) num = 0;
588                         break;
589                 default: num = 0;
590         }
591         fclose(fp);
592         return num;
593 }
594
595 INDICE *emufs_buscar_indice_por_nombre(EMUFS *emu, const char *nombre)
596 {
597         INDICE *tmp;
598
599         tmp = emu->indices;
600         while (tmp) {
601                 if (strcmp(tmp->nombre, nombre) == 0) break;
602                 tmp = tmp->sig;
603         }
604         return tmp;
605 }