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