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