filesdb.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670
  1. /*
  2. * dpkg - main program for package management
  3. * filesdb.c - management of database of files installed on system
  4. *
  5. * Copyright (C) 1995 Ian Jackson <iwj10@cus.cam.ac.uk>
  6. *
  7. * This is free software; you can redistribute it and/or modify
  8. * it under the terms of the GNU General Public License as
  9. * published by the Free Software Foundation; either version 2,
  10. * or (at your option) any later version.
  11. *
  12. * This is distributed in the hope that it will be useful, but
  13. * WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public
  18. * License along with dpkg; if not, write to the Free Software
  19. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  20. */
  21. #include <assert.h>
  22. #include <unistd.h>
  23. #include <string.h>
  24. #include <errno.h>
  25. #include <sys/stat.h>
  26. #include <config.h>
  27. #include <dpkg.h>
  28. #include <dpkg-db.h>
  29. #include "filesdb.h"
  30. #include "main.h"
  31. #ifdef HAVE_SYS_SYSINFO_H
  32. #include <sys/sysinfo.h>
  33. #endif
  34. /*** Generic data structures and routines ***/
  35. static int allpackagesdone= 0;
  36. static int nfiles= 0;
  37. static struct diversion *diversions= 0;
  38. static FILE *diversionsfile= 0;
  39. void note_must_reread_files_inpackage(struct pkginfo *pkg) {
  40. allpackagesdone= 0;
  41. ensure_package_clientdata(pkg);
  42. pkg->clientdata->fileslistvalid= 0;
  43. }
  44. static int saidread=0;
  45. void ensure_packagefiles_available(struct pkginfo *pkg) {
  46. static struct varbuf fnvb;
  47. static char stdiobuf[8192];
  48. FILE *file;
  49. const char *filelistfile;
  50. struct fileinlist **lendp, *newent, *current;
  51. struct filepackages *packageslump;
  52. int search, findlast, putat, l;
  53. char *thefilename;
  54. char linebuf[1024];
  55. if (pkg->clientdata && pkg->clientdata->fileslistvalid) return;
  56. ensure_package_clientdata(pkg);
  57. /* Throw away any the stale data, if there was any. */
  58. for (current= pkg->clientdata->files;
  59. current;
  60. current= current->next) {
  61. /* For each file that used to be in the package,
  62. * go through looking for this package's entry in the list
  63. * of packages containing this file, and blank it out.
  64. */
  65. for (packageslump= current->namenode->packages;
  66. packageslump;
  67. packageslump= packageslump->more)
  68. for (search= 0;
  69. search < PERFILEPACKAGESLUMP && packageslump->pkgs[search];
  70. search++)
  71. if (packageslump->pkgs[search] == pkg) {
  72. /* Hah! Found it. */
  73. for (findlast= search+1;
  74. findlast < PERFILEPACKAGESLUMP && packageslump->pkgs[findlast];
  75. findlast++);
  76. findlast--;
  77. /* findlast is now the last occupied entry, which may be the same as
  78. * search. We blank out the entry for this package. We also
  79. * have to copy the last entry into the empty slot, because
  80. * the list is null-pointer-terminated.
  81. */
  82. packageslump->pkgs[search]= packageslump->pkgs[findlast];
  83. packageslump->pkgs[findlast]= 0;
  84. /* This may result in an empty link in the list. This is OK. */
  85. goto xit_search_to_delete_from_perfilenodelist;
  86. }
  87. xit_search_to_delete_from_perfilenodelist:
  88. ;
  89. /* The actual filelist links were allocated using nfmalloc, so
  90. * we shouldn't free them.
  91. */
  92. }
  93. pkg->clientdata->files= 0;
  94. /* Packages which aren't installed don't have a files list. */
  95. if (pkg->status == stat_notinstalled) {
  96. pkg->clientdata->fileslistvalid= 1; return;
  97. }
  98. filelistfile= pkgadminfile(pkg,LISTFILE);
  99. onerr_abort++;
  100. file= fopen(filelistfile,"r");
  101. if (!file) {
  102. if (errno != ENOENT)
  103. ohshite(_("unable to open files list file for package `%.250s'"),pkg->name);
  104. onerr_abort--;
  105. if (pkg->status != stat_configfiles) {
  106. if (saidread == 1) putc('\n',stderr);
  107. fprintf(stderr,
  108. _("dpkg: serious warning: files list file for package `%.250s' missing,"
  109. " assuming package has no files currently installed.\n"), pkg->name);
  110. }
  111. pkg->clientdata->files= 0;
  112. pkg->clientdata->fileslistvalid= 1;
  113. return;
  114. }
  115. push_cleanup(cu_closefile,ehflag_bombout, 0,0, 1,(void*)file);
  116. if (setvbuf(file,stdiobuf,_IOFBF,sizeof(stdiobuf)))
  117. ohshite(_("unable to set buffering on `%.250s'"),filelistfile);
  118. lendp= &pkg->clientdata->files;
  119. varbufreset(&fnvb);
  120. while (fgets(linebuf,sizeof(linebuf),file)) {
  121. /* This is a very important loop, and it is therefore rather messy.
  122. * We break the varbuf abstraction even more than usual, and we
  123. * avoid copying where possible.
  124. */
  125. l= strlen(linebuf);
  126. if (l == 0) ohshit(_("fgets gave an empty null-terminated string from `%.250s'"),
  127. filelistfile);
  128. l--;
  129. if (linebuf[l] != '\n') {
  130. varbufaddstr(&fnvb,linebuf);
  131. continue;
  132. } else if (!fnvb.used && l>0 && linebuf[l-1] != '/') { /* fast path */
  133. linebuf[l]= 0;
  134. thefilename= linebuf;
  135. } else {
  136. if (l>0 && linebuf[l-1] == '/') l--; /* strip trailing slashes */
  137. linebuf[l]= 0;
  138. varbufaddstr(&fnvb,linebuf);
  139. varbufaddc(&fnvb,0);
  140. fnvb.used= 0;
  141. thefilename= fnvb.buf;
  142. }
  143. if (!*thefilename)
  144. ohshit(_("files list file for package `%.250s' contains empty filename"),pkg->name);
  145. newent= nfmalloc(sizeof(struct fileinlist));
  146. newent->namenode= findnamenode(thefilename);
  147. newent->next= 0;
  148. *lendp= newent;
  149. lendp= &newent->next;
  150. }
  151. if (ferror(file))
  152. ohshite(_("error reading files list file for package `%.250s'"),pkg->name);
  153. pop_cleanup(ehflag_normaltidy); /* file= fopen() */
  154. if (fclose(file))
  155. ohshite(_("error closing files list file for package `%.250s'"),pkg->name);
  156. if (fnvb.used)
  157. ohshit(_("files list file for package `%.250s' is truncated"),pkg->name);
  158. onerr_abort--;
  159. for (newent= pkg->clientdata->files; newent; newent= newent->next) {
  160. packageslump= newent->namenode->packages;
  161. if (packageslump) {
  162. for (putat= 0;
  163. putat < PERFILEPACKAGESLUMP && packageslump->pkgs[putat];
  164. putat++);
  165. if (putat >= PERFILEPACKAGESLUMP) packageslump= 0;
  166. }
  167. if (!packageslump) {
  168. packageslump= nfmalloc(sizeof(struct filepackages));
  169. packageslump->more= newent->namenode->packages;
  170. newent->namenode->packages= packageslump;
  171. putat= 0;
  172. }
  173. packageslump->pkgs[putat]= pkg;
  174. if (++putat < PERFILEPACKAGESLUMP) packageslump->pkgs[putat]= 0;
  175. }
  176. pkg->clientdata->fileslistvalid= 1;
  177. }
  178. void ensure_allinstfiles_available(void) {
  179. struct pkgiterator *it;
  180. struct pkginfo *pkg;
  181. if (allpackagesdone) return;
  182. if (saidread<2) {
  183. saidread=1;
  184. printf(f_largemem>0 ? _("(Reading database ... ") : _("(Scanning database ... "));
  185. }
  186. it= iterpkgstart();
  187. while ((pkg= iterpkgnext(it)) != 0) ensure_packagefiles_available(pkg);
  188. iterpkgend(it);
  189. allpackagesdone= 1;
  190. if (saidread==1) {
  191. printf(_("%d files and directories currently installed.)\n"),nfiles);
  192. saidread=2;
  193. }
  194. }
  195. void ensure_allinstfiles_available_quiet(void) {
  196. saidread=2;
  197. ensure_allinstfiles_available();
  198. }
  199. void write_filelist_except(struct pkginfo *pkg, struct fileinlist *list, int leaveout) {
  200. /* If leaveout is nonzero, will not write any file whose filenamenode
  201. * has the fnnf_elide_other_lists flag set.
  202. */
  203. static struct varbuf vb, newvb;
  204. FILE *file;
  205. varbufreset(&vb);
  206. varbufaddstr(&vb,admindir);
  207. varbufaddstr(&vb,"/" INFODIR);
  208. varbufaddstr(&vb,pkg->name);
  209. varbufaddstr(&vb,"." LISTFILE);
  210. varbufaddc(&vb,0);
  211. varbufreset(&newvb);
  212. varbufaddstr(&newvb,vb.buf);
  213. varbufaddstr(&newvb,NEWDBEXT);
  214. varbufaddc(&newvb,0);
  215. file= fopen(newvb.buf,"w+");
  216. if (!file)
  217. ohshite(_("unable to create updated files list file for package %s"),pkg->name);
  218. push_cleanup(cu_closefile,ehflag_bombout, 0,0, 1,(void*)file);
  219. while (list) {
  220. if (!(leaveout && (list->namenode->flags & fnnf_elide_other_lists))) {
  221. fputs(list->namenode->name,file);
  222. putc('\n',file);
  223. }
  224. list= list->next;
  225. }
  226. if (ferror(file))
  227. ohshite(_("failed to write to updated files list file for package %s"),pkg->name);
  228. if (fflush(file))
  229. ohshite(_("failed to flush updated files list file for package %s"),pkg->name);
  230. if (fsync(fileno(file)))
  231. ohshite(_("failed to sync updated files list file for package %s"),pkg->name);
  232. pop_cleanup(ehflag_normaltidy); /* file= fopen() */
  233. if (fclose(file))
  234. ohshite(_("failed to close updated files list file for package %s"),pkg->name);
  235. if (rename(newvb.buf,vb.buf))
  236. ohshite(_("failed to install updated files list file for package %s"),pkg->name);
  237. note_must_reread_files_inpackage(pkg);
  238. }
  239. void reversefilelist_init(struct reversefilelistiter *iterptr,
  240. struct fileinlist *files) {
  241. /* Initialises an iterator that appears to go through the file
  242. * list `files' in reverse order, returning the namenode from
  243. * each. What actually happens is that we walk the list here,
  244. * building up a reverse list, and then peel it apart one
  245. * entry at a time.
  246. */
  247. struct fileinlist *newent;
  248. iterptr->todo= 0;
  249. while (files) {
  250. newent= m_malloc(sizeof(struct fileinlist));
  251. newent->namenode= files->namenode;
  252. newent->next= iterptr->todo;
  253. iterptr->todo= newent;
  254. files= files->next;
  255. }
  256. }
  257. struct filenamenode *reversefilelist_next(struct reversefilelistiter *iterptr) {
  258. struct filenamenode *ret;
  259. struct fileinlist *todo;
  260. todo= iterptr->todo;
  261. if (!todo) return 0;
  262. ret= todo->namenode;
  263. iterptr->todo= todo->next;
  264. free(todo);
  265. return ret;
  266. }
  267. void reversefilelist_abort(struct reversefilelistiter *iterptr) {
  268. /* Clients must call this function to clean up the reversefilelistiter
  269. * if they wish to break out of the iteration before it is all done.
  270. * Calling this function is not necessary if reversefilelist_next has
  271. * been called until it returned 0.
  272. */
  273. while (reversefilelist_next(iterptr));
  274. }
  275. void ensure_diversions(void) {
  276. static struct varbuf vb;
  277. struct stat stab1, stab2;
  278. char linebuf[MAXDIVERTFILENAME];
  279. FILE *file;
  280. struct diversion *ov, *oicontest, *oialtname;
  281. int l;
  282. varbufreset(&vb);
  283. varbufaddstr(&vb,admindir);
  284. varbufaddstr(&vb,"/" DIVERSIONSFILE);
  285. varbufaddc(&vb,0);
  286. onerr_abort++;
  287. file= fopen(vb.buf,"r");
  288. if (!file) {
  289. if (errno != ENOENT) ohshite(_("failed to open diversions file"));
  290. if (!diversionsfile) { onerr_abort--; return; }
  291. } else if (diversionsfile) {
  292. if (fstat(fileno(diversionsfile),&stab1))
  293. ohshite(_("failed to fstat previous diversions file"));
  294. if (fstat(fileno(file),&stab2))
  295. ohshite(_("failed to fstat diversions file"));
  296. if (stab1.st_dev == stab2.st_dev && stab1.st_ino == stab2.st_ino) {
  297. fclose(file); onerr_abort--; return;
  298. }
  299. }
  300. if (diversionsfile) fclose(diversionsfile);
  301. diversionsfile= file;
  302. for (ov= diversions; ov; ov= ov->next) {
  303. ov->useinstead->divert->camefrom->divert= 0;
  304. ov->useinstead->divert= 0;
  305. }
  306. diversions= 0;
  307. if (!file) { onerr_abort--; return; }
  308. while (fgets(linebuf,sizeof(linebuf),file)) {
  309. oicontest= nfmalloc(sizeof(struct diversion));
  310. oialtname= nfmalloc(sizeof(struct diversion));
  311. l= strlen(linebuf);
  312. if (l == 0) ohshit(_("fgets gave an empty string from diversions [i]"));
  313. if (linebuf[--l] != '\n') ohshit(_("diversions file has too-long line or EOF [i]"));
  314. linebuf[l]= 0;
  315. oialtname->camefrom= findnamenode(linebuf);
  316. oialtname->useinstead= 0;
  317. if (!fgets(linebuf,sizeof(linebuf),file)) {
  318. if (ferror(file)) ohshite(_("read error in diversions [ii]"));
  319. else ohshit(_("unexpected EOF in diversions [ii]"));
  320. }
  321. l= strlen(linebuf);
  322. if (l == 0) ohshit(_("fgets gave an empty string from diversions [ii]"));
  323. if (linebuf[--l] != '\n') ohshit(_("diversions file has too-long line or EOF [ii]"));
  324. linebuf[l]= 0;
  325. oicontest->useinstead= findnamenode(linebuf);
  326. oicontest->camefrom= 0;
  327. if (!fgets(linebuf,sizeof(linebuf),file)) {
  328. if (ferror(file)) ohshite(_("read error in diversions [iii]"));
  329. else ohshit(_("unexpected EOF in diversions [iii]"));
  330. }
  331. l= strlen(linebuf);
  332. if (l == 0) ohshit(_("fgets gave an empty string from diversions [iii]"));
  333. if (linebuf[--l] != '\n') ohshit(_("diversions file has too-long line or EOF [ii]"));
  334. linebuf[l]= 0;
  335. oicontest->pkg= oialtname->pkg=
  336. strcmp(linebuf,":") ? findpackage(linebuf) : 0;
  337. if (oialtname->camefrom->divert || oicontest->useinstead->divert)
  338. ohshit(_("conflicting diversions involving `%.250s' or `%.250s'"),
  339. oialtname->camefrom->name, oicontest->useinstead->name);
  340. oialtname->camefrom->divert= oicontest;
  341. oicontest->useinstead->divert= oialtname;
  342. oicontest->next= diversions;
  343. diversions= oicontest;
  344. }
  345. if (ferror(file)) ohshite(_("read error in diversions [i]"));
  346. diversionsfile= file;
  347. onerr_abort--;
  348. }
  349. /*** Data structures common to both in-core databases ***/
  350. struct fileiterator {
  351. union {
  352. struct {
  353. struct filenamenode *current;
  354. } low;
  355. struct {
  356. struct filenamenode *namenode;
  357. int nbinn;
  358. } high;
  359. } u;
  360. };
  361. /*** Data structures for fast, large memory usage database ***/
  362. #define BINS (1 << 13)
  363. /* This must always be a power of two. If you change it
  364. * consider changing the per-character hashing factor (currently
  365. * 1785 = 137*13) too.
  366. */
  367. static struct filenamenode *bins[BINS];
  368. /*** Data structures for low-memory-footprint in-core files database ***/
  369. struct fdirents {
  370. struct fdirents *more;
  371. struct { const char *component; struct fdirnode *go; } entries[1];
  372. /* first one has one entry, then two, then four, &c */
  373. };
  374. struct fdirnode {
  375. struct filenamenode *here;
  376. struct fdirents *contents;
  377. };
  378. static struct fdirnode fdirroot;
  379. static struct filenamenode *allfiles;
  380. struct filenamesblock {
  381. struct filenamesblock *next;
  382. char *data;
  383. };
  384. static struct filenamesblock *namesarea= 0;
  385. static int namesarealeft= 0;
  386. /*** Code for both. This is rather hacky, sorry ... ***/
  387. struct fileiterator *iterfilestart(void) {
  388. struct fileiterator *i;
  389. i= m_malloc(sizeof(struct fileiterator));
  390. switch (f_largemem) {
  391. case 1:
  392. i->u.high.namenode= 0;
  393. i->u.high.nbinn= 0;
  394. break;
  395. case -1:
  396. i->u.low.current= allfiles;
  397. break;
  398. default:
  399. internerr("iterfilestart no f_largemem");
  400. }
  401. return i;
  402. }
  403. struct filenamenode *iterfilenext(struct fileiterator *i) {
  404. struct filenamenode *r;
  405. switch (f_largemem) {
  406. case 1:
  407. while (!i->u.high.namenode) {
  408. if (i->u.high.nbinn >= BINS) return 0;
  409. i->u.high.namenode= bins[i->u.high.nbinn++];
  410. }
  411. r= i->u.high.namenode;
  412. i->u.high.namenode= r->next;
  413. break;
  414. case -1:
  415. if (!i->u.low.current) return 0;
  416. r= i->u.low.current;
  417. i->u.low.current= i->u.low.current->next;
  418. break;
  419. default:
  420. internerr("iterfilenext no f_largemem");
  421. }
  422. return r;
  423. }
  424. void iterfileend(struct fileiterator *i) {
  425. free(i);
  426. }
  427. static int autodetect_largemem(void) {
  428. #ifdef HAVE_SYSINFO
  429. struct sysinfo info;
  430. if (sysinfo(&info)) return 0;
  431. if (info.freeram + (info.sharedram>>2) + (info.bufferram>>2) < 24576*1024 &&
  432. info.totalram < 24576*1024)
  433. return 0;
  434. #endif
  435. return 1;
  436. }
  437. void filesdbinit(void) {
  438. struct filenamenode *fnn;
  439. int i;
  440. if (!f_largemem)
  441. f_largemem= autodetect_largemem() ? 1 : -1;
  442. switch (f_largemem) {
  443. case 1:
  444. for (i=0; i<BINS; i++)
  445. for (fnn= bins[i]; fnn; fnn= fnn->next) {
  446. fnn->flags= 0;
  447. fnn->oldhash= 0;
  448. fnn->filestat= 0;
  449. }
  450. break;
  451. case -1:
  452. for (fnn= allfiles;
  453. fnn;
  454. fnn= fnn->next) {
  455. fnn->flags= 0;
  456. fnn->oldhash= 0;
  457. fnn->filestat= 0;
  458. }
  459. break;
  460. default:
  461. internerr("filesdbinit no f_largemem");
  462. }
  463. }
  464. static struct filenamenode *findnamenode_high(const char *name);
  465. static struct filenamenode *findnamenode_low(const char *name);
  466. struct filenamenode *findnamenode(const char *name) {
  467. switch (f_largemem) {
  468. case 1:
  469. return findnamenode_high(name);
  470. case -1:
  471. return findnamenode_low(name);
  472. default:
  473. internerr("findnamenode no f_largemem");
  474. }
  475. }
  476. /*** Code for low-memory-footprint in-core files database ***/
  477. static struct filenamenode *findnamenode_low(const char *name) {
  478. struct fdirnode *traverse;
  479. struct fdirents *ents, **addto;
  480. const char *nameleft, *slash;
  481. char *p;
  482. struct filenamesblock *newblock;
  483. int n, i, nentrieshere, alloc;
  484. /* We skip initial slashes and ./ pairs, and add our own single leading slash. */
  485. name= skip_slash_dotslash(name);
  486. nameleft= name;
  487. traverse= &fdirroot;
  488. while (nameleft) {
  489. slash= strchr(nameleft,'/');
  490. if (slash) {
  491. n= (int)(slash-nameleft); slash++;
  492. } else {
  493. n= strlen(nameleft);
  494. }
  495. ents= traverse->contents; addto= &traverse->contents; i= 0; nentrieshere= 1;
  496. for (;;) {
  497. if (!ents) break;
  498. if (!ents->entries[i].component) break;
  499. if (!strncmp(ents->entries[i].component,nameleft,n) &&
  500. !ents->entries[i].component[n]) {
  501. break;
  502. }
  503. i++;
  504. if (i < nentrieshere) continue;
  505. addto= &ents->more;
  506. ents= ents->more;
  507. nentrieshere += nentrieshere;
  508. i=0;
  509. }
  510. if (!ents) {
  511. ents= nfmalloc(sizeof(struct fdirents) +
  512. sizeof(ents->entries[0])*(nentrieshere-1));
  513. i=0;
  514. ents->entries[i].component= 0;
  515. ents->more= 0;
  516. *addto= ents;
  517. }
  518. if (!ents->entries[i].component) {
  519. p= nfmalloc(n+1);
  520. memcpy(p,nameleft,n); p[n]= 0;
  521. ents->entries[i].component= p;
  522. ents->entries[i].go= nfmalloc(sizeof(struct fdirnode));
  523. ents->entries[i].go->here= 0;
  524. ents->entries[i].go->contents= 0;
  525. if (i+1 < nentrieshere)
  526. ents->entries[i+1].component= 0;
  527. }
  528. traverse= ents->entries[i].go;
  529. nameleft= slash;
  530. }
  531. if (traverse->here) return traverse->here;
  532. traverse->here= nfmalloc(sizeof(struct filenamenode));
  533. traverse->here->packages= 0;
  534. traverse->here->flags= 0;
  535. traverse->here->divert= 0;
  536. traverse->here->filestat= 0;
  537. n= strlen(name)+2;
  538. if (namesarealeft < n) {
  539. newblock= m_malloc(sizeof(struct filenamesblock));
  540. alloc= 256*1024;
  541. if (alloc<n) alloc= n;
  542. newblock->data= m_malloc(alloc);
  543. newblock->next= namesarea;
  544. namesarea= newblock;
  545. namesarealeft= alloc;
  546. }
  547. namesarealeft-= n;
  548. p= namesarea->data+namesarealeft;
  549. traverse->here->name= p; *p++= '/'; strcpy(p,name);
  550. traverse->here->next= allfiles;
  551. allfiles= traverse->here;
  552. nfiles++;
  553. return traverse->here;
  554. }
  555. /*** Code for high memory usage fast database ***/
  556. static int hash(const char *name) {
  557. int v= 0;
  558. while (*name) { v *= 1785; v += *name; name++; }
  559. return v;
  560. }
  561. struct filenamenode *findnamenode_high(const char *name) {
  562. struct filenamenode **pointerp, *newnode;
  563. /* We skip initial slashes and ./ pairs, and add our own single leading slash. */
  564. name= skip_slash_dotslash(name);
  565. pointerp= bins + (hash(name) & (BINS-1));
  566. while (*pointerp) {
  567. assert((*pointerp)->name[0] == '/');
  568. if (!strcmp((*pointerp)->name+1,name)) break;
  569. pointerp= &(*pointerp)->next;
  570. }
  571. if (*pointerp) return *pointerp;
  572. newnode= nfmalloc(sizeof(struct filenamenode));
  573. newnode->packages= 0;
  574. newnode->name= nfmalloc(strlen(name)+2);
  575. newnode->name[0]= '/'; strcpy(newnode->name+1,name);
  576. newnode->flags= 0;
  577. newnode->next= 0;
  578. newnode->divert= 0;
  579. newnode->filestat= 0;
  580. *pointerp= newnode;
  581. nfiles++;
  582. return newnode;
  583. }