ce6972d8f23acb0a5fea0d3bd65ae0ac4858ae7b
[idzebra-moved-to-github.git] / bfile / bfile.c
1 /*
2  * Copyright (C) 1994-1999, Index Data
3  * All rights reserved.
4  * Sebastian Hammer, Adam Dickmeiss
5  *
6  * $Log: bfile.c,v $
7  * Revision 1.32  2000-03-15 15:00:30  adam
8  * First work on threaded version.
9  *
10  * Revision 1.31  1999/12/08 15:03:11  adam
11  * Implemented bf_reset.
12  *
13  * Revision 1.30  1999/10/14 14:33:49  adam
14  * Added truncation 5=106.
15  *
16  * Revision 1.29  1999/05/26 07:49:12  adam
17  * C++ compilation.
18  *
19  * Revision 1.28  1999/05/12 13:08:05  adam
20  * First version of ISAMS.
21  *
22  * Revision 1.27  1999/02/02 14:50:01  adam
23  * Updated WIN32 code specific sections. Changed header.
24  *
25  * Revision 1.26  1998/02/17 10:32:52  adam
26  * Fixed bug: binary files weren't opened with flag b on NT.
27  *
28  * Revision 1.25  1997/10/27 14:25:38  adam
29  * Fixed memory leaks.
30  *
31  * Revision 1.24  1997/09/18 08:59:16  adam
32  * Extra generic handle for the character mapping routines.
33  *
34  * Revision 1.23  1997/09/17 12:19:06  adam
35  * Zebra version corresponds to YAZ version 1.4.
36  * Changed Zebra server so that it doesn't depend on global common_resource.
37  *
38  * Revision 1.22  1997/09/09 13:37:52  adam
39  * Partial port to WIN95/NT.
40  *
41  * Revision 1.21  1996/10/29 13:56:13  adam
42  * Include of zebrautl.h instead of alexutil.h.
43  *
44  * Revision 1.20  1996/03/26 15:59:04  adam
45  * The directory of the shadow table file can be specified by the new
46  * bf_lockDir call.
47  *
48  * Revision 1.19  1996/02/05  12:28:58  adam
49  * Removed a LOG_LOG message.
50  *
51  * Revision 1.18  1996/01/02  08:59:06  quinn
52  * Changed "commit" setting to "shadow".
53  *
54  * Revision 1.17  1995/12/11  09:03:51  adam
55  * New function: cf_unlink.
56  * New member of commit file head: state (0) deleted, (1) hash file.
57  *
58  * Revision 1.16  1995/12/08  16:21:13  adam
59  * Work on commit/update.
60  *
61  * Revision 1.15  1995/12/01  16:24:28  adam
62  * Commit files use separate meta file area.
63  *
64  * Revision 1.14  1995/12/01  11:37:21  adam
65  * Cached/commit files implemented as meta-files.
66  *
67  * Revision 1.13  1995/11/30  17:00:49  adam
68  * Several bug fixes. Commit system runs now.
69  *
70  * Revision 1.12  1995/11/30  08:33:10  adam
71  * Started work on commit facility.
72  *
73  * Revision 1.11  1995/09/04  12:33:21  adam
74  * Various cleanup. YAZ util used instead.
75  *
76  * Revision 1.10  1994/08/25  10:15:54  quinn
77  * Trivial
78  *
79  * Revision 1.9  1994/08/24  08:45:48  quinn
80  * Using mfile.
81  *
82  * Revision 1.8  1994/08/23  15:03:34  quinn
83  * *** empty log message ***
84  *
85  * Revision 1.7  1994/08/23  14:25:45  quinn
86  * Added O_CREAT because some geek wanted it. Sheesh.
87  *
88  * Revision 1.6  1994/08/23  14:21:38  quinn
89  * Fixed call to log
90  *
91  * Revision 1.5  1994/08/18  08:10:08  quinn
92  * Minimal changes
93  *
94  * Revision 1.4  1994/08/17  14:27:32  quinn
95  * last mods
96  *
97  * Revision 1.2  1994/08/17  14:09:32  quinn
98  * Compiles cleanly (still only dummy).
99  *
100  * Revision 1.1  1994/08/17  13:55:08  quinn
101  * New blocksystem. dummy only
102  *
103  */
104
105 #include <stdio.h>
106 #include <stdlib.h>
107 #include <string.h>
108 #include <assert.h>
109 #ifdef WIN32
110 #include <io.h>
111 #else
112 #include <unistd.h>
113 #endif
114
115 #include <zebrautl.h>
116 #include <bfile.h>
117 #include "cfile.h"
118
119 struct BFiles_struct {
120     MFile_area commit_area;
121     MFile_area_struct *register_area;
122     char *lockDir;
123 };
124
125 BFiles bfs_create (const char *spec)
126 {
127     BFiles bfs = (BFiles) xmalloc (sizeof(*bfs));
128     bfs->commit_area = NULL;
129     bfs->register_area = mf_init("register", spec);
130     bfs->lockDir = NULL;
131     if (!bfs->register_area)
132     {
133         bfs_destroy(bfs);
134         return 0;
135     }
136     return bfs;
137 }
138
139 void bfs_destroy (BFiles bfs)
140 {
141     xfree (bfs->lockDir);
142     mf_destroy (bfs->commit_area);
143     mf_destroy (bfs->register_area);
144     xfree (bfs);
145 }
146
147 static FILE *open_cache (BFiles bfs, const char *flags)
148 {
149     char cacheFilename[1024];
150     FILE *file;
151
152     sprintf (cacheFilename, "%scache",
153              bfs->lockDir ? bfs->lockDir : "");
154     file = fopen (cacheFilename, flags);
155     return file;
156 }
157
158 static void unlink_cache (BFiles bfs)
159 {
160     char cacheFilename[1024];
161
162     sprintf (cacheFilename, "%scache",
163              bfs->lockDir ? bfs->lockDir : "");
164     unlink (cacheFilename);
165 }
166
167 void bf_lockDir (BFiles bfs, const char *lockDir)
168 {
169     size_t len;
170     
171     xfree (bfs->lockDir);
172     if (lockDir == NULL)
173         lockDir = "";
174     len = strlen(lockDir);
175     bfs->lockDir = (char *) xmalloc (len+2);
176     strcpy (bfs->lockDir, lockDir);
177     
178     if (len > 0 && bfs->lockDir[len-1] != '/')
179         strcpy (bfs->lockDir + len, "/");
180 }
181
182 void bf_cache (BFiles bfs, const char *spec)
183 {
184     if (spec)
185     {
186         if (!bfs->commit_area)
187             bfs->commit_area = mf_init ("shadow", spec);
188     }
189     else
190         bfs->commit_area = NULL;
191 }
192
193 int bf_close (BFile bf)
194 {
195     zebra_lock_rdwr_destroy (&bf->rdwr_lock);
196     if (bf->cf)
197         cf_close (bf->cf);
198     mf_close (bf->mf);
199     xfree (bf);
200     return 0;
201 }
202
203 BFile bf_open (BFiles bfs, const char *name, int block_size, int wflag)
204 {
205     BFile tmp = (BFile) xmalloc(sizeof(BFile_struct));
206
207     if (bfs->commit_area)
208     {
209         int first_time;
210
211         tmp->mf = mf_open (bfs->register_area, name, block_size, 0);
212         tmp->cf = cf_open (tmp->mf, bfs->commit_area, name, block_size,
213                            wflag, &first_time);
214         if (first_time)
215         {
216             FILE *outf;
217
218             outf = open_cache (bfs, "ab");
219             if (!outf)
220             {
221                 logf (LOG_FATAL|LOG_ERRNO, "open %scache",
222                       bfs->lockDir ? bfs->lockDir : "");
223                 exit (1);
224             }
225             fprintf (outf, "%s %d\n", name, block_size);
226             fclose (outf);
227         }
228     }
229     else
230     {
231         tmp->mf = mf_open(bfs->register_area, name, block_size, wflag);
232         tmp->cf = NULL;
233     }
234     if (!tmp->mf)
235     {
236         logf (LOG_FATAL, "mf_open failed for %s", name);
237         xfree (tmp);
238         return 0;
239     }
240     zebra_lock_rdwr_init (&tmp->rdwr_lock);
241     return(tmp);
242 }
243
244 int bf_read (BFile bf, int no, int offset, int nbytes, void *buf)
245 {
246     int r;
247
248     zebra_lock_rdwr_rlock (&bf->rdwr_lock);
249     if (bf->cf)
250     {
251         if ((r = cf_read (bf->cf, no, offset, nbytes, buf)) == -1)
252             r = mf_read (bf->mf, no, offset, nbytes, buf);
253     }
254     else 
255         r = mf_read (bf->mf, no, offset, nbytes, buf);
256     zebra_lock_rdwr_runlock (&bf->rdwr_lock);
257     return r;
258 }
259
260 int bf_write (BFile bf, int no, int offset, int nbytes, const void *buf)
261 {
262     int r;
263     zebra_lock_rdwr_wlock (&bf->rdwr_lock);
264     if (bf->cf)
265         r = cf_write (bf->cf, no, offset, nbytes, buf);
266     else
267         r = mf_write (bf->mf, no, offset, nbytes, buf);
268     zebra_lock_rdwr_wunlock (&bf->rdwr_lock);
269     return r;
270 }
271
272 int bf_commitExists (BFiles bfs)
273 {
274     FILE *inf;
275
276     inf = open_cache (bfs, "rb");
277     if (inf)
278     {
279         fclose (inf);
280         return 1;
281     }
282     return 0;
283 }
284
285 void bf_reset (BFiles bfs)
286 {
287     mf_reset (bfs->commit_area);
288     mf_reset (bfs->register_area);
289 }
290
291 void bf_commitExec (BFiles bfs)
292 {
293     FILE *inf;
294     int block_size;
295     char path[256];
296     MFile mf;
297     CFile cf;
298     int first_time;
299
300     assert (bfs->commit_area);
301     if (!(inf = open_cache (bfs, "rb")))
302     {
303         logf (LOG_LOG, "No commit file");
304         return ;
305     }
306     while (fscanf (inf, "%s %d", path, &block_size) == 2)
307     {
308         mf = mf_open (bfs->register_area, path, block_size, 1);
309         cf = cf_open (mf, bfs->commit_area, path, block_size, 0, &first_time);
310
311         cf_commit (cf);
312
313         cf_close (cf);
314         mf_close (mf);
315     }
316     fclose (inf);
317 }
318
319 void bf_commitClean (BFiles bfs, const char *spec)
320 {
321     FILE *inf;
322     int block_size;
323     char path[256];
324     MFile mf;
325     CFile cf;
326     int mustDisable = 0;
327     int firstTime;
328
329     if (!bfs->commit_area)
330     {
331         bf_cache (bfs, spec);
332         mustDisable = 1;
333     }
334
335     if (!(inf = open_cache (bfs, "rb")))
336         return ;
337     while (fscanf (inf, "%s %d", path, &block_size) == 2)
338     {
339         mf = mf_open (bfs->register_area, path, block_size, 0);
340         cf = cf_open (mf, bfs->commit_area, path, block_size, 1, &firstTime);
341         cf_unlink (cf);
342         cf_close (cf);
343         mf_close (mf);
344     }
345     fclose (inf);
346     unlink_cache (bfs);
347     if (mustDisable)
348         bf_cache (bfs, 0);
349 }