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