]> git.llucax.com Git - z.facultad/75.06/jacu.git/blob - src/vfile/vfile.c
Subo BS (Merge con exito!)
[z.facultad/75.06/jacu.git] / src / vfile / vfile.c
1 /* vim: set noexpandtab tabstop=4 shiftwidth=4 wrap:
2  *----------------------------------------------------------------------------
3  *                                  jacu
4  *----------------------------------------------------------------------------
5  * This file is part of jacu.
6  *
7  * jacu 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  * jacu 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 jacu; if not, write to the Free Software Foundation, Inc., 59 Temple
19  * Place, Suite 330, Boston, MA  02111-1307  USA
20  *----------------------------------------------------------------------------
21  * Creado:  mié jun 16 14:04:55 ART 2004
22  * Autores: Leandro Lucarella <llucare@fi.uba.ar>
23  *----------------------------------------------------------------------------
24  *
25  * $Id$
26  *
27  */
28
29 #include "common.h"
30 #include "vfile.h"
31 #include <malloc.h>
32 #include <string.h>
33
34 /** \file
35  *
36  * Archivo virtual divisible en volúmenes.
37  * 
38  * Implementación de un archivo virtual divisible en volúmenes.
39  * Provee algunas funciones compatibles con la stdio de ANSI C para utilizar
40  * de forma transparente archivos virtuales divididos en varios volúmenes.
41  *
42  */
43
44 /** Abre un volumen. */
45 int vfvol_open_next(VFILE* vfp);
46
47 /** Cierra un volumen. */
48 int vfvol_close(VFILE* vfp);
49
50 VFILE* vfopen(const char* path, const char* mode, long volsize)
51 {
52         VFILE* vfp = malloc(sizeof(VFILE));
53         if (!vfp) return 0; /* no hay más memoria */
54         if (volsize < VFMINVOLSIZE) /* tamaño de volumen inválido. */
55         {
56                 PERR("vfopen: volsize = 0");
57                 vfp->volsize = 0;
58         }
59         else /* tamaño de volumen válido. */
60         {
61                 vfp->volsize = --volsize; /* Uno menos para guardar cabecera. */
62         }
63          /* Chequeo que sea un modo correcto. */
64         if (mode[0] == 'r' && mode[1] != '+')      vfp->mode = VFREAD;
65         else if (mode[0] == 'w' && mode[1] != '+') vfp->mode = VFWRITE;
66         else /* no es un modo válido. */
67         {
68                 PERR("vfopen: modo inválido!");
69                 free(vfp);
70                 return 0;
71         }
72         if (!(vfp->name = str_dup(path))) /* no hay más memoria */
73         {
74                 PERR("vfopen: no se pudo hacer str_dup!");
75                 free(vfp);
76                 return 0;
77         }
78         /* Abrimos primer archivo de los volumenes. */
79         vfp->currvol = -1;
80         vfp->lastvol = 0;
81         if (vfvol_open_next(vfp)) /* no se pudo abrir el primer volumen. */
82         {
83                 PERR("vfopen: no se pudo abrir archivo inicial!");
84                 free(vfp->name);
85                 free(vfp);
86                 return 0;
87         }
88         return vfp; /* todo ok. */
89 }
90
91 int vfclose(VFILE* vfp)
92 {
93         int ret;
94         vfp->lastvol = 1; /* es el último volumen. */
95         ret = vfvol_close(vfp);
96         free(vfp->name);
97         free(vfp);
98         return ret;
99 }
100
101 int vfeof(VFILE* vfp)
102 {
103         return vfp->lastvol && feof(vfp->fp);
104 }
105
106 int vfgetc(VFILE* vfp)
107 {
108         int c;
109         if ((c = fgetc(vfp->fp)) == EOF)
110         {
111                 PERR("vfgetc: fgetc == EOF!");
112                 if (vfp->lastvol) return EOF; /* último volumen. */
113                 if (vfvol_close(vfp)) return EOF; /* error al cerrar. */
114                 if (vfvol_open_next(vfp)) return EOF; /* error al abrir. */
115                 c = fgetc(vfp->fp); /* obtengo caracter */
116         }
117         /* vfp->currpos++; */
118         return c;
119 }
120
121 int vfputc(int c, VFILE* vfp)
122 {
123         /* Si no es multivolumen o hay lugar, agrego y salgo. */
124         if (!vfp->volsize || vfp->room--) return fputc(c, vfp->fp);
125         PERR("vfputc: Necesito otro volumen!\n");
126         /* Si no hay lugar, abro otro volumen. */
127         if (vfvol_close(vfp)) return EOF; /* error al cerrar. */
128         if (vfvol_open_next(vfp)) return EOF; /* error al abrir. */
129         vfp->room--; /* resto de nuevo el espacio porque al abrirlo lo resetea. */
130         return fputc(c, vfp->fp);
131 }
132
133 size_t vfread(void* ptr, size_t size, size_t nmemb, VFILE* vfp)
134 {
135         int c;
136         size_t i = 0;
137         size_t total = size * nmemb;
138         /* leo uno a uno y si hay error salgo. */
139         while (i < total)
140         {
141                 if ((c = vfgetc(vfp)) == EOF)
142                 {
143                         PERR("vfread: EOF");
144                         break;
145                 }
146                 else ((char*)ptr)[i++] = c;
147         }
148         return i / size;
149 }
150
151 size_t vfwrite(const void *ptr, size_t size, size_t nmemb, VFILE* vfp)
152 {
153         size_t i = 0;
154         size_t total = size * nmemb;
155         /* escribo uno a uno y si hay error salgo. */
156         while (i < total && (vfputc(((char*)ptr)[i++], vfp)) != EOF);
157         return i / size;
158 }
159
160 int vfvol_close(VFILE* vfp)
161 {
162         int ret = 0;
163         if (vfp->fp)
164         {
165                 /* Si es de escritura y el último guardo la cabecera. */
166                 if (vfp->mode == VFWRITE && vfp->lastvol)
167                 {
168                         int ret;
169                         PERR("vfvol_close: modo == VFWRITE");
170                         /* Me posiciono al principio del archivo. */
171                         if ((ret = fseek(vfp->fp, 0l, SEEK_SET)))
172                         {
173                                 PERR("vfvol_close: fseek error");
174                                 return ret; /* fseek error. */
175                         }
176                         /* Guardo cabecera para indicar si es el último volumen o no. */
177                         if ((ret = fputc(vfp->lastvol, vfp->fp)) == EOF)
178                         {
179                                 PERR("vfvol_close: fputc error");
180                                 return ret; /* fputc error. */
181                         }
182                 }
183                 ret = fclose(vfp->fp);
184                 vfp->fp = 0;
185         }
186         return ret;
187 }
188
189 int vfvol_open_next(VFILE* vfp)
190 {
191         char* volname = 0;
192         char* name    = vfp->name; /* si es el archivo principal uso el nombre. */
193         PERR("vfvol_open_next: ping");
194         if (vfp->currvol >= 0) /* si no es el archivo principal. */
195         {
196                 PERR("vfvol_open_next: No es el archivo principal");
197                 /* 1 para el \0 y sizeof(int) * 3 para el número de volumen. */
198                 volname = malloc(strlen(vfp->name) + 1 + sizeof(int) * 3);
199                 if (!volname) return 1; /* no hay más memoria */
200                 /* Construyo el nombre del archivo. */
201                 sprintf(volname, VFNAMETEMPLATE, vfp->name, vfp->currvol + 1);
202                 name = volname; /* uso este nuevo nombre. */
203         }
204         /* Abro dependiendo del modo. */
205         if (!(vfp->fp = fopen(name, (vfp->mode == VFREAD) ? "r" : "w")))
206         {
207                 PERR("vfvol_open_next: error al abrir!");
208                 if (volname) free(volname);
209                 return 2; /* error al abrir. */
210         }
211         vfp->currvol++;
212         if (volname) free(volname);
213         /* Si es para lectura, me fijo si es el últio a leer. */
214         if (vfp->mode == VFREAD) vfp->lastvol = fgetc(vfp->fp);
215         /* Si es para escritura, guardo header por default (hay más volúmenes). */
216         if (vfp->mode == VFWRITE)
217         {
218                 vfp->room = vfp->volsize; /* tengo todo el espacio disponible. */
219                 return fputc(vfp->lastvol, vfp->fp) == EOF;
220         }
221         return 0;
222 }
223
224 long vfsize(const char* path)
225 {
226         VFILE* vfp = vfopen(path, "r", 0);
227         long size;
228         if (!vfp) return -1; /* error */
229         if (fseek(vfp->fp, 0l, SEEK_END) == -1)
230         {
231                 vfclose(vfp);
232                 return -1; /* error */
233         }
234         else
235         {
236                 size = ftell(vfp->fp);
237                 if (size == -1)
238                 {
239                         vfclose(vfp);
240                         return -1; /* error */
241                 }
242         }
243         while (!vfp->lastvol) /* mientras no sea el último volumen */
244         {
245                 if (vfvol_open_next(vfp))
246                 {
247                         vfclose(vfp);
248                         return -1; /* error */
249                 }
250                 if (fseek(vfp->fp, 0l, SEEK_END) == -1)
251                 {
252                         vfclose(vfp);
253                         return -1; /* error */
254                 }
255                 else
256                 {
257                         long curr_size = ftell(vfp->fp);
258                         if (curr_size == -1)
259                         {
260                                 vfclose(vfp);
261                                 return -1; /* error */
262                         }
263                         size += curr_size;
264                 }
265                 if (vfvol_close(vfp))
266                 {
267                         vfclose(vfp);
268                         return -1; /* error */
269                 }
270         }
271         vfclose(vfp);
272         return size;
273 }
274