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