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