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