utils.c

00001 /*
00002  * Copyright (c) 2005-2012 by KoanLogic s.r.l. <http://www.koanlogic.com>
00003  * All rights reserved.
00004  *
00005  * This file is part of KLone, and as such it is subject to the license stated
00006  * in the LICENSE file which you have received as part of this distribution.
00007  *
00008  * $Id: utils.c,v 1.58 2009/05/29 12:14:59 tho Exp $
00009  */
00010 
00011 #include "klone_conf.h"
00012 #include <stdlib.h>
00013 #include <stdio.h>
00014 #include <time.h>
00015 #include <string.h>
00016 #include <ctype.h>
00017 #include <fcntl.h>
00018 #include <unistd.h>
00019 #include <dirent.h>
00020 #include <sys/stat.h>
00021 #include <u/libu.h>
00022 #include <klone/os.h>
00023 #include <klone/io.h>
00024 #include <klone/codecs.h>
00025 #include <klone/emb.h>
00026 #include <klone/mime_map.h>
00027 #include <klone/version.h>
00028 #include <klone/utils.h>
00029 #ifdef HAVE_STRINGS
00030 #include <strings.h>
00031 #endif
00032 #ifdef SSL_CYASSL
00033 #include <config.h>
00034 #include <types.h>
00035 #include <ctc_aes.h>
00036 #endif
00037 
00038 enum { LF = 0xA, CR = 0xD };
00039 
00040 static struct html_entities_s
00041 {
00042     int s_char;
00043     const char *entity; 
00044 } entities[] = {
00045     { '&',  "&amp;"  },
00046     { '"',  "&quot;" },
00047     { '\'', "&#39;"  }, 
00048     { '<',  "&lt;"   },
00049     { '>',  "&gt;"   },
00050     { 0, NULL     }
00051 };
00052 
00053 #ifdef OS_UNIX
00054 inline int u_sig_block(int sig)
00055 {
00056     sigset_t sset;
00057 
00058     sigemptyset(&sset);
00059     sigaddset(&sset, sig);
00060     dbg_err_if(sigprocmask(SIG_BLOCK, &sset, NULL));
00061 
00062     return 0;
00063 err:
00064     return ~0;
00065 }
00066 
00067 inline int u_sig_unblock(int sig)
00068 {
00069     sigset_t sset;
00070 
00071     sigemptyset(&sset);
00072     sigaddset(&sset, sig);
00073     dbg_err_if(sigprocmask(SIG_UNBLOCK, &sset, NULL));
00074 
00075     return 0;
00076 err:
00077     return ~0;
00078 }
00079 #endif /* OS_UNIX */
00080 
00081 
00082 /* Get address from addr+port combo string.  UNIX IPC paths are returned 
00083  * AS-IS. */
00084 const char *u_addr_get_ip (const char *a, char *d, size_t dlen)
00085 {
00086     char *e;
00087     const char *b;
00088 
00089     dbg_return_if (a == NULL, NULL);
00090     dbg_return_if (d == NULL, NULL);
00091     dbg_return_if (dlen == 0, NULL);
00092 
00093     switch (a[0])
00094     {
00095         case '/':   /* UNIX path is returned as-is. */
00096             dbg_if (u_strlcpy(d, a, dlen));
00097             return d;
00098         case '[':   /* Handle IPv6. */
00099             e = strchr(a, ']');
00100             b = a + 1;
00101             break;
00102         default:    /* Assume IPv4. */
00103             e = strchr(a, ':');
00104             b = a;
00105             break;
00106     }
00107 
00108     if (e != NULL)
00109     {
00110         dbg_if (u_strlcpy(d, b, U_MIN((size_t) (e - b + 1), dlen)) + 1);
00111         return d;
00112     }
00113 
00114     u_warn("unable to get an IP from '%s'", a);
00115     return NULL;
00116 }
00117 
00118 /* Get port from addr+port combo string.  UNIX IPC paths return the empty
00119  * string. */
00120 const char *u_addr_get_port (const char *a, char *d, size_t dlen)
00121 {
00122     char *e, *p;
00123 
00124     dbg_return_if (a == NULL, NULL);
00125     dbg_return_if (d == NULL, NULL);
00126     dbg_return_if (dlen == 0, NULL);
00127 
00128     /* Empty port returned on UNIX path. */
00129     if (a[0] == '/')
00130     {
00131         d[0] = '\0';
00132         return d;
00133     }
00134 
00135     /* Extra check. */
00136     dbg_return_if ((e = strchr(a, '\0')) == NULL, NULL);
00137 
00138     /* Go backwards until the addr/port separator is found. */
00139     for (p = e; *p != ':' && p > a; --p)
00140         ;
00141 
00142     dbg_if (u_strlcpy(d, (p > a) ? p + 1 : "", dlen));
00143         
00144     return d;
00145 }
00146 
00147 /* Format address string to be used in request->{peer,local}_addr fields.
00148  * Basically this function tries to emulate u_sa_ntop() + UNIX IPC paths 
00149  * handling. */
00150 const char *u_addr_fmt (const char *ip, const char *port, char *d, size_t dlen)
00151 {
00152     int isv6 = 1;
00153 
00154     dbg_return_if (d == NULL, NULL);
00155     dbg_return_if (dlen == 0, NULL);
00156 
00157     /* At least 'ip' must be there. */
00158     if (!ip || ip[0] == '\0')
00159     {
00160         d[0] = '\0';
00161         return d;
00162     }
00163 
00164     /* Handle UNIX IPC endpoints: make verbatim copy of the 'ip' parameter,
00165      * and ignore 'port' altogether. */
00166     if (ip[0] == '/')
00167     {
00168         dbg_if (u_strlcpy(d, ip, dlen));
00169         return d;
00170     }
00171 
00172     /* Tell v4 from v6 -- this test may be made less silly :-) */
00173     if (strchr(ip, '.'))
00174         isv6 = 0;
00175 
00176     /* In case 'port' is NULL, a fake '0' port is added anyway. */
00177     dbg_if (u_snprintf(d, dlen, "%s%s%s:%s", 
00178                 isv6 ? "[" : "", ip, isv6 ? "]" : "", port ? port : "0"));
00179 
00180     return d;
00181 }
00182 
00198 char *u_strnstr(const char *buf, const char *sub, size_t buflen)
00199 {
00200     ssize_t len = strlen(sub);
00201     ssize_t plen;
00202     char *p;
00203 
00204     if (*sub == 0)
00205         return (char *)buf;
00206 
00207     plen = buflen;
00208     for (p = (char *)buf; p != NULL; p = memchr(p + 1, *sub, plen - 1))
00209     {
00210         plen = buflen - (p - buf);
00211 
00212         if (plen < len)
00213             return NULL;
00214 
00215         if (strncmp(p, sub, len) == 0)
00216             return (p);
00217     }
00218 
00219     return NULL;
00220 }
00221 
00238 int u_foreach_dir_item(const char *path, unsigned int mask,
00239     int (*cb)(struct dirent*, const char *, void*), void* arg)
00240 {
00241     struct dirent *de;
00242     struct stat st;
00243     DIR *dir = NULL;
00244     char buf[U_FILENAME_MAX];
00245     int rc;
00246 
00247     dbg_return_if (path == NULL, ~0);
00248     dbg_return_if (cb == NULL, ~0);
00249     
00250     /* open the given directory */
00251     dir = opendir(path);
00252     dbg_err_if(dir == NULL);
00253 
00254     while((de = readdir(dir)) != NULL)
00255     {
00256         /* skip . and .. dirs */
00257         if(!strcmp(de->d_name, ".") || !strcmp(de->d_name, ".."))
00258             continue;
00259 
00260         /* build fully qualified name of this item */
00261         dbg_err_if(u_snprintf(buf, U_FILENAME_MAX, "%s/%s", path, de->d_name));
00262 
00263         dbg_err_if( (rc = stat(buf, &st)) == -1);
00264 
00265         /* skip if its type is not in the requested mask */
00266         if(((st.st_mode & S_IFMT) & mask) != 0 && cb(de, path, arg))
00267             break;
00268     }
00269 
00270     closedir(dir);
00271 
00272     return 0;
00273 err:
00274     return ~0;
00275 }
00276 
00291 int u_match_ext(const char *filename, const char *extension)
00292 {
00293     const char *fn, *ext;
00294     size_t flen, elen;
00295 
00296     if(filename == NULL || extension == NULL)
00297         return 0;
00298 
00299     flen = strlen(filename);
00300     elen = strlen(extension);
00301     if(elen > flen)
00302         return 0;
00303 
00304     fn = filename + flen - 1;
00305     ext = extension + elen - 1;
00306     for( ; elen; --fn, --ext, --elen)
00307     {
00308         if(tolower(*fn) != tolower(*ext))
00309             return 0;
00310     }
00311     return 1;
00312 }
00313 
00314 /* hex char to int */
00315 static short htoi(unsigned char c)
00316 {
00317     c = tolower(c);
00318 
00319     if(c >= '0' && c <= '9')
00320         return c - '0';
00321     else if(c >= 'a' && c <= 'z')
00322         return c - 'a' + 10;
00323     else
00324         return 0;
00325 }
00326 
00327 
00328 static ssize_t u_sqlncpy_encode(char *d, const char *s, size_t slen)
00329 {
00330     ssize_t wr = 0;
00331     unsigned char c;
00332 
00333     dbg_return_if (d == NULL, -1);
00334     dbg_return_if (s == NULL, -1);
00335 
00336     for(; slen; --slen)
00337     {
00338         c = *d++ = *s++;
00339         wr++;
00340         if(c == '\'') 
00341         {
00342             dbg_err_if(slen < 2);
00343             *d++ = '\'';
00344             wr++;
00345             --slen;
00346         } 
00347     }
00348     *d = 0;
00349 
00350     return wr;
00351 err:
00352     return -1;
00353 }
00354 
00355 static ssize_t u_sqlncpy_decode(char *d, const char *s, size_t slen)
00356 {
00357     unsigned char c, last = 0;
00358     ssize_t wr = 0;
00359     
00360     dbg_return_if (d == NULL, -1);
00361     dbg_return_if (s == NULL, -1);
00362 
00363     for(; slen; --slen)
00364     {
00365         c = *s++;
00366         if(c == '\'' && last == c) 
00367         {
00368             last = 0; 
00369             ; /* skip */
00370         } else {
00371             *d++ = c;
00372             last = c;
00373             wr++;
00374         }
00375     }
00376     *d = 0;
00377 
00378     return wr;
00379 }
00380 
00397 ssize_t u_sqlncpy(char *d, const char *s, size_t slen, int flags)
00398 {
00399     dbg_return_if (d == NULL, -1);
00400     dbg_return_if (s == NULL, -1);
00401 
00402     switch(flags)
00403     {
00404     case SQLCPY_ENCODE:
00405         return u_sqlncpy_encode(d, s, slen);
00406     case SQLCPY_DECODE:
00407         return u_sqlncpy_decode(d, s, slen);
00408     default:
00409         u_strlcpy(d, s, slen + 1);
00410         return slen;
00411     }
00412 
00413     return -1;
00414 }
00415 
00416 static ssize_t u_urlncpy_encode(char *d, const char *s, size_t slen)
00417 {
00418     const char hexc[] = "0123456789ABCDEF";
00419     ssize_t wr = 0;
00420     unsigned char c;
00421 
00422     dbg_return_if (d == NULL, -1);
00423     dbg_return_if (s == NULL, -1);
00424 
00425     for(; slen; --slen)
00426     {
00427         c = *s++;
00428         if(c == ' ') {
00429             *d++ = '+';
00430             wr++;
00431         } else if(isalnum(c) || c == '_' || c == '-' || c == '.') {
00432             *d++ = c;
00433             wr++;
00434         } else {
00435             *d++ = '%';                                        
00436             *d++ = hexc[(c >> 4) & 0xF];             
00437             *d++ = hexc[c & 0xF];  
00438             wr += 3;
00439         }
00440     }
00441     *d = 0;
00442 
00443     return wr;
00444 }
00445 
00446 static ssize_t u_urlncpy_decode(char *d, const char *s, size_t slen)
00447 {
00448     unsigned char c;
00449     ssize_t wr = 0;
00450 
00451     dbg_return_if (d == NULL, -1);
00452     dbg_return_if (s == NULL, -1);
00453 
00454     for(; slen; --slen, ++wr)
00455     {
00456         c = *s++;
00457         if(c == '%')
00458         {
00459             dbg_err_if(slen < 2 || !isxdigit(s[0]) || !isxdigit(s[1]));
00460             c = htoi(s[0]) << 4 | htoi(s[1]);
00461             //dbg_err_if(c == 0);
00462             *d++ = (char)c;
00463             s += 2;
00464             slen -= 2;
00465         } else if(c == '+') {
00466             *d++ = ' ';
00467         } else {
00468             *d++ = c;
00469         }
00470     }
00471     *d = 0;
00472 
00473     return wr;
00474 err:
00475     return -1;
00476 
00477 }
00478 
00495 ssize_t u_urlncpy(char *d, const char *s, size_t slen, int flags)
00496 {
00497     dbg_return_if (d == NULL, -1);
00498     dbg_return_if (s == NULL, -1);
00499 
00500     switch(flags)
00501     {
00502     case URLCPY_ENCODE:
00503         return u_urlncpy_encode(d, s, slen);
00504     case URLCPY_DECODE:
00505         return u_urlncpy_decode(d, s, slen);
00506     default:
00507         u_strlcpy(d, s, slen + 1);
00508         return slen;
00509     }
00510 
00511     return -1;
00512 }
00513 
00514 inline char u_tochex(int n)
00515 {
00516         if(n > 15)
00517                 return '?';
00518         return ( n < 10 ? n + '0' : n-10 + 'a');
00519 }
00520 
00521 static int u_hex2ch(char c)
00522 {
00523     if(c >= 'a' && c <= 'z') 
00524         return c - 'a' + 10;
00525     else if(c >= 'A' && c <= 'Z')
00526         return c - 'A' + 10;
00527     else if(c >= '0' && c <= '9') 
00528         return c - '0';
00529     else
00530         return -1; /* error */
00531 }
00532 
00533 void u_print_version_and_exit(void)
00534 {
00535     static const char *vv = 
00536     "KLone %s - Copyright (c) 2005-2012 KoanLogic s.r.l. - "
00537     "All rights reserved. \n\n";
00538 
00539     fprintf(stderr, vv, klone_version());
00540 
00541     exit(EXIT_FAILURE);
00542 }
00543 
00544 static ssize_t u_hexncpy_decode(char *d, const char *s, size_t slen)
00545 {
00546         size_t i, t;
00547 
00548     dbg_return_if (d == NULL, -1);
00549     dbg_return_if (s == NULL, -1);
00550 
00551     /* slen must be multiple of 2 */
00552     dbg_err_if((slen % 2) != 0);
00553 
00554         for(i = 0, t = 0; i < slen; ++t, i += 2)
00555         d[t] = (u_hex2ch(s[i]) << 4) | u_hex2ch(s[i+1]); 
00556 
00557     d[t] = 0; /* zero-term */
00558 
00559     return t;
00560 err:
00561     return -1;
00562 }
00563 
00564 static ssize_t u_hexncpy_encode(char *d, const char *s, size_t slen)
00565 {
00566         size_t c, i, t;
00567 
00568     dbg_return_if (d == NULL, -1);
00569     dbg_return_if (s == NULL, -1);
00570 
00571         for(i = 0, t = 0; i < slen; ++i, t += 2)
00572         {
00573                 c = s[i];
00574         d[t]   = u_tochex((c >> 4) & 0x0F);
00575         d[t+1] = u_tochex(c & 0x0F);
00576         }
00577     d[t] = 0; /* zero-term */
00578 
00579     return t;
00580 }
00581 
00598 ssize_t u_hexncpy(char *d, const char *s, size_t slen, int flags)
00599 {
00600     dbg_err_if (d == NULL);
00601     dbg_err_if (s == NULL);
00602 
00603     switch(flags)
00604     {
00605     case HEXCPY_ENCODE:
00606         return u_hexncpy_encode(d, s, slen);
00607     case HEXCPY_DECODE:
00608         return u_hexncpy_decode(d, s, slen);
00609     default:
00610         u_strlcpy(d, s, slen + 1);
00611         return slen;
00612     }
00613 
00614 err:
00615     return -1;
00616 }
00617 
00618 static ssize_t u_htmlncpy_encode(char *d, const char *s, size_t slen)
00619 {
00620     struct html_entities_s *p;
00621     const char *map[256];
00622     size_t elen;
00623     unsigned char c;
00624     ssize_t wr = 0;
00625 
00626     dbg_return_if (d == NULL, -1);
00627     dbg_return_if (s == NULL, -1);
00628 
00629     /* build the map table (could be static but it wouldn't be thread-safe) */
00630     memset(map, 0, sizeof(map));
00631     for(p = entities; p->s_char; ++p)
00632         map[p->s_char] = p->entity;
00633 
00634     while(slen)
00635     {
00636         c = *s++;
00637         if(map[c] == NULL)
00638         {
00639             *d++ = c;   /* this char doesn't need encoding */
00640             wr++;
00641             --slen;
00642         } else {
00643             elen = strlen(map[c]);
00644             strcpy(d, map[c]); /* append the entity */
00645             --slen;
00646             d += elen;
00647             wr += elen;
00648         }
00649     }
00650     *d = 0;
00651 
00652     return wr;
00653 }
00654 
00655 static ssize_t u_htmlncpy_decode(char *d, const char *s, size_t slen)
00656 {
00657     struct html_entities_s *p;
00658     char *found, *after;
00659 
00660     dbg_return_if (d == NULL, -1);
00661     dbg_return_if (s == NULL, -1);
00662 
00663     u_strlcpy(d, s, slen + 1);
00664 
00665     for(p = entities; p->s_char; ++p)
00666     {
00667         while((found = u_stristr(d, p->entity)) != NULL)
00668         {
00669             *found = p->s_char;
00670             after = found + strlen(p->entity);
00671             memmove(++found, after, 1 + strlen(after));
00672         }
00673     }
00674 
00675     return strlen(d);
00676 }
00677 
00694 ssize_t u_htmlncpy(char *d, const char *s, size_t slen, int flags)
00695 {
00696     dbg_err_if (d == NULL);
00697     dbg_err_if (s == NULL);
00698 
00699     switch(flags)
00700     {
00701     case HTMLCPY_ENCODE:
00702         return u_htmlncpy_encode(d, s, slen);
00703     case HTMLCPY_DECODE:
00704         return u_htmlncpy_decode(d, s, slen);
00705     default:
00706         u_strlcpy(d, s, slen + 1);
00707         return slen;
00708     }
00709 err:
00710     return -1;
00711 }
00712 
00726 char *u_stristr(const char *string, const char *sub)
00727 {
00728     const char *p;
00729     size_t len;
00730 
00731     dbg_err_if (sub == NULL);
00732     dbg_err_if (string == NULL);
00733 
00734     len = strlen(sub);
00735     for(p = string; *p; ++p)
00736     {
00737         if(strncasecmp(p, sub, len) == 0)
00738             return (char*)p;
00739     }
00740 
00741 err: /* fall through */
00742     return NULL;
00743 }
00744 
00758 char* u_strnrchr(const char *s, char c, size_t len)
00759 {
00760     register int i = len - 1;
00761 
00762     dbg_err_if (s == NULL);
00763     
00764     for(; i >= 0; --i)
00765         if(s[i] == c)
00766             return (char*)s + i; /* found */
00767 err:
00768     return NULL;
00769 }
00770 
00785 int u_tmpfile_open (const char *tmpdir, io_t **pio)
00786 {
00787     int fd = -1;
00788     unsigned int i;
00789     char tmpf[U_FILENAME_MAX];
00790     const char *pfx = "kloned_tmp_";
00791     /* Mimic tempnam(3) directory search for backwards compatibility. */
00792     const char *dirs[] = {
00793         tmpdir,
00794         getenv("TMPDIR"),
00795         P_tmpdir,
00796         "/tmp",
00797         "."
00798     };
00799 
00800     dbg_return_if (pio == NULL, ~0);
00801 
00802     for (i = 0; i < (sizeof(dirs) / sizeof(char *)); i++)
00803     {
00804         if (dirs[i])
00805         {
00806             /* Do the template for the temporary file name. */
00807             if (u_path_snprintf(tmpf, sizeof tmpf, U_PATH_SEPARATOR, 
00808                         "%s/%sXXXXXXXXXX", dirs[i], pfx))
00809                 continue;
00810 
00811             /* Try to create it in the file system. */
00812             if ((fd = mkstemps(tmpf, 0)) == -1)
00813                 continue;
00814 
00815             /* Abort on any error subsequent to file creation. */
00816             dbg_err_if (io_fd_create(fd, IO_FD_CLOSE, pio));
00817             dbg_err_if (io_name_set(*pio, tmpf));
00818 
00819             return 0;
00820         }
00821     }
00822 
00823     /* Loop exhausted, bail out. */
00824 
00825 err:
00826     if (fd != -1)
00827         (void) close(fd);
00828 
00829     return ~0;
00830 }
00831 
00847 int u_file_open(const char *file, int flags, io_t **pio)
00848 {
00849     int fmod = 0; /* flags modifier */
00850     int fd;
00851 
00852 #ifdef OS_WIN
00853     fmod = _O_BINARY;
00854 #endif
00855     
00856     dbg_return_if (file == NULL, ~0);
00857     dbg_return_if (pio == NULL, ~0);
00858     
00859     fd = open(file, fmod | flags, 0600);
00860     dbg_err_if(fd < 0);
00861 
00862     dbg_err_if(io_fd_create(fd, IO_FD_CLOSE, pio));
00863 
00864     /* name the stream */
00865     dbg_err_if(io_name_set(*pio, file));
00866 
00867     return 0;
00868 err:
00869     if(fd < 0)
00870         dbg_strerror(errno);
00871     else
00872         close(fd);
00873     return ~0;
00874 }
00875 
00889 int u_getline(io_t *io, u_string_t *ln)
00890 {
00891     enum { BUFSZ = 1024 };
00892     char buf[BUFSZ];
00893     ssize_t len, rc;
00894 
00895     dbg_return_if (io == NULL, ~0);
00896     dbg_return_if (ln == NULL, ~0);
00897     
00898     u_string_clear(ln);
00899 
00900     while((rc = len = io_gets(io, buf, BUFSZ)) > 0)
00901     {
00902         dbg_err_if(u_string_append(ln, buf, --len));
00903         if(!u_isnl(buf[len]))
00904             continue; /* line's longer the bufsz (or eof);get next line chunk */
00905         else
00906             break;
00907     }
00908 
00909     dbg_if(rc < 0); /* io_gets error */
00910 
00911 err:
00912     return (rc <= 0 ? ~0 : 0);
00913 }
00914 
00928 int u_fgetline(FILE *in, u_string_t *ln)
00929 {
00930     enum { BUFSZ = 256 };
00931     char buf[BUFSZ];
00932     size_t len;
00933 
00934     dbg_return_if (in == NULL, ~0);
00935     dbg_return_if (ln == NULL, ~0);
00936     
00937     u_string_clear(ln);
00938 
00939     while(!ferror(in) && !feof(in) && fgets(buf, BUFSZ, in))
00940     {
00941         len = strlen(buf);
00942         dbg_err_if(u_string_append(ln, buf, len));
00943         if(!u_isnl(buf[len-1]))
00944             continue; /* line's longer the bufsz, get next line chunk */
00945         else
00946             break;
00947     }
00948 
00949     if(ferror(in))
00950         dbg_strerror(errno);
00951 err:
00952     return (u_string_len(ln) ? 0 : ~0);
00953 }
00954 
00955 int u_printf_ccstr(io_t *o, const char *buf, size_t sz)
00956 {
00957     char prev, c = 0;
00958     int pos = 0;
00959     size_t i;
00960 
00961     dbg_return_if (o == NULL, ~0);
00962     dbg_return_if (buf == NULL, ~0);
00963     
00964     for(i = 0; i < sz; ++i)
00965     {
00966         prev = c;
00967         c = buf[i];
00968         if(pos++ == 0) // first line char
00969             io_putc(o, '"');
00970         switch(c)
00971         {
00972         case CR:
00973             if(prev != LF) 
00974             io_printf(o, "\\n\"\n");
00975             pos = 0;
00976             break;
00977         case LF:
00978             if(prev != CR) 
00979             io_printf(o, "\\n\"\n");
00980             pos = 0;
00981             break;
00982         case '"':
00983             io_printf(o, "\\\"");
00984             break;
00985         case '\\':
00986             io_printf(o, "\\\\");
00987             break;
00988         default:
00989             if(isprint(c))
00990                 io_putc(o, c);
00991             else {
00992                 io_printf(o, "\\x%c%c", u_tochex((c >> 4) & 0x0F),
00993                 u_tochex(c & 0x0F));
00994             }
00995         }
00996     }
00997     if(pos)
00998         io_putc(o, '"');
00999 
01000     return 0;
01001 }
01002 
01013 int u_file_exists(const char *fqn)
01014 {
01015     struct stat st;
01016 
01017     dbg_return_if (fqn == NULL, 0);
01018     
01019     return stat(fqn, &st) == 0 && S_ISREG(st.st_mode);
01020 }
01021 
01036 void u_tohex(char *hex, const char *src, size_t sz)
01037 {
01038     size_t c, i, t;
01039 
01040     dbg_ifb (hex == NULL) return;
01041     dbg_ifb (src == NULL) return;
01042     
01043     for(i = 0, t = 0; i < sz; ++i, t += 2)
01044     {
01045         c = src[i];
01046         hex[t]   = u_tochex((c >> 4) & 0x0F);
01047         hex[t+1] = u_tochex(c & 0x0F);
01048     }
01049 
01050     hex[t] = 0; /* zero-term */
01051 }
01052 
01067 int u_md5(const char *buf, size_t sz, char out[MD5_DIGEST_BUFSZ])
01068 {
01069     md5_state_t md5ctx;
01070     md5_byte_t md5_digest[16]; /* binary digest */
01071 
01072     dbg_return_if (buf == NULL, ~0);
01073     dbg_return_if (out == NULL, ~0);
01074     
01075     md5_init(&md5ctx);
01076     md5_append(&md5ctx, (md5_byte_t*)buf, sz);
01077     md5_finish(&md5ctx, md5_digest);
01078 
01079     u_tohex(out, (const char*)md5_digest, 16);
01080 
01081     out[MD5_DIGEST_LEN] = 0;
01082 
01083     return 0;
01084 }
01085 
01100 int u_md5io(io_t *io, char out[MD5_DIGEST_BUFSZ])
01101 {
01102     enum { page_sz = 4096 };
01103     md5_state_t md5ctx;
01104     md5_byte_t md5_digest[16]; /* binary digest */
01105     char buf[page_sz];
01106     size_t cnt;
01107 
01108     dbg_err_if (io == NULL);
01109     dbg_err_if (out == NULL);
01110 
01111     md5_init(&md5ctx);
01112 
01113     while((cnt = io_read(io, buf, page_sz)) > 0)
01114         md5_append(&md5ctx, (md5_byte_t*)buf, cnt);
01115 
01116     md5_finish(&md5ctx, md5_digest);
01117 
01118     u_tohex(out, (const char*)md5_digest, 16);
01119 
01120     out[MD5_DIGEST_LEN] = 0;
01121 
01122     return 0;
01123 err:
01124     return ~0;
01125 }
01126 
01127 int u_signal(int sig, u_sig_t handler)
01128 {
01129 #ifdef OS_WIN
01130     dbg_err_if(signal(sig, handler) == SIG_ERR);
01131 #else
01132     struct sigaction action;
01133     sigset_t all;
01134 
01135     sigfillset(&all); 
01136     action.sa_mask = all;
01137     action.sa_handler = handler;
01138 
01139     /* disable child shell jobs notification */
01140     action.sa_flags = (sig == SIGCHLD ? SA_NOCLDSTOP : 0);
01141 #ifdef HAVE_SA_RESTART
01142     action.sa_flags |= SA_RESTART;
01143 #endif
01144     dbg_err_if(sigaction(sig, &action, (struct sigaction *) 0));
01145 #endif
01146 
01147     return 0;
01148 err:
01149     return ~0;
01150 }                                                             
01151 
01162 const mime_map_t *u_get_mime_map(const char *file_name)
01163 {
01164     char *ext;
01165     mime_map_t *mm;
01166 
01167     dbg_goto_if (file_name == NULL, notfound);
01168 
01169     if((ext = strrchr(file_name, '.')) != NULL)
01170     {
01171         ++ext; /* skip '.' */
01172         /* FIXME binary search here */
01173         for(mm = mime_map; mm->ext && mm->mime_type; ++mm)
01174         {
01175             if(strcasecmp(mm->ext, ext) == 0)
01176                 return mm;
01177         }
01178     }
01179 
01180 notfound:
01181     return mime_map; /* the first item is the default */
01182 }
01183 
01195 const char *u_guess_mime_type(const char *file_name)
01196 {
01197     char *ext;
01198     mime_map_t *mm;
01199 
01200     dbg_goto_if (file_name == NULL, notfound);
01201     
01202     if((ext = strrchr(file_name, '.')) != NULL)
01203     {
01204         ++ext; /* skip '.' */
01205         for(mm = mime_map; mm->ext && mm->mime_type; ++mm)
01206             if(strcasecmp(mm->ext, ext) == 0)
01207                 return mm->mime_type;
01208     }
01209 
01210 notfound:
01211     return "application/octet-stream";
01212 }
01213 
01214 #ifdef HAVE_LIBZ
01215 
01230 int u_io_unzip_copy(io_t *out, const char *data, size_t sz)
01231 {
01232     codec_t *zip = NULL;
01233     io_t *ios = NULL;
01234 
01235     dbg_return_if (out == NULL, ~0);
01236     dbg_return_if (data == NULL, ~0);
01237     
01238     /* create an io_t around the HTML block */
01239     dbg_err_if(io_mem_create((char*)data, sz, 0, &ios));
01240 
01241     /* apply a gzip codec */
01242     dbg_err_if(codec_gzip_create(GZIP_UNCOMPRESS, &zip));
01243     dbg_err_if(io_codec_add_tail(ios, zip));
01244     zip = NULL; /* io_free() will free the codec */
01245 
01246     /* pipe ios to out */
01247     dbg_err_if(io_pipe(out, ios) < 0);
01248 
01249     io_free(ios);
01250 
01251     return 0;
01252 err:
01253     if(zip)
01254         codec_free(zip);
01255     if(ios)
01256         io_free(ios);
01257     return ~0;
01258 }
01259 #endif
01260 
01261 #ifdef SSL_OPENSSL
01262 
01284 int u_cipher_encrypt(const EVP_CIPHER *cipher, unsigned char *key, 
01285     unsigned char *iv, char *dst, size_t *dcount, const char *src, size_t ssz)
01286 {
01287     EVP_CIPHER_CTX ctx;
01288     ssize_t dlen = 0;  /* dst buffer length */
01289     int wr;
01290 
01291     dbg_return_if (cipher == NULL, ~0);
01292     dbg_return_if (key == NULL, ~0);
01293     dbg_return_if (iv == NULL, ~0);
01294     dbg_return_if (dcount == NULL, ~0);
01295     dbg_return_if (src == NULL, ~0);
01296     dbg_return_if (dst == NULL, ~0);
01297     
01298     /* init the context */
01299     EVP_CIPHER_CTX_init(&ctx);
01300 
01301     /* be sure that the cipher has been loaded */
01302     EVP_add_cipher(cipher);
01303     
01304     dbg_err_if(!EVP_EncryptInit_ex(&ctx, cipher, NULL, key, iv));
01305 
01306     dbg_err_if(!EVP_EncryptUpdate(&ctx, dst, &wr, src, ssz));
01307     dlen += wr;
01308     dst += wr;
01309 
01310     dbg_err_if(!EVP_EncryptFinal_ex(&ctx, dst, &wr));
01311     dlen += wr;
01312 
01313     *dcount = dlen; /* # of bytes written to dst */
01314 
01315     EVP_CIPHER_CTX_cleanup(&ctx);
01316 
01317     return 0;
01318 err:
01319     EVP_CIPHER_CTX_cleanup(&ctx);
01320     return ~0;
01321 }
01322 
01343 int u_cipher_decrypt(const EVP_CIPHER *cipher, unsigned char *key, 
01344     unsigned char *iv, char *dst, size_t *dcount, const char *src, size_t ssz)
01345 {
01346     EVP_CIPHER_CTX ctx;
01347     ssize_t dlen = 0;  /* dst buffer length */
01348     int wr;
01349 
01350     dbg_return_if (cipher == NULL, ~0);
01351     dbg_return_if (key == NULL, ~0);
01352     dbg_return_if (iv == NULL, ~0);
01353     dbg_return_if (dcount == NULL, ~0);
01354     dbg_return_if (src == NULL, ~0);
01355     dbg_return_if (dst == NULL, ~0);
01356 
01357     /* init the context */
01358     EVP_CIPHER_CTX_init(&ctx);
01359 
01360     /* be sure that the cipher has been loaded */
01361     EVP_add_cipher(cipher);
01362     
01363     dbg_err_if(!EVP_DecryptInit_ex(&ctx, cipher, NULL, key, iv));
01364 
01365     dbg_err_if(!EVP_DecryptUpdate(&ctx, dst, &wr, src, ssz));
01366     dlen += wr;
01367     dst += wr;
01368 
01369     dbg_err_if(!EVP_DecryptFinal_ex(&ctx, dst, &wr));
01370     dlen += wr;
01371 
01372     *dcount = dlen; /* # of bytes written to dst */
01373 
01374     EVP_CIPHER_CTX_cleanup(&ctx);
01375 
01376     return 0;
01377 err:
01378     EVP_CIPHER_CTX_cleanup(&ctx);
01379     return ~0;
01380 }
01381 
01382 #endif
01383 
01384 #ifdef SSL_CYASSL
01385 static int u_cipher_op(int op, const EVP_CIPHER *cipher, unsigned char *key, 
01386     unsigned char *iv, char *dst, size_t *dcount, const char *src, size_t ssz)
01387 {
01388     io_t *io = NULL;
01389     codec_t *codec = NULL;
01390     size_t avail;
01391     ssize_t rd;
01392 
01393     dbg_return_if (cipher == NULL, ~0);
01394     dbg_return_if (key == NULL, ~0);
01395     dbg_return_if (iv == NULL, ~0);
01396     dbg_return_if (dcount == NULL, ~0);
01397     dbg_return_if (src == NULL, ~0);
01398     dbg_return_if (dst == NULL, ~0);
01399     dbg_return_if (*dcount < ssz, ~0);
01400 
01401     dbg_err_if(io_mem_create(src, ssz, 0, &io));
01402 
01403     dbg_err_if(codec_cipher_create(op, cipher, key, iv, &codec));
01404     dbg_err_if(io_codec_add_tail(io, codec));
01405     codec = NULL;
01406 
01407     avail = *dcount;
01408     *dcount = 0;
01409 
01410     while(avail > 0)
01411     {
01412         dbg_err_if((rd = io_read(io, dst, avail)) < 0);
01413 
01414         if(rd == 0)
01415             break; /* eof */
01416 
01417         dbg_err_if(avail < rd); /* dst too small */
01418         
01419         avail -= rd; 
01420         dst += rd; 
01421         *dcount += rd;
01422     }
01423 
01424     io_free(io);
01425 
01426     return 0;
01427 err:
01428     if(codec)
01429         codec_free(codec);
01430     if(io)
01431         io_free(io);
01432     return ~0;
01433 }
01434 
01435 int u_cipher_encrypt(const EVP_CIPHER *cipher, unsigned char *key, 
01436     unsigned char *iv, char *dst, size_t *dcount, const char *src, size_t ssz)
01437 {
01438     return u_cipher_op(CIPHER_ENCRYPT, cipher, key, iv, dst, dcount, src, ssz);
01439 }
01440 
01441 int u_cipher_decrypt(const EVP_CIPHER *cipher, unsigned char *key, 
01442     unsigned char *iv, char *dst, size_t *dcount, const char *src, size_t ssz)
01443 {
01444     return u_cipher_op(CIPHER_DECRYPT, cipher, key, iv, dst, dcount, src, ssz);
01445 }
01446 
01447 #endif

←Products
Copyright © 2005-2012 - KoanLogic S.r.l. - All rights reserved