"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