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