Fixed up base64_dump() users and interfaces to fix memory leaks
[jigit.git] / parse_jigdo.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <errno.h>
4 #include <string.h>
5 #include <fcntl.h>
6 #include <sys/types.h>
7 #include <sys/stat.h>
8 #include <limits.h>
9 #include <zlib.h>
10 #ifdef BZ2_SUPPORT
11 #   include <bzlib.h>
12 #endif
13 #include "jigdb.h"
14 #include "jte.h"
15
16 INT64 get_file_size(char *filename)
17 {
18     struct stat sb;
19     int error = 0;
20     
21     error = stat(filename, &sb);
22     if (error)
23         return MISSING;
24     else
25         return sb.st_size;
26 }
27
28 md5_list_t *find_file_in_md5_list(unsigned char *base64_md5)
29 {
30     md5_list_t *md5_list_entry = G_md5_list_head;
31     
32     while (md5_list_entry)
33     {        
34         if (!memcmp(md5_list_entry->md5, base64_md5, 16))
35             return md5_list_entry;
36         /* else */
37         md5_list_entry = md5_list_entry->next;
38     }
39     return NULL; /* Not found */
40 }
41
42 static int add_md5_entry(INT64 size, char *md5, char *path)
43 {
44     md5_list_t *new = NULL;    
45     new = calloc(1, sizeof(*new));
46     if (!new)
47         return ENOMEM;
48
49     new->md5 = md5;
50     new->full_path = path;
51     new->file_size = size;
52     
53     if (!G_md5_list_head)
54     {
55         G_md5_list_head = new;
56         G_md5_list_tail = new;
57     }
58     else
59     {
60         G_md5_list_tail->next = new;
61         G_md5_list_tail = new;
62     }
63     
64     return 0;
65 }
66
67 static int parse_md5_entry(char *md5_entry)
68 {
69     int error = 0;
70     char *file_name = NULL;
71     char *md5 = NULL;
72     INT64 file_size = 0;
73
74     md5_entry[22] = 0;
75     md5_entry[23] = 0;
76
77     md5 = md5_entry;
78     file_name = &md5_entry[24];
79
80     if ('\n' == file_name[strlen(file_name) -1])
81         file_name[strlen(file_name) - 1] = 0;
82     
83     file_size = get_file_size(file_name);
84
85     error = add_md5_entry(file_size, md5, file_name);
86     return 0;
87 }
88
89 int parse_md5_file(char *filename)
90 {
91     char buf[2048];
92     FILE *file = NULL;
93     char *ret = NULL;
94     int error = 0;
95
96     file = fopen(filename, "rb");
97     if (!file)
98     {
99         fprintf(G_logfile, "Failed to open MD5 file %s, error %d!\n", filename, errno);
100         return errno;
101     }
102     
103     while(1)
104     {
105         ret = fgets(buf, sizeof(buf), file);
106         if (NULL == ret)
107             break;
108         error = parse_md5_entry(strdup(buf));
109     }
110     return 0;
111 }
112
113 static int file_exists(char *path, INT64 *size)
114 {
115     struct stat sb;
116     int error = 0;
117     
118     error = stat(path, &sb);
119     if (!error && S_ISREG(sb.st_mode))
120     {
121         *size = sb.st_size;
122         return 1;
123     }
124     
125     /* else */
126     return 0;
127 }
128
129 static int find_file_in_mirror(char *jigdo_match, char *jigdo_name,
130                                char *match, INT64 *file_size, char **mirror_path)
131 {
132     match_list_t *entry = G_match_list_head;
133     char path[PATH_MAX];
134
135     while (entry)
136     {
137         if (!strcmp(entry->match, match))
138         {
139             sprintf(path, "%s/%s", entry->mirror_path, jigdo_name);
140             if (file_exists(path, file_size))
141             {
142                 *mirror_path = strdup(path);
143                 return 0;
144             }
145         }
146         entry = entry->next;
147     }
148     
149     *mirror_path = jigdo_name;
150     return ENOENT;
151 }
152
153
154 /* DELIBERATELY do not sort these, or do anything clever with
155    insertion. The entries in the jigdo file should be in the same
156    order as the ones we'll want from the template. Simply add to the
157    end of the singly-linked list each time! */
158 static int add_file_entry(char *jigdo_entry)
159 {
160     int error = 0;
161     char *file_name = NULL;
162     INT64 file_size = 0;
163     char *ptr = jigdo_entry;
164     char *base64_md5 = NULL;
165     char *match = NULL;
166     char *jigdo_name = NULL;
167     
168     /* Grab out the component strings from the entry in the jigdo file */
169     base64_md5 = jigdo_entry;
170     while (0 != *ptr)
171     {
172         if ('=' == *ptr)
173         {
174             *ptr = 0;
175             ptr++;
176             match = ptr;
177         }
178         else if (':' == *ptr)
179         {
180             *ptr = 0;
181             ptr++;
182             jigdo_name = ptr;
183         }
184         else if ('\n' == *ptr)
185             *ptr = 0;
186         else
187             ptr++;
188     }
189
190     if (find_file_in_md5_list(base64_md5))
191         return 0; /* We already have an entry for this file; don't
192                    * waste any more time on it */
193
194     /* else look for the file in the filesystem */
195     if (NULL == match || NULL == jigdo_name)
196     {
197         fprintf(G_logfile, "Could not parse malformed jigdo entry \"%s\"\n", jigdo_entry);
198         return EINVAL;
199     }
200     error = find_file_in_mirror(match, jigdo_name, match, &file_size, &file_name);
201
202     if (error)
203         {
204                 if (G_missing_filename)
205                         add_md5_entry(MISSING, base64_md5, file_name);
206                 else
207                 {
208                         fprintf(G_logfile, "Unable to find a file to match %s\n", file_name);
209                         fprintf(G_logfile, "Abort!\n");
210                         exit (ENOENT);
211                 }
212         }
213     else
214         add_md5_entry(file_size, base64_md5, file_name);
215     return 0;
216 }
217
218
219
220 int parse_jigdo_file(char *filename)
221 {
222     char buf[2048];
223     gzFile *file = NULL;
224     char *ret = NULL;
225     int error = 0;
226     
227     file = gzopen(filename, "rb");
228     if (!file)
229     {
230         fprintf(G_logfile, "Failed to open jigdo file %s, error %d!\n", filename, errno);
231         return errno;
232     }
233
234     /* Find the [Parts] section of the jigdo file */
235     while (1)
236     {
237         ret = gzgets(file, buf, sizeof(buf));
238         if (NULL == ret)
239             break;
240         if (!strncmp(buf, "[Parts]", 7))
241             break;
242     }
243
244     /* Now grab the individual file entries and build a list */
245     while (1)
246     {
247         ret = gzgets(file, buf, sizeof(buf));
248         if (NULL == ret || !strcmp(buf, "\n"))
249             break;
250         if (!strcmp(buf, "[") || !strcmp(buf, "#"))
251             continue;
252         error = add_file_entry(strdup(buf));
253         if (error)
254             break;
255     }
256
257     gzclose(file);
258     return error;
259 }