"Fossies" - the Fresh Open Source Software Archive

Member "unipkg-0.6.5/unipkglib/unipkg-directory.c" (16 Dec 2005, 27662 Bytes) of package /linux/privat/old/unipkg-0.6.5.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file.

    1 /******************************************************************************\
    2 *                                                                              *
    3 * UNIPKG (c) iSteve <isteve@bofh.cz>, 2005                                     *
    4 *                                                                              *
    5 * Universal PacKaGer.                                                          *
    6 * Licensed under GNU/GPL - if you don't like the software, fix it!             *
    7 *                                                                              *
    8 \******************************************************************************/
    9 
   10 ///////////////////////////////////////////////////////////////////////////////
   11 //                                                                           //
   12 // B A S E   I N C L U S I O N S   A N D   D E F I N I T I O N S             //
   13 //                                                                           //
   14 ///////////////////////////////////////////////////////////////////////////////
   15 #define _GNU_SOURCE
   16 #include <stdlib.h>
   17 #include <stdio.h>
   18 #include <string.h>
   19 #include <unistd.h>
   20 #include <fnmatch.h>
   21 #include <errno.h>
   22 #include <dlfcn.h>
   23 #include <libgen.h>
   24 #include <dirent.h>
   25 #include <fcntl.h>
   26 #include <ctype.h>
   27 
   28 #include <sys/stat.h>
   29 #include <sys/mman.h>
   30 #include <sys/types.h>
   31 
   32 #include "../config.h"
   33 #include "../common.h"
   34 
   35 #ifndef NO_NETLIB
   36 #include "../netlib.h"
   37 #endif
   38 
   39 typedef struct {
   40     struct dirent   **namelist;
   41     long        curname;
   42     long        namecount;
   43     char        *fpath;
   44     int         writeable;
   45 } dbhandle;
   46 
   47 typedef struct {
   48     struct dirent   **namelist;
   49     long        namecount;
   50     char        *fpath;
   51     int         writeable;
   52 } netapi_dbhandle;
   53 
   54 ///////////////////////////////////////////////////////////////////////////////
   55 //                                                                           //
   56 // B A S E   F U N C T I O N S                                               //
   57 //                                                                           //
   58 ///////////////////////////////////////////////////////////////////////////////
   59 
   60 // SWITCHCONTROLKEY()
   61 //
   62 // Switches key in the package descripting file.
   63 //
   64 // Parameters:
   65 //   The line being checked
   66 //
   67 // Return value:
   68 //   0 if not identified
   69 //   1 if name
   70 //   2 if version
   71 //   3 if description
   72 //   4 if preinstall script
   73 //   5 if postinstall script
   74 //   6 if preremove script
   75 //   7 if postremove script
   76 //   8 if a filename
   77 static int switchcontrolkey(char *line) {
   78     if (!strncmp(line, "Name:", 5)) { return 1; }
   79     if (!strncmp(line, "Version:", 8)) { return 2; }
   80     if (!strncmp(line, "Description:", 12)) { return 3; }
   81     
   82     if (!strncmp(line, "Preinst:", 8)) { return 4; }
   83     if (!strncmp(line, "Postinst:", 9)) { return 5; }
   84     if (!strncmp(line, "Prerm:", 6)) { return 6; }
   85     if (!strncmp(line, "Postrm:", 7)) { return 7; }
   86     
   87     if (!strncmp(line, "File:", 5)) { return 8; }
   88     if (!strncmp(line, "Size:", 5)) { return 9; }
   89     
   90     if (!strncmp(line, "PreinstParam:", 13)) { return 10; }
   91     if (!strncmp(line, "PostinstParam:", 14)) { return 11; }
   92     if (!strncmp(line, "PrermParam:", 11)) { return 12; }
   93     if (!strncmp(line, "PostrmParam:", 12)) { return 13; }
   94     return 0;
   95 }
   96 
   97 // SWITCHCACHECONTROLKEY()
   98 //
   99 // Switches key in the package descripting file.
  100 //
  101 // Parameters:
  102 //   The line being checked
  103 //
  104 // Return value:
  105 //   0 if not identified
  106 //   1 if name
  107 //   2 if version
  108 //   3 if description
  109 //   4 if URL
  110 //   5 if dependency
  111 static int switchcachecontrolkey(char *line) {
  112     if (!strncmp(line, "Name:", 5)) { return 1; }
  113     if (!strncmp(line, "Version:", 8)) { return 2; }
  114     if (!strncmp(line, "Description:", 12)) { return 3; }
  115     if (!strncmp(line, "URL:", 4)) { return 4; }
  116     if (!strncmp(line, "Dep:", 4)) { return 5; }
  117     return 0;
  118 }
  119 
  120 
  121 // READCONTROLBLOCK()
  122 //
  123 // Reads a control block designated by \0\n sequence, \0 for easy machine reading,
  124 // and \n for easy human reading.
  125 //
  126 // Parameters:
  127 //   pointer to start of the line
  128 //   pointer to end of the line
  129 //
  130 // Return value:
  131 //   pointer to the value within the line
  132 static char *readcontrolblock(char *start, char *end) {
  133     char *ptr;
  134     
  135     ptr = start;
  136     while (ptr < end-1) {
  137         if ((ptr[0] == '\0') && (ptr[1] == '\n')) {
  138             return ptr+1;
  139         }
  140         ptr++;
  141     }
  142     return NULL;
  143 }
  144 
  145 // INFILTER()
  146 //
  147 // Trivial function for scandir, to filter out only packages-* files in the
  148 // Debian's /var/lib/dpkg/info dir. Note that the /var/lib/dpkg
  149 // mentioned here (and above) is only for reference, this backend
  150 // takes path just like any other -- see README for details.
  151 //
  152 // Parameters:
  153 //   pointer to dirent structure, containing match
  154 //
  155 // Return value:
  156 //   zero if not matching
  157 //   non-zero if match
  158 static int infilter(const struct dirent *inname) {
  159     return !fnmatch("package-*", inname->d_name, 0);
  160 }
  161 
  162 // ESCAPESPECIALCHARS()
  163 //
  164 // Escapes chars outside of alnum and _-+. into &XX; format, while XX is hex
  165 // representation of the character.
  166 //
  167 // Parameters:
  168 //   the input string
  169 //
  170 // Return value:
  171 //   allocated new string
  172 static char *escapespecialchars(char *input) {
  173     char *buf, *ptr;
  174     unsigned long buflen;
  175     
  176     buflen = 0;
  177     buf = malloc(buflen+1);
  178     buf[0] = '\0';
  179     
  180     ptr = input;
  181     while (*ptr != '\0') {
  182         // If it isn't something really common, escape it.
  183         if ((!isalnum(*ptr)) && (*ptr != '_') && (*ptr != '-') && (*ptr != '+') && (*ptr != '.')) {
  184             buflen += 4;
  185             buf = realloc(buf, buflen+1);
  186             sprintf(buf + buflen - 4, "&%02x;", *ptr);
  187             buf[buflen] = '\0';
  188         } else {
  189             buflen ++;
  190             buf = realloc(buf, buflen+1);
  191             buf[buflen-1] = *ptr;
  192             buf[buflen] = '\0';
  193         }
  194         ptr++;
  195     }
  196     return buf;
  197 }
  198 
  199 // REBUILDSPECIALCHARS()
  200 //
  201 // Rebuilds chars from the &XX; format, generated by escapespecialchars.
  202 //
  203 // Parameters:
  204 //   the input string
  205 //
  206 // Return value:
  207 //   allocated new string
  208 static char *rebuildspecialchars(char *input) {
  209     char *buf, *ptr, *rptr, *tmpbuf;
  210     unsigned long buflen;
  211     int c;
  212     
  213     buflen = 0;
  214     buf = malloc(buflen+1);
  215     buf[0] = '\0';
  216     
  217     ptr = input;
  218     while (*ptr != '\0') {
  219         c = *ptr;
  220         if (*ptr == '&') {
  221             rptr = ptr;
  222             while ((*rptr != '\0') && (*rptr != ';') && (rptr - ptr < 4)) {
  223                 rptr++;
  224             }
  225             
  226             if (*rptr == ';') {
  227                 tmpbuf = strndup(ptr + 1, 2);
  228                 c = strtol(tmpbuf, NULL, 16);
  229                 ptr+=3;
  230             }
  231         }
  232         
  233         buflen ++;
  234         buf = realloc(buf, buflen+1);
  235         buf[buflen-1] = c;
  236         buf[buflen] = '\0';
  237         ptr++;
  238     }
  239     return buf;
  240 }
  241 
  242 
  243 ///////////////////////////////////////////////////////////////////////////////
  244 //                                                                           //
  245 // A P I   F U N C T I O N S                                                 //
  246 //                                                                           //
  247 ///////////////////////////////////////////////////////////////////////////////
  248 void *opendb(char *path) {
  249     dbhandle    *reval;
  250     struct stat statbuf;
  251     
  252     reval = malloc(sizeof(dbhandle));
  253     
  254     if (mkdir(path, 0755)) {
  255         if (errno != EEXIST) {
  256             free(reval);
  257             return NULL;
  258         }
  259     }
  260 
  261     reval->writeable = 0;
  262     stat(path, &statbuf);
  263     
  264     // We are chowning to the current owner/group... a nice trick to find
  265     // out our privileges.
  266     if (!chown(path, statbuf.st_uid, statbuf.st_gid)) {
  267         reval->writeable = 1;
  268     }
  269     
  270     reval->fpath = strdup(path);
  271     reval->namecount = scandir(path, &reval->namelist, infilter, alphasort);
  272     if (reval -> namecount < 0) {
  273         free(reval->fpath);
  274         free(reval);
  275         return NULL;
  276     }
  277     reval->curname = 0;
  278     return reval;
  279 }
  280 void rewinddb(dbhandle *handle) {
  281     long i, tmp_namecount;
  282     struct dirent **tmp_namelist;
  283 
  284     handle->curname = 0;
  285     
  286     tmp_namecount = scandir(handle->fpath, &tmp_namelist, infilter, alphasort);
  287     
  288     if (tmp_namecount < 0) {
  289         // This means reading the new db failed. Let's keep old data
  290         // and clear the new.
  291         for (i = 0; i < tmp_namecount; i++) {
  292             free(tmp_namelist[i]);
  293         }
  294         free(tmp_namelist);
  295         
  296         // But if there was a trouble, we can't write.
  297         handle->writeable = 0;
  298         return;
  299     }
  300     
  301     for (i = 0; i < handle->namecount; i++) {
  302         free(handle->namelist[i]);
  303     }
  304     free(handle->namelist);
  305     
  306     handle->namelist = tmp_namelist;
  307     handle->namecount = tmp_namecount;
  308 }
  309 int iswriteable(dbhandle *handle) {
  310     return handle->writeable;
  311 }
  312 int closedb(dbhandle *handle) {
  313     long i;
  314     for (i=0; i<handle->namecount; i++) {
  315         free(handle->namelist[i]);
  316     }
  317     free(handle->namelist);
  318     free(handle->fpath);
  319     free(handle);
  320     return 0;
  321 }
  322 int readpkg(dbhandle *handle, pkginfo *pinfo) {
  323     char            *buf, *ptr;
  324     
  325     struct stat     statbuf;
  326     void            *filemap;
  327     int         fd, i;
  328     
  329     if (handle->curname >= handle->namecount) {
  330         return 1;
  331     }
  332     
  333     buf = malloc(strlen(handle->fpath) + strlen(handle->namelist[handle->curname]->d_name) + 2);
  334     buf = strcpy(buf, handle->fpath);
  335     if (buf[strlen(handle->fpath)-1] != '/') {
  336         buf = strcat(buf, "/");
  337     }
  338     buf = strcat(buf, handle->namelist[handle->curname]->d_name);
  339     
  340     if ((fd = open(buf, O_RDONLY)) == -1) { 
  341         free(buf);
  342         return 1; 
  343     }
  344     fstat(fd, &statbuf);
  345     free(buf);
  346 
  347     // It's easier to mmap the file if we want to parse it.
  348     filemap = mmap(0, statbuf.st_size, PROT_READ, MAP_SHARED, fd, 0);
  349     if (filemap == MAP_FAILED) { return 1; }
  350     
  351     ptr = filemap;
  352     
  353     //clearpinfo(pinfo);
  354     
  355     while (ptr < (char*)(filemap + statbuf.st_size)) {
  356         switch (switchcontrolkey(ptr)) {
  357             case 1:
  358                 // This +something is to skip the key, such as 'Name:'
  359                 // We can call strdup, because it terminates with \0.
  360                 pinfo->name = strdup(ptr + 5);
  361                 ptr += 5 + strlen(pinfo->name);
  362                 break;
  363             case 2:
  364                 pinfo->version = strdup(ptr + 8);
  365                 ptr += 8 + strlen(pinfo->version);
  366                 break;
  367             case 3:
  368                 pinfo->description = strdup(ptr + 12);
  369                 ptr += 12 + strlen(pinfo->description);
  370                 break;
  371 
  372             case 4:
  373                 pinfo->preinst.len = strtoul(ptr+8, &ptr, 16);
  374                 ptr++;  // To skip the space.
  375                 pinfo->preinst.data = malloc(pinfo->preinst.len);
  376                 memcpy(pinfo->preinst.data, ptr, pinfo->preinst.len);
  377                 ptr += pinfo->preinst.len;
  378                 break;
  379             case 5:
  380                 pinfo->postinst.len = strtoul(ptr+9, &ptr, 16);
  381                 ptr++;
  382                 pinfo->postinst.data = malloc(pinfo->postinst.len);
  383                 memcpy(pinfo->postinst.data, ptr, pinfo->postinst.len);
  384                 ptr += pinfo->postinst.len;
  385                 break;
  386             case 6:
  387                 pinfo->prerm.len = strtoul(ptr+6, &ptr, 16);
  388                 ptr++;
  389                 pinfo->prerm.data = malloc(pinfo->prerm.len);
  390                 memcpy(pinfo->prerm.data, ptr, pinfo->prerm.len);
  391                 ptr += pinfo->prerm.len;
  392                 break;
  393             case 7:
  394                 pinfo->postrm.len = strtoul(ptr+7, &ptr, 16);
  395                 ptr++;
  396                 pinfo->postrm.data = malloc(pinfo->postrm.len);
  397                 memcpy(pinfo->postrm.data, ptr, pinfo->postrm.len);
  398                 ptr += pinfo->postrm.len;
  399                 break;
  400             
  401             case 8:
  402                 addfile(pinfo, strdup(ptr + 5), F_IRRELEVANT);
  403                 ptr += 5 + strlen(pinfo->files[pinfo->filecount-1].name);
  404                 break;
  405             case 9:
  406                 pinfo->pkgsize = strtoul(ptr + 5, &ptr, 10);
  407                 break;
  408 
  409             case 10:
  410                 i = strtoul(ptr+13, &ptr, 10);
  411                 if (i >= A_COUNT) break;
  412                 pinfo->preinst.parameters[i] = strdup(ptr);
  413                 break;
  414             case 11:
  415                 i = strtoul(ptr+14, &ptr, 10);
  416                 if (i >= A_COUNT) break;
  417                 pinfo->postinst.parameters[i] = strdup(ptr);
  418                 break;
  419             case 12:
  420                 i = strtoul(ptr+11, &ptr, 10);
  421                 if (i >= A_COUNT) break;
  422                 pinfo->prerm.parameters[i] = strdup(ptr);
  423                 break;
  424             case 13:
  425                 i = strtoul(ptr+12, &ptr, 10);
  426                 if (i >= A_COUNT) break;
  427                 pinfo->postrm.parameters[i] = strdup(ptr);
  428                 break;
  429             
  430             default:
  431                 ptr = pstrnstr(ptr, "\0\n", (unsigned long)(filemap + statbuf.st_size - (void*)ptr), 2);
  432                 if (ptr == NULL) { ptr = (char*)(filemap + statbuf.st_size); }
  433                 break;
  434         }
  435         ptr+=2;
  436     }
  437     munmap(filemap, statbuf.st_size);
  438     close(fd);
  439 
  440     handle->curname++;
  441     return 0;
  442 }
  443 int writepkg(dbhandle *handle, pkginfo *pinfo) {
  444     FILE                *fp;
  445     char            *buf, *nname;
  446     unsigned long   i;
  447     struct stat     statbuf;
  448     
  449     
  450     nname = escapespecialchars(pinfo->name);
  451     buf = malloc(strlen(handle->fpath) + 8 + strlen(nname) + 2);
  452     buf = strcpy(buf, handle->fpath);
  453     if (buf[strlen(handle->fpath)-1] != '/') {
  454         buf = strcat(buf, "/");
  455     }
  456     buf = strcat(buf, "package-");
  457     buf = strcat(buf, nname);
  458     free(nname);
  459     
  460     // Aren't we overwriting something?
  461     if (!stat(buf, &statbuf)) {
  462         free(buf);
  463         return 1;
  464     }
  465     
  466     // No? Well, let's open the file...
  467     if ((fp = fopen(buf, "w")) == NULL) {
  468         free(buf);
  469         return 1;
  470     }
  471     free(buf);
  472     
  473     // ... write the base package info ...
  474     //fprintf(fp, "Name:%s\0\nVersion:%s\0\nDescription:%s\0\n", pinfo->name, pinfo->version, pinfo->description);
  475     fprintf(fp, "Name:%s", pinfo->name);
  476     fwrite("\0\n", 2, 1, fp);
  477     fprintf(fp, "Version:%s", pinfo->version);
  478     fwrite("\0\n", 2, 1, fp);
  479     fprintf(fp, "Description:%s", pinfo->description);
  480     fwrite("\0\n", 2, 1, fp);
  481     fprintf(fp, "Size:%ld", pinfo->pkgsize);
  482     fwrite("\0\n", 2, 1, fp);
  483     
  484     // ... the handling scripts ...
  485     if (pinfo->preinst.len > 0) {
  486         fprintf(fp, "Preinst:%lX ", pinfo->preinst.len);
  487         fwrite(pinfo->preinst.data, pinfo->preinst.len, 1, fp);
  488         fwrite("\0\n", 2, 1, fp);
  489         
  490         for (i = 0; i < A_COUNT; i++) {
  491             if (pinfo->preinst.parameters[i] != NULL) {
  492                 fprintf(fp, "PreinstParam:%li %s", i, pinfo->preinst.parameters[i]);
  493                 fwrite("\0\n", 2, 1, fp);
  494             }
  495         }
  496     }
  497     if (pinfo->postinst.len > 0) {
  498         fprintf(fp, "Postinst:%lX ", pinfo->postinst.len);
  499         fwrite(pinfo->postinst.data, pinfo->postinst.len, 1, fp);
  500         fwrite("\0\n", 2, 1, fp);
  501         
  502         for (i = 0; i < A_COUNT; i++) {
  503             if (pinfo->postinst.parameters[i] != NULL) {
  504                 fprintf(fp, "PostinstParam:%li %s", i, pinfo->postinst.parameters[i]);
  505                 fwrite("\0\n", 2, 1, fp);
  506             }
  507         }
  508     }
  509     if (pinfo->prerm.len > 0) {
  510         fprintf(fp, "Prerm:%lX ", pinfo->prerm.len);
  511         fwrite(pinfo->prerm.data, pinfo->prerm.len, 1, fp);
  512         fwrite("\0\n", 2, 1, fp);
  513         
  514         for (i = 0; i < A_COUNT; i++) {
  515             if (pinfo->prerm.parameters[i] != NULL) {
  516                 fprintf(fp, "PrermParam:%li %s", i, pinfo->prerm.parameters[i]);
  517                 fwrite("\0\n", 2, 1, fp);
  518             }
  519         }
  520     }
  521     if (pinfo->postrm.len > 0) {
  522         fprintf(fp, "Postrm:%lX ", pinfo->postrm.len);
  523         fwrite(pinfo->postrm.data, pinfo->postrm.len, 1, fp);
  524         fwrite("\0\n", 2, 1, fp);
  525         
  526         for (i = 0; i < A_COUNT; i++) {
  527             if (pinfo->postrm.parameters[i] != NULL) {
  528                 fprintf(fp, "PostrmParam:%li %s", i, pinfo->postrm.parameters[i]);
  529                 fwrite("\0\n", 2, 1, fp);
  530             }
  531         }
  532     }
  533     
  534     // ... each file ...
  535     for (i=0; i < pinfo->filecount; i++) {
  536         fprintf(fp, "File:%s", pinfo->files[i].name);
  537         fwrite("\0\n", 2, 1, fp);
  538     }
  539     
  540     // ... and happily close the file.
  541     fclose(fp);
  542     return 0;
  543 }
  544 int delpkg(dbhandle *handle, char *pneedle) {
  545     char *nname, *buf;
  546     
  547     handle->curname = 0;
  548     while (handle->curname < handle->namecount) {
  549         nname = rebuildspecialchars(handle->namelist[handle->curname]->d_name + 8);
  550         if (!fnmatch(pneedle, nname, 0)) {
  551             buf = malloc(strlen(handle->fpath) + strlen(handle->namelist[handle->curname]->d_name) + 2);
  552             buf = strcpy(buf, handle->fpath);
  553             if (buf[strlen(handle->fpath)-1] != '/') {
  554                 buf = strcat(buf, "/");
  555             }
  556             buf = strcat(buf, handle->namelist[handle->curname]->d_name);
  557             
  558             if (unlink(buf)) {
  559                 return 1;
  560             }
  561             free(buf);
  562         }
  563         free(nname);
  564         handle->curname++;
  565     }
  566     return 0;
  567 }
  568 int findpkg(dbhandle *handle, pkginfo needle, pkginfo *reval, int matchtype) {
  569     char    *nname, *buf, *ptr, *nptr;
  570 
  571     struct stat     statbuf;
  572     void            *filemap;
  573     int             fd;
  574     
  575     unsigned long   i;
  576     
  577     
  578     while (handle->curname < handle->namecount) {
  579 
  580         if ((matchtype & MATCH_NAME) && (!(matchtype & MATCH_FILE))) {
  581             nname = rebuildspecialchars(handle->namelist[handle->curname]->d_name + 8);
  582             if (!fnmatch(needle.name, nname, 0)) {
  583                 
  584                 if (reval != NULL) { 
  585                     if (readpkg(handle, reval)) {
  586                         continue;
  587                     }
  588                 } else {
  589                     handle->curname++;
  590                 }
  591                 
  592                 if ((matchtype & MATCH_OVRWR) && (!strcmp(nname, needle.name))) {
  593                     free(nname);
  594                     return -1;
  595                 } else {
  596                     free(nname);
  597                     return 1;
  598                 }
  599             }
  600             free(nname);
  601         } else if ((matchtype & MATCH_FILE) && (!(matchtype & MATCH_NAME))) {
  602             buf = malloc(strlen(handle->fpath) + strlen(handle->namelist[handle->curname]->d_name) + 2);
  603             buf = strcpy(buf, handle->fpath);
  604             if (buf[strlen(handle->fpath)-1] != '/') {
  605                 buf = strcat(buf, "/");
  606             }
  607             buf = strcat(buf, handle->namelist[handle->curname]->d_name);
  608             
  609             if ((fd = open(buf, O_RDONLY)) == -1) { 
  610                 free(buf);
  611                 continue; 
  612             }
  613             fstat(fd, &statbuf);
  614             free(buf);
  615         
  616             // It's easier to mmap the file if we want to parse it.
  617             filemap = mmap(0, statbuf.st_size, PROT_READ, MAP_SHARED, fd, 0);
  618             if (filemap == MAP_FAILED) { continue; }
  619     
  620             ptr = filemap;
  621             while ((nptr = readcontrolblock(ptr, filemap + statbuf.st_size)) != NULL) {
  622                 buf = strndup(ptr, nptr - ptr);
  623                 ptr = nptr+1;
  624                 if (switchcontrolkey(buf) == 8) {
  625                     for (i=0; i<needle.filecount; i++) {
  626                         // We do NOT want to match directories.
  627                         if (needle.files[i].flag == F_DIRECTORY) 
  628                             continue;
  629                         
  630                         if (!fnmatch(needle.files[i].name, buf+5, 0)) {
  631                             
  632                             nname = rebuildspecialchars(handle->namelist[handle->curname]->d_name + 8);
  633                             
  634                             if (reval != NULL) { 
  635                                 if (readpkg(handle, reval)) {
  636                                     continue;
  637                                 }
  638                             } else {
  639                                 handle->curname++;
  640                                 if (handle->curname >= handle->namecount) { 
  641                                     handle->curname = 0; 
  642                                 }
  643                             }
  644                             
  645                             free(buf);
  646                             munmap(filemap, statbuf.st_size);
  647                             close(fd);
  648                             
  649                             if ((needle.name != NULL) && (matchtype & MATCH_OVRWR) && (!strcmp(nname, needle.name))) {
  650                                 free(nname);
  651                                 return -1;
  652                             } else {
  653                                 free(nname);
  654                                 return 1;
  655                             }
  656                         }
  657                     }
  658                 }
  659                 free(buf);
  660             }
  661             munmap(filemap, statbuf.st_size);
  662             close(fd);
  663         } else if ((matchtype & MATCH_NAME) && (matchtype & MATCH_FILE)) {
  664             nname = rebuildspecialchars(handle->namelist[handle->curname]->d_name + 8);
  665             if (!fnmatch(needle.name, nname, 0)) {
  666                 buf = malloc(strlen(handle->fpath) + strlen(handle->namelist[handle->curname]->d_name) + 2);
  667                 buf = strcpy(buf, handle->fpath);
  668                 if (buf[strlen(handle->fpath)-1] != '/') {
  669                     buf = strcat(buf, "/");
  670                 }
  671                 buf = strcat(buf, handle->namelist[handle->curname]->d_name);
  672                 
  673                 if ((fd = open(buf, O_RDONLY)) == -1) { 
  674                     free(buf);
  675                     continue; 
  676                 }
  677                 fstat(fd, &statbuf);
  678                 free(buf);
  679             
  680                 // It's easier to mmap the file if we want to parse it.
  681                 filemap = mmap(0, statbuf.st_size, PROT_READ, MAP_SHARED, fd, 0);
  682                 if (filemap == MAP_FAILED) { continue; }
  683         
  684                 ptr = filemap;
  685                 while ((nptr = readcontrolblock(ptr, filemap + statbuf.st_size)) != NULL) {
  686                     buf = strndup(ptr, nptr - ptr);
  687                     ptr = nptr+1;
  688                     if (switchcontrolkey(buf) == 8) {
  689                         for (i=0; i<needle.filecount; i++) {
  690                             // We do NOT want to match directories.
  691                             if (needle.files[i].flag == F_DIRECTORY) 
  692                                 continue;
  693                             if (!fnmatch(needle.files[i].name, buf+5, 0)) {
  694                                 free(buf);
  695                                 munmap(filemap, statbuf.st_size);
  696                                 
  697                                 if (reval != NULL) { 
  698                                     if (readpkg(handle, reval)) {
  699                                         continue;
  700                                     }
  701                                 } else {
  702                                     handle->curname++;
  703                                 }
  704 
  705                                 if ((matchtype & MATCH_OVRWR) && (!strcmp(nname, needle.name))) {
  706                                     free(nname);
  707                                     return -1;
  708                                 } else {
  709                                     free(nname);
  710                                     return 1;
  711                                 }
  712                             }
  713                         }
  714                     }
  715                     free(buf);
  716                 }
  717                 free(nname);
  718                 munmap(filemap, statbuf.st_size);
  719                 close(fd);
  720             } else {
  721                 free(nname);
  722             }
  723         }
  724         
  725         handle->curname++;
  726     }
  727     handle->curname = 0;
  728 
  729     return 0;
  730 }
  731 
  732 #ifndef NO_NETLIB
  733 
  734 ///////////////////////////////////////////////////////////////////////////////
  735 //                                                                           //
  736 // N E T A P I   F U N C T I O N S                                           //
  737 //                                                                           //
  738 ///////////////////////////////////////////////////////////////////////////////
  739 
  740 void *opencache(char *path, trepository *repository) {
  741     dbhandle    *reval;
  742     struct stat statbuf;
  743     char        *realpath, *hash;
  744     
  745     reval = malloc(sizeof(dbhandle));
  746     
  747     if (mkdir(path, 0755)) {
  748         if (errno != EEXIST) {
  749             free(reval);
  750             return NULL;
  751         }
  752     }
  753     
  754     realpath = malloc(strlen(repository->baseurl) + strlen(repository->rel_pkglist) + 1);
  755     strcpy(realpath, repository->baseurl);
  756     strcat(realpath, repository->rel_pkglist);
  757     
  758     hash = trivialhash(realpath);
  759     
  760     realpath = realloc(realpath, strlen(path) + 1 + strlen(hash) + 1);
  761     strcpy(realpath, path);
  762     strcat(realpath, "/");
  763     strcat(realpath, hash);
  764     free(hash);
  765     
  766     if (mkdir(realpath, 0755)) {
  767         if (errno != EEXIST) {
  768             free(reval);
  769             free(realpath);
  770             return NULL;
  771         }
  772     }
  773     
  774     reval->writeable = 0;
  775     
  776     // We are chowning to the current owner/group... a nice trick to find
  777     // out our privileges.
  778     stat(realpath, &statbuf);
  779     if (!chown(realpath, statbuf.st_uid, statbuf.st_gid)) {
  780         reval->writeable = 1;
  781     }
  782     
  783     reval->fpath = realpath;
  784     reval->namecount = scandir(reval->fpath, &reval->namelist, infilter, alphasort);
  785     if (reval -> namecount < 0) {
  786         free(reval->fpath);
  787         free(reval);
  788         return NULL;
  789     }
  790     reval->curname = 0;
  791     return reval;
  792 }
  793 
  794 int cacheiswriteable(dbhandle *handle) {
  795     return handle->writeable;
  796 }
  797 
  798 void rewindcache(dbhandle *handle) {
  799     rewinddb(handle);   // Same shit, different name.
  800 }
  801 
  802 void flushcache(dbhandle *handle) {
  803     long    i;
  804     char    *buf;
  805     
  806     for (i=0; i<handle->namecount; i++) {
  807         buf = malloc(strlen(handle->fpath) + strlen(handle->namelist[i]->d_name) + 2);
  808         buf = strcpy(buf, handle->fpath);
  809         if (buf[strlen(handle->fpath)-1] != '/') {
  810             buf = strcat(buf, "/");
  811         }
  812         buf = strcat(buf, handle->namelist[i]->d_name);
  813         
  814         remove(buf);
  815         
  816         free(buf);
  817     }
  818     rewinddb(handle);
  819 }
  820 
  821 int closecache(dbhandle *handle) {
  822     long i;
  823     for (i=0; i<handle->namecount; i++) {
  824         free(handle->namelist[i]);
  825     }
  826     free(handle->namelist);
  827     free(handle->fpath);
  828     free(handle);
  829     return 0;
  830 }
  831 
  832 int writepkgcache(dbhandle *handle, tremotepkg *rpkg) {
  833     FILE                *fp;
  834     char            *buf, *nname;
  835     unsigned long   i;
  836     struct stat     statbuf;
  837     dependency      *curdep;
  838     
  839     nname = escapespecialchars(rpkg->name);
  840     buf = malloc(strlen(handle->fpath) + 8 + strlen(nname) + 2);
  841     buf = strcpy(buf, handle->fpath);
  842     if (buf[strlen(handle->fpath)-1] != '/') {
  843         buf = strcat(buf, "/");
  844     }
  845     buf = strcat(buf, "package-");
  846     buf = strcat(buf, nname);
  847     free(nname);
  848     
  849     // Aren't we overwriting something?
  850     if (!stat(buf, &statbuf)) {
  851         free(buf);
  852         return 1;
  853     }
  854     
  855     // No? Well, let's open the file...
  856     if ((fp = fopen(buf, "w")) == NULL) {
  857         free(buf);
  858         return 1;
  859     }
  860     free(buf);
  861     
  862     // Write basic info
  863     fprintf(fp, "Name:%s", rpkg->name);
  864     fwrite("\0\n", 2, 1, fp);
  865     fprintf(fp, "Version:%s", rpkg->version);
  866     fwrite("\0\n", 2, 1, fp);
  867     fprintf(fp, "Description:%s", rpkg->description);
  868     fwrite("\0\n", 2, 1, fp);
  869     fprintf(fp, "URL:%s", rpkg->url);   // This is already absolute, which is handled earlier...
  870     fwrite("\0\n", 2, 1, fp);
  871     
  872     // For each dependency, write name, relationship and target version.
  873     for (i = 0; i < rpkg->depcount; i++) {
  874         fprintf(fp, "Dep:%s %i %s", rpkg->dependencies[i].name, rpkg->dependencies[i].type, rpkg->dependencies[i].version);
  875         curdep = rpkg->dependencies[i].ordep;
  876         
  877         // WHEN READPKG CAN HANDLE ORDEP, UNCOMMENT BELOW
  878         // And also any possible alternative for the dependency.
  879         while (curdep != NULL) {
  880             fprintf(fp, " OR %s %i %s", curdep->name, curdep->type, curdep->version);
  881             curdep = curdep->ordep;
  882         }
  883         fwrite("\0\n", 2, 1, fp);
  884     }
  885     fclose(fp);
  886     
  887     return 0;
  888 }
  889 
  890 int readpkgcache(dbhandle *handle, tremotepkg *rpkg) {
  891     FILE                *fp;
  892     char            *buf;
  893     struct stat     statbuf;
  894     dependency      *curdep;
  895     char            *ptr;
  896     void            *filemap;
  897     char            *tmpname, *tmpversion, *sptr, *rptr;
  898     int             tmprel;
  899     off_t               buflen;
  900     
  901     if (handle->curname >= handle->namecount) {
  902         return 1;
  903     }
  904 
  905     buf = malloc(strlen(handle->fpath) + strlen(handle->namelist[handle->curname]->d_name) + 2);
  906     buf = strcpy(buf, handle->fpath);
  907     if (buf[strlen(handle->fpath)-1] != '/') {
  908         buf = strcat(buf, "/");
  909     }
  910     buf = strcat(buf, handle->namelist[handle->curname]->d_name);
  911     
  912     // No? Well, let's open the file...
  913     if ((fp = fopen(buf, "r")) == NULL) {
  914         free(buf);
  915         return 1;
  916     }
  917     free(buf);
  918     fstat(fileno(fp), &statbuf);
  919 
  920     // It's easier to mmap the file if we want to parse it.
  921     filemap = mmap(0, statbuf.st_size, PROT_READ, MAP_SHARED, fileno(fp), 0);
  922     if (filemap == MAP_FAILED) { fprintf(stderr, "B\n"); return 1; }
  923     
  924     ptr = filemap;
  925 
  926     rpkg->depcount = 0;
  927     while (ptr < (char*)(filemap + statbuf.st_size)) {
  928         switch (switchcachecontrolkey(ptr)) {
  929             case 1:
  930                 // This +something is to skip the key, such as 'Name:'
  931                 // We can call strdup, because it terminates with \0.
  932                 rpkg->name = strdup(ptr + 5);
  933                 ptr += 5 + strlen(rpkg->name);
  934                 break;
  935             case 2:
  936                 rpkg->version = strdup(ptr + 8);
  937                 ptr += 8 + strlen(rpkg->version);
  938                 break;
  939             case 3:
  940                 rpkg->description = strdup(ptr + 12);
  941                 ptr += 12 + strlen(rpkg->description);
  942                 break;
  943             case 4:
  944                 rpkg->url = strdup(ptr + 4);
  945                 ptr += 4 + strlen(rpkg->url);
  946                 break;
  947             case 5:
  948                 buf = strdup(ptr + 4);
  949                 buflen = strlen(buf);
  950                 ptr += 4 + buflen;
  951                 sptr = buf;
  952             
  953                 rptr = pstrnstr(sptr, " ", (off_t)(buflen), 1);
  954                 if (rptr == NULL) {
  955                     free(buf);
  956                     break;
  957                 }
  958                 tmpname = strndup(buf, rptr-buf);
  959                 
  960                 sptr = rptr+1;
  961                 if (sptr >= buf + buflen) {
  962                     free(buf);
  963                     free(tmpname);
  964                     break;
  965                 }
  966                 tmprel = strtol(sptr, &sptr, 10);
  967                 
  968                 sptr++;
  969                 if (sptr >= buf + buflen) {
  970                     free(buf);
  971                     free(tmpname);
  972                     break;
  973                 }
  974                 rptr = pstrnstr(sptr, " ", (unsigned long)(strlen(buf)), 1);
  975                 if (rptr == NULL) {
  976                     tmpversion = strdup(sptr);
  977                 } else {
  978                     tmpversion = strndup(sptr, rptr-sptr);
  979                 }
  980                 
  981                 adddependency(rpkg, tmpname, tmpversion, tmprel);
  982                 free(tmpname);
  983                 free(tmpversion);
  984                 
  985                 sptr += 4;// +4 = " OR "
  986                 if (sptr < buf + buflen) {
  987                     while (!strncmp(sptr, " OR ", 4)) {
  988                         curdep = (dependency*)rpkg->dependencies[rpkg->depcount - 1].ordep;
  989                         while (curdep != NULL)
  990                             curdep = curdep->ordep;
  991                         
  992                         curdep->ordep = malloc(sizeof(dependency));
  993                         curdep = curdep->ordep;
  994                         
  995                         rptr = pstrnstr(sptr, " ", (off_t)(buflen), 1);
  996                         if (rptr == NULL) {
  997                             free(buf);
  998                             break;
  999                         }
 1000                         tmpname = strndup(buf, rptr-buf);
 1001                         
 1002                         sptr = rptr+1;
 1003                         if (sptr >= buf + buflen) {
 1004                             free(buf);
 1005                             free(tmpname);
 1006                             break;
 1007                         }
 1008                         tmprel = strtol(sptr, &sptr, 10);
 1009                         
 1010                         sptr++;
 1011                         if (sptr >= buf + buflen) {
 1012                             free(buf);
 1013                             free(tmpname);
 1014                             break;
 1015                         }
 1016                         rptr = pstrnstr(sptr, " ", (unsigned long)(strlen(buf)), 1);
 1017                         if (rptr == NULL) {
 1018                             tmpversion = strdup(sptr);
 1019                         } else {
 1020                             tmpversion = strndup(sptr, rptr-sptr);
 1021                         }
 1022                         
 1023                         curdep->name = tmpname;
 1024                         curdep->version = tmpversion;
 1025                         curdep->type = tmprel;
 1026                         curdep->satisfied = 0;
 1027                         curdep->ordep = NULL;
 1028                         
 1029                         sptr += 4;
 1030                         if (sptr >= buf + buflen)
 1031                             break;
 1032                     }
 1033                 }
 1034                 
 1035                 free(buf);
 1036                 break;
 1037             default:
 1038                 ptr = pstrnstr(ptr, "\0\n", (unsigned long)(filemap + statbuf.st_size - (void*)ptr), 2);
 1039                 if (ptr == NULL) { ptr = (char*)(filemap + statbuf.st_size); }
 1040                 break;
 1041         }
 1042         ptr+=2;
 1043     }
 1044     munmap(filemap, statbuf.st_size);
 1045     fclose(fp);
 1046 
 1047     handle->curname++;
 1048     
 1049     return 0;
 1050 }
 1051 
 1052 int findpkgcache(dbhandle *handle, tremotepkg *reval, char *needle, int mtype) {
 1053     char    *buf;
 1054     
 1055     while (handle->curname < handle->namecount) {
 1056         if (mtype == M_NAME) {
 1057             buf = rebuildspecialchars(handle->namelist[handle->curname]->d_name + 8);
 1058             if (!fnmatch(needle, buf, 0)) {
 1059                 if (reval != NULL) { 
 1060                     if (readpkgcache(handle, reval)) {
 1061                         free(buf);
 1062                         continue;
 1063                     }
 1064                 } else {
 1065                     handle->curname++;
 1066                 }
 1067                 free(buf);
 1068                 return 1;
 1069             }
 1070             free(buf);
 1071         } else if (mtype == M_DESC) {
 1072             // TODO
 1073         }
 1074         handle->curname++;
 1075     }
 1076     
 1077     return 0;
 1078 }
 1079 #endif