1 #include <stdio.h>
  2 #include <sys/types.h>
  3 #include <sys/stat.h>
  4 #include <fcntl.h>
  5 #include <sys/mman.h>
  6 #include <unistd.h>
  7 #include "buffer_readline.h"
  8 #include "rh_string.h"
  9 #include "mimetype.h"
 10 #include "log.h"
 11 
 12 #define MAP_WANT_ALNUM  MAP_ALNUM
 13 #include "rh_charmap.h"
 14 
 15 static void mimetype_remove_internal (mimetype_entry_t *entry);
 16 
 17 void mimetype_base_init (mimetype_base_t *base)
 18 {
 19         TYPE_ZERO(base);
 20 }
 21 
 22 void mimetype_base_destroy (mimetype_base_t *base)
 23 {
 24         size_t  i;
 25         size_t  elements;
 26         
 27         elements = base->elements;
 28 
 29         DEBUGLOG ("base(%p): elements(%zu)", (void*)base, elements);
 30 
 31         for (i=0; i<base->nbuckets && elements; ++i) {
 32                 struct mimetype_list    *list;
 33                 
 34                 list = &base->buckets[i];
 35 
 36                 while (!LIST_EMPTY(list)) {
 37                         mimetype_entry_t        *entry;
 38 
 39                         entry = LIST_FIRST(list);
 40 
 41                         mimetype_remove_internal (entry);
 42                         --elements;
 43                 }
 44         }
 45 
 46         if (base->buckets)
 47                 free (base->buckets);
 48         
 49         TYPE_ZERO(base);
 50 }
 51 
 52 int mimetype_load (mimetype_base_t *base, enum mimetype_type type,
 53                             const char *filename)
 54 {
 55         int             return_code = 0;
 56         struct stat     stbuf;
 57         int             fd;
 58         void            *mapping = MAP_FAILED;
 59         struct buffer_readline  lines;
 60 
 61 
 62         /*
 63          *
 64          * open config file
 65          *
 66          *
 67          */
 68 
 69         fd = open (filename, O_RDONLY);
 70         if (fd == -1)
 71                 return -1;
 72 
 73         if (-1 == fstat (fd, &stbuf)) {
 74                 return_code = -1;
 75                 goto out;
 76         }
 77 
 78         mapping = mmap (NULL, stbuf.st_size, PROT_READ, MAP_SHARED, fd, 0);
 79         if (MAP_FAILED == mapping) {
 80                 return_code = -1;
 81                 goto out;
 82         }       
 83 
 84 
 85         /*
 86          *
 87          * parse config file:
 88          *
 89          * # comment
 90          *
 91          * mime/type    ext1 ext2 #comment
 92          *
 93          */
 94 
 95         BUFFER_READLINE_INIT(&lines, mapping, stbuf.st_size);
 96 
 97         while (0 == buffer_readline(&lines)) {
 98                 struct buffer_readline  split;
 99                 const char              *val;
100                 size_t                  nval;
101                 
102                 buffer_readline_strip_comment (&lines);
103                 if (0 == lines.nline)
104                         continue;
105 
106                 buffer_split_init(&split, lines.line, lines.nline, " \t");
107                 
108                 if (0 != buffer_split(&split))
109                         break;
110 
111                 val = split.line;
112                 nval = split.nline;
113 
114                 while (0 == buffer_split(&split)) {
115 
116                         if (0 != mimetype_insert (
117                                                 base,
118                                                 type,
119                                                 split.line, split.nline,
120                                                 val, nval) )
121                         {
122                                 return_code = -1;
123                                 goto out;
124                         }
125                 }
126         }
127         
128         
129         
130 
131 
132         /*
133          *
134          * done
135          *
136          *
137          */
138 out:
139         if (fd > -1) {
140                 if (mapping != MAP_FAILED)
141                         munmap (mapping, stbuf.st_size);
142                 close (fd);
143         }
144         
145         return return_code;
146 }
147 
148 /*
149  *
150  * grows base->buckets if necessary
151  *
152  */
153 static int mimetype_base_grow (mimetype_base_t *base)
154 {
155         struct mimetype_list    *buckets;
156         size_t                  nbuckets;
157         size_t                  i;
158         size_t                  elements;
159 
160         if (0 == base->nbuckets) {
161                 nbuckets = 15;
162         } else {
163                 /* ~ 5 elements per bucket */
164                 if ( ( (1+base->elements) / base->nbuckets) < 5)
165                         return 0;
166                 
167                 nbuckets = base->nbuckets * 2;
168         }
169 
170         /* LIST_INIT() is just setting NULL */
171         buckets  = calloc(nbuckets, sizeof(*buckets));
172         
173         if (NULL == buckets)
174                 return -1;
175         
176 
177         /* re hash */
178 
179         elements = base->elements;
180         
181         for (i=0; i<base->nbuckets && elements; ++i) {
182                 struct mimetype_list    *list_src;
183                 
184                 list_src = &base->buckets[i];
185 
186                 while (!LIST_EMPTY(list_src)) {
187                         struct mimetype_list    *list_dst;
188                         mimetype_entry_t        *entry;
189 
190                         entry = LIST_FIRST(list_src);
191                         LIST_REMOVE(entry, list);
192 
193                         list_dst = &buckets[entry->key.hash % nbuckets];
194 
195                         LIST_INSERT_HEAD(list_dst, entry, list);
196 
197                         --elements;
198                 }
199         }
200 
201         free (base->buckets);
202 
203         base->buckets = buckets;
204         base->nbuckets = nbuckets;
205 
206         return 0;
207 }
208 
209 static mimetype_entry_t * mimetype_get_internal (
210                 mimetype_base_t *base, const char *key, size_t nkey)
211 {
212         size_t                  hashkey;
213         mimetype_entry_t        *entry;
214         struct mimetype_list    *list;
215 
216         if (NULL == base->buckets || 0 == base->nbuckets)
217                 return NULL;
218         
219         hashkey = rh_hashcase33(key, nkey);
220                         
221         list = &base->buckets[hashkey % base->nbuckets];
222 
223         LIST_FOREACH(entry, list, list) {
224 #if 0
225                 printf ("%s(): [%.*s] == [%.*s]?\n", __FUNCTION__,
226                                 entry->key.used, entry->key.data,
227                                 nkey, key);
228 #endif
229         
230                 if (entry->key.used != nkey)
231                         continue;
232 
233                 if (0 != rh_memcasecmp(entry->key.data, key, nkey))
234                         continue;
235                 
236 
237                 return entry;
238         }
239 
240         return NULL;
241 }
242 
243 static void mimetype_remove_internal (mimetype_entry_t *entry)
244 {
245 #if 0
246         printf ("%s(%p): removed(%d) used(%zu) key[%.*s] val[%.*s]\n",
247                         __FUNCTION__,
248                         (void*)entry,
249                         entry->removed,
250                         entry->used,
251                         entry->key.used, entry->key.data,
252                         entry->value.used, entry->value.data );
253 #endif
254         if (entry->base) {
255                 if (!entry->removed) {
256                         --entry->base->elements;
257                         LIST_REMOVE(entry, list);
258                         entry->removed = 1;
259                 }
260         }
261                 
262         if (entry->used)
263                 --entry->used;
264         
265         if (entry->used)
266                 return;
267 
268         rh_buffer_destroy(&entry->key);
269         rh_buffer_destroy(&entry->value);
270                         
271         TYPE_ZERO(entry);
272         
273         free (entry);
274 }
275         
276 int mimetype_insert (mimetype_base_t *base,
277                      enum mimetype_type type,
278                      const char *key, size_t nkey,
279                      const char *value, size_t nvalue)
280 {
281         mimetype_entry_t        *entry;
282         struct mimetype_list    *list;
283         
284         entry = mimetype_get_internal (base, key, nkey);
285         
286         if (entry)
287                 mimetype_remove_internal(entry);
288 
289         if (0 != mimetype_base_grow (base))
290                 return -1;
291 
292         entry = calloc(1, sizeof(*entry));
293         if (NULL == entry)
294                 return -1;
295                 
296         if (0 != rh_buffer_append(&entry->key, key, nkey))
297                 goto error_out;
298         
299         if (0 != rh_buffer_append(&entry->value, value, nvalue))
300                 goto error_out;
301 
302         if (base->max_typelength < nvalue)
303                 base->max_typelength = nvalue;
304 
305         entry->type = type;
306         entry->base = base;
307         ++entry->base->elements;
308 
309         rh_buffer_hashcase (&entry->key);
310         
311         list = &base->buckets[entry->key.hash % base->nbuckets];
312 
313         LIST_INSERT_HEAD(list, entry, list);
314         
315         entry->used = 1;
316         
317         return 0;
318 
319 error_out:
320         if (entry) {
321                 rh_buffer_destroy(&entry->key);
322                 rh_buffer_destroy(&entry->value);
323         }
324         return -1;
325 }
326 
327 int mimetype_remove (mimetype_base_t *base, const char *key, size_t nkey)
328 {
329         mimetype_entry_t        *entry;
330 
331         entry = mimetype_get_internal (base, key, nkey);
332         if (entry)
333                 mimetype_remove_internal(entry);
334         
335         return 0;
336 }
337 
338 void mimetype_dump (const mimetype_t *mime)
339 {
340         size_t i;
341 
342         printf ("%s(%p):\n", __FUNCTION__, (void *)mime);
343 
344         for (i=0; i<MIMETYPE_MAX; ++i) {
345                 const mimetype_entry_t *entry;
346 
347                 entry = mime->entries[i];
348         
349                 printf ("  %2d  : ", i);
350 
351                 if (entry) {
352                         printf ("[%.*s]\n",
353                                         entry->value.used, entry->value.data);
354                 } else {
355                         printf ("(NULL)\n");
356                 }
357         }
358 }
359 
360 int  mimetype_pop  (mimetype_base_t *base, mimetype_t *mime,
361                     const char *filename, size_t nfilename)
362 {
363         const char      *ext, *end;
364         size_t          next;
365 
366 #if 0
367         printf ("%s(): file(%.*s)\n", __FUNCTION__, nfilename, filename);
368 #endif
369         
370         TYPE_ZERO(mime);
371         mime->initialized = 1;
372 
373         if (0 == nfilename)
374                 return 0;
375 
376         end = filename;
377         next = 0;
378 
379         for (   ext = filename + nfilename - 1;
380                 ext > end && next < base->max_typelength;
381                 --ext)
382         {
383                 unsigned char ch = ext[0];
384 
385                 if ('.' == ch) {
386                         mimetype_entry_t        *entry;
387 
388                         if (0 == next)
389                                 return 0;
390 #if 0
391                         printf ("%s(): ext[%.*s] next(%zu)\n", __FUNCTION__,
392                                         next, ext + 1,
393                                         next);
394 #endif
395         
396                         entry = mimetype_get_internal (base, ext + 1, next);
397                         if (NULL == entry)
398                                 return 0;
399 #if 0
400                         printf ("%s(): val[%.*s]\n", __FUNCTION__,
401                                         entry->value.used, entry->value.data);
402 #endif
403 
404 
405                         /* found "that" entry already */
406                         if (mime->entries[entry->type])
407                                 return 0;
408                         
409                         mime->entries[entry->type] = entry;
410 
411                         ++entry->used;
412                         
413                         next = 0;
414 
415                         continue;
416                 }
417 
418                 if (0 == MAP_ALNUM[ch])
419                         return 0;
420                 
421                 ++next;
422         }
423         
424         return 0;
425 }
426 
427 void mimetype_push (mimetype_t *mime)
428 {
429         unsigned int i;
430 
431         if (NULL == mime)
432                 return;
433 
434         for (i=0; i<MIMETYPE_MAX; ++i){
435                 if (mime->entries[i]) {
436                         mimetype_entry_t *entry = (void*)mime->entries[i];
437                         
438                         if (entry->used < 1)
439                                 mimetype_remove_internal (entry);
440                         else
441                                 --entry->used;
442                 }
443         }
444 
445         TYPE_ZERO(mime);
446 }


syntax highlighted by Code2HTML, v. 0.9.1