Bump copyright year
[idzebra-moved-to-github.git] / index / update_file.c
1 /* This file is part of the Zebra server.
2    Copyright (C) 1994-2010 Index Data
3
4 Zebra is free software; you can redistribute it and/or modify it under
5 the terms of the GNU General Public License as published by the Free
6 Software Foundation; either version 2, or (at your option) any later
7 version.
8
9 Zebra is distributed in the hope that it will be useful, but WITHOUT ANY
10 WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12 for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
17
18 */
19
20 #include <stdio.h>
21 #include <assert.h>
22 #include <sys/types.h>
23 #ifdef WIN32
24 #include <io.h>
25 #define S_ISREG(x) (x & _S_IFREG)
26 #define S_ISDIR(x) (x & _S_IFDIR)
27 #endif
28 #if HAVE_UNISTD_H
29 #include <unistd.h>
30 #endif
31 #include <direntz.h>
32 #include <fcntl.h>
33 #include <time.h>
34
35 #include "index.h"
36
37 #if 0
38 static int dump_file_dict_func(char *name, const char *info, int pos,
39                                 void *client)
40 {
41     yaz_log(YLOG_LOG, "%s", name);
42     return 0;
43 }
44 static void dump_file_dict(Dict dict)
45 {
46     int before = 10;
47     int after = 1000;
48     char term[1000];
49     
50     strcpy(term, "0");
51     dict_scan(dict, term, &before, &after, 0, dump_file_dict_func);
52 }
53 #endif
54
55 static int repComp(const char *a, const char *b, size_t len)
56 {
57     if (!len)
58         return 0;
59     return memcmp(a, b, len);
60 }
61
62 static void fileDelete_r(ZebraHandle zh,
63                          struct dirs_info *di, struct dirs_entry *dst,
64                          const char *base, char *src)
65 {
66     char tmppath[1024];
67     size_t src_len = strlen(src);
68
69     while (dst && !repComp(dst->path, src, src_len+1))
70     {
71         switch (dst->kind)
72         {
73         case dirs_file:
74             sprintf(tmppath, "%s%s", base, dst->path);
75             zebra_extract_file(zh, &dst->sysno, tmppath, action_delete);
76             strcpy(tmppath, dst->path);
77             dst = dirs_read(di); 
78             dirs_del(di, tmppath);
79             break;
80         case dirs_dir:
81             strcpy(tmppath, dst->path);
82             dst = dirs_read(di);
83             dirs_rmdir(di, tmppath);
84             break;
85         default:
86             dst = dirs_read(di);
87         }
88     }
89 }
90
91 static void file_update_r(ZebraHandle zh,
92                           struct dirs_info *di, struct dirs_entry *dst,
93                           const char *base, char *src, 
94                           int level)
95 {
96     struct dir_entry *e_src;
97     int i_src = 0;
98     static char tmppath[1024];
99     size_t src_len = strlen(src);
100
101     sprintf(tmppath, "%s%s", base, src);
102     e_src = dir_open(tmppath, zh->path_reg, zh->m_follow_links);
103     yaz_log(YLOG_LOG, "dir %s", tmppath);
104
105 #if 0
106     if (!dst || repComp(dst->path, src, src_len))
107 #else
108     if (!dst || strcmp(dst->path, src))
109 #endif
110     {
111         if (!e_src)
112             return;
113
114         if (src_len && src[src_len-1] != '/')
115         {
116             src[src_len] = '/';
117             src[++src_len] = '\0';
118         }
119         dirs_mkdir(di, src, 0);
120         if (dst && repComp(dst->path, src, src_len))
121             dst = NULL;
122     }
123     else if (!e_src)
124     {
125         strcpy(src, dst->path);
126         fileDelete_r(zh, di, dst, base, src);
127         return;
128     }
129     else
130     {
131         if (src_len && src[src_len-1] != '/')
132         {
133             src[src_len] = '/';
134             src[++src_len] = '\0';
135         }
136         dst = dirs_read(di); 
137     }
138     dir_sort(e_src);
139
140     while (1)
141     {
142         int sd;
143
144         if (dst && !repComp(dst->path, src, src_len))
145         {
146             if (e_src[i_src].name)
147             {
148                 yaz_log(YLOG_DEBUG, "dst=%s src=%s", dst->path + src_len,
149                       e_src[i_src].name);
150                 sd = strcmp(dst->path + src_len, e_src[i_src].name);
151             }
152             else
153                 sd = -1;
154         }
155         else if (e_src[i_src].name)
156             sd = 1;
157         else
158             break;
159         yaz_log(YLOG_DEBUG, "trav sd=%d", sd);
160
161         if (sd == 0)
162         {
163             strcpy(src + src_len, e_src[i_src].name);
164             sprintf(tmppath, "%s%s", base, src);
165             
166             switch(e_src[i_src].kind)
167             {
168             case dirs_file:
169                 if (e_src[i_src].mtime > dst->mtime)
170                 {
171                     if (zebra_extract_file(zh, &dst->sysno, tmppath, action_update) == ZEBRA_OK)
172                     {
173                         dirs_add(di, src, dst->sysno, e_src[i_src].mtime);
174                     }
175                     yaz_log(YLOG_DEBUG, "old: %s", ctime(&dst->mtime));
176                     yaz_log(YLOG_DEBUG, "new: %s", ctime(&e_src[i_src].mtime));
177                 }
178                 dst = dirs_read(di);
179                 break;
180             case dirs_dir:
181                 file_update_r(zh, di, dst, base, src, level+1);
182                 dst = dirs_last(di);
183                 yaz_log(YLOG_DEBUG, "last is %s", dst ? dst->path : "null");
184                 break;
185             default:
186                 dst = dirs_read(di); 
187             }
188             i_src++;
189         }
190         else if (sd > 0)
191         {
192             zint sysno = 0;
193             strcpy(src + src_len, e_src[i_src].name);
194             sprintf(tmppath, "%s%s", base, src);
195
196             switch (e_src[i_src].kind)
197             {
198             case dirs_file:
199                 if (zebra_extract_file(zh, &sysno, tmppath, action_update) == ZEBRA_OK)
200                     dirs_add(di, src, sysno, e_src[i_src].mtime);            
201                 break;
202             case dirs_dir:
203                 file_update_r(zh, di, dst, base, src, level+1);
204                 if (dst)
205                     dst = dirs_last(di);
206                 break;
207             }
208             i_src++;
209         }
210         else  /* sd < 0 */
211         {
212             strcpy(src, dst->path);
213             sprintf(tmppath, "%s%s", base, dst->path);
214
215             switch (dst->kind)
216             {
217             case dirs_file:
218                 zebra_extract_file(zh, &dst->sysno, tmppath, action_delete);
219                 dirs_del(di, dst->path);
220                 dst = dirs_read(di);
221                 break;
222             case dirs_dir:
223                 fileDelete_r(zh, di, dst, base, src);
224                 dst = dirs_last(di);
225             }
226         }
227     }
228     dir_free(&e_src);
229 }
230
231 static void file_update_top(ZebraHandle zh, Dict dict, const char *path)
232 {
233     struct dirs_info *di;
234     struct stat sbuf;
235     char src[1024];
236     char dst[1024];
237     int src_len, ret;
238
239     assert(path);
240
241     if (zh->path_reg && !yaz_is_abspath(path))
242     {
243         strcpy(src, zh->path_reg);
244         strcat(src, "/");
245     }
246     else
247         *src = '\0';
248     strcat(src, path);
249     ret = zebra_file_stat(src, &sbuf, zh->m_follow_links);
250
251     strcpy(src, path);
252     src_len = strlen(src);
253
254     if (ret == -1)
255     {
256         yaz_log(YLOG_WARN|YLOG_ERRNO, "Cannot access path %s", src);
257     } 
258     else if (S_ISREG(sbuf.st_mode))
259     {
260         struct dirs_entry *e_dst;
261         di = dirs_fopen(dict, src, zh->m_flag_rw);
262
263         e_dst = dirs_read(di);
264         if (e_dst)
265         {
266             if (sbuf.st_mtime > e_dst->mtime)
267                 if (zebra_extract_file(zh, &e_dst->sysno, src, action_update) == ZEBRA_OK)
268                     dirs_add(di, src, e_dst->sysno, sbuf.st_mtime);
269         }
270         else
271         {
272             zint sysno = 0;
273             if (zebra_extract_file(zh, &sysno, src, action_update) == ZEBRA_OK)
274                  dirs_add(di, src, sysno, sbuf.st_mtime);
275         }
276         dirs_free(&di);
277     }
278     else if (S_ISDIR(sbuf.st_mode))
279     {
280         if (src_len && src[src_len-1] != '/')
281         {
282             src[src_len] = '/';
283             src[++src_len] = '\0';
284         }
285         di = dirs_open(dict, src, zh->m_flag_rw);
286         *dst = '\0';
287         file_update_r(zh, di, dirs_read(di), src, dst, 0);
288         dirs_free (&di);
289     }
290     else
291     {
292         yaz_log(YLOG_WARN, "Skipping path %s", src);
293     }
294 }
295
296 static ZEBRA_RES zebra_open_fmatch(ZebraHandle zh, Dict *dictp)
297 {
298     char fmatch_fname[1024];
299     int ord;
300
301     ord = zebraExplain_get_database_ord(zh->reg->zei);
302     sprintf(fmatch_fname, FMATCH_DICT, ord);
303     if (!(*dictp = dict_open_res(zh->reg->bfs, fmatch_fname, 50,
304                                 zh->m_flag_rw, 0, zh->res)))
305     {
306         yaz_log(YLOG_FATAL, "dict_open fail of %s", fmatch_fname);
307         return ZEBRA_FAIL;
308     }
309     return ZEBRA_OK;
310 }
311
312 ZEBRA_RES zebra_remove_file_match(ZebraHandle zh)
313 {
314     Dict dict;
315     
316     if (zebra_open_fmatch(zh, &dict) != ZEBRA_OK)
317         return ZEBRA_FAIL;
318
319     dict_clean(dict);
320     dict_close(dict);
321
322     return ZEBRA_OK;
323 }
324
325 ZEBRA_RES zebra_update_file_match(ZebraHandle zh, const char *path)
326 {
327     Dict dict;
328
329     if (zebraExplain_curDatabase(zh->reg->zei, zh->basenames[0]))
330     {
331         if (zebraExplain_newDatabase(zh->reg->zei, zh->basenames[0], 0))
332             return ZEBRA_FAIL;
333     }
334     if (zebra_open_fmatch(zh, &dict) != ZEBRA_OK)
335         return ZEBRA_FAIL;
336     
337     if (!strcmp(path, "") || !strcmp(path, "-"))
338     {
339         char src[1024];
340         while (scanf("%s", src) == 1)
341             file_update_top(zh, dict, src);
342     }
343     else
344         file_update_top(zh, dict, path);
345 #if 0
346     dump_file_dict(dict);
347 #endif
348     dict_close(dict);
349     return ZEBRA_OK;
350 }
351
352
353 /*
354  * Local variables:
355  * c-basic-offset: 4
356  * c-file-style: "Stroustrup"
357  * indent-tabs-mode: nil
358  * End:
359  * vim: shiftwidth=4 tabstop=8 expandtab
360  */
361