Yet more work on record match.
[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.9  1995-11-21 09:20:32  adam
8  * Yet more work on record match.
9  *
10  * Revision 1.8  1995/11/20  16:59:46  adam
11  * New update method: the 'old' keys are saved for each records.
12  *
13  * Revision 1.7  1995/11/20  11:56:28  adam
14  * Work on new traversal.
15  *
16  * Revision 1.6  1995/11/17  15:54:42  adam
17  * Started work on virtual directory structure.
18  *
19  * Revision 1.5  1995/10/17  18:02:09  adam
20  * New feature: databases. Implemented as prefix to words in dictionary.
21  *
22  * Revision 1.4  1995/09/28  09:19:46  adam
23  * xfree/xmalloc used everywhere.
24  * Extract/retrieve method seems to work for text records.
25  *
26  * Revision 1.3  1995/09/06  16:11:18  adam
27  * Option: only one word key per file.
28  *
29  * Revision 1.2  1995/09/04  12:33:43  adam
30  * Various cleanup. YAZ util used instead.
31  *
32  * Revision 1.1  1995/09/01  14:06:36  adam
33  * Split of work into more files.
34  *
35  */
36 #include <stdio.h>
37 #include <assert.h>
38 #include <unistd.h>
39 #include <dirent.h>
40 #include <sys/stat.h>
41 #include <sys/types.h>
42 #include <fcntl.h>
43 #include <ctype.h>
44
45 #include <alexutil.h>
46 #include "index.h"
47
48 #if 0
49 static void repository_extract_r (int cmd, char *rep, char *databaseName)
50 {
51     struct dir_entry *e;
52     int i;
53     struct stat fs;
54     size_t rep_len = strlen (rep);
55
56     e = dir_open (rep);
57     if (!e)
58         return;
59     if (rep[rep_len-1] != '/')
60         rep[rep_len] = '/';
61     else
62         --rep_len;
63     for (i=0; e[i].name; i++)
64     {
65         strcpy (rep +rep_len+1, e[i].name);
66         stat (rep, &fs);
67         switch (fs.st_mode & S_IFMT)
68         {
69         case S_IFREG:
70             file_extract (cmd, rep, rep, databaseName);
71             break;
72         case S_IFDIR:
73             repository_extract_r (cmd, rep, databaseName);
74             break;
75         }
76     }
77     dir_free (&e);
78 }
79
80 void copy_file (const char *dst, const char *src)
81 {
82     int d_fd = open (dst, O_WRONLY|O_CREAT, 0666);
83     int s_fd = open (src, O_RDONLY);
84     char *buf;
85     size_t i, r, w;
86
87     if (d_fd == -1)
88     {
89         logf (LOG_FATAL|LOG_ERRNO, "Cannot create %s", dst);
90         exit (1);
91     }
92     if (s_fd == -1)
93     {
94         logf (LOG_FATAL|LOG_ERRNO, "Cannot open %s", src);
95         exit (1);
96     }
97     buf = xmalloc (4096);
98     while ((r=read (s_fd, buf, 4096))>0)
99         for (w = 0; w < r; w += i)
100         {
101             i = write (d_fd, buf + w, r - w);
102             if (i == -1)
103             {
104                 logf (LOG_FATAL|LOG_ERRNO, "write");
105                 exit (1);
106             }
107         }
108     if (r)
109     {
110         logf (LOG_FATAL|LOG_ERRNO, "read");
111         exit (1);
112     }
113     xfree (buf);
114     close (d_fd);
115     close (s_fd);
116 }
117
118 void del_file (const char *dst)
119 {
120     unlink (dst);
121 }
122
123 void del_dir (const char *dst)
124 {
125     logf (LOG_DEBUG, "rmdir of %s", dst);
126     if (rmdir (dst) == -1)
127         logf (LOG_ERRNO|LOG_WARN, "rmdir");
128 }
129
130 void repository_update_r (int cmd, char *dst, char *src, char *databaseName);
131
132 void repository_add_tree (int cmd, char *dst, char *src, char *databaseName)
133 {
134     mkdir (dst, 0755);
135     repository_update_r (cmd, dst, src, databaseName);
136 }
137
138 void repository_del_tree (int cmd, char *dst, char *src, char *databaseName)
139 {
140     size_t dst_len = strlen (dst);
141     size_t src_len = strlen (src);
142     struct dir_entry *e_dst;
143     int i_dst = 0;
144     struct stat fs_dst;
145
146     e_dst = dir_open (dst);
147
148     dir_sort (e_dst);
149
150     if (src[src_len-1] != '/')
151         src[src_len] = '/';
152     else
153         --src_len;
154     if (dst[dst_len-1] != '/')
155         dst[dst_len] = '/';
156     else
157         --dst_len;
158     while (e_dst[i_dst].name)
159     {
160         strcpy (dst +dst_len+1, e_dst[i_dst].name);
161         strcpy (src +src_len+1, e_dst[i_dst].name);
162         
163         stat (dst, &fs_dst);
164         switch (fs_dst.st_mode & S_IFMT)
165         {
166         case S_IFREG:
167             file_extract ('d', dst, dst, databaseName);
168             del_file (dst);
169             break;
170         case S_IFDIR:
171             repository_del_tree (cmd, dst, src, databaseName);
172             break;
173         }
174         i_dst++;
175     }
176     dir_free (&e_dst);
177     if (dst_len > 0)
178     {
179         dst[dst_len] = '\0';
180         del_dir (dst);
181     }
182 }
183
184 void repository_update_r (int cmd, char *dst, char *src, char *databaseName)
185 {
186     struct dir_entry *e_dst, *e_src;
187     int i_dst = 0, i_src = 0;
188     struct stat fs_dst, fs_src;
189     size_t dst_len = strlen (dst);
190     size_t src_len = strlen (src);
191
192     e_dst = dir_open (dst);
193     e_src = dir_open (src);
194
195     if (!e_dst && !e_src)
196         return;
197     if (!e_dst)
198     {
199         dir_free (&e_src);
200         repository_add_tree (cmd, dst, src, databaseName);
201         return;
202     }
203     else if (!e_src)
204     {
205         dir_free (&e_dst);
206         repository_del_tree (cmd, dst, src, databaseName);
207         return;
208     }
209
210     dir_sort (e_src);
211     dir_sort (e_dst);
212
213     if (src[src_len-1] != '/')
214         src[src_len] = '/';
215     else
216         --src_len;
217     if (dst[dst_len-1] != '/')
218         dst[dst_len] = '/';
219     else
220         --dst_len;
221     while (e_dst[i_dst].name || e_src[i_src].name)
222     {
223         int sd;
224
225         if (e_dst[i_dst].name && e_src[i_src].name)
226             sd = strcmp (e_dst[i_dst].name, e_src[i_src].name);
227         else if (e_src[i_src].name)
228             sd = 1;
229         else
230             sd = -1;
231                 
232         if (sd == 0)
233         {
234             strcpy (dst +dst_len+1, e_dst[i_dst].name);
235             strcpy (src +src_len+1, e_src[i_src].name);
236             
237             /* check type, date, length */
238
239             stat (dst, &fs_dst);
240             stat (src, &fs_src);
241                 
242             switch (fs_dst.st_mode & S_IFMT)
243             {
244             case S_IFREG:
245                 if (fs_src.st_ctime > fs_dst.st_ctime)
246                 {
247                     file_extract ('d', dst, dst, databaseName);
248                     file_extract ('a', src, dst, databaseName);
249                     copy_file (dst, src);
250                 }
251                 break;
252             case S_IFDIR:
253                 repository_update_r (cmd, dst, src, databaseName);
254                 break;
255             }
256             i_src++;
257             i_dst++;
258         }
259         else if (sd > 0)
260         {
261             strcpy (dst +dst_len+1, e_src[i_src].name);
262             strcpy (src +src_len+1, e_src[i_src].name);
263             
264             stat (src, &fs_src);
265             switch (fs_src.st_mode & S_IFMT)
266             {
267             case S_IFREG:
268                 file_extract ('a', src, dst, databaseName);
269                 copy_file (dst, src);
270                 break;
271             case S_IFDIR:
272                 repository_add_tree (cmd, dst, src, databaseName);
273                 break;
274             }
275             i_src++;
276         }
277         else 
278         {
279             strcpy (dst +dst_len+1, e_dst[i_dst].name);
280             strcpy (src +src_len+1, e_dst[i_dst].name);
281             
282             stat (dst, &fs_dst);
283             switch (fs_dst.st_mode & S_IFMT)
284             {
285             case S_IFREG:
286                 file_extract ('d', dst, dst, databaseName);
287                 del_file (dst);
288                 break;
289             case S_IFDIR:
290                 repository_del_tree (cmd, dst, src, databaseName);
291                 break;
292             }
293             i_dst++;
294         }
295     }
296     dir_free (&e_dst);
297     dir_free (&e_src);
298 }
299
300 void repository (int cmd, const char *rep, const char *base_path,
301                  char *databaseName)
302 {
303     char rep_tmp1[2048];
304     char rep_tmp2[2048];
305
306     strcpy (rep_tmp1, rep);
307     if (base_path)
308     {
309         strcpy (rep_tmp2, base_path);
310         repository_update_r (cmd, rep_tmp2, rep_tmp1, databaseName);
311     }
312     else
313         repository_extract_r (cmd, rep_tmp1, databaseName);
314 }
315 #endif
316
317 static int repComp (const char *a, const char *b, size_t len)
318 {
319     if (!len)
320         return 0;
321     return memcmp (a, b, len);
322 }
323
324 static void repositoryUpdateR (struct dirs_info *di, struct dirs_entry *dst,
325                                const char *base, char *src, char *databaseName)
326 {
327     struct dir_entry *e_src;
328     int i_src = 0;
329     static char tmppath[256];
330     size_t src_len = strlen (src);
331
332     sprintf (tmppath, "%s%s", base, src);
333     e_src = dir_open (tmppath);
334
335 #if 1
336     if (!dst || repComp (dst->path, src, src_len))
337 #else
338     if (!dst || strcmp (dst->path, src))
339 #endif
340     {
341         if (!e_src)
342             return;
343         if (src_len && src[src_len-1] == '/')
344             --src_len;
345         else
346             src[src_len] = '/';
347         src[src_len+1] = '\0';
348         dirs_mkdir (di, src, 0);
349         dst = NULL;
350     }
351     else if (!e_src)
352     {
353         /* delete tree dst */
354         return;
355     }
356     else
357     {
358         if (src_len && src[src_len-1] == '/')
359             --src_len;
360         else
361             src[src_len] = '/';
362         src[src_len+1] = '\0';
363         dst = dirs_read (di); 
364     }
365     dir_sort (e_src);
366
367     while (1)
368     {
369         int sd;
370
371         if (dst && !repComp (dst->path, src, src_len+1))
372         {
373             if (e_src[i_src].name)
374             {
375                 logf (LOG_DEBUG, "dst=%s src=%s", dst->path + src_len+1, 
376                       e_src[i_src].name);
377                 sd = strcmp (dst->path + src_len+1, e_src[i_src].name);
378             }
379             else
380                 sd = -1;
381         }
382         else if (e_src[i_src].name)
383             sd = 1;
384         else
385             break;
386         logf (LOG_DEBUG, "trav sd=%d", sd);
387         if (sd == 0)
388         {
389             strcpy (src + src_len+1, e_src[i_src].name);
390             sprintf (tmppath, "%s%s", base, src);
391             
392             switch (e_src[i_src].kind)
393             {
394             case dirs_file:
395                 if (e_src[i_src].ctime > dst->ctime)
396                 {
397                     if (fileExtract (&dst->sysno, tmppath, databaseName, 0))
398                         dirs_add (di, src, dst->sysno, e_src[i_src].ctime);
399                 }
400                 dst = dirs_read (di);
401                 break;
402             case dirs_dir:
403                 repositoryUpdateR (di, dst, base, src, databaseName);
404                 dst = dirs_last (di);
405                 logf (LOG_DEBUG, "last is %s", dst ? dst->path : "null");
406                 break;
407             default:
408                 dst = dirs_read (di); 
409             }
410             i_src++;
411         }
412         else if (sd > 0)
413         {
414             SYSNO sysno = 0;
415             strcpy (src + src_len+1, e_src[i_src].name);
416             sprintf (tmppath, "%s%s", base, src);
417
418             switch (e_src[i_src].kind)
419             {
420             case dirs_file:
421                 if (fileExtract (&sysno, tmppath, databaseName, 0))
422                     dirs_add (di, src, sysno, e_src[i_src].ctime);            
423                 break;
424             case dirs_dir:
425                 repositoryUpdateR (di, dst, base, src, databaseName);
426                 if (dst)
427                     dst = dirs_last (di);
428                 break;
429             }
430             i_src++;
431         }
432         else  /* sd < 0 */
433         {
434             assert (0);
435         }
436     }
437     dir_free (&e_src);
438 }
439
440 void repositoryUpdate (const char *path, char *databaseName)
441 {
442     struct dirs_info *di;
443     char src[256];
444     Dict dict;
445
446     dict = dict_open ("repdict", 40, 1);
447     
448     di = dirs_open (dict, path);
449     strcpy (src, "");
450     repositoryUpdateR (di, dirs_read (di), path, src, databaseName);
451     dirs_free (&di);
452
453     dict_close (dict);
454 }