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