]> mj.ucw.cz Git - libucw.git/blob - lib/fb-file.c
73a2f14337a856f3034b3cca9e04276b7adec297
[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   switch (FB_FILE(f)->is_temp_file)
67     {
68     case 1:
69       if (unlink(f->name) < 0)
70         log(L_ERROR, "unlink(%s): %m", f->name);
71     case 0:
72       close(FB_FILE(f)->fd);
73     }
74   xfree(f);
75 }
76
77 static struct fastbuf *
78 bfdopen_internal(int fd, uns buflen, byte *name)
79 {
80   int namelen = strlen(name) + 1;
81   struct fb_file *F = xmalloc(sizeof(struct fb_file) + buflen + namelen);
82   struct fastbuf *f = &F->fb;
83
84   bzero(F, sizeof(*F));
85   f->buffer = (char *)(F+1);
86   f->bptr = f->bstop = f->buffer;
87   f->bufend = f->buffer + buflen;
88   f->name = f->bufend;
89   memcpy(f->name, name, namelen);
90   F->fd = fd;
91   f->refill = bfd_refill;
92   f->spout = bfd_spout;
93   f->seek = bfd_seek;
94   f->close = bfd_close;
95   return f;
96 }
97
98 struct fastbuf *
99 bopen(byte *name, uns mode, uns buffer)
100 {
101   struct fastbuf *b;
102   int fd = sh_open(name, mode, 0666);
103   if (fd < 0)
104     die("Unable to %s file %s: %m",
105         (mode & O_CREAT) ? "create" : "open", name);
106   b = bfdopen_internal(fd, buffer, name);
107   if (mode & O_APPEND)
108     bfd_seek(b, 0, SEEK_END);
109   return b;
110 }
111
112 struct fastbuf *
113 bfdopen(int fd, uns buffer)
114 {
115   byte x[32];
116
117   sprintf(x, "fd%d", fd);
118   return bfdopen_internal(fd, buffer, x);
119 }
120
121 struct fastbuf *
122 bfdopen_shared(int fd, uns buffer)
123 {
124   struct fastbuf *f = bfdopen(fd, buffer);
125   FB_FILE(f)->is_temp_file = -1;
126   return f;
127 }
128
129 void bbcopy(struct fastbuf *f, struct fastbuf *t, uns l)
130 {
131   uns rf = f->bstop - f->bptr;
132   uns tbuflen = t->bufend - t->buffer;
133
134   ASSERT(f->close == bfd_close);
135   ASSERT(t->close == bfd_close);
136   if (!l)
137     return;
138   if (rf)
139     {
140       uns k = MIN(rf, l);
141       bwrite(t, f->bptr, k);
142       f->bptr += k;
143       l -= k;
144       if (!l)
145         return;
146     }
147   while (l >= tbuflen)
148     {
149       t->spout(t);
150       if ((uns) read(FB_FILE(f)->fd, t->buffer, tbuflen) != tbuflen)
151         die("bbcopy: %s exhausted", f->name);
152       f->pos += tbuflen;
153       f->bstop = f->bptr = f->buffer;
154       t->bptr = t->bufend;
155       l -= tbuflen;
156     }
157   while (l)
158     {
159       uns k = t->bufend - t->bptr;
160
161       if (!k)
162         {
163           t->spout(t);
164           k = t->bufend - t->bptr;
165         }
166       if (k > l)
167         k = l;
168       bread(f, t->bptr, k);
169       t->bptr += k;
170       l -= k;
171     }
172 }
173
174 #ifdef TEST
175
176 int main(int argc, char **argv)
177 {
178   struct fastbuf *f, *t;
179
180   f = bopen("/etc/profile", O_RDONLY, 16);
181   t = bfdopen(1, 13);
182   bbcopy(f, t, 100);
183   printf("%d %d\n", (int)btell(f), (int)btell(t));
184   bclose(f);
185   bclose(t);
186   return 0;
187 }
188
189 #endif