bad sprintf
[idzebra-moved-to-github.git] / rset / rstemp.c
1 /*
2  * Copyright (C) 1994-2002, Index Data
3  * All rights reserved.
4  * Sebastian Hammer, Adam Dickmeiss
5  *
6  * $Id: rstemp.c,v 1.32 2002-05-03 13:46:33 adam Exp $
7  */
8
9 #include <fcntl.h>
10 #include <assert.h>
11 #ifdef WIN32
12 #include <io.h>
13 #else
14 #include <unistd.h>
15 #endif
16 #include <string.h>
17 #include <sys/types.h>
18 #include <stdio.h>
19
20 #include <zebrautl.h>
21 #include <rstemp.h>
22
23 static void *r_create(RSET ct, const struct rset_control *sel, void *parms);
24 static RSFD r_open (RSET ct, int flag);
25 static void r_close (RSFD rfd);
26 static void r_delete (RSET ct);
27 static void r_rewind (RSFD rfd);
28 static int r_count (RSET ct);
29 static int r_read (RSFD rfd, void *buf, int *term_index);
30 static int r_write (RSFD rfd, const void *buf);
31
32 static const struct rset_control control = 
33 {
34     "temp",
35     r_create,
36     r_open,
37     r_close,
38     r_delete,
39     r_rewind,
40     r_count,
41     r_read,
42     r_write,
43 };
44
45 const struct rset_control *rset_kind_temp = &control;
46
47 struct rset_temp_info {
48     int     fd;
49     char   *fname;
50     size_t  key_size;      /* key size */
51     char   *buf_mem;       /* window buffer */
52     size_t  buf_size;      /* size of window */
53     size_t  pos_end;       /* last position in set */
54     size_t  pos_cur;       /* current position in set */
55     size_t  pos_buf;       /* position of first byte in window */
56     size_t  pos_border;    /* position of last byte+1 in window */
57     int     dirty;         /* window is dirty */
58     int     hits;          /* no of hits */
59     char   *temp_path;
60     int     (*cmp)(const void *p1, const void *p2);
61 };
62
63 struct rset_temp_rfd {
64     struct rset_temp_info *info;
65     struct rset_temp_rfd *next;
66     int *countp;
67     void *buf;
68 };
69
70 static void *r_create(RSET ct, const struct rset_control *sel, void *parms)
71 {
72     rset_temp_parms *temp_parms = (rset_temp_parms *) parms;
73     struct rset_temp_info *info;
74    
75     info = (struct rset_temp_info *) xmalloc (sizeof(struct rset_temp_info));
76     info->fd = -1;
77     info->fname = NULL;
78     info->key_size = temp_parms->key_size;
79     info->buf_size = 4096;
80     info->buf_mem = (char *) xmalloc (info->buf_size);
81     info->pos_cur = 0;
82     info->pos_end = 0;
83     info->pos_buf = 0;
84     info->dirty = 0;
85     info->hits = -1;
86     info->cmp = temp_parms->cmp;
87     if (!temp_parms->temp_path)
88         info->temp_path = NULL;
89     else
90     {
91         info->temp_path = (char *) xmalloc (strlen(temp_parms->temp_path)+1);
92         strcpy (info->temp_path, temp_parms->temp_path);
93     }
94     ct->no_rset_terms = 1;
95     ct->rset_terms = (RSET_TERM *) xmalloc (sizeof(*ct->rset_terms));
96     ct->rset_terms[0] = temp_parms->rset_term;
97
98     return info;
99 }
100
101 static RSFD r_open (RSET ct, int flag)
102 {
103     struct rset_temp_info *info = (struct rset_temp_info *) ct->buf;
104     struct rset_temp_rfd *rfd;
105
106     assert (info->fd == -1);
107     if (info->fname)
108     {
109         if (flag & RSETF_WRITE)
110             info->fd = open (info->fname, O_BINARY|O_RDWR|O_CREAT, 0666);
111         else
112             info->fd = open (info->fname, O_BINARY|O_RDONLY);
113         if (info->fd == -1)
114         {
115             logf (LOG_FATAL|LOG_ERRNO, "open %s", info->fname);
116             exit (1);
117         }
118     }
119     rfd = (struct rset_temp_rfd *) xmalloc (sizeof(*rfd));
120     rfd->info = info;
121     r_rewind (rfd);
122
123     rfd->countp = &ct->rset_terms[0]->count;
124     rfd->buf = xmalloc (info->key_size);
125
126     return rfd;
127 }
128
129 /* r_flush:
130       flush current window to file if file is assocated with set
131  */
132 static void r_flush (RSFD rfd, int mk)
133 {
134     struct rset_temp_info *info = ((struct rset_temp_rfd*) rfd)->info;
135
136     if (!info->fname && mk)
137     {
138 #if HAVE_MKSTEMP
139         char template[1024];
140
141         if (info->temp_path)
142             sprintf (template, "%s/zrsXXXXXX", info->temp_path);
143         else
144             sprintf (template, "zrsXXXXXX");
145
146         info->fd = mkstemp (template);
147
148         if (info->fd == -1)
149         {
150             logf (LOG_FATAL|LOG_ERRNO, "mkstemp %s", template);
151             exit (1);
152         }
153         info->fname = (char *) xmalloc (strlen(template)+1);
154         strcpy (info->fname, template);
155 #else
156         char *s = (char*) tempnam (info->temp_path, "zrs");
157         info->fname = (char *) xmalloc (strlen(s)+1);
158         strcpy (info->fname, s);
159
160         logf (LOG_DEBUG, "creating tempfile %s", info->fname);
161         info->fd = open (info->fname, O_BINARY|O_RDWR|O_CREAT, 0666);
162         if (info->fd == -1)
163         {
164             logf (LOG_FATAL|LOG_ERRNO, "open %s", info->fname);
165             exit (1);
166         }
167 #endif
168     }
169     if (info->fname && info->fd != -1 && info->dirty)
170     {
171         size_t count;
172         int r;
173         
174         if (lseek (info->fd, info->pos_buf, SEEK_SET) == -1)
175         {
176             logf (LOG_FATAL|LOG_ERRNO, "lseek %s", info->fname);
177             exit (1);
178         }
179         count = info->buf_size;
180         if (count > info->pos_end - info->pos_buf)
181             count = info->pos_end - info->pos_buf;
182         if ((r = write (info->fd, info->buf_mem, count)) < (int) count)
183         {
184             if (r == -1)
185                 logf (LOG_FATAL|LOG_ERRNO, "read %s", info->fname);
186             else
187                 logf (LOG_FATAL, "write of %ld but got %ld",
188                       (long) count, (long) r);
189             exit (1);
190         }
191         info->dirty = 0;
192     }
193 }
194
195 static void r_close (RSFD rfd)
196 {
197     struct rset_temp_info *info = ((struct rset_temp_rfd*)rfd)->info;
198
199     r_flush (rfd, 0);
200     if (info->fname && info->fd != -1)
201     {
202         close (info->fd);
203         info->fd = -1;
204     }
205     xfree (((struct rset_temp_rfd *)rfd)->buf);
206     xfree (rfd);
207 }
208
209 static void r_delete (RSET ct)
210 {
211     struct rset_temp_info *info = (struct rset_temp_info*) ct->buf;
212
213     if (info->fname)
214         unlink (info->fname);        
215     xfree (info->buf_mem);
216     logf (LOG_DEBUG, "r_delete: set size %ld", (long) info->pos_end);
217     if (info->fname)
218     {
219         logf (LOG_DEBUG, "r_delete: unlink %s", info->fname);
220         unlink (info->fname);
221         xfree (info->fname);
222     }
223     if (info->temp_path)
224         xfree (info->temp_path);
225     rset_term_destroy (ct->rset_terms[0]);
226     xfree (ct->rset_terms);
227     xfree (info);
228 }
229
230 /* r_reread:
231       read from file to window if file is assocated with set -
232       indicated by fname
233  */
234 static void r_reread (RSFD rfd)
235 {
236     struct rset_temp_info *info = ((struct rset_temp_rfd*)rfd)->info;
237
238     if (info->fname)
239     {
240         size_t count;
241         int r;
242
243         info->pos_border = info->pos_cur + info->buf_size;
244         if (info->pos_border > info->pos_end)
245             info->pos_border = info->pos_end;
246         count = info->pos_border - info->pos_buf;
247         if (count > 0)
248         {
249             if (lseek (info->fd, info->pos_buf, SEEK_SET) == -1)
250             {
251                 logf (LOG_FATAL|LOG_ERRNO, "lseek %s", info->fname);
252                 exit (1);
253             }
254             if ((r = read (info->fd, info->buf_mem, count)) < (int) count)
255             {
256                 if (r == -1)
257                     logf (LOG_FATAL|LOG_ERRNO, "read %s", info->fname);
258                 else
259                     logf (LOG_FATAL, "read of %ld but got %ld",
260                           (long) count, (long) r);
261                 exit (1);
262             }
263         }
264     }
265     else
266         info->pos_border = info->pos_end;
267 }
268
269 static void r_rewind (RSFD rfd)
270 {
271     struct rset_temp_info *info = ((struct rset_temp_rfd*)rfd)->info;
272
273     r_flush (rfd, 0);
274     info->pos_cur = 0;
275     info->pos_buf = 0;
276     r_reread (rfd);
277 }
278
279 static int r_count (RSET ct)
280 {
281     struct rset_temp_info *info = (struct rset_temp_info *) ct->buf;
282
283     return info->pos_end / info->key_size;
284 }
285
286 static int r_read (RSFD rfd, void *buf, int *term_index)
287 {
288     struct rset_temp_rfd *mrfd = (struct rset_temp_rfd*) rfd;
289     struct rset_temp_info *info = mrfd->info;
290
291     size_t nc = info->pos_cur + info->key_size;
292
293     if (nc > info->pos_border)
294     {
295         if (nc > info->pos_end)
296             return 0;
297         r_flush (rfd, 0);
298         info->pos_buf = info->pos_cur;
299         r_reread (rfd);
300     }
301     memcpy (buf, info->buf_mem + (info->pos_cur - info->pos_buf),
302             info->key_size);
303     info->pos_cur = nc;
304     *term_index = 0;
305
306     if (*mrfd->countp == 0 || (*info->cmp)(buf, mrfd->buf) > 1)
307     {
308         memcpy (mrfd->buf, buf, mrfd->info->key_size);
309         (*mrfd->countp)++;
310     }
311     return 1;
312 }
313
314 static int r_write (RSFD rfd, const void *buf)
315 {
316     struct rset_temp_info *info = ((struct rset_temp_rfd*)rfd)->info;
317
318     size_t nc = info->pos_cur + info->key_size;
319
320     if (nc > info->pos_buf + info->buf_size)
321     {
322         r_flush (rfd, 1);
323         info->pos_buf = info->pos_cur;
324         if (info->pos_buf < info->pos_end)
325             r_reread (rfd);
326     }
327     info->dirty = 1;
328     memcpy (info->buf_mem + (info->pos_cur - info->pos_buf), buf,
329             info->key_size);
330     info->pos_cur = nc;
331     if (nc > info->pos_end)
332         info->pos_border = info->pos_end = nc;
333     return 1;
334 }