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