]> mj.ucw.cz Git - libucw.git/blob - lib/fb-file.c
1fc85de5ed500445ec178a237961ce9bdd63a974
[libucw.git] / lib / fb-file.c
1 /*
2  *      Sherlock Library -- Fast Buffered I/O on Files
3  *
4  *      (c) 1997--2002 Martin Mares <mj@ucw.cz>
5  *
6  *      This software may be freely distributed and used according to the terms
7  *      of the GNU Lesser General Public License.
8  */
9
10 #include "lib/lib.h"
11 #include "lib/fastbuf.h"
12 #include "lib/lfs.h"
13
14 #include <stdlib.h>
15 #include <string.h>
16 #include <fcntl.h>
17 #include <unistd.h>
18
19 static int
20 bfd_refill(struct fastbuf *f)
21 {
22   int l = read(FB_FILE(f)->fd, f->buffer, f->bufend-f->buffer);
23   if (l < 0)
24     die("Error reading %s: %m", f->name);
25   f->bptr = f->buffer;
26   f->bstop = f->buffer + l;
27   f->pos += l;
28   return l;
29 }
30
31 static void
32 bfd_spout(struct fastbuf *f)
33 {
34   int l = f->bptr - f->buffer;
35   char *c = f->buffer;
36
37   f->pos += l;
38   while (l)
39     {
40       int z = write(FB_FILE(f)->fd, c, l);
41       if (z <= 0)
42         die("Error writing %s: %m", f->name);
43       l -= z;
44       c += z;
45     }
46   f->bptr = f->buffer;
47 }
48
49 static void
50 bfd_seek(struct fastbuf *f, sh_off_t pos, int whence)
51 {
52   sh_off_t l;
53
54   if (whence == SEEK_SET && pos == f->pos)
55     return;
56
57   l = sh_seek(FB_FILE(f)->fd, pos, whence);
58   if (l < 0)
59     die("lseek on %s: %m", f->name);
60   f->pos = l;
61 }
62
63 static void
64 bfd_close(struct fastbuf *f)
65 {
66   close(FB_FILE(f)->fd);
67   if (FB_FILE(f)->is_temp_file && unlink(f->name) < 0)
68     die("unlink(%s): %m", f->name);
69   xfree(f);
70 }
71
72 static struct fastbuf *
73 bfdopen_internal(int fd, uns buflen, byte *name)
74 {
75   int namelen = strlen(name) + 1;
76   struct fb_file *F = xmalloc(sizeof(struct fb_file) + buflen + namelen);
77   struct fastbuf *f = &F->fb;
78
79   bzero(F, sizeof(*F));
80   f->buffer = (char *)(F+1);
81   f->bptr = f->bstop = f->buffer;
82   f->bufend = f->buffer + buflen;
83   f->name = f->bufend;
84   memcpy(f->name, name, namelen);
85   F->fd = fd;
86   f->refill = bfd_refill;
87   f->spout = bfd_spout;
88   f->seek = bfd_seek;
89   f->close = bfd_close;
90   return f;
91 }
92
93 struct fastbuf *
94 bopen(byte *name, uns mode, uns buffer)
95 {
96   struct fastbuf *b;
97   int fd = sh_open(name, mode, 0666);
98   if (fd < 0)
99     die("Unable to %s file %s: %m",
100         (mode & O_CREAT) ? "create" : "open", name);
101   b = bfdopen_internal(fd, buffer, name);
102   if (mode & O_APPEND)
103     bfd_seek(b, 0, SEEK_END);
104   return b;
105 }
106
107 struct fastbuf *
108 bfdopen(int fd, uns buffer)
109 {
110   byte x[32];
111
112   sprintf(x, "fd%d", fd);
113   return bfdopen_internal(fd, buffer, x);
114 }
115
116 void bbcopy(struct fastbuf *f, struct fastbuf *t, uns l)
117 {
118   uns rf = f->bstop - f->bptr;
119   uns tbuflen = t->bufend - t->buffer;
120
121   ASSERT(f->close == bfd_close);
122   ASSERT(t->close == bfd_close);
123   if (!l)
124     return;
125   if (rf)
126     {
127       uns k = MIN(rf, l);
128       bwrite(t, f->bptr, k);
129       f->bptr += k;
130       l -= k;
131       if (!l)
132         return;
133     }
134   while (l >= tbuflen)
135     {
136       t->spout(t);
137       if ((uns) read(FB_FILE(f)->fd, t->buffer, tbuflen) != tbuflen)
138         die("bbcopy: %s exhausted", f->name);
139       f->pos += tbuflen;
140       f->bstop = f->bptr = f->buffer;
141       t->bptr = t->bufend;
142       l -= tbuflen;
143     }
144   while (l)
145     {
146       uns k = t->bufend - t->bptr;
147
148       if (!k)
149         {
150           t->spout(t);
151           k = t->bufend - t->bptr;
152         }
153       if (k > l)
154         k = l;
155       bread(f, t->bptr, k);
156       t->bptr += k;
157       l -= k;
158     }
159 }
160
161 #ifdef TEST
162
163 int main(int argc, char **argv)
164 {
165   struct fastbuf *f, *t;
166
167   f = bopen("/etc/profile", O_RDONLY, 16);
168   t = bfdopen(1, 13);
169   bbcopy(f, t, 100);
170   printf("%d %d\n", (int)btell(f), (int)btell(t));
171   bclose(f);
172   bclose(t);
173   return 0;
174 }
175
176 #endif