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