Towards GPL
[idzebra-moved-to-github.git] / index / trav.c
1 /* $Id: trav.c,v 1.40 2002-08-02 19:26:55 adam Exp $
2    Copyright (C) 1995,1996,1997,1998,1999,2000,2001,2002
3    Index Data Aps
4
5 This file is part of the Zebra server.
6
7 Zebra is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free
9 Software Foundation; either version 2, or (at your option) any later
10 version.
11
12 Zebra is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15 for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with Zebra; see the file LICENSE.zebra.  If not, write to the
19 Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
20 02111-1307, USA.
21 */
22
23
24
25
26 #include <stdio.h>
27 #include <assert.h>
28 #include <sys/types.h>
29 #include <sys/stat.h>
30 #ifdef WIN32
31 #include <io.h>
32 #define S_ISREG(x) (x & _S_IFREG)
33 #define S_ISDIR(x) (x & _S_IFDIR)
34 #else
35 #include <unistd.h>
36 #endif
37 #include <direntz.h>
38 #include <fcntl.h>
39 #include <time.h>
40
41 #include "index.h"
42
43 static int repComp (const char *a, const char *b, size_t len)
44 {
45     if (!len)
46         return 0;
47     return memcmp (a, b, len);
48 }
49
50 static void repositoryExtractR (ZebraHandle zh, int deleteFlag, char *rep,
51                                 struct recordGroup *rGroup,
52                                 int level)
53 {
54     struct dir_entry *e;
55     int i;
56     size_t rep_len = strlen (rep);
57
58     e = dir_open (rep, zh->path_reg);
59     if (!e)
60         return;
61     logf (LOG_LOG, "dir %s", rep);
62     if (rep[rep_len-1] != '/')
63         rep[rep_len] = '/';
64     else
65         --rep_len;
66     
67     for (i=0; e[i].name; i++)
68     {
69         char *ecp;
70         strcpy (rep +rep_len+1, e[i].name);
71         if ((ecp = strrchr (e[i].name, '/')))
72             *ecp = '\0';
73         if (level == 0 && rGroup->databaseNamePath)
74             rGroup->databaseName = e[i].name;
75
76         switch (e[i].kind)
77         {
78         case dirs_file:
79             fileExtract (zh, NULL, rep, rGroup, deleteFlag);
80             break;
81         case dirs_dir:
82             repositoryExtractR (zh, deleteFlag, rep, rGroup, level+1);
83             break;
84         }
85     }
86     dir_free (&e);
87
88 }
89
90 static void fileDeleteR (ZebraHandle zh,
91                          struct dirs_info *di, struct dirs_entry *dst,
92                          const char *base, char *src,
93                          struct recordGroup *rGroup)
94 {
95     char tmppath[1024];
96     size_t src_len = strlen (src);
97
98     while (dst && !repComp (dst->path, src, src_len+1))
99     {
100         switch (dst->kind)
101         {
102         case dirs_file:
103             sprintf (tmppath, "%s%s", base, dst->path);
104             fileExtract (zh, &dst->sysno, tmppath, rGroup, 1);
105              
106             strcpy (tmppath, dst->path);
107             dst = dirs_read (di); 
108             dirs_del (di, tmppath);
109             break;
110         case dirs_dir:
111             strcpy (tmppath, dst->path);
112             dst = dirs_read (di);
113             dirs_rmdir (di, tmppath);
114             break;
115         default:
116             dst = dirs_read (di);
117         }
118     }
119 }
120
121 static void fileUpdateR (ZebraHandle zh,
122                          struct dirs_info *di, struct dirs_entry *dst,
123                          const char *base, char *src, 
124                          struct recordGroup *rGroup,
125                          int level)
126 {
127     struct dir_entry *e_src;
128     int i_src = 0;
129     static char tmppath[1024];
130     size_t src_len = strlen (src);
131
132     sprintf (tmppath, "%s%s", base, src);
133     e_src = dir_open (tmppath, zh->path_reg);
134     logf (LOG_LOG, "dir %s", tmppath);
135
136 #if 0
137     if (!dst || repComp (dst->path, src, src_len))
138 #else
139     if (!dst || strcmp (dst->path, src))
140 #endif
141     {
142         if (!e_src)
143             return;
144
145         if (src_len && src[src_len-1] != '/')
146         {
147             src[src_len] = '/';
148             src[++src_len] = '\0';
149         }
150         dirs_mkdir (di, src, 0);
151         if (dst && repComp (dst->path, src, src_len))
152             dst = NULL;
153     }
154     else if (!e_src)
155     {
156         strcpy (src, dst->path);
157         fileDeleteR (zh, di, dst, base, src, rGroup);
158         return;
159     }
160     else
161     {
162         if (src_len && src[src_len-1] != '/')
163         {
164             src[src_len] = '/';
165             src[++src_len] = '\0';
166         }
167         dst = dirs_read (di); 
168     }
169     dir_sort (e_src);
170
171     while (1)
172     {
173         int sd;
174
175         if (dst && !repComp (dst->path, src, src_len))
176         {
177             if (e_src[i_src].name)
178             {
179                 logf (LOG_DEBUG, "dst=%s src=%s", dst->path + src_len,
180                       e_src[i_src].name);
181                 sd = strcmp (dst->path + src_len, e_src[i_src].name);
182             }
183             else
184                 sd = -1;
185         }
186         else if (e_src[i_src].name)
187             sd = 1;
188         else
189             break;
190         logf (LOG_DEBUG, "trav sd=%d", sd);
191
192         if (level == 0 && rGroup->databaseNamePath)
193             rGroup->databaseName = e_src[i_src].name;
194         if (sd == 0)
195         {
196             strcpy (src + src_len, e_src[i_src].name);
197             sprintf (tmppath, "%s%s", base, src);
198             
199             switch (e_src[i_src].kind)
200             {
201             case dirs_file:
202                 if (e_src[i_src].mtime > dst->mtime)
203                 {
204                     if (fileExtract (zh, &dst->sysno, tmppath, rGroup, 0))
205                     {
206                         dirs_add (di, src, dst->sysno, e_src[i_src].mtime);
207                     }
208                     logf (LOG_DEBUG, "old: %s", ctime (&dst->mtime));
209                     logf (LOG_DEBUG, "new: %s", ctime (&e_src[i_src].mtime));
210                 }
211                 dst = dirs_read (di);
212                 break;
213             case dirs_dir:
214                 fileUpdateR (zh, di, dst, base, src, rGroup, level+1);
215                 dst = dirs_last (di);
216                 logf (LOG_DEBUG, "last is %s", dst ? dst->path : "null");
217                 break;
218             default:
219                 dst = dirs_read (di); 
220             }
221             i_src++;
222         }
223         else if (sd > 0)
224         {
225             SYSNO sysno = 0;
226             strcpy (src + src_len, e_src[i_src].name);
227             sprintf (tmppath, "%s%s", base, src);
228
229             switch (e_src[i_src].kind)
230             {
231             case dirs_file:
232                 if (fileExtract (zh, &sysno, tmppath, rGroup, 0))
233                     dirs_add (di, src, sysno, e_src[i_src].mtime);            
234                 break;
235             case dirs_dir:
236                 fileUpdateR (zh, di, dst, base, src, rGroup, level+1);
237                 if (dst)
238                     dst = dirs_last (di);
239                 break;
240             }
241             i_src++;
242         }
243         else  /* sd < 0 */
244         {
245             strcpy (src, dst->path);
246             sprintf (tmppath, "%s%s", base, dst->path);
247
248             switch (dst->kind)
249             {
250             case dirs_file:
251                 fileExtract (zh, &dst->sysno, tmppath, rGroup, 1);
252                 dirs_del (di, dst->path);
253                 dst = dirs_read (di);
254                 break;
255             case dirs_dir:
256                 fileDeleteR (zh, di, dst, base, src, rGroup);
257                 dst = dirs_last (di);
258             }
259         }
260     }
261     dir_free (&e_src);
262 }
263
264 static void groupRes (ZebraHandle zh, struct recordGroup *rGroup)
265 {
266     char resStr[256];
267     char gPrefix[256];
268
269     if (!rGroup->groupName || !*rGroup->groupName)
270         *gPrefix = '\0';
271     else
272         sprintf (gPrefix, "%s.", rGroup->groupName);
273
274     sprintf (resStr, "%srecordId", gPrefix);
275     rGroup->recordId = res_get (zh->res, resStr);
276     sprintf (resStr, "%sdatabasePath", gPrefix);
277     rGroup->databaseNamePath =
278         atoi (res_get_def (zh->res, resStr, "0"));
279 }
280
281 void repositoryShow (ZebraHandle zh)
282                      
283 {
284     struct recordGroup *rGroup = &zh->rGroup;
285     char src[1024];
286     int src_len;
287     struct dirs_entry *dst;
288     Dict dict;
289     struct dirs_info *di;
290     
291     if (!(dict = dict_open (zh->reg->bfs, FMATCH_DICT, 50, 0, 0)))
292     {
293         logf (LOG_FATAL, "dict_open fail of %s", FMATCH_DICT);
294         return;
295     }
296     
297     assert (rGroup->path);    
298     strcpy (src, rGroup->path);
299     src_len = strlen (src);
300     
301     if (src_len && src[src_len-1] != '/')
302     {
303         src[src_len] = '/';
304         src[++src_len] = '\0';
305     }
306     
307     di = dirs_open (dict, src, rGroup->flagRw);
308     
309     while ( (dst = dirs_read (di)) )
310         logf (LOG_LOG, "%s", dst->path);
311     dirs_free (&di);
312     dict_close (dict);
313 }
314
315 static void fileUpdate (ZebraHandle zh,
316                         Dict dict, struct recordGroup *rGroup,
317                         const char *path)
318 {
319     struct dirs_info *di;
320     struct stat sbuf;
321     char src[1024];
322     char dst[1024];
323     int src_len;
324
325     assert (path);
326
327     if (zh->path_reg && !yaz_is_abspath(path))
328     {
329         strcpy (src, zh->path_reg);
330         strcat (src, "/");
331     }
332     else
333         *src = '\0';
334     strcat (src, path);
335     stat (src, &sbuf);
336
337     strcpy (src, path);
338     src_len = strlen (src);
339
340     if (S_ISREG(sbuf.st_mode))
341     {
342         struct dirs_entry *e_dst;
343         di = dirs_fopen (dict, src);
344
345         e_dst = dirs_read (di);
346         if (e_dst)
347         {
348             if (sbuf.st_mtime > e_dst->mtime)
349                 if (fileExtract (zh, &e_dst->sysno, src, rGroup, 0))
350                     dirs_add (di, src, e_dst->sysno, sbuf.st_mtime);
351         }
352         else
353         {
354             SYSNO sysno = 0;
355             if (fileExtract (zh, &sysno, src, rGroup, 0))
356                  dirs_add (di, src, sysno, sbuf.st_mtime);
357         }
358         dirs_free (&di);
359     }
360     else if (S_ISDIR(sbuf.st_mode))
361     {
362         if (src_len && src[src_len-1] != '/')
363         {
364             src[src_len] = '/';
365             src[++src_len] = '\0';
366         }
367         di = dirs_open (dict, src, rGroup->flagRw);
368         *dst = '\0';
369         fileUpdateR (zh, di, dirs_read (di), src, dst, rGroup, 0);
370         dirs_free (&di);
371     }
372     else
373     {
374         logf (LOG_WARN, "Ignoring path %s", src);
375     }
376 }
377
378
379 static void repositoryExtract (ZebraHandle zh,
380                                int deleteFlag, struct recordGroup *rGroup,
381                                const char *path)
382 {
383     struct stat sbuf;
384     char src[1024];
385
386     assert (path);
387
388     if (zh->path_reg && !yaz_is_abspath(path))
389     {
390         strcpy (src, zh->path_reg);
391         strcat (src, "/");
392     }
393     else
394         *src = '\0';
395     strcat (src, path);
396     stat (src, &sbuf);
397
398     strcpy (src, path);
399
400     if (S_ISREG(sbuf.st_mode))
401         fileExtract (zh, NULL, src, rGroup, deleteFlag);
402     else if (S_ISDIR(sbuf.st_mode))
403         repositoryExtractR (zh, deleteFlag, src, rGroup, 0);
404     else
405         logf (LOG_WARN, "Ignoring path %s", src);
406 }
407
408 static void repositoryExtractG (ZebraHandle zh,
409                                 int deleteFlag, struct recordGroup *rGroup)
410 {
411     if (*rGroup->path == '\0' || !strcmp(rGroup->path, "-"))
412     {
413         char src[1024];
414
415         while (scanf ("%1020s", src) == 1)
416             repositoryExtract (zh, deleteFlag, rGroup, src);
417     }
418     else
419         repositoryExtract (zh, deleteFlag, rGroup, rGroup->path);
420 }
421
422 void repositoryUpdate (ZebraHandle zh)
423 {
424     struct recordGroup *rGroup = &zh->rGroup;
425     groupRes (zh, rGroup);
426     assert (rGroup->path);
427     if (rGroup->recordId && !strcmp (rGroup->recordId, "file"))
428     {
429         Dict dict;
430         if (!(dict = dict_open (zh->reg->bfs, FMATCH_DICT, 50,
431                                 rGroup->flagRw, 0)))
432         {
433             logf (LOG_FATAL, "dict_open fail of %s", FMATCH_DICT);
434             return ;
435         }
436         if (*rGroup->path == '\0' || !strcmp(rGroup->path, "-"))
437         {
438             char src[1024];
439             while (scanf ("%s", src) == 1)
440                 fileUpdate (zh, dict, rGroup, src);
441         }
442         else
443             fileUpdate (zh, dict, rGroup, rGroup->path);
444         dict_close (dict);
445     }
446     else 
447         repositoryExtractG (zh, 0, rGroup);
448 }
449
450 void repositoryDelete (ZebraHandle zh)
451 {
452     repositoryExtractG (zh, 1, &zh->rGroup);
453 }
454