2 * libdpkg - Debian packaging suite library routines
3 * fsys-hash.c - filesystem nodes hash table
5 * Copyright © 1995 Ian Jackson <ijackson@chiark.greenend.org.uk>
6 * Copyright © 2000, 2001 Wichert Akkerman <wakkerma@debian.org>
7 * Copyright © 2008-2014 Guillem Jover <guillem@debian.org>
9 * This is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program. If not, see <https://www.gnu.org/licenses/>.
29 #include <dpkg/dpkg.h>
30 #include <dpkg/dpkg-db.h>
31 #include <dpkg/string.h>
32 #include <dpkg/path.h>
36 /* This must always be a prime for optimal performance.
37 * This is the closest one to 2^18 (262144). */
40 static struct fsys_namenode
*bins
[BINS
];
41 static int nfiles
= 0;
46 struct fsys_namenode
*fnn
;
49 for (i
= 0; i
< BINS
; i
++) {
50 for (fnn
= bins
[i
]; fnn
; fnn
= fnn
->next
) {
54 fnn
->file_ondisk_id
= NULL
;
62 memset(bins
, 0, sizeof(bins
));
67 fsys_hash_entries(void)
72 struct fsys_namenode
*
73 fsys_hash_find_node(const char *name
, enum fsys_hash_find_flags flags
)
75 struct fsys_namenode
**pointerp
, *newnode
;
76 const char *orig_name
= name
;
78 /* We skip initial slashes and ‘./’ pairs, and add our own single
80 name
= path_skip_slash_dotslash(name
);
82 pointerp
= bins
+ (str_fnv_hash(name
) % (BINS
));
84 /* XXX: This should not be needed, but it has been a constant
85 * source of assertions over the years. Hopefully with the
86 * internerr() we will get better diagnostics. */
87 if ((*pointerp
)->name
[0] != '/')
88 internerr("filename node '%s' does not start with '/'",
91 if (strcmp((*pointerp
)->name
+ 1, name
) == 0)
93 pointerp
= &(*pointerp
)->next
;
96 if (flags
& FHFF_NO_NEW
)
99 newnode
= nfmalloc(sizeof(*newnode
));
100 memset(newnode
, 0, sizeof(*newnode
));
101 if ((flags
& FHFF_NO_COPY
) && name
> orig_name
&& name
[-1] == '/') {
102 newnode
->name
= name
- 1;
104 char *newname
= nfmalloc(strlen(name
) + 2);
107 strcpy(newname
+ 1, name
);
108 newnode
->name
= newname
;
117 fsys_hash_report(FILE *file
)
119 struct fsys_namenode
*node
;
122 int empty
= 0, used
= 0, collided
= 0;
124 freq
= m_malloc(sizeof(freq
[0]) * nfiles
+ 1);
125 for (i
= 0; i
<= nfiles
; i
++)
127 for (i
= 0; i
< BINS
; i
++) {
128 for (c
= 0, node
= bins
[i
]; node
; c
++, node
= node
->next
);
129 fprintf(file
, "fsys-hash: bin %5d has %7d\n", i
, c
);
140 for (i
= nfiles
; i
> 0 && freq
[i
] == 0; i
--);
142 fprintf(file
, "fsys-hash: size %7d occurs %5d times\n",
146 fprintf(file
, "fsys-hash: bins empty %d\n", empty
);
147 fprintf(file
, "fsys-hash: bins used %d (collided %d)\n", used
,
150 m_output(file
, "<hash report>");
159 struct fsys_hash_iter
{
160 struct fsys_namenode
*namenode
;
164 struct fsys_hash_iter
*
165 fsys_hash_iter_new(void)
167 struct fsys_hash_iter
*iter
;
169 iter
= m_malloc(sizeof(*iter
));
170 iter
->namenode
= NULL
;
176 struct fsys_namenode
*
177 fsys_hash_iter_next(struct fsys_hash_iter
*iter
)
179 struct fsys_namenode
*fnn
= NULL
;
181 while (!iter
->namenode
) {
182 if (iter
->nbinn
>= BINS
)
184 iter
->namenode
= bins
[iter
->nbinn
++];
186 fnn
= iter
->namenode
;
187 iter
->namenode
= fnn
->next
;
193 fsys_hash_iter_free(struct fsys_hash_iter
*iter
)