]> mj.ucw.cz Git - libucw.git/blob - lib/fb-param.c
Cleanup of file fastbufs.
[libucw.git] / lib / fb-param.c
1 /*
2  *      UCW Library -- FastIO on files with run-time parametrization
3  *
4  *      (c) 2007 Pavel Charvat <pchar@ucw.cz>
5  *      (c) 2007 Martin Mares <mj@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/conf.h"
13 #include "lib/lfs.h"
14 #include "lib/fastbuf.h"
15
16 #include <fcntl.h>
17 #include <stdio.h>
18
19 struct fb_params fbpar_def = {
20   .buffer_size = 65536,
21   .read_ahead = 1,
22   .write_back = 1,
23 }; 
24
25 struct cf_section fbpar_cf = {
26 # define F(x) PTR_TO(struct fb_params, x)
27   CF_TYPE(struct fb_params),
28   CF_ITEMS {
29     CF_LOOKUP("Type", (int *)F(type), ((char *[]){"std", "direct", "mmap", NULL})),
30     CF_UNS("BufSize", F(buffer_size)),
31     CF_UNS("KeepBackBuf", F(keep_back_buf)),
32     CF_UNS("ReadAhead", F(read_ahead)),
33     CF_UNS("WriteBack", F(write_back)),
34     CF_END
35   }
36 # undef F
37 };
38
39 static struct cf_section fbpar_global_cf = {
40   CF_ITEMS {
41     CF_SECTION("Defaults", &fbpar_def, &fbpar_cf),
42     CF_END
43   }
44 };
45
46 static void CONSTRUCTOR
47 fbpar_global_init(void)
48 {
49   cf_declare_section("FBParam", &fbpar_global_cf, 0);
50 }
51
52 static struct fastbuf *
53 bopen_fd_internal(int fd, struct fb_params *params, uns mode, const char *name)
54 {
55   char buf[32];
56   if (!name)
57     {
58       sprintf(buf, "fd%d", fd);
59       name = buf;
60     }
61   struct fastbuf *fb;
62   switch (params->type)
63     {
64       case FB_STD:
65         fb = bfdopen_internal(fd, name,
66             params->buffer_size ? : fbpar_def.buffer_size);
67         if (params->keep_back_buf)
68           bconfig(fb, BCONFIG_KEEP_BACK_BUF, 1);
69         return fb;
70       case FB_DIRECT:
71         fb = fbdir_open_fd_internal(fd, name, params->asio,
72             params->buffer_size ? : fbpar_def.buffer_size,
73             params->read_ahead ? : fbpar_def.read_ahead,
74             params->write_back ? : fbpar_def.write_back);
75         if (!~mode && !fbdir_cheat && ((int)(mode = fcntl(fd, F_GETFL)) < 0 || fcntl(fd, F_SETFL, mode | O_DIRECT)) < 0)
76           msg(L_WARN, "Cannot set O_DIRECT on fd %d: %m", fd);
77         return fb;
78       case FB_MMAP:
79         if (!~mode && (int)(mode = fcntl(fd, F_GETFL)) < 0)
80           die("Cannot get flags of fd %d: %m", fd);
81         return bfmmopen_internal(fd, name, mode);
82       default:
83         ASSERT(0);
84     }
85 }
86
87 static struct fastbuf *
88 bopen_file_internal(const char *name, int mode, struct fb_params *params, int try)
89 {
90   if (!params)
91     params = &fbpar_def;
92   if (params->type == FB_DIRECT && !fbdir_cheat)
93     mode |= O_DIRECT;
94   if (params->type == FB_MMAP && (mode & O_ACCMODE) == O_WRONLY)
95     mode = (mode & ~O_ACCMODE) | O_RDWR;
96   int fd = sh_open(name, mode, 0666);
97   if (fd < 0)
98     if (try)
99       return NULL;
100     else
101       die("Unable to %s file %s: %m", (mode & O_CREAT) ? "create" : "open", name);
102   struct fastbuf *fb = bopen_fd_internal(fd, params, mode, name);
103   ASSERT(fb);
104   if (mode & O_APPEND)
105     bseek(fb, 0, SEEK_END);
106   return fb;
107 }
108
109 struct fastbuf *
110 bopen_file(const char *name, int mode, struct fb_params *params)
111 {
112   return bopen_file_internal(name, mode, params, 0);
113 }
114
115 struct fastbuf *
116 bopen_file_try(const char *name, int mode, struct fb_params *params)
117 {
118   return bopen_file_internal(name, mode, params, 1);
119 }
120
121 struct fastbuf *
122 bopen_fd(int fd, struct fb_params *params)
123 {
124   return bopen_fd_internal(fd, params ? : &fbpar_def, ~0U, NULL);
125 }
126
127 /* Function for use by individual file back-ends */
128
129 void
130 bclose_file_helper(struct fastbuf *f, int fd, int is_temp_file)
131 {
132   switch (is_temp_file)
133     {
134     case 1:
135       if (unlink(f->name) < 0)
136         msg(L_ERROR, "unlink(%s): %m", f->name);
137     case 0:
138       if (close(fd))
139         die("close(%s): %m", f->name);
140     }
141 }
142
143 /* Compatibility wrappers */
144
145 struct fastbuf *
146 bopen_try(const char *name, uns mode, uns buflen)
147 {
148   return bopen_file_try(name, mode, &(struct fb_params){ .type = FB_STD, .buffer_size = buflen });
149 }
150
151 struct fastbuf *
152 bopen(const char *name, uns mode, uns buflen)
153 {
154   return bopen_file(name, mode, &(struct fb_params){ .type = FB_STD, .buffer_size = buflen });
155 }
156
157 struct fastbuf *
158 bfdopen(int fd, uns buflen)
159 {
160   return bopen_fd(fd, &(struct fb_params){ .type = FB_STD, .buffer_size = buflen });
161 }
162
163 struct fastbuf *
164 bfdopen_shared(int fd, uns buflen)
165 {
166   struct fastbuf *f = bfdopen(fd, buflen);
167   bconfig(f, BCONFIG_IS_TEMP_FILE, -1);
168   return f;
169 }
170