Work locking mechanisms for concurrent updates/commit.
[idzebra-moved-to-github.git] / index / trav.c
1 /*
2  * Copyright (C) 1994-1995, Index Data I/S 
3  * All rights reserved.
4  * Sebastian Hammer, Adam Dickmeiss
5  *
6  * $Log: trav.c,v $
7  * Revision 1.15  1995-12-07 17:38:48  adam
8  * Work locking mechanisms for concurrent updates/commit.
9  *
10  * Revision 1.14  1995/12/06  12:41:26  adam
11  * New command 'stat' for the index program.
12  * Filenames can be read from stdin by specifying '-'.
13  * Bug fix/enhancement of the transformation from terms to regular
14  * expressons in the search engine.
15  *
16  * Revision 1.13  1995/11/28  09:09:46  adam
17  * Zebra config renamed.
18  * Use setting 'recordId' to identify record now.
19  * Bug fix in recindex.c: rec_release_blocks was invokeded even
20  * though the blocks were already released.
21  * File traversal properly deletes records when needed.
22  *
23  * Revision 1.12  1995/11/24  11:31:37  adam
24  * Commands add & del read filenames from stdin if source directory is
25  * empty.
26  * Match criteria supports 'constant' strings.
27  *
28  * Revision 1.11  1995/11/22  17:19:19  adam
29  * Record management uses the bfile system.
30  *
31  * Revision 1.10  1995/11/21  15:01:16  adam
32  * New general match criteria implemented.
33  * New feature: document groups.
34  *
35  * Revision 1.9  1995/11/21  09:20:32  adam
36  * Yet more work on record match.
37  *
38  * Revision 1.8  1995/11/20  16:59:46  adam
39  * New update method: the 'old' keys are saved for each records.
40  *
41  * Revision 1.7  1995/11/20  11:56:28  adam
42  * Work on new traversal.
43  *
44  * Revision 1.6  1995/11/17  15:54:42  adam
45  * Started work on virtual directory structure.
46  *
47  * Revision 1.5  1995/10/17  18:02:09  adam
48  * New feature: databases. Implemented as prefix to words in dictionary.
49  *
50  * Revision 1.4  1995/09/28  09:19:46  adam
51  * xfree/xmalloc used everywhere.
52  * Extract/retrieve method seems to work for text records.
53  *
54  * Revision 1.3  1995/09/06  16:11:18  adam
55  * Option: only one word key per file.
56  *
57  * Revision 1.2  1995/09/04  12:33:43  adam
58  * Various cleanup. YAZ util used instead.
59  *
60  * Revision 1.1  1995/09/01  14:06:36  adam
61  * Split of work into more files.
62  *
63  */
64 #include <stdio.h>
65 #include <assert.h>
66 #include <unistd.h>
67 #include <dirent.h>
68 #include <sys/stat.h>
69 #include <sys/types.h>
70 #include <fcntl.h>
71 #include <ctype.h>
72
73 #include <alexutil.h>
74 #include "index.h"
75
76 static int repComp (const char *a, const char *b, size_t len)
77 {
78     if (!len)
79         return 0;
80     return memcmp (a, b, len);
81 }
82
83 static void repositoryExtractR (int deleteFlag, char *rep,
84                                 struct recordGroup *rGroup)
85 {
86     struct dir_entry *e;
87     int i;
88     size_t rep_len = strlen (rep);
89
90     e = dir_open (rep);
91     if (!e)
92         return;
93     if (rep[rep_len-1] != '/')
94         rep[rep_len] = '/';
95     else
96         --rep_len;
97     for (i=0; e[i].name; i++)
98     {
99         strcpy (rep +rep_len+1, e[i].name);
100         switch (e[i].kind)
101         {
102         case dirs_file:
103             fileExtract (NULL, rep, rGroup, deleteFlag);
104             break;
105         case dirs_dir:
106             repositoryExtractR (deleteFlag, rep, rGroup);
107             break;
108         }
109     }
110     dir_free (&e);
111
112 }
113
114 static void stdinExtractR (int deleteFlag, struct recordGroup *rGroup)
115 {
116     char tmppath[256];
117
118     logf (LOG_LOG, "stdinExtractR");
119     while (scanf ("%s", tmppath) == 1)
120         fileExtract (NULL, tmppath, rGroup, deleteFlag);
121 }
122
123 static void repositoryDeleteR (struct dirs_info *di, struct dirs_entry *dst,
124                                const char *base, char *src,
125                                struct recordGroup *rGroup)
126 {
127     char tmppath[256];
128     size_t src_len = strlen (src);
129
130     while (dst && !repComp (dst->path, src, src_len+1))
131     {
132         switch (dst->kind)
133         {
134         case dirs_file:
135             sprintf (tmppath, "%s%s", base, dst->path);
136             fileExtract (&dst->sysno, tmppath, rGroup, 1);
137              
138             strcpy (tmppath, dst->path);
139             dst = dirs_read (di); 
140             dirs_del (di, tmppath);
141             break;
142         case dirs_dir:
143             strcpy (tmppath, dst->path);
144             dst = dirs_read (di);
145             dirs_rmdir (di, tmppath);
146             break;
147         default:
148             dst = dirs_read (di);
149         }
150     }
151 }
152
153 static void repositoryUpdateR (struct dirs_info *di, struct dirs_entry *dst,
154                                const char *base, char *src, 
155                                struct recordGroup *rGroup)
156 {
157     struct dir_entry *e_src;
158     int i_src = 0;
159     static char tmppath[256];
160     size_t src_len = strlen (src);
161
162     sprintf (tmppath, "%s%s", base, src);
163     e_src = dir_open (tmppath);
164
165 #if 1
166     if (!dst || repComp (dst->path, src, src_len))
167 #else
168     if (!dst || strcmp (dst->path, src))
169 #endif
170     {
171         if (!e_src)
172             return;
173         if (src_len && src[src_len-1] == '/')
174             --src_len;
175         else
176             src[src_len] = '/';
177         src[src_len+1] = '\0';
178         dirs_mkdir (di, src, 0);
179         dst = NULL;
180     }
181     else if (!e_src)
182     {
183         strcpy (src, dst->path);
184         repositoryDeleteR (di, dst, base, src, rGroup);
185         return;
186     }
187     else
188     {
189         if (src_len && src[src_len-1] == '/')
190             --src_len;
191         else
192             src[src_len] = '/';
193         src[src_len+1] = '\0';
194         dst = dirs_read (di); 
195     }
196     dir_sort (e_src);
197
198     while (1)
199     {
200         int sd;
201
202         if (dst && !repComp (dst->path, src, src_len+1))
203         {
204             if (e_src[i_src].name)
205             {
206                 logf (LOG_DEBUG, "dst=%s src=%s", dst->path + src_len+1, 
207                       e_src[i_src].name);
208                 sd = strcmp (dst->path + src_len+1, e_src[i_src].name);
209             }
210             else
211                 sd = -1;
212         }
213         else if (e_src[i_src].name)
214             sd = 1;
215         else
216             break;
217         logf (LOG_DEBUG, "trav sd=%d", sd);
218         if (sd == 0)
219         {
220             strcpy (src + src_len+1, e_src[i_src].name);
221             sprintf (tmppath, "%s%s", base, src);
222             
223             switch (e_src[i_src].kind)
224             {
225             case dirs_file:
226                 if (e_src[i_src].ctime > dst->ctime)
227                 {
228                     if (fileExtract (&dst->sysno, tmppath, rGroup, 0))
229                     {
230                         logf (LOG_LOG, "dirs_add");
231                         dirs_add (di, src, dst->sysno, e_src[i_src].ctime);
232                     }
233                 }
234                 dst = dirs_read (di);
235                 break;
236             case dirs_dir:
237                 repositoryUpdateR (di, dst, base, src, rGroup);
238                 dst = dirs_last (di);
239                 logf (LOG_DEBUG, "last is %s", dst ? dst->path : "null");
240                 break;
241             default:
242                 dst = dirs_read (di); 
243             }
244             i_src++;
245         }
246         else if (sd > 0)
247         {
248             SYSNO sysno = 0;
249             strcpy (src + src_len+1, e_src[i_src].name);
250             sprintf (tmppath, "%s%s", base, src);
251
252             switch (e_src[i_src].kind)
253             {
254             case dirs_file:
255                 if (fileExtract (&sysno, tmppath, rGroup, 0))
256                     dirs_add (di, src, sysno, e_src[i_src].ctime);            
257                 break;
258             case dirs_dir:
259                 repositoryUpdateR (di, dst, base, src, rGroup);
260                 if (dst)
261                     dst = dirs_last (di);
262                 break;
263             }
264             i_src++;
265         }
266         else  /* sd < 0 */
267         {
268             strcpy (src, dst->path);
269             sprintf (tmppath, "%s%s", base, dst->path);
270
271             switch (dst->kind)
272             {
273             case dirs_file:
274                 fileExtract (&dst->sysno, tmppath, rGroup, 1);
275                 dirs_del (di, dst->path);
276                 dst = dirs_read (di);
277                 break;
278             case dirs_dir:
279                 repositoryDeleteR (di, dst, base, src, rGroup);
280                 dst = dirs_last (di);
281             }
282         }
283     }
284     dir_free (&e_src);
285 }
286
287 static void groupRes (struct recordGroup *rGroup)
288 {
289     char resStr[256];
290     char gPrefix[256];
291
292     if (!rGroup->groupName || !*rGroup->groupName)
293         *gPrefix = '\0';
294     else
295         sprintf (gPrefix, "%s.", rGroup->groupName);
296
297     sprintf (resStr, "%srecordId", gPrefix);
298     rGroup->recordId = res_get (common_resource, resStr);
299 }
300
301 void repositoryUpdate (struct recordGroup *rGroup)
302 {
303     char src[256];
304
305     groupRes (rGroup);
306     if (rGroup->recordId && !strcmp (rGroup->recordId, "file"))
307     {
308         Dict dict;
309         struct dirs_info *di;
310
311         if (!(dict = dict_open (FMATCH_DICT, 50, 1)))
312         {
313             logf (LOG_FATAL, "dict_open fail of %s", FMATCH_DICT);
314             exit (1);
315         }
316         assert (rGroup->path);
317         di = dirs_open (dict, rGroup->path);
318         strcpy (src, "");
319         repositoryUpdateR (di, dirs_read (di), rGroup->path, src, rGroup);
320         dirs_free (&di);
321         dict_close (dict);
322     }
323     else 
324     {
325         strcpy (src, rGroup->path);
326         if (*src == '\0' || !strcmp (src, "-"))
327             stdinExtractR (0, rGroup);
328         else
329             repositoryExtractR (0, src, rGroup);
330     }
331 }
332
333 void repositoryDelete (struct recordGroup *rGroup)
334 {
335     char src[256];
336
337     assert (rGroup->path);
338     groupRes (rGroup);
339     strcpy (src, rGroup->path);
340     if (*src == '\0' || !strcmp(src, "-"))
341         stdinExtractR (1, rGroup);
342     else
343         repositoryExtractR (1, src, rGroup);
344 }
345