filesdb.c 21 KB

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