]> mj.ucw.cz Git - libucw.git/blob - lib/fastbuf.c
c3b8b80d009976a66d1914b216b8ba2f6ca52f61
[libucw.git] / lib / fastbuf.c
1 /*
2  *      Sherlock Library -- Fast File Buffering
3  *
4  *      (c) 1997--1999 Martin Mares <mj@atrey.karlin.mff.cuni.cz>
5  */
6
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <string.h>
10 #include <fcntl.h>
11 #include <unistd.h>
12
13 #include "lib.h"
14 #include "fastbuf.h"
15 #include "lfs.h"
16
17 struct fastbuf *__bfdopen(int fd, uns buffer, byte *name)
18 {
19   struct fastbuf *b = xmalloc(sizeof(struct fastbuf));
20
21   b->buflen = buffer;
22   b->buffer = xmalloc(buffer);
23   b->bptr = b->bstop = b->buffer;
24   b->bufend = b->buffer + buffer;
25   b->name = stralloc(name);
26   b->pos = b->fdpos = 0;
27   b->fd = fd;
28   return b;
29 }
30
31 struct fastbuf *
32 bopen(byte *name, uns mode, uns buffer)
33 {
34   int fd = sh_open(name, mode, 0666);
35   if (fd < 0)
36     die("Unable to %s file %s: %m",
37         (mode & O_CREAT) ? "create" : "open", name);
38   return __bfdopen(fd, buffer, name);
39 }
40
41 struct fastbuf *
42 bfdopen(int fd, uns buffer)
43 {
44   byte x[32];
45
46   sprintf(x, "fd%d", fd);
47   return __bfdopen(fd, buffer, x);
48 }
49
50 void bclose(struct fastbuf *f)
51 {
52   bflush(f);
53   close(f->fd);
54   free(f->name);
55   free(f->buffer);
56   free(f);
57 }
58
59 static int
60 rdbuf(struct fastbuf *f)
61 {
62   int l = read(f->fd, f->buffer, f->buflen);
63
64   if (l < 0)
65     die("Error reading %s: %m", f->name);
66   f->bptr = f->buffer;
67   f->bstop = f->buffer + l;
68   f->pos = f->fdpos;
69   f->fdpos += l;
70   return l;
71 }
72
73 static void
74 wrbuf(struct fastbuf *f)
75 {
76   int l = f->bptr - f->buffer;
77   char *c = f->buffer;
78
79   while (l)
80     {
81       int z = write(f->fd, c, l);
82       if (z <= 0)
83         die("Error writing %s: %m", f->name);
84       /* FIXME */
85       if (z != l)
86         log(L_ERROR "wrbuf: %d != %d (pos %Ld)", z, l, sh_seek(f->fd, 0, SEEK_CUR));
87       f->fdpos += z;
88       l -= z;
89       c += z;
90     }
91   f->bptr = f->buffer;
92   f->pos = f->fdpos;
93 }
94
95 void bflush(struct fastbuf *f)
96 {
97   if (f->bptr != f->buffer)
98     {                                   /* Have something to flush */
99       if (f->bstop > f->buffer)         /* Read data? */
100         {
101           f->bptr = f->bstop = f->buffer;
102           f->pos = f->fdpos;
103         }
104       else                              /* Write data... */
105         wrbuf(f);
106     }
107 }
108
109 inline void bsetpos(struct fastbuf *f, sh_off_t pos)
110 {
111   if (pos >= f->pos && (pos <= f->pos + (f->bptr - f->buffer) || pos <= f->pos + (f->bstop - f->buffer)))
112     f->bptr = f->buffer + (pos - f->pos);
113   else
114     {
115       bflush(f);
116       if (f->fdpos != pos && sh_seek(f->fd, pos, SEEK_SET) < 0)
117         die("lseek on %s: %m", f->name);
118       f->fdpos = f->pos = pos;
119     }
120 }
121
122 void bseek(struct fastbuf *f, sh_off_t pos, int whence)
123 {
124   sh_off_t l;
125
126   switch (whence)
127     {
128     case SEEK_SET:
129       return bsetpos(f, pos);
130     case SEEK_CUR:
131       return bsetpos(f, btell(f) + pos);
132     case SEEK_END:
133       bflush(f);
134       l = sh_seek(f->fd, pos, whence);
135       if (l < 0)
136         die("lseek on %s: %m", f->name);
137       f->fdpos = f->pos = l;
138       break;
139     default:
140       die("bseek: invalid whence=%d", whence);
141     }
142 }
143
144 int bgetc_slow(struct fastbuf *f)
145 {
146   if (f->bptr < f->bstop)
147     return *f->bptr++;
148   if (!rdbuf(f))
149     return EOF;
150   return *f->bptr++;
151 }
152
153 int bpeekc_slow(struct fastbuf *f)
154 {
155   if (f->bptr < f->bstop)
156     return *f->bptr;
157   if (!rdbuf(f))
158     return EOF;
159   return *f->bptr;
160 }
161
162 void bputc_slow(struct fastbuf *f, byte c)
163 {
164   if (f->bptr >= f->bufend)
165     wrbuf(f);
166   *f->bptr++ = c;
167 }
168
169 word bgetw_slow(struct fastbuf *f)
170 {
171   word w = bgetc_slow(f);
172 #ifdef CPU_BIG_ENDIAN
173   return (w << 8) | bgetc_slow(f);
174 #else
175   return w | (bgetc_slow(f) << 8);
176 #endif
177 }
178
179 u32 bgetl_slow(struct fastbuf *f)
180 {
181   u32 l = bgetc_slow(f);
182 #ifdef CPU_BIG_ENDIAN
183   l = (l << 8) | bgetc_slow(f);
184   l = (l << 8) | bgetc_slow(f);
185   return (l << 8) | bgetc_slow(f);
186 #else
187   l = (bgetc_slow(f) << 8) | l;
188   l = (bgetc_slow(f) << 16) | l;
189   return (bgetc_slow(f) << 24) | l;
190 #endif
191 }
192
193 u64 bgetq_slow(struct fastbuf *f)
194 {
195   u32 l, h;
196 #ifdef CPU_BIG_ENDIAN
197   h = bgetl_slow(f);
198   l = bgetl_slow(f);
199 #else
200   l = bgetl_slow(f);
201   h = bgetl_slow(f);
202 #endif
203   return ((u64) h << 32) | l;
204 }
205
206 u64 bget5_slow(struct fastbuf *f)
207 {
208   u32 l, h;
209 #ifdef CPU_BIG_ENDIAN
210   h = bgetc_slow(f);
211   l = bgetl_slow(f);
212 #else
213   l = bgetl_slow(f);
214   h = bgetc_slow(f);
215 #endif
216   return ((u64) h << 32) | l;
217 }
218
219 void bputw_slow(struct fastbuf *f, word w)
220 {
221 #ifdef CPU_BIG_ENDIAN
222   bputc_slow(f, w >> 8);
223   bputc_slow(f, w);
224 #else
225   bputc_slow(f, w);
226   bputc_slow(f, w >> 8);
227 #endif
228 }
229
230 void bputl_slow(struct fastbuf *f, u32 l)
231 {
232 #ifdef CPU_BIG_ENDIAN
233   bputc_slow(f, l >> 24);
234   bputc_slow(f, l >> 16);
235   bputc_slow(f, l >> 8);
236   bputc_slow(f, l);
237 #else
238   bputc_slow(f, l);
239   bputc_slow(f, l >> 8);
240   bputc_slow(f, l >> 16);
241   bputc_slow(f, l >> 24);
242 #endif
243 }
244
245 void bputq_slow(struct fastbuf *f, u64 q)
246 {
247 #ifdef CPU_BIG_ENDIAN
248   bputl_slow(f, q >> 32);
249   bputl_slow(f, q);
250 #else
251   bputl_slow(f, q);
252   bputl_slow(f, q >> 32);
253 #endif
254 }
255
256 void bput5_slow(struct fastbuf *f, u64 o)
257 {
258   u32 hi = o >> 32;
259   u32 low = o;
260 #ifdef CPU_BIG_ENDIAN
261   bputc_slow(f, hi);
262   bputl_slow(f, low);
263 #else
264   bputl_slow(f, low);
265   bputc_slow(f, hi);
266 #endif
267 }
268
269 void bread_slow(struct fastbuf *f, void *b, uns l)
270 {
271   while (l)
272     {
273       uns k = f->bstop - f->bptr;
274
275       if (!k)
276         {
277           rdbuf(f);
278           k = f->bstop - f->bptr;
279           if (!k)
280             die("bread on %s: file exhausted", f->name);
281         }
282       if (k > l)
283         k = l;
284       memcpy(b, f->bptr, k);
285       f->bptr += k;
286       b = (byte *)b + k;
287       l -= k;
288     }
289 }
290
291 void bwrite_slow(struct fastbuf *f, void *b, uns l)
292 {
293   while (l)
294     {
295       uns k = f->bufend - f->bptr;
296
297       if (!k)
298         {
299           wrbuf(f);
300           k = f->bufend - f->bptr;
301         }
302       if (k > l)
303         k = l;
304       memcpy(f->bptr, b, k);
305       f->bptr += k;
306       b = (byte *)b + k;
307       l -= k;
308     }
309 }
310
311 byte *                                  /* Non-standard */
312 bgets(struct fastbuf *f, byte *b, uns l)
313 {
314   byte *e = b + l - 1;
315   int k;
316
317   k = bgetc(f);
318   if (k == EOF)
319     return NULL;
320   while (b < e)
321     {
322       if (k == '\n' || k == EOF)
323         {
324           *b = 0;
325           return b;
326         }
327       *b++ = k;
328       k = bgetc(f);
329     }
330   die("%s: Line too long", f->name);
331 }
332
333 void bbcopy(struct fastbuf *f, struct fastbuf *t, uns l)
334 {
335   uns rf = f->bstop - f->bptr;
336
337   if (!l)
338     return;
339   if (rf)
340     {
341       uns k = (rf <= l) ? rf : l;
342       bwrite(t, f->bptr, k);
343       f->bptr += k;
344       l -= k;
345     }
346   while (l >= t->buflen)
347     {
348       wrbuf(t);
349       if ((uns) read(f->fd, t->buffer, t->buflen) != t->buflen)
350         die("bbcopy: %s exhausted", f->name);
351       f->pos = f->fdpos;
352       f->fdpos += t->buflen;
353       f->bstop = f->bptr = f->buffer;
354       t->bptr = t->bufend;
355       l -= t->buflen;
356     }
357   while (l)
358     {
359       uns k = t->bufend - t->bptr;
360
361       if (!k)
362         {
363           wrbuf(t);
364           k = t->bufend - t->bptr;
365         }
366       if (k > l)
367         k = l;
368       bread(f, t->bptr, k);
369       t->bptr += k;
370       l -= k;
371     }
372 }
373
374 #ifdef TEST
375
376 int main(int argc, char **argv)
377 {
378   struct fastbuf *f, *t;
379   int c;
380
381   f = bopen("/etc/profile", O_RDONLY, 16);
382   t = bfdopen(1, 13);
383   bbcopy(f, t, 100);
384   bclose(f);
385   bclose(t);
386 }
387
388 #endif