2 * rnmh.c -- functions to read BSD format name cache information from a
8 * Copyright 1997 Purdue Research Foundation, West Lafayette, Indiana
9 * 47907. All rights reserved.
11 * Written by Victor A. Abell
13 * This software is not subject to any license of the American Telephone
14 * and Telegraph Company or the Regents of the University of California.
16 * Permission is granted to anyone to use this software for any purpose on
17 * any computer system, and to alter it and redistribute it freely, subject
18 * to the following restrictions:
20 * 1. Neither the authors nor Purdue University are responsible for any
21 * consequences of the use of this software.
23 * 2. The origin of this software must not be misrepresented, either by
24 * explicit claim or by omission. Credit to the authors and Purdue
25 * University must appear in documentation and sources.
27 * 3. Altered versions must be plainly marked as such, and must not be
28 * misrepresented as being the original software.
30 * 4. This notice may not be removed or altered.
34 #include "../machine.h"
36 #if defined(HASNCACHE) && defined(USE_LIB_RNMH)
39 static char copyright[] =
40 "@(#) Copyright 1997 Purdue Research Foundation.\nAll rights reserved.\n";
41 static char *rcsid = "$Id: rnmh.c,v 1.13 2008/10/21 16:13:23 abe Exp $";
42 # endif /* !defined(lint) */
48 * rnmh.c - read BSD format hashed kernel name cache
54 * #include the relevant header file -- e.g., <sys/namei.h>.
56 * Define X_NCACHE as the nickname for the kernel cache hash tables
59 * Define X_NCSIZE as the nickname for the size of the kernel cache has
62 * Define NCACHE_NO_ROOT if the calling dialect doesn't support
63 * the locating of the root node of a file system.
65 * Define the name of the name cache structure -- e.g.,
67 * #define NCACHE <structure name>
70 * Define the following casts, if they differ from the defaults:
72 * NCACHE_SZ_CAST case for X_NCSIZE (default unsigned long)
74 * Define the names of these elements of struct NCACHE:
76 * #define NCACHE_NM <name>
77 * #define NCACHE_NXT <link to next entry>
78 * #define NCACHE_NODEADDR <node address>
79 * #define NCACHE_PARADDR <parent node address>
83 * #define NCACHE_NMLEN <name length>
85 * Optionally define *both*:
87 * #define NCACHE_NODEID <node capability ID>
88 * #define NCACHE_PARID <parent node capability ID>
90 * The caller may need to:
92 * Define this prototype for ncache_load():
94 * _PROTOTYPE(static void ncache_load,(void));
96 * Define NCACHE_VROOT to be the value of the flag that signifies that
97 * the vnode is the root of its file system.
99 * E.g., for BSDI >= 5:
101 * #define NCACHE_VROOT VV_ROOT
103 * If not defined, NCACHE_VROOT is defined as "VROOT".
105 * Define VNODE_VFLAG if the vnode's flag member's name isn't v_flag.
107 * Note: if NCHNAMLEN is defined, the name is assumed to be in
108 * NCACHE_NM[NCHNAMLEN]; if it isn't defined, the name is assumed to be in an
109 * extension that begins at NCACHE_NM[0].
111 * Note: if NCACHE_NMLEN is not defined, then NCACHE_NM must be a pointer to
112 * a kernel allocated, NUL-terminated, string buffer.
120 # if !defined(NCACHE_NC_CAST)
121 #define NCACHE_SZ_CAST unsigned long
122 # endif /* !defined(NCACHE_NC_CAST) */
129 # if !defined(NCACHE_NMLEN)
131 # endif /* !defined(NCACHE_NMLEN) */
133 # if !defined(NCACHE_VROOT)
134 #define NCACHE_VROOT VROOT /* vnode is root of its file system */
135 # endif /* !defined(NCACHE_VROOT) */
137 # if !defined(VNODE_VFLAG)
138 #define VNODE_VFLAG v_flag
139 # endif /* !defined(VNODE_VFLAG) */
143 * Local static values
146 static int Mch; /* name cache hash mask */
149 KA_T na; /* node address */
150 KA_T pa; /* parent node address */
151 struct l_nch *pla; /* parent local node address */
152 int nl; /* name length */
153 struct l_nch *next; /* next entry */
155 # if defined(NCACHE_NODEID)
156 unsigned long id; /* capability ID */
157 unsigned long did; /* parent capability ID */
158 # endif /* defined(NCACHE_NODEID) */
160 # if defined(NCHNAMLEN)
161 char nm[NCHNAMLEN + 1]; /* name */
162 # else /* !defined(NCHNAMLEN) */
163 char nm[1]; /* variable length name */
164 # endif /* defined(NCHNAMLEN) */
168 static struct l_nch *Ncache = (struct l_nch *)NULL;
169 /* the head of the local name cache */
170 static struct l_nch **Nchash = (struct l_nch **)NULL;
171 /* Ncache hash pointers */
173 # if defined(NCACHE_NODEID)
174 #define ncachehash(i,n) Nchash+(((((int)(n)>>2)+((int)(i)))*31415)&Mch)
175 _PROTOTYPE(static struct l_nch *ncache_addr,(unsigned long i, KA_T na));
176 # else /* !defined(NCACHE_NODEID) */
177 #define ncachehash(n) Nchash+((((int)(n)>>2)*31415)&Mch)
178 _PROTOTYPE(static struct l_nch *ncache_addr,(KA_T na));
179 # endif /* defined(NCACHE_NODEID) */
181 # if !defined(NCACHE_NO_ROOT)
182 _PROTOTYPE(static int ncache_isroot,(KA_T na, char *cp));
183 # endif /* !defined(NCACHE_NO_ROOT) */
187 * ncache_addr() - look up a node's local ncache address
190 static struct l_nch *
192 # if defined(NCACHE_NODEID)
194 unsigned long i; /* node's capability ID */
195 # else /* !defined(NCACHE_NODEID) */
197 # endif /* defined(NCACHE_NODEID) */
199 KA_T na; /* node's address */
203 # if defined(NCACHE_NODEID)
204 for (hp = ncachehash(i, na); *hp; hp++)
205 # else /* !defined(NCACHE_NODEID) */
206 for (hp = ncachehash(na); *hp; hp++)
207 # endif /* defined(NCACHE_NODEID) */
211 # if defined(NCACHE_NODEID)
212 if ((*hp)->id == i && (*hp)->na == na)
213 # else /* !defined(NCACHE_NODEID) */
215 # endif /* defined(NCACHE_NODEID) */
219 return((struct l_nch *)NULL);
223 # if !defined(NCACHE_NO_ROOT)
225 * ncache_isroot() - is head of name cache path a file system root?
229 ncache_isroot(na, cp)
230 KA_T na; /* kernel node address */
231 char *cp; /* partial path */
233 char buf[MAXPATHLEN];
239 static KA_T *nc = (KA_T *)NULL;
246 * Search the root vnode cache.
248 for (i = 0; i < ncn; i++) {
253 * Read the vnode and see if it's a VDIR node with the NCACHE_VROOT flag set.
254 * If it is, then the path is complete.
256 * If it isn't, and if the file has an inode number, search the mount table
257 * and see if the file system's inode number is known. If it is, form the
258 * possible full path, safely stat() it, and see if it's inode number matches
259 * the one we have for this file. If it does, then the path is complete.
261 if (kread((KA_T)na, (char *)&v, sizeof(v))
262 || v.v_type != VDIR || !(v.VNODE_VFLAG & NCACHE_VROOT)) {
265 * The vnode tests failed. Try the inode tests.
267 if (Lf->inp_ty != 1 || !Lf->inode
268 || !Lf->fsdir || (len = strlen(Lf->fsdir)) < 1)
270 if ((len + 1 + strlen(cp) + 1) > sizeof(buf))
272 for (mtp = readmnt(); mtp; mtp = mtp->next) {
273 if (!mtp->dir || !mtp->inode)
275 if (strcmp(Lf->fsdir, mtp->dir) == 0)
280 (void) strcpy(buf, Lf->fsdir);
281 if (buf[len - 1] != '/')
283 (void) strcpy(&buf[len], cp);
284 if (statsafely(buf, &sb) != 0
285 || (unsigned long)sb.st_ino != Lf->inode)
289 * Add the node address to the root node cache.
293 len = (MALLOC_S)(10 * sizeof(KA_T));
294 nc = (KA_T *)malloc(len);
296 len = (MALLOC_S)((nca + 10) * sizeof(KA_T));
297 nc = (KA_T *)realloc(nc, len);
300 (void) fprintf(stderr, "%s: no space for root node table\n",
309 # endif /* !defined(NCACHE_NO_ROOT) */
313 * ncache_load() - load the kernel's name cache
320 struct l_nch **hp, *ln;
322 static struct NCACHE **khp = (struct namecache **)NULL;
326 static struct l_nch *lc = (struct l_nch *)NULL;
328 int len, lim, n, nch, nchl, nlcl;
332 # if !defined(NCHNAMLEN)
333 int cin = sizeof(c.NCACHE_NM);
334 KA_T nmo = (KA_T)offsetof(struct NCACHE, NCACHE_NM);
335 # endif /* !defined(NCHNAMLEN) */
337 # if !defined(NCACHE_NMLEN)
338 char nbf[MAXPATHLEN + 1];
339 int nbfl = (int)(sizeof(nbf) - 1);
345 # endif /* !defined(NCACHE_NMLEN) */
350 * Free previously allocated space.
352 for (lc = Ncache; lc; lc = ln) {
354 (void) free((FREE_P *)lc);
356 Ncache = (struct l_nch *)NULL;
358 (void) free((FREE_P *)Nchash);
359 Nchash = (struct l_nch **)NULL;
361 * Get kernel cache hash table size
364 if (get_Nl_value(X_NCSIZE, (struct drive_Nl *)NULL, &v) < 0
366 || kread((KA_T)v, (char *)&khsz, sizeof(khsz)))
369 (void) fprintf(stderr,
370 "%s: WARNING: can't read name cache hash size: %s\n",
371 Pn, print_kptr(v, (char *)NULL, 0));
376 (void) fprintf(stderr,
377 "%s: WARNING: name cache hash size length error: %#lx\n",
382 * Get kernel cache hash table address.
386 if (get_Nl_value(X_NCACHE, (struct drive_Nl *)NULL, &v) < 0
388 || kread((KA_T)v, (char *)&ka, sizeof(ka))
392 (void) fprintf(stderr,
393 "%s: WARNING: unusable name cache hash pointer: (%s)=%s\n",
394 Pn, print_kptr(v, tbuf, sizeof(tbuf)),
395 print_kptr(ka, (char *)NULL, 0));
399 * Allocate space for the hash table pointers and read them.
401 len = (MALLOC_S)(khsz * sizeof(struct NCACHE *));
404 khp = (struct NCACHE **)realloc((MALLOC_P *)khp, len);
406 khp = (struct NCACHE **)malloc(len);
408 (void) fprintf(stderr,
409 "%s: can't allocate %d bytes for name cache hash table\n",
415 if (kread((KA_T)ka, (char *)khp, len)) {
416 (void) fprintf(stderr,
417 "%s: can't read name cache hash pointers from: %s\n",
418 Pn, print_kptr(ka, (char *)NULL, 0));
422 * Process the kernel's name cache hash table buckets.
425 for (kx = nch = 0; kx < khsz; kx++) {
428 * Loop through the entries for a hash bucket.
430 for (ka = (KA_T)khp[kx], n = 0; ka; ka = knx, n++) {
433 (void) fprintf(stderr,
434 "%s: WARNING: name cache hash chain too long\n",
438 if (kread(ka, (char *)&c, sizeof(c)))
440 knx = (KA_T)c.NCACHE_NXT;
441 if (!c.NCACHE_NODEADDR)
444 # if defined(NCACHE_NMLEN)
445 if ((len = c.NCACHE_NMLEN) < 1)
447 # else /* !defined(NCACHE_NMLEN) */
449 * If it's possible to read the first four characters of the name,
450 * do so and check for "." and "..".
453 || kread((KA_T)c.NCACHE_NM, nbf, 4))
457 || ((nbf[1] == '.') && !nbf[2]))
461 * Read the rest of the name, 32 characters at a time, until a NUL
462 * character has been read or nbfl characters have been read.
465 if ((len = (int)strlen(nbf)) < 4) {
469 for (np = &nbf[4]; len < nbfl; np += rl) {
470 if ((rl = nbfl - len) > 32) {
472 nbf[len + rl] = '\0';
474 nk = (KA_T)((char *)c.NCACHE_NM + len);
475 if (kread(nk, np, rl)) {
479 rl = (int)strlen(np);
487 # endif /* defined(NCACHE_NMLEN) */
490 * Allocate a cache entry long enough to contain the name and
491 * move the name to it.
494 # if defined(NCHNAMLEN)
497 if (len < 3 && c.NCACHE_NM[0] == '.') {
498 if (len == 1 || (len == 2 && c.NCACHE_NM[1] == '.'))
501 if ((nlcl = sizeof(struct l_nch)) > lcl)
502 # else /* !defined(NCHNAMLEN) */
503 if ((nlcl = sizeof(struct l_nch) + len) > lcl)
504 # endif /* defined(NCHNAMLEN) */
508 lc = (struct l_nch *)realloc(lc, nlcl);
510 lc = (struct l_nch *)malloc(nlcl);
512 (void) fprintf(stderr,
513 "%s: can't allocate %d local name cache bytes\n",
520 # if defined(NCHNAMLEN)
521 (void) strncpy(lc->nm, c.NCACHE_NM, len);
522 # else /* !defined(NCHNAMLEN) */
523 # if defined(NCACHE_NMLEN)
524 if ((len < 3) && (cin > 1)) {
527 * If this is a one or two character name, and if NCACHE_NM[]
528 * in c has room for at least two characters, check for "."
529 * and ".." first, ignoring this entry if the name is either.
531 if (len < 3 && c.NCACHE_NM[0] == '.') {
532 if (len == 1 || (len == 2 && c.NCACHE_NM[1] == '.'))
539 * If not all (possibly not any, depending on the value in
540 * cin) of the name has yet been read to lc->nm[], read it
541 * or the rest of it. If it wasn't possible before to check
542 * for "." or "..", do that. too.
545 (void) strncpy(lc->nm, c.NCACHE_NM, cin);
546 if (kread(ka + (KA_T)(nmo + cin), &lc->nm[cin], len - cin))
548 if ((cin < 2) && (len < 3) && (lc->nm[0] == '.')) {
549 if (len == 1 || (len == 2 && lc->nm[1] == '.'))
553 (void) strncpy(lc->nm, c.NCACHE_NM, len);
554 # else /* !defined(NCACHE_NMLEN) */
555 (void) strncpy(lc->nm, nbf, len);
556 # endif /* defined(NCACHE_NMLEN) */
558 # endif /* defined(NCHNAMLEN) */
561 * Complete the new local cache entry and link it to the previous
566 lc->na = (KA_T)c.NCACHE_NODEADDR;
568 lc->pa = (KA_T)c.NCACHE_PARADDR;
569 lc->pla = (struct l_nch *)NULL;
571 # if defined(NCACHE_NODEID)
572 lc->id = c.NCACHE_NODEID;
573 lc->did = c.NCACHE_PARID;
574 # endif /* defined(NCACHE_NODEID) */
577 lc = (struct l_nch *)NULL;
582 * Reduce memory usage, as required.
585 (void) free((FREE_P *)khp);
586 khp = (struct NCACHE **)NULL;
591 (void) fprintf(stderr,
592 "%s: WARNING: unusable name cache size: %d\n", Pn, nch);
596 * Build a hash table to locate Ncache entries.
598 for (nchl = 1; nchl < nch; nchl <<= 1)
603 if (!(Nchash = (struct l_nch **)calloc(len, sizeof(struct l_nch *)))) {
605 (void) fprintf(stderr,
606 "%s: no space for %d local name cache hash pointers\n",
610 for (lc = Ncache; lc; lc = lc->next) {
612 # if defined(NCACHE_NODEID)
613 for (hp = ncachehash(lc->id, lc->na),
614 # else /* !defined(NCACHE_NODEID) */
615 for (hp = ncachehash(lc->na),
616 # endif /* defined(NCACHE_NODEID) */
620 if ((*hp)->na == lc->na && strcmp((*hp)->nm, lc->nm) == 0) {
631 * Make a final pass through the local cache and convert parent node
632 * addresses to local name cache pointers.
634 for (lc = Ncache; lc; lc = lc->next) {
638 # if defined(NCACHE_NODEID)
639 lc->pla = ncache_addr(lc->did, lc->pa);
640 # else /* !defined(NCACHE_NODEID) */
641 lc->pla = ncache_addr(lc->pa);
642 # endif /* defined(NCACHE_NODEID) */
649 * ncache_lookup() - look up a node's name in the kernel's name cache
653 ncache_lookup(buf, blen, fp)
654 char *buf; /* receiving name buffer */
655 int blen; /* receiving buffer length */
656 int *fp; /* full path reply */
666 # if defined(HASFSINO)
668 * If the entry has an inode number that matches the inode number of the
669 * file system mount point, return an empty path reply. That tells the
670 * caller to print the file system mount point name only.
672 if ((Lf->inp_ty == 1) && Lf->fs_ino && (Lf->inode == Lf->fs_ino))
674 # endif /* defined(HASFSINO) */
677 * Look up the name cache entry for the node address.
680 # if defined(NCACHE_NODEID)
681 if (!Nchash || !(lc = ncache_addr(Lf->id, Lf->na)))
682 # else /* !defined(NCACHE_NODEID) */
683 if (!Nchash || !(lc = ncache_addr(Lf->na)))
684 # endif /* defined(NCACHE_NODEID) */
689 * If the node has no cache entry, see if it's the mount
690 * point of a known file system.
692 if (!Lf->fsdir || !Lf->dev_def || Lf->inp_ty != 1)
693 return((char *)NULL);
694 for (mtp = readmnt(); mtp; mtp = mtp->next) {
695 if (!mtp->dir || !mtp->inode)
697 if (Lf->dev == mtp->dev
698 && mtp->inode == Lf->inode
699 && (strcmp(mtp->dir, Lf->fsdir) == 0))
702 return((char *)NULL);
705 * Start the path assembly.
707 if ((nl = lc->nl) > (blen - 1))
708 return((char *)NULL);
709 cp = buf + blen - nl - 1;
710 rlen = blen - nl - 1;
711 (void) strcpy(cp, lc->nm);
713 * Look up the name cache entries that are parents of the node address.
717 * the name length is too large to fit in the receiving buffer.
722 # if !defined(NCACHE_NO_ROOT)
723 if (ncache_isroot(lc->pa, cp))
725 # endif /* !defined(NCACHE_NO_ROOT) */
730 if (((nl = lc->nl) + 1) > rlen)
735 (void) strncpy((cp - nl), lc->nm, nl);
741 #else /* !defined(HASNCACHE) || !defined(USE_LIB_RNMH) */
742 char rnmh_d1[] = "d"; char *rnmh_d2 = rnmh_d1;
743 #endif /* defined(HASNCACHE) && defined(USE_LIB_RNMH) */