]> mj.ucw.cz Git - libucw.git/blob - lib/fb-file.c
31c3bf180674b677d0e65e8e3aa7370148b7302d
[libucw.git] / lib / fb-file.c
1 /*
2  *      Sherlock Library -- Fast Buffered I/O on Files
3  *
4  *      (c) 1997--2000 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 <stdio.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(f->fd, f->buffer, f->buflen);
23
24   if (l < 0)
25     die("Error reading %s: %m", f->name);
26   f->bptr = f->buffer;
27   f->bstop = f->buffer + l;
28   f->pos = f->fdpos;
29   f->fdpos += l;
30   return l;
31 }
32
33 static void
34 bfd_spout(struct fastbuf *f)
35 {
36   int l = f->bptr - f->buffer;
37   char *c = f->buffer;
38
39   while (l)
40     {
41       int z = write(f->fd, c, l);
42       if (z <= 0)
43         die("Error writing %s: %m", f->name);
44       f->fdpos += z;
45       l -= z;
46       c += z;
47     }
48   f->bptr = f->buffer;
49   f->pos = f->fdpos;
50 }
51
52 static void
53 bfd_seek(struct fastbuf *f, sh_off_t pos, int whence)
54 {
55   sh_off_t l;
56
57   if (whence == SEEK_SET && pos == f->fdpos)
58     return;
59
60   l = sh_seek(f->fd, pos, whence);
61   if (l < 0)
62     die("lseek on %s: %m", f->name);
63   f->fdpos = f->pos = l;
64 }
65
66 static void
67 bfd_close(struct fastbuf *f)
68 {
69   close(f->fd);
70   if (f->is_temp_file && unlink(f->name) < 0)
71     die("unlink(%s): %m", f->name);
72 }
73
74 static struct fastbuf *
75 bfdopen_internal(int fd, uns buflen, byte *name)
76 {
77   int namelen = strlen(name) + 1;
78   struct fastbuf *b = xmalloc_zero(sizeof(struct fastbuf) + buflen + namelen);
79
80   b->buflen = buflen;
81   b->buffer = (char *)(b+1);
82   b->bptr = b->bstop = b->buffer;
83   b->bufend = b->buffer + buflen;
84   b->name = b->bufend;
85   strcpy(b->name, name);
86   b->fd = fd;
87   b->refill = bfd_refill;
88   b->spout = bfd_spout;
89   b->seek = bfd_seek;
90   b->close = bfd_close;
91   return b;
92 }
93
94 struct fastbuf *
95 bopen(byte *name, uns mode, uns buffer)
96 {
97   struct fastbuf *b;
98   int fd = sh_open(name, mode, 0666);
99   if (fd < 0)
100     die("Unable to %s file %s: %m",
101         (mode & O_CREAT) ? "create" : "open", name);
102   b = bfdopen_internal(fd, buffer, name);
103   if (mode & O_APPEND)
104     bfd_seek(b, 0, SEEK_END);
105   return b;
106 }
107
108 struct fastbuf *
109 bfdopen(int fd, uns buffer)
110 {
111   byte x[32];
112
113   sprintf(x, "fd%d", fd);
114   return bfdopen_internal(fd, buffer, x);
115 }
116
117 void bbcopy(struct fastbuf *f, struct fastbuf *t, uns l)
118 {
119   uns rf = f->bstop - f->bptr;
120
121   if (!l)
122     return;
123   if (rf)
124     {
125       uns k = (rf <= l) ? rf : l;
126       bwrite(t, f->bptr, k);
127       f->bptr += k;
128       l -= k;
129     }
130   while (l >= t->buflen)
131     {
132       t->spout(t);
133       if ((uns) read(f->fd, t->buffer, t->buflen) != t->buflen)
134         die("bbcopy: %s exhausted", f->name);
135       f->pos = f->fdpos;
136       f->fdpos += t->buflen;
137       f->bstop = f->bptr = f->buffer;
138       t->bptr = t->bufend;
139       l -= t->buflen;
140     }
141   while (l)
142     {
143       uns k = t->bufend - t->bptr;
144
145       if (!k)
146         {
147           t->spout(t);
148           k = t->bufend - t->bptr;
149         }
150       if (k > l)
151         k = l;
152       bread(f, t->bptr, k);
153       t->bptr += k;
154       l -= k;
155     }
156 }
157
158 #ifdef TEST
159
160 int main(int argc, char **argv)
161 {
162   struct fastbuf *f, *t;
163   int c;
164
165   f = bopen("/etc/profile", O_RDONLY, 16);
166   t = bfdopen(1, 13);
167   bbcopy(f, t, 100);
168   bclose(f);
169   bclose(t);
170 }
171
172 #endif