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