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