Split of work into more files.
[idzebra-moved-to-github.git] / index / trav.c
1 /*
2  * Copyright (C) 1995, Index Data I/S 
3  * All rights reserved.
4  * Sebastian Hammer, Adam Dickmeiss
5  *
6  * $Log: trav.c,v $
7  * Revision 1.1  1995-09-01 14:06:36  adam
8  * Split of work into more files.
9  *
10  */
11 #include <stdio.h>
12 #include <assert.h>
13 #include <unistd.h>
14 #include <dirent.h>
15 #include <sys/stat.h>
16 #include <sys/types.h>
17 #include <fcntl.h>
18 #include <ctype.h>
19
20 #include <util.h>
21 #include "index.h"
22
23 static void repository_extract_r (int cmd, char *rep)
24 {
25     struct dir_entry *e;
26     int i;
27     struct stat fs;
28     size_t rep_len = strlen (rep);
29
30     e = dir_open (rep);
31     if (!e)
32         return;
33     if (rep[rep_len-1] != '/')
34         rep[rep_len] = '/';
35     else
36         --rep_len;
37     for (i=0; e[i].name; i++)
38     {
39         strcpy (rep +rep_len+1, e[i].name);
40         stat (rep, &fs);
41         switch (fs.st_mode & S_IFMT)
42         {
43         case S_IFREG:
44             file_extract (cmd, rep, rep);
45             break;
46         case S_IFDIR:
47             repository_extract_r (cmd, rep);
48             break;
49         }
50     }
51     dir_free (&e);
52 }
53
54 void copy_file (const char *dst, const char *src)
55 {
56     int d_fd = open (dst, O_WRONLY|O_CREAT, 0666);
57     int s_fd = open (src, O_RDONLY);
58     char *buf;
59     size_t i, r, w;
60
61     if (d_fd == -1)
62     {
63         log (LOG_FATAL|LOG_ERRNO, "Cannot create %s", dst);
64         exit (1);
65     }
66     if (s_fd == -1)
67     {
68         log (LOG_FATAL|LOG_ERRNO, "Cannot open %s", src);
69         exit (1);
70     }
71     if (!(buf = malloc (4096)))
72     {
73         log (LOG_FATAL|LOG_ERRNO, "malloc");
74         exit (1);
75     }
76     while ((r=read (s_fd, buf, 4096))>0)
77         for (w = 0; w < r; w += i)
78         {
79             i = write (d_fd, buf + w, r - w);
80             if (i == -1)
81             {
82                 log (LOG_FATAL|LOG_ERRNO, "write");
83                 exit (1);
84             }
85         }
86     if (r)
87     {
88         log (LOG_FATAL|LOG_ERRNO, "read");
89         exit (1);
90     }
91     free (buf);
92     close (d_fd);
93     close (s_fd);
94 }
95
96 void del_file (const char *dst)
97 {
98     unlink (dst);
99 }
100
101 void del_dir (const char *dst)
102 {
103     log (LOG_DEBUG, "rmdir of %s", dst);
104     if (rmdir (dst) == -1)
105         log (LOG_ERRNO|LOG_WARN, "rmdir");
106 }
107
108 void repository_update_r (int cmd, char *dst, char *src);
109
110 void repository_add_tree (int cmd, char *dst, char *src)
111 {
112     mkdir (dst, 0755);
113     repository_update_r (cmd, dst, src);
114 }
115
116 void repository_del_tree (int cmd, char *dst, char *src)
117 {
118     size_t dst_len = strlen (dst);
119     size_t src_len = strlen (src);
120     struct dir_entry *e_dst;
121     int i_dst = 0;
122     struct stat fs_dst;
123
124     e_dst = dir_open (dst);
125
126     dir_sort (e_dst);
127
128     if (src[src_len-1] != '/')
129         src[src_len] = '/';
130     else
131         --src_len;
132     if (dst[dst_len-1] != '/')
133         dst[dst_len] = '/';
134     else
135         --dst_len;
136     while (e_dst[i_dst].name)
137     {
138         strcpy (dst +dst_len+1, e_dst[i_dst].name);
139         strcpy (src +src_len+1, e_dst[i_dst].name);
140         
141         stat (dst, &fs_dst);
142         switch (fs_dst.st_mode & S_IFMT)
143         {
144         case S_IFREG:
145             file_extract ('d', dst, dst);
146             del_file (dst);
147             break;
148         case S_IFDIR:
149             repository_del_tree (cmd, dst, src);
150             break;
151         }
152         i_dst++;
153     }
154     dir_free (&e_dst);
155     if (dst_len > 0)
156     {
157         dst[dst_len] = '\0';
158         del_dir (dst);
159     }
160 }
161
162 void repository_update_r (int cmd, char *dst, char *src)
163 {
164     struct dir_entry *e_dst, *e_src;
165     int i_dst = 0, i_src = 0;
166     struct stat fs_dst, fs_src;
167     size_t dst_len = strlen (dst);
168     size_t src_len = strlen (src);
169
170     e_dst = dir_open (dst);
171     e_src = dir_open (src);
172
173     if (!e_dst && !e_src)
174         return;
175     if (!e_dst)
176     {
177         dir_free (&e_src);
178         repository_add_tree (cmd, dst, src);
179         return;
180     }
181     else if (!e_src)
182     {
183         dir_free (&e_dst);
184         repository_del_tree (cmd, dst, src);
185         return;
186     }
187
188     dir_sort (e_src);
189     dir_sort (e_dst);
190
191     if (src[src_len-1] != '/')
192         src[src_len] = '/';
193     else
194         --src_len;
195     if (dst[dst_len-1] != '/')
196         dst[dst_len] = '/';
197     else
198         --dst_len;
199     while (e_dst[i_dst].name || e_src[i_src].name)
200     {
201         int sd;
202
203         if (e_dst[i_dst].name && e_src[i_src].name)
204             sd = strcmp (e_dst[i_dst].name, e_src[i_src].name);
205         else if (e_src[i_src].name)
206             sd = 1;
207         else
208             sd = -1;
209                 
210         if (sd == 0)
211         {
212             strcpy (dst +dst_len+1, e_dst[i_dst].name);
213             strcpy (src +src_len+1, e_src[i_src].name);
214             
215             /* check type, date, length */
216
217             stat (dst, &fs_dst);
218             stat (src, &fs_src);
219                 
220             switch (fs_dst.st_mode & S_IFMT)
221             {
222             case S_IFREG:
223                 if (fs_src.st_ctime > fs_dst.st_ctime)
224                 {
225                     file_extract ('d', dst, dst);
226                     file_extract ('a', src, dst);
227                     copy_file (dst, src);
228                 }
229                 break;
230             case S_IFDIR:
231                 repository_update_r (cmd, dst, src);
232                 break;
233             }
234             i_src++;
235             i_dst++;
236         }
237         else if (sd > 0)
238         {
239             strcpy (dst +dst_len+1, e_src[i_src].name);
240             strcpy (src +src_len+1, e_src[i_src].name);
241             
242             stat (src, &fs_src);
243             switch (fs_src.st_mode & S_IFMT)
244             {
245             case S_IFREG:
246                 file_extract ('a', src, dst);
247                 copy_file (dst, src);
248                 break;
249             case S_IFDIR:
250                 repository_add_tree (cmd, dst, src);
251                 break;
252             }
253             i_src++;
254         }
255         else 
256         {
257             strcpy (dst +dst_len+1, e_dst[i_dst].name);
258             strcpy (src +src_len+1, e_dst[i_dst].name);
259             
260             stat (dst, &fs_dst);
261             switch (fs_dst.st_mode & S_IFMT)
262             {
263             case S_IFREG:
264                 file_extract ('d', dst, dst);
265                 del_file (dst);
266                 break;
267             case S_IFDIR:
268                 repository_del_tree (cmd, dst, src);
269                 break;
270             }
271             i_dst++;
272         }
273     }
274     dir_free (&e_dst);
275     dir_free (&e_src);
276 }
277
278 void repository (int cmd, const char *rep, const char *base_path)
279 {
280     char rep_tmp1[2048];
281     char rep_tmp2[2048];
282
283     strcpy (rep_tmp1, rep);
284     if (base_path)
285     {
286         strcpy (rep_tmp2, base_path);
287         repository_update_r (cmd, rep_tmp2, rep_tmp1);
288     }
289     else
290         repository_extract_r (cmd, rep_tmp1);
291 }
292