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