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