]> git.llucax.com Git - z.facultad/75.06/emufs.git/blob - emufs/tipo1.c
- Se agrega leer_estadisticas().
[z.facultad/75.06/emufs.git] / emufs / tipo1.c
1 /* vim: set noexpandtab tabstop=4 shiftwidth=4 wrap:
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:  vie abr  9 16:47:32 ART 2004
22  * Autores: Leandro Lucarella <llucare@fi.uba.ar>
23  *----------------------------------------------------------------------------
24  *
25  * $Id$
26  *
27  */
28
29 /** \file
30  *
31  * Archivo con bloque de longitud parametrizada, registro de longitud variable.
32  * 
33  * Implementación del archivo con bloques de longitud parametrizada y registros
34  * de longitud variable.
35  *
36  */
37
38 #include "tipo1.h"
39 #include "idx.h"
40 #include "fsc.h"
41 #include "did.h"
42 #include <stdio.h>
43 #include <stdlib.h>
44 #include <string.h>
45 #include <unistd.h>
46
47 #ifndef MIN
48 #       define MIN(x, y) (((x) > (y)) ? (y) : (x))
49 #endif
50
51 /*------------------ Declaraciones privadas ----------------------*/
52
53 /** Cabecera de un registro de un archivo tipo1. */
54 typedef struct {
55         EMUFS_REG_ID   id;   /**< Identificador del registro. */
56         EMUFS_REG_SIZE size; /**< Tamaño del registro. */
57 } EMUFS_TIPO1_REG_HEADER;
58
59 static size_t emufs_tipo1_header_size(void);
60
61 static int emufs_tipo1_header_jump(FILE*);
62
63 static int emufs_tipo1_block_jump(EMUFS*, FILE*, EMUFS_BLOCK_ID);
64
65 static void emufs_tipo1_escribir_reg_en_memoria(char*, EMUFS_TIPO1_REG_HEADER,
66                 char*);
67
68 static void emufs_tipo1_escribir_reg_chunk_en_memoria(char* dst,
69                 EMUFS_TIPO1_REG_HEADER header, char* reg, EMUFS_REG_SIZE reg_size);
70
71 /** Lee el bloque \param num_bloque y lo almacena en \c ptr. */
72 static void* emufs_tipo1_leer_bloque(EMUFS*, EMUFS_BLOCK_ID, int*);
73
74 /** Graba el bloque apuntado por \c ptr en el archivo. */
75 static EMUFS_BLOCK_ID emufs_tipo1_grabar_bloque(EMUFS*, void*, EMUFS_BLOCK_ID,
76                 int*);
77
78 /*------------------ Funciones públicas ----------------------*/
79
80 int emufs_tipo1_inicializar(EMUFS* efs)
81 {
82         /* como mínimo el tamaño de bloque debe ser 2 veces el tamaño de la cabecera
83          * (una relación 1/2 entre datos e info de control ya es lo suficientemente
84          * mala */
85         if (efs->tam_bloque < (sizeof(EMUFS_TIPO1_REG_HEADER) * 2)) {
86                 PERR("bloque demasiado chico");
87                 return 1000; /* EMUFS_ERROR_BLOCK_SIZE_TOO_SMALL */
88         }
89         /* Asigna punteros a funciones. */
90         efs->leer_bloque       = emufs_tipo1_leer_bloque;
91         efs->grabar_registro   = emufs_tipo1_grabar_registro;
92         efs->borrar_registro   = emufs_tipo1_borrar_registro;
93         efs->leer_registro     = emufs_tipo1_leer_registro;
94         efs->leer_registro_raw = emufs_tipo1_leer_registro_raw;
95         efs->leer_estadisticas = emufs_tipo1_leer_estadisticas;
96         return 0; /* EMUFS_OK */
97 }
98
99 void* emufs_tipo1_leer_registro(EMUFS* efs, EMUFS_REG_ID reg_id,
100                 EMUFS_REG_SIZE* reg_size, int *err)
101 {
102         char* block; /* bloque leido (en donde está el registro a leer) */
103         char* registro; /* registro a leer */
104         EMUFS_BLOCK_ID block_id; /* id del bloque en donde esta el registro a leer */
105         EMUFS_BLOCK_SIZE offset; /* offset del bloque leído */
106         EMUFS_TIPO1_REG_HEADER curr_reg_header; /* cabecera del registro a leer */
107
108         block_id = emufs_idx_buscar_registro(efs, reg_id);
109         if (block_id == EMUFS_NOT_FOUND) {
110                 /* TODO Manejo de errores */
111                 PERR("Registro no encontrado");
112                 *err = EMUFS_NOT_FOUND;
113                 return NULL;
114         }
115         if (!(block = (char*) emufs_tipo1_leer_bloque(efs, block_id, err))) {
116                 /* TODO Manejo de errores */
117                 PERR("no se pudo reservar memoria");
118                 *err = 2; /* EMUFS_ERROR_OUT_OF_MEMORY */
119                 return NULL;
120         }
121
122         /* Busco secuencialmente en el bloque el registro a leer */
123         offset = 0;
124         do {
125                 /* Copio la cabecera del registro actual. */
126                 memcpy(&curr_reg_header, block + offset, sizeof(EMUFS_TIPO1_REG_HEADER));
127                 offset += sizeof(EMUFS_TIPO1_REG_HEADER);
128                 if (curr_reg_header.id == reg_id) {
129                         /* tamaño máximo ultilizable para datos en un bloque */
130                         EMUFS_BLOCK_SIZE block_space
131                                         = efs->tam_bloque - sizeof(EMUFS_TIPO1_REG_HEADER);
132                         /* tamaño de la porción de registro que se guarda */
133                         EMUFS_REG_SIZE chunk_size = 0; 
134                         /* puntero a la porción actual del registro */
135                         char* chunk_ptr;
136
137                         *reg_size = curr_reg_header.size;
138                         registro = chunk_ptr = (char*) malloc(*reg_size);
139                         if (registro == NULL) {
140                                 /* TODO Manejo de errores */
141                                 free(block);
142                                 PERR("No hay memoria");
143                                 *err = 2; /* EMUFS_ERROR_OUT_OF_MEMORY */
144                                 return NULL;
145                         }
146                         while (1) {
147                                 chunk_ptr += chunk_size; /* Avanzo para guardar prox chunk */
148                                 curr_reg_header.size -= chunk_size; /* Resto lo que ya guardé */
149                                 chunk_size = MIN(curr_reg_header.size, block_space);
150                                 /* copio porción de registro en el buffer */
151                                 memcpy(chunk_ptr, block + offset, chunk_size);
152                                  /* falta leer un bloque */
153                                 if (curr_reg_header.size > block_space) {
154                                         free(block);
155                                         if (!(block = (char*) emufs_tipo1_leer_bloque(efs,
156                                                                         ++block_id, err))) {
157                                                 /* TODO Manejo de errores */
158                                                 free(registro);
159                                                 PERR("no se pudo reservar memoria");
160                                                 *err = 2; /* EMUFS_ERROR_OUT_OF_MEMORY */
161                                                 return NULL;
162                                         }
163                                 } else { /* se terminó de leer */
164                                         break;
165                                 }
166                         }
167                         break;
168                 }
169                 /* Desplazo el offset */
170                 offset += curr_reg_header.size;
171
172         /* esto no debería ser nunca false porque sé positivamente que el */
173         } while (offset < efs->tam_bloque); /* registro está en el bloque */
174
175         free(block);
176         return registro;
177 }
178
179 /* @todo TODO hacer que soporte registros de más de un bloque */
180 void* emufs_tipo1_leer_registro_raw(EMUFS *efs, EMUFS_REG_ID id,
181                 EMUFS_REG_SIZE *size, int *pos)
182 {
183         char* block; /* bloque leido (en donde está el registro a leer) */
184         EMUFS_BLOCK_ID block_id; /* id del bloque en donde esta el registro a leer */
185         EMUFS_BLOCK_SIZE offset; /* offset del bloque leído */
186         EMUFS_TIPO1_REG_HEADER curr_reg_header; /* cabecera del registro a leer */
187         int err;
188
189         block_id = emufs_idx_buscar_registro(efs, id);
190         if (block_id == EMUFS_NOT_FOUND) {
191                 return NULL;
192         }
193         err = 0;
194         if (!(block = (char*) emufs_tipo1_leer_bloque(efs, block_id, &err))) {
195                 return NULL;
196         }
197
198         /* Busco secuencialmente en el bloque el registro a leer */
199         offset = 0;
200         do {
201                 /* Copio la cabecera del registro. */
202                 memcpy(&curr_reg_header, block + offset, sizeof(EMUFS_TIPO1_REG_HEADER));
203                 offset += sizeof(EMUFS_TIPO1_REG_HEADER);
204                 if (curr_reg_header.id == id) {
205                         *pos = offset - sizeof(EMUFS_TIPO1_REG_HEADER);
206                         break;
207                 }
208                 /* Desplazo el offset */
209                 offset += curr_reg_header.size;
210         } while (offset < efs->tam_bloque);
211
212         (*size) = efs->tam_bloque;
213         return block;
214 }
215
216 void* emufs_tipo1_leer_bloque(EMUFS* efs, EMUFS_BLOCK_ID block_id, int *err)
217 {
218         FILE* file;
219         char* block; /* bloque leido (en donde está el registro a leer) */
220         char  name_f[255];
221
222         strcpy(name_f,efs->nombre);
223         strcat(name_f,".dat");
224
225         if ((file = fopen(name_f, "r")) == NULL) {
226                 PERR("No se puede abrir archivo");
227                 *err = 4; /* EMUFS_ERROR_CANT_OPEN_FILE */
228                 return NULL; /* FIXME ERROR */
229         }
230         emufs_tipo1_header_jump(file); /* salta cabeceras */
231         emufs_tipo1_block_jump(efs, file, block_id); /* salta bloques */
232         /* FIXME: verificar que no se pase de fin de archivo*/
233         block = (char*) malloc(efs->tam_bloque);
234         if (block == NULL) {
235                 /* TODO Manejo de errores */
236                 PERR("No hay memoria");
237                 *err = 2; /* EMUFS_ERROR_OUT_OF_MEMORY */
238                 return NULL;
239         }
240         if (fread(block, efs->tam_bloque, 1, file) != 1) {
241                 /* TODO Manejo de errores */
242                 free(block);
243                 PERR("Error al leer bloque");
244                 *err = 3; /* EMUFS_ERROR_FILE_READ */
245                 return NULL;
246         }
247         fclose(file);
248         return block;
249 }
250
251 EMUFS_REG_ID emufs_tipo1_grabar_registro(EMUFS* efs, void* reg, EMUFS_REG_SIZE reg_size, int* err)
252 {
253         EMUFS_TIPO1_REG_HEADER reg_header; /* cabecera del registro a guardar */
254         EMUFS_FREE             fs; /* espacio libre en el bloque */
255         EMUFS_BLOCK_ID         block_id; /* identificador del 1er bloque */
256         char*                  block; /* buffer del bloque a guardar en disco */
257         char                   name_f[255];
258
259         strcpy(name_f, efs->nombre);
260         strcat(name_f, ".dat");
261
262         /* pongo tamaño del registro en la cabecera. */
263         reg_header.size = reg_size;
264         /* busco lugar para el registro en un bloque existente */
265         block_id = emufs_fsc_buscar_lugar(efs, sizeof(EMUFS_TIPO1_REG_HEADER)
266                         + reg_size, &fs);
267         /* si no hay bloques con suficiente espacio creo un bloque nuevo */
268         if (block_id == EMUFS_NOT_FOUND) {
269                 /* tamaño máximo ultilizable para datos en un bloque */
270                 EMUFS_BLOCK_SIZE block_space = efs->tam_bloque - sizeof(EMUFS_TIPO1_REG_HEADER);
271                 /* identificador del bloque que se guarda */
272                 EMUFS_BLOCK_ID curr_block_id = EMUFS_NOT_FOUND;
273                 /* tamaño de la porción de registro que se guarda */
274                 EMUFS_REG_SIZE chunk_size = 0; 
275                 /* puntero a la poción del registro */
276                 char* chunk_ptr = reg; 
277
278                 /* crear un nuevo bloque en memoria */
279                 block = (char*) malloc(efs->tam_bloque);
280                 if (block == NULL) {
281                         /* TODO Manejo de errores */
282                         PERR("No hay memoria");
283                         *err = 2; /* EMUFS_ERROR_OUT_OF_MEMORY */
284                         return EMUFS_NOT_FOUND;
285                 }
286                 reg_header.id = emufs_idx_get_new_id(efs, err);
287                 do {
288                         memset(block, 0, efs->tam_bloque); /* inicializa bloque */
289                         chunk_ptr += chunk_size; /* Avanzo para guardar prox chunk */
290                         reg_header.size -= chunk_size; /* Resto lo que ya guardé */
291                         chunk_size = MIN(reg_header.size, block_space);
292                         /* graba porción del registro en bloque */
293                         emufs_tipo1_escribir_reg_chunk_en_memoria(block, reg_header, chunk_ptr, chunk_size);
294                         /* graba el bloque en el archivo */
295                         curr_block_id = emufs_tipo1_grabar_bloque(efs, block, EMUFS_NOT_FOUND, err);
296                         if (*err) {
297                                 PERR("error al grabar bloque");
298                                 free(block);
299                                 return EMUFS_NOT_FOUND;
300                         }
301                         /* grabo el nuevo registro en el archivo de espacios libres */
302                         *err = emufs_fsc_agregar(efs, curr_block_id, block_space - chunk_size);
303                         if (*err) {
304                                 PERR("No se pudo agregar fsc");
305                                 free(block);
306                                 return EMUFS_NOT_FOUND;
307                         }
308                         /* si es el primer id de bloque obtenido, lo guardo para
309                          * agregarlo después al archivo de índices. */
310                         if (block_id == EMUFS_NOT_FOUND) {
311                                 block_id = curr_block_id;
312                         }
313                 } while (reg_header.size > block_space);
314                 free(block);
315
316         /* Encontró espacio en un bloque existente, graba registro ahí */
317         } else {
318                 /* cargo el bloque en block_id */
319                 if (!(block = (char*) emufs_tipo1_leer_bloque(efs, block_id, err))) {
320                         /* TODO Manejo de errores */
321                         PERR("no se pudo leer el bloque");
322                         return EMUFS_NOT_FOUND;
323                 }
324                 /* inserta el registro en el bloque */
325                 /* tengo que buscar un ID válido para el nuevo registro */
326                 reg_header.id = emufs_idx_get_new_id(efs, err);
327                 /* graba registro en bloque */
328                 emufs_tipo1_escribir_reg_en_memoria(block + efs->tam_bloque - fs,
329                                 reg_header, reg);
330                 /* graba el bloque en el archivo */
331                 block_id = emufs_tipo1_grabar_bloque(efs, block, block_id, err);
332                 if (*err) {
333                         PERR("error al grabar bloque");
334                         free(block);
335                         return EMUFS_NOT_FOUND;
336                 }
337                 free(block);
338                 /* actualizo el archivo de espacios libres */
339                 *err = emufs_fsc_actualizar(efs, block_id, fs - reg_size
340                                 - sizeof(EMUFS_TIPO1_REG_HEADER));
341                 if (*err) {
342                         PERR("No se pudo actualizar fsc");
343                         return EMUFS_NOT_FOUND;
344                 }
345         }
346                 
347         /* actualizo el indice de bloques y registros */
348         *err = emufs_idx_agregar(efs, reg_header.id, block_id);
349         if (*err){
350                 PERR("No se pudo agregar idx");
351                 return EMUFS_NOT_FOUND;
352         }
353         
354         return reg_header.id;
355 }
356
357 int emufs_tipo1_borrar_registro(EMUFS* efs, EMUFS_REG_ID reg_id)
358 {
359         char* block; /* bloque leido (en donde está el registro a leer) */
360         EMUFS_BLOCK_ID block_id; /* id del bloque en donde esta el registro a leer */
361         EMUFS_BLOCK_SIZE offset; /* offset del bloque leído */
362         EMUFS_TIPO1_REG_HEADER curr_reg_header; /* cabecera del registro a leer */
363         int err = 0; /* para almacenar código de error */
364
365         block_id = emufs_idx_buscar_registro(efs, reg_id);
366         if (block_id == EMUFS_NOT_FOUND) {
367                 /* TODO Manejo de errores */
368                 PERR("Registro no encontrado");
369                 return EMUFS_NOT_FOUND;
370         }
371         if (!(block = (char*) emufs_tipo1_leer_bloque(efs, block_id, &err))) {
372                 /* TODO Manejo de errores */
373                 PERR("no se pudo reservar memoria");
374                 return err;
375         }
376
377         /* Busco secuencialmente en el bloque el registro a leer */
378         offset = 0;
379         do {
380                 /* Copio la cabecera del registro actual. */
381                 memcpy(&curr_reg_header, block + offset, sizeof(EMUFS_TIPO1_REG_HEADER));
382                 if (curr_reg_header.id == reg_id) {
383                         /* identificador del bloque actual */
384                         EMUFS_BLOCK_ID curr_block_id = block_id;
385                         /* tamaño máximo ultilizable para datos en un bloque */
386                         EMUFS_BLOCK_SIZE block_space
387                                         = efs->tam_bloque - sizeof(EMUFS_TIPO1_REG_HEADER);
388                         EMUFS_FREE fs; /* cantidad de espacio libre en el bloque */
389
390                         while (1) {
391                                 /* actualizo archivo de espacio libre por bloque */
392                                 fs = emufs_fsc_get_fs(efs, curr_block_id)
393                                         + MIN(curr_reg_header.size, block_space)
394                                         + sizeof(EMUFS_TIPO1_REG_HEADER);
395                                 if ((err = emufs_fsc_actualizar(efs, curr_block_id, fs))) {
396                                         /* TODO Manejo de errores */
397                                         PERR("no se pudo actualizar .fsc");
398                                         free(block);
399                                         return err;
400                                 }
401                                 /* falta liberar un bloque (o porción) */
402                                 if (curr_reg_header.size > block_space) {
403                                         free(block);
404                                         if (!(block = (char*) emufs_tipo1_leer_bloque(efs,
405                                                                         ++curr_block_id, &err))) {
406                                                 /* TODO Manejo de errores */
407                                                 PERR("no se pudo leer el bloque");
408                                                 return err;
409                                         }
410                                         /* copio la cabecera del primer registro (si ocupa más de un
411                                          * registro está en bloques contiguos) */
412                                         memcpy(&curr_reg_header, block,
413                                                         sizeof(EMUFS_TIPO1_REG_HEADER));
414                                 } else { /* se terminó de leer */
415                                         break;
416                                 }
417                         }
418
419                         /* actualizo archivo de identificadores de registros borrados */
420                         if ((err = emufs_did_agregar(efs, reg_id))) {
421                                 /* TODO Manejo de errores */
422                                 PERR("no se pudo actualizar .did");
423                                 free(block);
424                                 return err;
425                         }
426                         /*actualizo archivo .idx*/
427                         if ((err = emufs_idx_borrar(efs, reg_id))) {
428                                 /* TODO Manejo de errores */
429                                 PERR("no se pudo actualizar .did");
430                                 free(block);
431                                 return err;
432                         }
433
434                         /* desplazo registros a izquierda */
435                         {   /* offset del fin del registro a borrar */
436                                 EMUFS_BLOCK_SIZE offset_reg_end = offset
437                                         + sizeof(EMUFS_TIPO1_REG_HEADER) + curr_reg_header.size;
438                                 /* si es necesario desplazar */
439                                 if (offset < offset_reg_end) {
440                                         /* muevo la porción de bloque a izquierda */
441                                         memcpy(block + offset, block + offset_reg_end,
442                                                 efs->tam_bloque - offset_reg_end);
443                                 }
444                         }
445                         /* guardo el bloque en disco */
446                         emufs_tipo1_grabar_bloque(efs, block, curr_block_id, &err);
447                         if (err) {
448                                 /* TODO Manejo de errores */
449                                 PERR("no se pudo grabar bloque en disco");
450                                 free(block);
451                                 return err;
452                         }
453
454                         break; /* salgo del loop, ya hice todo lo que tenía que hacer */
455                 }
456                 /* desplazo el offset */
457                 offset += sizeof(EMUFS_TIPO1_REG_HEADER) + curr_reg_header.size;
458
459         /* esto no debería ser nunca false porque sé positivamente que el */
460         } while (offset < efs->tam_bloque); /* registro está en el bloque */
461
462         free(block);
463         return 0; /* EMUFS_OK */
464 }
465
466 EMUFS_Estadisticas emufs_tipo1_leer_estadisticas(EMUFS* efs)
467 {
468         EMUFS_Estadisticas stats;
469         memset(&stats, 0, sizeof(EMUFS_Estadisticas));
470
471         /* obtengo tamaño de archivo en bytes */
472         {
473                 FILE* file;
474                 char name_f[255];
475
476                 strcpy(name_f,efs->nombre);
477                 strcat(name_f,".dat");
478                 if ((file = fopen(name_f, "ab")) == NULL) {
479                         /* TODO Manejo de errores */
480                         PERR("Error al abrir archivo");
481                         /* *err = 4; / * EMUFS_ERROR_CANT_OPEN_FILE */
482                         return stats;
483                 }
484                 stats.tam_archivo_bytes = ftell(file);
485                 fclose(file);
486         }
487
488         /* obtengo cantidad de bloques */
489         stats.cant_bloques = /* tamaño del archivo sin la cabecera */
490                 (stats.tam_archivo_bytes - sizeof(EMUFS_Tipo) - sizeof(EMUFS_BLOCK_SIZE))
491                 / efs->tam_bloque; /* dividido el tamaño de un bloque */
492
493         /* obtengo la cantidad de registros en el archivo */
494         {
495                 EMUFS_REG_ID *tmp = emufs_idx_get(efs, &stats.tam_archivo);
496                 if (tmp) free(tmp); /* libera memoria innecesaria */
497         }
498
499         /* obtengo total de información de control que guarda el archivo */
500         stats.info_control =
501                         /* cabecera del archivo */
502                         sizeof(EMUFS_Tipo) + sizeof(EMUFS_BLOCK_SIZE)
503                         /* cabeceras de registros */
504                         + stats.tam_archivo * sizeof(EMUFS_TIPO1_REG_HEADER);
505
506         /* obtengo las estadísticas del archivo de espacio libre por bloque */
507         stats.total_fs = emufs_fsc_get_total_fs(efs);
508         stats.media_fs = emufs_fsc_get_media_fs(efs);
509         emufs_fsc_get_max_min_fs(efs, &stats.min_fs, &stats.max_fs);
510
511         return stats;   
512 }
513
514 EMUFS_BLOCK_ID emufs_tipo1_grabar_bloque(EMUFS *efs, void *block,
515                 EMUFS_BLOCK_ID block_id, int* err)
516 {
517         FILE* file;
518         char name_f[255];
519
520         strcpy(name_f,efs->nombre);
521         strcat(name_f,".dat");
522
523         if ((file = fopen(name_f, "r+b")) == NULL) {
524                 /* TODO Manejo de errores */
525                 PERR("Error al abrir archivo");
526                 *err = 4; /* EMUFS_ERROR_CANT_OPEN_FILE */
527                 return EMUFS_NOT_FOUND;
528         }
529         /* Si es NOT_FOUND tengo que agregar un bloque al final del archivo */
530         if (block_id == EMUFS_NOT_FOUND) {
531                 /* me paro al final del archivo */
532                 if (fseek(file, 0l, SEEK_END)) {
533                         /* TODO Manejo de errores */
534                         PERR("No se pudo hacer fseek()");
535                         fclose(file);
536                         *err = 8; /* EMUFS_ERROR_SEEK_FILE */
537                         return EMUFS_NOT_FOUND;
538                 }
539                 /* Obtengo ID del bloque nuevo */
540                 block_id = (ftell(file) - emufs_tipo1_header_size()) / efs->tam_bloque;
541         /* Si es un ID válido, salto hasta ese bloque. */
542         } else {
543                 /* Salta el header del archivo */
544                 if ((*err = emufs_tipo1_header_jump(file))) {
545                         PERR("no se pudo saltar la cabecera del archivo");
546                         fclose(file);
547                         return EMUFS_NOT_FOUND;
548                 }
549                 /* Salta bloques */
550                 if ((*err = emufs_tipo1_block_jump(efs, file, block_id))) {
551                         PERR("no se pudo saltar la cabecera del bloque");
552                         fclose(file);
553                         return EMUFS_NOT_FOUND;
554                 }
555         }
556         /* Grabo el bloque */
557         if (fwrite(block, efs->tam_bloque, 1, file) != 1) {
558                 PERR("No se pudo escribir el archivo");
559                 fclose(file);
560                 *err = 6; /* EMUFS_ERROR_WRITE_FILE */
561                 return EMUFS_NOT_FOUND;
562         }
563
564         fclose(file);
565         return block_id;
566 }
567
568 EMUFS_REG_ID emufs_tipo1_modificar_registro(EMUFS *emu, EMUFS_REG_ID id,
569                 void *data, EMUFS_REG_SIZE size, int *error)
570 {
571         emufs_tipo1_borrar_registro(emu, id);
572         return emufs_tipo1_grabar_registro(emu, data, size, error);
573 }
574
575 size_t emufs_tipo1_header_size(void)
576 {
577         return sizeof(EMUFS_Tipo) + sizeof(EMUFS_BLOCK_SIZE);
578 }
579
580 int emufs_tipo1_header_jump(FILE* fp)
581 {
582         if (fseek(fp, emufs_tipo1_header_size(), SEEK_CUR)) {
583                 PERR("No se pudo hacer fseek()");
584                 return 8; /* EMUFS_ERROR_SEEK_FILE */
585         }
586         return 0; /* EMUFS_OK */
587 }
588
589 int emufs_tipo1_block_jump(EMUFS* efs, FILE* fp, EMUFS_BLOCK_ID block_count)
590 {
591         if (fseek(fp, block_count * efs->tam_bloque, SEEK_CUR)) {
592                 PERR("No se pudo hacer fseek()");
593                 return 8; /* EMUFS_ERROR_SEEK_FILE */
594         }
595         return 0; /* EMUFS_OK */
596 }
597
598 void emufs_tipo1_escribir_reg_en_memoria(char* dst, EMUFS_TIPO1_REG_HEADER header,
599                 char* reg)
600 {
601         emufs_tipo1_escribir_reg_chunk_en_memoria(dst, header, reg, header.size);
602 }
603
604 void emufs_tipo1_escribir_reg_chunk_en_memoria(char* dst,
605                 EMUFS_TIPO1_REG_HEADER header, char* reg, EMUFS_REG_SIZE reg_size)
606 {
607         /* grabo cabecera del registro en el bloque */
608         memcpy(dst, &header, sizeof(EMUFS_TIPO1_REG_HEADER));
609         /* incremento puntero de escritura */
610         dst += sizeof(EMUFS_TIPO1_REG_HEADER);
611         /* grabo el registro en el bloque */
612         memcpy(dst, reg, reg_size);
613 }
614