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