1 /* vim: set noexpandtab tabstop=4 shiftwidth=4 wrap:
2 *----------------------------------------------------------------------------
4 *----------------------------------------------------------------------------
5 * This file is part of jacu.
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
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
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 *----------------------------------------------------------------------------
36 * Archivo virtual divisible en volúmenes.
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.
44 /** Abre un volumen. */
45 int vfvol_open_next(VFILE* vfp);
47 /** Cierra un volumen. */
48 int vfvol_close(VFILE* vfp);
50 VFILE* vfopen(const char* path, const char* mode, long volsize)
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. */
56 PERR("vfopen: volsize = 0");
59 else /* tamaño de volumen válido. */
61 vfp->volsize = --volsize; /* Uno menos para guardar cabecera. */
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. */
68 PERR("vfopen: modo inválido!");
72 if (!(vfp->name = str_dup(path))) /* no hay más memoria */
74 PERR("vfopen: no se pudo hacer str_dup!");
78 /* Abrimos primer archivo de los volumenes. */
81 if (vfvol_open_next(vfp)) /* no se pudo abrir el primer volumen. */
83 PERR("vfopen: no se pudo abrir archivo inicial!");
88 return vfp; /* todo ok. */
91 int vfclose(VFILE* vfp)
94 vfp->lastvol = 1; /* es el último volumen. */
95 ret = vfvol_close(vfp);
101 int vfeof(VFILE* vfp)
103 return vfp->lastvol && feof(vfp->fp);
106 int vfgetc(VFILE* vfp)
109 if ((c = fgetc(vfp->fp)) == EOF)
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 */
117 /* vfp->currpos++; */
121 int vfputc(int c, VFILE* vfp)
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);
133 size_t vfread(void* ptr, size_t size, size_t nmemb, VFILE* vfp)
137 size_t total = size * nmemb;
138 /* leo uno a uno y si hay error salgo. */
141 if ((c = vfgetc(vfp)) == EOF)
146 else ((char*)ptr)[i++] = c;
151 size_t vfwrite(const void *ptr, size_t size, size_t nmemb, VFILE* vfp)
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);
160 int vfvol_close(VFILE* vfp)
165 /* Si es de escritura y el último guardo la cabecera. */
166 if (vfp->mode == VFWRITE && vfp->lastvol)
169 PERR("vfvol_close: modo == VFWRITE");
170 /* Me posiciono al principio del archivo. */
171 if ((ret = fseek(vfp->fp, 0l, SEEK_SET)))
173 PERR("vfvol_close: fseek error");
174 return ret; /* fseek error. */
176 /* Guardo cabecera para indicar si es el último volumen o no. */
177 if ((ret = fputc(vfp->lastvol, vfp->fp)) == EOF)
179 PERR("vfvol_close: fputc error");
180 return ret; /* fputc error. */
183 ret = fclose(vfp->fp);
189 int vfvol_open_next(VFILE* vfp)
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. */
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. */
204 /* Abro dependiendo del modo. */
205 if (!(vfp->fp = fopen(name, (vfp->mode == VFREAD) ? "r" : "w")))
207 PERR("vfvol_open_next: error al abrir!");
208 if (volname) free(volname);
209 return 2; /* error al abrir. */
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)
218 vfp->room = vfp->volsize; /* tengo todo el espacio disponible. */
219 return fputc(vfp->lastvol, vfp->fp) == EOF;
224 long vfsize(const char* path)
226 VFILE* vfp = vfopen(path, "r", 0);
228 if (!vfp) return -1; /* error */
229 if (fseek(vfp->fp, 0l, SEEK_END) == -1)
232 return -1; /* error */
236 size = ftell(vfp->fp);
240 return -1; /* error */
243 while (!vfp->lastvol) /* mientras no sea el último volumen */
245 if (vfvol_open_next(vfp))
248 return -1; /* error */
250 if (fseek(vfp->fp, 0l, SEEK_END) == -1)
253 return -1; /* error */
257 long curr_size = ftell(vfp->fp);
261 return -1; /* error */
265 if (vfvol_close(vfp))
268 return -1; /* error */