check for null mbuf ptr before freeing (4.3BSD/sys/{130,131,133})
[unix-history] / usr / src / sys / kern / vfs_lookup.c
CommitLineData
da7c5cc6 1/*
0880b18e 2 * Copyright (c) 1982, 1986 Regents of the University of California.
da7c5cc6
KM
3 * All rights reserved. The Berkeley software License Agreement
4 * specifies the terms and conditions for redistribution.
5 *
609e7cfa 6 * @(#)vfs_lookup.c 7.2 (Berkeley) %G%
da7c5cc6 7 */
10873320 8
94368568
JB
9#include "param.h"
10#include "systm.h"
11#include "inode.h"
12#include "fs.h"
13#include "mount.h"
14#include "dir.h"
15#include "user.h"
16#include "buf.h"
17#include "conf.h"
18#include "uio.h"
19#include "kernel.h"
10873320 20
4a0415d6 21struct buf *blkatoff();
db9631a2 22struct buf *freenamebuf;
4f083fd7 23int dirchk = 0;
f93197fc
KM
24
25/*
26 * Structures associated with name cacheing.
27 */
28#define NCHHASH 32 /* size of hash table */
29
30#if ((NCHHASH)&((NCHHASH)-1)) != 0
31#define NHASH(h, i, d) ((unsigned)((h) + (i) + 13 * (int)(d)) % (NCHHASH))
32#else
33#define NHASH(h, i, d) ((unsigned)((h) + (i) + 13 * (int)(d)) & ((NCHHASH)-1))
34#endif
35
a5e62f37
MK
36union nchash {
37 union nchash *nch_head[2];
7dba1c03 38 struct namecache *nch_chain[2];
f93197fc
KM
39} nchash[NCHHASH];
40#define nch_forw nch_chain[0]
41#define nch_back nch_chain[1]
42
7dba1c03 43struct namecache *nchhead, **nchtail; /* LRU chain pointers */
d17f522c 44struct nchstats nchstats; /* cache effectiveness statistics */
f93197fc 45
10873320 46/*
7f69b0e6 47 * Convert a pathname into a pointer to a locked inode.
6bd0bb92 48 * This is a very central and rather complicated routine.
4f083fd7 49 * If the file system is not maintained in a strict tree hierarchy,
7f69b0e6
KM
50 * this can result in a deadlock situation (see comments in code below).
51 *
52 * The flag argument is LOOKUP, CREATE, or DELETE depending on whether
53 * the name is to be looked up, created, or deleted. When CREATE or
54 * DELETE is specified, information usable in creating or deleteing a
55 * directory entry is also calculated. If flag has LOCKPARENT or'ed
56 * into it and the target of the pathname exists, namei returns both
57 * the target and its parent directory locked. When creating and
4f083fd7
SL
58 * LOCKPARENT is specified, the target may not be ".". When deleting
59 * and LOCKPARENT is specified, the target may be ".", but the caller
60 * must check to insure it does an irele and iput instead of two iputs.
61 *
d870be74 62 * The FOLLOW flag is set when symbolic links are to be followed
4f083fd7 63 * when they occur at the end of the name translation process.
7f69b0e6
KM
64 * Symbolic links are always followed for all other pathname
65 * components other than the last.
66 *
67 * The segflg defines whether the name is to be copied from user
68 * space or kernel space.
10873320 69 *
f93197fc
KM
70 * Name caching works as follows:
71 *
a5e62f37
MK
72 * Names found by directory scans are retained in a cache
73 * for future reference. It is managed LRU, so frequently
74 * used names will hang around. Cache is indexed by hash value
75 * obtained from (ino,dev,name) where ino & dev refer to the
76 * directory containing name.
f93197fc 77 *
a5e62f37 78 * For simplicity (and economy of storage), names longer than
7f69b0e6 79 * a maximum length of NCHNAMLEN are not cached; they occur
a5e62f37 80 * infrequently in any case, and are almost never of interest.
f93197fc 81 *
a5e62f37
MK
82 * Upon reaching the last segment of a path, if the reference
83 * is for DELETE, or NOCACHE is set (rewrite), and the
84 * name is located in the cache, it will be dropped.
f93197fc 85 *
f93197fc 86 * Overall outline of namei:
6bd0bb92
BJ
87 *
88 * copy in name
89 * get starting directory
90 * dirloop:
91 * check accessibility of directory
92 * dirloop2:
d870be74 93 * copy next component of name to ndp->ni_dent
6bd0bb92 94 * handle degenerate case where name is null string
f93197fc
KM
95 * look for name in cache, if found, then if at end of path
96 * and deleting or creating, drop it, else to haveino
6bd0bb92
BJ
97 * search for name in directory, to found or notfound
98 * notfound:
4f083fd7 99 * if creating, return locked directory, leaving info on avail. slots
6bd0bb92
BJ
100 * else return error
101 * found:
102 * if at end of path and deleting, return information to allow delete
7f69b0e6 103 * if at end of path and rewriting (CREATE and LOCKPARENT), lock target
4f083fd7 104 * inode and return info to allow rewrite
6bd0bb92 105 * if .. and on mounted filesys, look in mount table for parent
7f69b0e6
KM
106 * if not at end, add name to cache; if at end and neither creating
107 * nor deleting, add name to cache
f93197fc 108 * haveino:
6bd0bb92
BJ
109 * if symbolic link, massage name in buffer and continue at dirloop
110 * if more components of name, do next level at dirloop
111 * return the answer as locked inode
4f083fd7
SL
112 *
113 * NOTE: (LOOKUP | LOCKPARENT) currently returns the parent inode,
114 * but unlocked.
10873320
BJ
115 */
116struct inode *
d870be74
KM
117namei(ndp)
118 register struct nameidata *ndp;
10873320 119{
6bd0bb92
BJ
120 register char *cp; /* pointer into pathname argument */
121/* these variables refer to things which must be freed or unlocked */
122 register struct inode *dp = 0; /* the directory we are searching */
7dba1c03 123 register struct namecache *ncp; /* cache slot for entry */
6bd0bb92
BJ
124 register struct fs *fs; /* file system that directory is in */
125 register struct buf *bp = 0; /* a buffer of directory entries */
126 register struct direct *ep; /* the current directory entry */
127 int entryoffsetinblock; /* offset of ep in bp's buffer */
128 register struct buf *nbp; /* buffer storing path name argument */
129/* these variables hold information about the search for a slot */
130 enum {NONE, COMPACT, FOUND} slotstatus;
131 int slotoffset = -1; /* offset of area with free space */
132 int slotsize; /* size of area at slotoffset */
133 int slotfreespace; /* amount of space free in slot */
134 int slotneeded; /* size of the entry we're seeking */
135/* */
84ef30ec
KM
136 int numdirpasses; /* strategy for directory search */
137 int endsearch; /* offset to end directory search */
d870be74 138 int prevoff; /* ndp->ni_offset of previous entry */
6bd0bb92
BJ
139 int nlink = 0; /* number of symbolic links taken */
140 struct inode *pdp; /* saved dp during symlink work */
d870be74 141 int error, i;
4f083fd7 142 int lockparent;
87c05e6e
KM
143 int docache; /* == 0 do not cache last component */
144 int makeentry; /* != 0 if name to be added to cache */
f93197fc
KM
145 unsigned hash; /* value of name hash for entry */
146 union nchash *nhp; /* cache chain head for entry */
147 int isdotdot; /* != 0 if current name is ".." */
d870be74 148 int flag; /* op ie, LOOKUP, CREATE, or DELETE */
9e7c949b 149 off_t enduseful; /* pointer past last used dir slot */
10873320 150
d870be74
KM
151 lockparent = ndp->ni_nameiop & LOCKPARENT;
152 docache = (ndp->ni_nameiop & NOCACHE) ^ NOCACHE;
153 flag = ndp->ni_nameiop &~ (LOCKPARENT|NOCACHE|FOLLOW);
87c05e6e 154 if (flag == DELETE || lockparent)
f93197fc 155 docache = 0;
f5039631 156 /*
6bd0bb92
BJ
157 * Get a buffer for the name to be translated, and copy the
158 * name into the buffer.
f5039631 159 */
db9631a2
KM
160 nbp = freenamebuf;
161 if (nbp == NULL)
162 nbp = geteblk(MAXPATHLEN);
163 else
164 freenamebuf = nbp->av_forw;
d870be74 165 if (ndp->ni_segflg == UIO_SYSSPACE)
76335100
KM
166 error = copystr(ndp->ni_dirp, nbp->b_un.b_addr, MAXPATHLEN,
167 (u_int *)0);
d870be74 168 else
76335100
KM
169 error = copyinstr(ndp->ni_dirp, nbp->b_un.b_addr, MAXPATHLEN,
170 (u_int *)0);
d870be74
KM
171 if (error) {
172 u.u_error = error;
6bd0bb92 173 goto bad;
d870be74 174 }
6bd0bb92 175
10873320 176 /*
6bd0bb92 177 * Get starting directory.
10873320 178 */
6bd0bb92 179 cp = nbp->b_un.b_addr;
f5039631
BJ
180 if (*cp == '/') {
181 while (*cp == '/')
182 cp++;
10873320
BJ
183 if ((dp = u.u_rdir) == NULL)
184 dp = rootdir;
6bd0bb92
BJ
185 } else
186 dp = u.u_cdir;
187 fs = dp->i_fs;
56700195 188 ILOCK(dp);
f5039631 189 dp->i_count++;
d870be74 190 ndp->ni_pdir = (struct inode *)0xc0000000; /* illegal */
9e7c949b 191 ndp->ni_endoff = 0;
6bd0bb92 192
10873320 193 /*
6bd0bb92
BJ
194 * We come to dirloop to search a new directory.
195 * The directory must be locked so that it can be
196 * iput, and fs must be already set to dp->i_fs.
10873320 197 */
6bd0bb92 198dirloop:
a0aead5a 199 /*
6bd0bb92 200 * Check accessiblity of directory.
a0aead5a 201 */
6bd0bb92 202 if ((dp->i_mode&IFMT) != IFDIR) {
10873320 203 u.u_error = ENOTDIR;
6bd0bb92
BJ
204 goto bad;
205 }
206 if (access(dp, IEXEC))
207 goto bad;
208
6f004ab5 209dirloop2:
6bd0bb92 210 /*
d870be74 211 * Copy next component of name to ndp->ni_dent.
6bd0bb92 212 */
f93197fc 213 hash = 0;
6bd0bb92 214 for (i = 0; *cp != 0 && *cp != '/'; cp++) {
6459ebe0 215 if (i >= MAXNAMLEN) {
067da729 216 u.u_error = ENAMETOOLONG;
d870be74
KM
217 goto bad;
218 }
067da729
KM
219 if (*cp & 0200)
220 if ((*cp&0377) == ('/'|0200) || flag != DELETE) {
221 u.u_error = EINVAL;
222 goto bad;
223 }
d870be74 224 ndp->ni_dent.d_name[i++] = *cp;
f93197fc 225 hash += (unsigned char)*cp * i;
6459ebe0 226 }
d870be74
KM
227 ndp->ni_dent.d_namlen = i;
228 ndp->ni_dent.d_name[i] = '\0';
4a287f19 229 isdotdot = (i == 2 &&
d870be74 230 ndp->ni_dent.d_name[0] == '.' && ndp->ni_dent.d_name[1] == '.');
87c05e6e
KM
231 makeentry = 1;
232 if (*cp == '\0' && docache == 0)
233 makeentry = 0;
6bd0bb92
BJ
234
235 /*
236 * Check for degenerate name (e.g. / or "")
237 * which is a way of talking about a directory,
238 * e.g. like "/." or ".".
239 */
d870be74 240 if (ndp->ni_dent.d_name[0] == '\0') {
f93197fc 241 if (flag != LOOKUP || lockparent) {
78abd7aa 242 u.u_error = EISDIR;
6bd0bb92 243 goto bad;
f5039631 244 }
db9631a2
KM
245 nbp->av_forw = freenamebuf;
246 freenamebuf = nbp;
6459ebe0 247 return (dp);
f5039631 248 }
6bd0bb92 249
f93197fc
KM
250 /*
251 * We now have a segment name to search for, and a directory to search.
252 *
253 * Before tediously performing a linear scan of the directory,
254 * check the name cache to see if the directory/name pair
255 * we are looking for is known already. We don't do this
256 * if the segment name is long, simply so the cache can avoid
257 * holding long names (which would either waste space, or
258 * add greatly to the complexity).
259 */
d870be74 260 if (ndp->ni_dent.d_namlen > NCHNAMLEN) {
f93197fc 261 nchstats.ncs_long++;
87c05e6e 262 makeentry = 0;
f93197fc
KM
263 } else {
264 nhp = &nchash[NHASH(hash, dp->i_number, dp->i_dev)];
7dba1c03 265 for (ncp = nhp->nch_forw; ncp != (struct namecache *)nhp;
f93197fc
KM
266 ncp = ncp->nc_forw) {
267 if (ncp->nc_ino == dp->i_number &&
268 ncp->nc_dev == dp->i_dev &&
d870be74
KM
269 ncp->nc_nlen == ndp->ni_dent.d_namlen &&
270 !bcmp(ncp->nc_name, ndp->ni_dent.d_name,
a5e62f37 271 (unsigned)ncp->nc_nlen))
f93197fc
KM
272 break;
273 }
7dba1c03 274 if (ncp == (struct namecache *)nhp) {
f93197fc
KM
275 nchstats.ncs_miss++;
276 ncp = NULL;
277 } else {
7dba1c03 278 if (ncp->nc_id != ncp->nc_ip->i_id)
8ac1234a 279 nchstats.ncs_falsehits++;
7dba1c03 280 else if (!makeentry)
4a287f19 281 nchstats.ncs_badhits++;
7dba1c03 282 else {
a5e62f37
MK
283 /*
284 * move this slot to end of LRU
285 * chain, if not already there
286 */
f93197fc 287 if (ncp->nc_nxt) {
a5e62f37 288 /* remove from LRU chain */
f93197fc
KM
289 *ncp->nc_prev = ncp->nc_nxt;
290 ncp->nc_nxt->nc_prev = ncp->nc_prev;
291
a5e62f37 292 /* and replace at end of it */
f93197fc
KM
293 ncp->nc_nxt = NULL;
294 ncp->nc_prev = nchtail;
295 *nchtail = ncp;
296 nchtail = &ncp->nc_nxt;
297 }
298
4a287f19
KM
299 /*
300 * Get the next inode in the path.
56700195 301 * See comment above other `IUNLOCK' code for
4a287f19
KM
302 * an explaination of the locking protocol.
303 */
f93197fc 304 pdp = dp;
87c05e6e
KM
305 if (!isdotdot || dp != u.u_rdir)
306 dp = ncp->nc_ip;
f93197fc 307 if (dp == NULL)
00e496b2 308 panic("namei: null cache ino");
7dba1c03 309 if (pdp == dp)
f93197fc 310 dp->i_count++;
7dba1c03 311 else if (isdotdot) {
87c05e6e
KM
312 IUNLOCK(pdp);
313 igrab(dp);
314 } else {
315 igrab(dp);
316 IUNLOCK(pdp);
8ac1234a 317 }
f93197fc 318
4a287f19
KM
319 /*
320 * Verify that the inode that we got
321 * did not change while we were waiting
322 * for it to be locked.
323 */
324 if (ncp->nc_id != ncp->nc_ip->i_id) {
325 iput(dp);
56700195 326 ILOCK(pdp);
4a287f19
KM
327 dp = pdp;
328 nchstats.ncs_falsehits++;
329 } else {
d870be74
KM
330 ndp->ni_dent.d_ino = dp->i_number;
331 /* ni_dent.d_reclen is garbage ... */
4a287f19
KM
332 nchstats.ncs_goodhits++;
333 goto haveino;
334 }
335 }
f93197fc
KM
336
337 /*
8ac1234a
SL
338 * Last component and we are renaming or deleting,
339 * the cache entry is invalid, or otherwise don't
340 * want cache entry to exist.
f93197fc 341 */
a5e62f37 342 /* remove from LRU chain */
f93197fc
KM
343 *ncp->nc_prev = ncp->nc_nxt;
344 if (ncp->nc_nxt)
345 ncp->nc_nxt->nc_prev = ncp->nc_prev;
346 else
347 nchtail = ncp->nc_prev;
a5e62f37
MK
348 remque(ncp); /* remove from hash chain */
349 /* insert at head of LRU list (first to grab) */
f93197fc
KM
350 ncp->nc_nxt = nchhead;
351 ncp->nc_prev = &nchhead;
352 nchhead->nc_prev = &ncp->nc_nxt;
353 nchhead = ncp;
a5e62f37 354 /* and make a dummy hash chain */
f93197fc
KM
355 ncp->nc_forw = ncp;
356 ncp->nc_back = ncp;
f93197fc
KM
357 ncp = NULL;
358 }
359 }
360
6459ebe0 361 /*
6bd0bb92
BJ
362 * Suppress search for slots unless creating
363 * file and at end of pathname, in which case
364 * we watch for a place to put the new file in
365 * case it doesn't already exist.
6459ebe0 366 */
6bd0bb92 367 slotstatus = FOUND;
4f083fd7 368 if (flag == CREATE && *cp == 0) {
6bd0bb92
BJ
369 slotstatus = NONE;
370 slotfreespace = 0;
d870be74 371 slotneeded = DIRSIZ(&ndp->ni_dent);
6bd0bb92 372 }
84ef30ec
KM
373 /*
374 * If this is the same directory that this process
375 * previously searched, pick up where we last left off.
f93197fc 376 * We cache only lookups as these are the most common
84ef30ec
KM
377 * and have the greatest payoff. Caching CREATE has little
378 * benefit as it usually must search the entire directory
379 * to determine that the entry does not exist. Caching the
380 * location of the last DELETE has not reduced profiling time
381 * and hence has been removed in the interest of simplicity.
382 */
383 if (flag != LOOKUP || dp->i_number != u.u_ncache.nc_inumber ||
384 dp->i_dev != u.u_ncache.nc_dev) {
d870be74 385 ndp->ni_offset = 0;
84ef30ec
KM
386 numdirpasses = 1;
387 } else {
00e496b2
KM
388 if (u.u_ncache.nc_prevoffset > dp->i_size)
389 u.u_ncache.nc_prevoffset = 0;
d870be74
KM
390 ndp->ni_offset = u.u_ncache.nc_prevoffset;
391 entryoffsetinblock = blkoff(fs, ndp->ni_offset);
84ef30ec 392 if (entryoffsetinblock != 0) {
d870be74 393 bp = blkatoff(dp, ndp->ni_offset, (char **)0);
84ef30ec
KM
394 if (bp == 0)
395 goto bad;
396 }
397 numdirpasses = 2;
f93197fc 398 nchstats.ncs_2passes++;
84ef30ec
KM
399 }
400 endsearch = roundup(dp->i_size, DIRBLKSIZ);
9e7c949b 401 enduseful = 0;
6bd0bb92 402
84ef30ec 403searchloop:
d870be74 404 while (ndp->ni_offset < endsearch) {
f5039631
BJ
405 /*
406 * If offset is on a block boundary,
407 * read the next directory block.
408 * Release previous if it exists.
409 */
d870be74 410 if (blkoff(fs, ndp->ni_offset) == 0) {
f5039631
BJ
411 if (bp != NULL)
412 brelse(bp);
d870be74 413 bp = blkatoff(dp, ndp->ni_offset, (char **)0);
6bd0bb92
BJ
414 if (bp == 0)
415 goto bad;
416 entryoffsetinblock = 0;
6459ebe0
KM
417 }
418 /*
6bd0bb92 419 * If still looking for a slot, and at a DIRBLKSIZE
d82d5deb 420 * boundary, have to start looking for free space again.
6459ebe0 421 */
6bd0bb92
BJ
422 if (slotstatus == NONE &&
423 (entryoffsetinblock&(DIRBLKSIZ-1)) == 0) {
424 slotoffset = -1;
425 slotfreespace = 0;
426 }
6bd0bb92 427 /*
d82d5deb
KM
428 * Get pointer to next entry.
429 * Full validation checks are slow, so we only check
430 * enough to insure forward progress through the
431 * directory. Complete checks can be run by patching
432 * "dirchk" to be true.
6bd0bb92
BJ
433 */
434 ep = (struct direct *)(bp->b_un.b_addr + entryoffsetinblock);
a5e62f37 435 if (ep->d_reclen == 0 ||
d82d5deb 436 dirchk && dirbadentry(ep, entryoffsetinblock)) {
d870be74 437 dirbad(dp, ndp->ni_offset, "mangled entry");
d82d5deb 438 i = DIRBLKSIZ - (entryoffsetinblock & (DIRBLKSIZ - 1));
d870be74 439 ndp->ni_offset += i;
6bd0bb92 440 entryoffsetinblock += i;
6459ebe0
KM
441 continue;
442 }
6bd0bb92 443
6459ebe0 444 /*
6bd0bb92 445 * If an appropriate sized slot has not yet been found,
6459ebe0
KM
446 * check to see if one is available. Also accumulate space
447 * in the current block so that we can determine if
448 * compaction is viable.
449 */
6bd0bb92
BJ
450 if (slotstatus != FOUND) {
451 int size = ep->d_reclen;
452
6459ebe0
KM
453 if (ep->d_ino != 0)
454 size -= DIRSIZ(ep);
455 if (size > 0) {
6bd0bb92
BJ
456 if (size >= slotneeded) {
457 slotstatus = FOUND;
d870be74 458 slotoffset = ndp->ni_offset;
6bd0bb92
BJ
459 slotsize = ep->d_reclen;
460 } else if (slotstatus == NONE) {
461 slotfreespace += size;
462 if (slotoffset == -1)
d870be74 463 slotoffset = ndp->ni_offset;
6bd0bb92
BJ
464 if (slotfreespace >= slotneeded) {
465 slotstatus = COMPACT;
d870be74
KM
466 slotsize = ndp->ni_offset +
467 ep->d_reclen - slotoffset;
6bd0bb92 468 }
6459ebe0 469 }
f5039631 470 }
f5039631 471 }
6bd0bb92 472
f5039631 473 /*
6bd0bb92 474 * Check for a name match.
f5039631 475 */
6bd0bb92 476 if (ep->d_ino) {
d870be74
KM
477 if (ep->d_namlen == ndp->ni_dent.d_namlen &&
478 !bcmp(ndp->ni_dent.d_name, ep->d_name,
a5e62f37 479 (unsigned)ep->d_namlen))
6bd0bb92
BJ
480 goto found;
481 }
d870be74
KM
482 prevoff = ndp->ni_offset;
483 ndp->ni_offset += ep->d_reclen;
6bd0bb92 484 entryoffsetinblock += ep->d_reclen;
9e7c949b
KM
485 if (ep->d_ino)
486 enduseful = ndp->ni_offset;
6bd0bb92 487 }
f93197fc 488/* notfound: */
84ef30ec 489 /*
f93197fc 490 * If we started in the middle of the directory and failed
84ef30ec
KM
491 * to find our target, we must check the beginning as well.
492 */
493 if (numdirpasses == 2) {
494 numdirpasses--;
d870be74 495 ndp->ni_offset = 0;
84ef30ec
KM
496 endsearch = u.u_ncache.nc_prevoffset;
497 goto searchloop;
498 }
6bd0bb92
BJ
499 /*
500 * If creating, and at end of pathname and current
4f083fd7
SL
501 * directory has not been removed, then can consider
502 * allowing file to be created.
6bd0bb92 503 */
4f083fd7 504 if (flag == CREATE && *cp == 0 && dp->i_nlink != 0) {
f5039631 505 /*
6bd0bb92
BJ
506 * Access for write is interpreted as allowing
507 * creation of files in the directory.
f5039631 508 */
6bd0bb92
BJ
509 if (access(dp, IWRITE))
510 goto bad;
f5039631 511 /*
6bd0bb92
BJ
512 * Return an indication of where the new directory
513 * entry should be put. If we didn't find a slot,
d870be74
KM
514 * then set ndp->ni_count to 0 indicating that the new
515 * slot belongs at the end of the directory. If we found
516 * a slot, then the new entry can be put in the range
517 * [ndp->ni_offset .. ndp->ni_offset + ndp->ni_count)
f5039631 518 */
84ef30ec 519 if (slotstatus == NONE) {
d870be74
KM
520 ndp->ni_offset = roundup(dp->i_size, DIRBLKSIZ);
521 ndp->ni_count = 0;
9e7c949b 522 enduseful = ndp->ni_offset;
84ef30ec 523 } else {
d870be74
KM
524 ndp->ni_offset = slotoffset;
525 ndp->ni_count = slotsize;
9e7c949b
KM
526 if (enduseful < slotoffset + slotsize)
527 enduseful = slotoffset + slotsize;
5485e062 528 }
9e7c949b 529 ndp->ni_endoff = roundup(enduseful, DIRBLKSIZ);
6bd0bb92
BJ
530 dp->i_flag |= IUPD|ICHG;
531 if (bp)
532 brelse(bp);
db9631a2
KM
533 nbp->av_forw = freenamebuf;
534 freenamebuf = nbp;
f5039631 535 /*
6bd0bb92
BJ
536 * We return with the directory locked, so that
537 * the parameters we set up above will still be
538 * valid if we actually decide to do a direnter().
539 * We return NULL to indicate that the entry doesn't
540 * currently exist, leaving a pointer to the (locked)
d870be74 541 * directory inode in ndp->ni_pdir.
f5039631 542 */
d870be74 543 ndp->ni_pdir = dp;
6bd0bb92
BJ
544 return (NULL);
545 }
546 u.u_error = ENOENT;
547 goto bad;
548found:
f93197fc
KM
549 if (numdirpasses == 2)
550 nchstats.ncs_pass2++;
6bd0bb92
BJ
551 /*
552 * Check that directory length properly reflects presence
553 * of this entry.
554 */
4a0415d6 555 if (entryoffsetinblock + DIRSIZ(ep) > dp->i_size) {
d870be74 556 dirbad(dp, ndp->ni_offset, "i_size too small");
4a0415d6 557 dp->i_size = entryoffsetinblock + DIRSIZ(ep);
6bd0bb92
BJ
558 dp->i_flag |= IUPD|ICHG;
559 }
560
561 /*
84ef30ec 562 * Found component in pathname.
f93197fc 563 * If the final component of path name, save information
84ef30ec
KM
564 * in the cache as to where the entry was found.
565 */
566 if (*cp == '\0' && flag == LOOKUP) {
00e496b2 567 u.u_ncache.nc_prevoffset = ndp->ni_offset &~ (DIRBLKSIZ - 1);
84ef30ec
KM
568 u.u_ncache.nc_inumber = dp->i_number;
569 u.u_ncache.nc_dev = dp->i_dev;
84ef30ec
KM
570 }
571 /*
87c05e6e 572 * Save directory entry's inode number and reclen in ndp->ni_dent,
84ef30ec 573 * and release directory buffer.
6bd0bb92 574 */
87c05e6e
KM
575 ndp->ni_dent.d_ino = ep->d_ino;
576 ndp->ni_dent.d_reclen = ep->d_reclen;
6bd0bb92
BJ
577 brelse(bp);
578 bp = NULL;
579
580 /*
581 * If deleting, and at end of pathname, return
582 * parameters which can be used to remove file.
4f083fd7 583 * If the lockparent flag isn't set, we return only
d870be74 584 * the directory (in ndp->ni_pdir), otherwise we go
4f083fd7 585 * on and lock the inode, being careful with ".".
6bd0bb92 586 */
4f083fd7 587 if (flag == DELETE && *cp == 0) {
6bd0bb92
BJ
588 /*
589 * Write access to directory required to delete files.
590 */
591 if (access(dp, IWRITE))
592 goto bad;
d870be74 593 ndp->ni_pdir = dp; /* for dirremove() */
6bd0bb92 594 /*
d870be74 595 * Return pointer to current entry in ndp->ni_offset,
6bd0bb92 596 * and distance past previous entry (if there
d870be74
KM
597 * is a previous entry in this block) in ndp->ni_count.
598 * Save directory inode pointer in ndp->ni_pdir for dirremove().
6bd0bb92 599 */
d870be74
KM
600 if ((ndp->ni_offset&(DIRBLKSIZ-1)) == 0)
601 ndp->ni_count = 0;
6bd0bb92 602 else
d870be74 603 ndp->ni_count = ndp->ni_offset - prevoff;
4f083fd7 604 if (lockparent) {
d870be74 605 if (dp->i_number == ndp->ni_dent.d_ino)
4f083fd7
SL
606 dp->i_count++;
607 else {
d870be74 608 dp = iget(dp->i_dev, fs, ndp->ni_dent.d_ino);
4f083fd7 609 if (dp == NULL) {
d870be74 610 iput(ndp->ni_pdir);
4f083fd7
SL
611 goto bad;
612 }
f93197fc 613 /*
9ba16c41 614 * If directory is "sticky", then user must own
f93197fc
KM
615 * the directory, or the file in it, else he
616 * may not delete it (unless he's root). This
617 * implements append-only directories.
618 */
d870be74 619 if ((ndp->ni_pdir->i_mode & ISVTX) &&
f93197fc 620 u.u_uid != 0 &&
d870be74 621 u.u_uid != ndp->ni_pdir->i_uid &&
f93197fc 622 dp->i_uid != u.u_uid) {
d870be74 623 iput(ndp->ni_pdir);
f93197fc
KM
624 u.u_error = EPERM;
625 goto bad;
626 }
4f083fd7
SL
627 }
628 }
db9631a2
KM
629 nbp->av_forw = freenamebuf;
630 freenamebuf = nbp;
6bd0bb92
BJ
631 return (dp);
632 }
633
634 /*
635 * Special handling for ".." allowing chdir out of mounted
636 * file system: indirect .. in root inode to reevaluate
637 * in directory file system was mounted on.
638 */
4a287f19 639 if (isdotdot) {
87c05e6e 640 if (dp == u.u_rdir) {
d870be74 641 ndp->ni_dent.d_ino = dp->i_number;
87c05e6e
KM
642 makeentry = 0;
643 } else if (ndp->ni_dent.d_ino == ROOTINO &&
6bd0bb92
BJ
644 dp->i_number == ROOTINO) {
645 for (i = 1; i < NMOUNT; i++)
646 if (mount[i].m_bufp != NULL &&
647 mount[i].m_dev == dp->i_dev) {
6459ebe0 648 iput(dp);
6bd0bb92 649 dp = mount[i].m_inodp;
56700195 650 ILOCK(dp);
f5039631 651 dp->i_count++;
6bd0bb92
BJ
652 fs = dp->i_fs;
653 cp -= 2; /* back over .. */
654 goto dirloop2;
f5039631 655 }
10873320 656 }
6bd0bb92
BJ
657 }
658
4f083fd7
SL
659 /*
660 * If rewriting (rename), return the inode and the
661 * information required to rewrite the present directory
662 * Must get inode of directory entry to verify it's a
663 * regular file, or empty directory.
664 */
665 if ((flag == CREATE && lockparent) && *cp == 0) {
666 if (access(dp, IWRITE))
667 goto bad;
d870be74 668 ndp->ni_pdir = dp; /* for dirrewrite() */
4f083fd7
SL
669 /*
670 * Careful about locking second inode.
671 * This can only occur if the target is ".".
672 */
d870be74 673 if (dp->i_number == ndp->ni_dent.d_ino) {
4f083fd7
SL
674 u.u_error = EISDIR; /* XXX */
675 goto bad;
676 }
d870be74 677 dp = iget(dp->i_dev, fs, ndp->ni_dent.d_ino);
4f083fd7 678 if (dp == NULL) {
d870be74 679 iput(ndp->ni_pdir);
4f083fd7
SL
680 goto bad;
681 }
db9631a2
KM
682 nbp->av_forw = freenamebuf;
683 freenamebuf = nbp;
4f083fd7
SL
684 return (dp);
685 }
686
6bd0bb92 687 /*
bde63aa5
KM
688 * Check for symbolic link, which may require us to massage the
689 * name before we continue translation. We do not `iput' the
690 * directory because we may need it again if the symbolic link
691 * is relative to the current directory. Instead we save it
692 * unlocked as "pdp". We must get the target inode before unlocking
693 * the directory to insure that the inode will not be removed
694 * before we get it. We prevent deadlock by always fetching
695 * inodes from the root, moving down the directory tree. Thus
696 * when following backward pointers ".." we must unlock the
697 * parent directory before getting the requested directory.
698 * There is a potential race condition here if both the current
699 * and parent directories are removed before the `iget' for the
700 * inode associated with ".." returns. We hope that this occurs
701 * infrequently since we cannot avoid this race condition without
a4358a25 702 * implementing a sophisticated deadlock detection algorithm.
bde63aa5
KM
703 * Note also that this simple deadlock detection scheme will not
704 * work if the file system has any hard links other than ".."
705 * that point backwards in the directory structure.
6bd0bb92
BJ
706 */
707 pdp = dp;
f93197fc 708 if (isdotdot) {
56700195 709 IUNLOCK(pdp); /* race to get the inode */
d870be74 710 dp = iget(dp->i_dev, fs, ndp->ni_dent.d_ino);
bde63aa5
KM
711 if (dp == NULL)
712 goto bad2;
d870be74 713 } else if (dp->i_number == ndp->ni_dent.d_ino) {
bde63aa5
KM
714 dp->i_count++; /* we want ourself, ie "." */
715 } else {
d870be74 716 dp = iget(dp->i_dev, fs, ndp->ni_dent.d_ino);
56700195 717 IUNLOCK(pdp);
bde63aa5
KM
718 if (dp == NULL)
719 goto bad2;
720 }
f93197fc
KM
721
722 /*
a5e62f37 723 * Insert name into cache if appropriate.
f93197fc 724 */
87c05e6e 725 if (makeentry) {
f93197fc 726 if (ncp != NULL)
00e496b2 727 panic("namei: duplicating cache");
a5e62f37
MK
728 /*
729 * Free the cache slot at head of lru chain.
730 */
f93197fc 731 if (ncp = nchhead) {
a5e62f37 732 /* remove from lru chain */
f93197fc
KM
733 *ncp->nc_prev = ncp->nc_nxt;
734 if (ncp->nc_nxt)
735 ncp->nc_nxt->nc_prev = ncp->nc_prev;
736 else
737 nchtail = ncp->nc_prev;
a5e62f37
MK
738 remque(ncp); /* remove from old hash chain */
739 /* grab the inode we just found */
f93197fc 740 ncp->nc_ip = dp;
a5e62f37 741 /* fill in cache info */
f93197fc
KM
742 ncp->nc_ino = pdp->i_number; /* parents inum */
743 ncp->nc_dev = pdp->i_dev; /* & device */
744 ncp->nc_idev = dp->i_dev; /* our device */
8ac1234a 745 ncp->nc_id = dp->i_id; /* identifier */
d870be74 746 ncp->nc_nlen = ndp->ni_dent.d_namlen;
a5e62f37
MK
747 bcopy(ndp->ni_dent.d_name, ncp->nc_name,
748 (unsigned)ncp->nc_nlen);
749 /* link at end of lru chain */
f93197fc
KM
750 ncp->nc_nxt = NULL;
751 ncp->nc_prev = nchtail;
752 *nchtail = ncp;
753 nchtail = &ncp->nc_nxt;
a5e62f37 754 /* and insert on hash chain */
f93197fc
KM
755 insque(ncp, nhp);
756 }
757 }
758
759haveino:
6bd0bb92
BJ
760 fs = dp->i_fs;
761
762 /*
763 * Check for symbolic link
764 */
d870be74
KM
765 if ((dp->i_mode & IFMT) == IFLNK &&
766 ((ndp->ni_nameiop & FOLLOW) || *cp == '/')) {
9f024ffc 767 u_int pathlen = strlen(cp) + 1;
6bd0bb92 768
067da729
KM
769 if (dp->i_size + pathlen >= MAXPATHLEN - 1) {
770 u.u_error = ENAMETOOLONG;
771 goto bad2;
772 }
773 if (++nlink > MAXSYMLINKS) {
6bd0bb92
BJ
774 u.u_error = ELOOP;
775 goto bad2;
776 }
d36096be 777 ovbcopy(cp, nbp->b_un.b_addr + dp->i_size, pathlen);
a6b6f679 778 u.u_error =
4f083fd7 779 rdwri(UIO_READ, dp, nbp->b_un.b_addr, (int)dp->i_size,
8011f5df 780 (off_t)0, 1, (int *)0);
6bd0bb92
BJ
781 if (u.u_error)
782 goto bad2;
783 cp = nbp->b_un.b_addr;
784 iput(dp);
f5039631 785 if (*cp == '/') {
6bd0bb92 786 irele(pdp);
f5039631
BJ
787 while (*cp == '/')
788 cp++;
6bd0bb92
BJ
789 if ((dp = u.u_rdir) == NULL)
790 dp = rootdir;
56700195 791 ILOCK(dp);
6bd0bb92
BJ
792 dp->i_count++;
793 } else {
794 dp = pdp;
56700195 795 ILOCK(dp);
f5039631 796 }
6bd0bb92
BJ
797 fs = dp->i_fs;
798 goto dirloop;
10873320 799 }
6bd0bb92 800
10873320 801 /*
6bd0bb92
BJ
802 * Not a symbolic link. If more pathname,
803 * continue at next component, else return.
10873320 804 */
6bd0bb92
BJ
805 if (*cp == '/') {
806 while (*cp == '/')
807 cp++;
4f083fd7 808 irele(pdp);
6bd0bb92 809 goto dirloop;
10873320 810 }
db9631a2
KM
811 nbp->av_forw = freenamebuf;
812 freenamebuf = nbp;
4f083fd7 813 if (lockparent)
d870be74 814 ndp->ni_pdir = pdp;
4f083fd7
SL
815 else
816 irele(pdp);
6bd0bb92
BJ
817 return (dp);
818bad2:
819 irele(pdp);
820bad:
821 if (bp)
822 brelse(bp);
823 if (dp)
824 iput(dp);
db9631a2
KM
825 nbp->av_forw = freenamebuf;
826 freenamebuf = nbp;
6459ebe0 827 return (NULL);
10873320
BJ
828}
829
f93197fc 830
d870be74 831dirbad(ip, offset, how)
6bd0bb92 832 struct inode *ip;
d870be74 833 off_t offset;
6bd0bb92
BJ
834 char *how;
835{
836
837 printf("%s: bad dir ino %d at offset %d: %s\n",
d870be74 838 ip->i_fs->fs_fsmnt, ip->i_number, offset, how);
6bd0bb92
BJ
839}
840
d82d5deb
KM
841/*
842 * Do consistency checking on a directory entry:
843 * record length must be multiple of 4
d82d5deb
KM
844 * entry must fit in rest of its DIRBLKSIZ block
845 * record must be large enough to contain entry
846 * name is not longer than MAXNAMLEN
847 * name must be as long as advertised, and null terminated
848 */
849dirbadentry(ep, entryoffsetinblock)
6bd0bb92 850 register struct direct *ep;
d82d5deb 851 int entryoffsetinblock;
6bd0bb92 852{
6bd0bb92
BJ
853 register int i;
854
a5e62f37 855 if ((ep->d_reclen & 0x3) != 0 ||
d82d5deb
KM
856 ep->d_reclen > DIRBLKSIZ - (entryoffsetinblock & (DIRBLKSIZ - 1)) ||
857 ep->d_reclen < DIRSIZ(ep) || ep->d_namlen > MAXNAMLEN)
858 return (1);
6bd0bb92 859 for (i = 0; i < ep->d_namlen; i++)
d870be74 860 if (ep->d_name[i] == '\0')
6bd0bb92
BJ
861 return (1);
862 return (ep->d_name[i]);
863}
864
6bd0bb92
BJ
865/*
866 * Write a directory entry after a call to namei, using the parameters
867 * which it left in the u. area. The argument ip is the inode which
d870be74 868 * the new directory entry will refer to. The u. area field ndp->ni_pdir is
6bd0bb92 869 * a pointer to the directory to be written, which was left locked by
d870be74 870 * namei. Remaining parameters (ndp->ni_offset, ndp->ni_count) indicate
6bd0bb92
BJ
871 * how the space for the new entry is to be gotten.
872 */
d870be74 873direnter(ip, ndp)
6bd0bb92 874 struct inode *ip;
d870be74 875 register struct nameidata *ndp;
f5039631 876{
6bd0bb92 877 register struct direct *ep, *nep;
9e7c949b 878 register struct inode *dp = ndp->ni_pdir;
6bd0bb92 879 struct buf *bp;
efa3a91c 880 int loc, spacefree, error = 0;
b32450f4
BJ
881 u_int dsize;
882 int newentrysize;
6bd0bb92 883 char *dirbuf;
f5039631 884
d870be74
KM
885 ndp->ni_dent.d_ino = ip->i_number;
886 newentrysize = DIRSIZ(&ndp->ni_dent);
887 if (ndp->ni_count == 0) {
6bd0bb92 888 /*
d870be74
KM
889 * If ndp->ni_count is 0, then namei could find no space in the
890 * directory. In this case ndp->ni_offset will be on a directory
6bd0bb92
BJ
891 * block boundary and we will write the new entry into a fresh
892 * block.
893 */
d870be74 894 if (ndp->ni_offset&(DIRBLKSIZ-1))
6bd0bb92 895 panic("wdir: newblk");
d870be74 896 ndp->ni_dent.d_reclen = DIRBLKSIZ;
9e7c949b 897 error = rdwri(UIO_WRITE, dp, (caddr_t)&ndp->ni_dent,
d870be74 898 newentrysize, ndp->ni_offset, 1, (int *)0);
23de9f20
KM
899 if (DIRBLKSIZ > dp->i_fs->fs_fsize)
900 panic("wdir: blksize"); /* XXX - should grow w/bmap() */
901 else
902 dp->i_size = roundup(dp->i_size, DIRBLKSIZ);
9e7c949b 903 iput(dp);
f2a5ad78 904 return (error);
6bd0bb92
BJ
905 }
906
907 /*
d870be74
KM
908 * If ndp->ni_count is non-zero, then namei found space for the new
909 * entry in the range ndp->ni_offset to ndp->ni_offset + ndp->ni_count.
6bd0bb92
BJ
910 * in the directory. To use this space, we may have to compact
911 * the entries located there, by copying them together towards
912 * the beginning of the block, leaving the free space in
913 * one usable chunk at the end.
914 */
915
916 /*
917 * Increase size of directory if entry eats into new space.
918 * This should never push the size past a new multiple of
919 * DIRBLKSIZE.
23de9f20
KM
920 *
921 * N.B. - THIS IS AN ARTIFACT OF 4.2 AND SHOULD NEVER HAPPEN.
6bd0bb92 922 */
9e7c949b
KM
923 if (ndp->ni_offset + ndp->ni_count > dp->i_size)
924 dp->i_size = ndp->ni_offset + ndp->ni_count;
6bd0bb92
BJ
925 /*
926 * Get the block containing the space for the new directory
f2a5ad78 927 * entry. Should return error by result instead of u.u_error.
6bd0bb92 928 */
9e7c949b 929 bp = blkatoff(dp, ndp->ni_offset, (char **)&dirbuf);
4f083fd7 930 if (bp == 0) {
9e7c949b 931 iput(dp);
f2a5ad78 932 return (u.u_error);
4f083fd7 933 }
6bd0bb92
BJ
934 /*
935 * Find space for the new entry. In the simple case, the
936 * entry at offset base will have the space. If it does
937 * not, then namei arranged that compacting the region
d870be74 938 * ndp->ni_offset to ndp->ni_offset+ndp->ni_count would yield the space.
6bd0bb92
BJ
939 */
940 ep = (struct direct *)dirbuf;
941 dsize = DIRSIZ(ep);
efa3a91c 942 spacefree = ep->d_reclen - dsize;
d870be74 943 for (loc = ep->d_reclen; loc < ndp->ni_count; ) {
6bd0bb92
BJ
944 nep = (struct direct *)(dirbuf + loc);
945 if (ep->d_ino) {
946 /* trim the existing slot */
947 ep->d_reclen = dsize;
948 ep = (struct direct *)((char *)ep + dsize);
949 } else {
950 /* overwrite; nothing there; header is ours */
efa3a91c 951 spacefree += dsize;
6bd0bb92
BJ
952 }
953 dsize = DIRSIZ(nep);
efa3a91c 954 spacefree += nep->d_reclen - dsize;
6bd0bb92 955 loc += nep->d_reclen;
9f024ffc 956 bcopy((caddr_t)nep, (caddr_t)ep, dsize);
6bd0bb92
BJ
957 }
958 /*
959 * Update the pointer fields in the previous entry (if any),
960 * copy in the new entry, and write out the block.
961 */
962 if (ep->d_ino == 0) {
efa3a91c 963 if (spacefree + dsize < newentrysize)
6bd0bb92 964 panic("wdir: compact1");
d870be74 965 ndp->ni_dent.d_reclen = spacefree + dsize;
6bd0bb92 966 } else {
efa3a91c 967 if (spacefree < newentrysize)
6bd0bb92 968 panic("wdir: compact2");
d870be74 969 ndp->ni_dent.d_reclen = spacefree;
6bd0bb92
BJ
970 ep->d_reclen = dsize;
971 ep = (struct direct *)((char *)ep + dsize);
972 }
d870be74 973 bcopy((caddr_t)&ndp->ni_dent, (caddr_t)ep, (u_int)newentrysize);
6bd0bb92 974 bwrite(bp);
9e7c949b
KM
975 dp->i_flag |= IUPD|ICHG;
976 if (ndp->ni_endoff && ndp->ni_endoff < dp->i_size)
a5e62f37 977 itrunc(dp, (u_long)ndp->ni_endoff);
9e7c949b 978 iput(dp);
f2a5ad78 979 return (error);
6bd0bb92
BJ
980}
981
4f083fd7
SL
982/*
983 * Remove a directory entry after a call to namei, using the
984 * parameters which it left in the u. area. The u. entry
d870be74
KM
985 * ni_offset contains the offset into the directory of the
986 * entry to be eliminated. The ni_count field contains the
4f083fd7
SL
987 * size of the previous record in the directory. If this
988 * is 0, the first entry is being deleted, so we need only
989 * zero the inode number to mark the entry as free. If the
990 * entry isn't the first in the directory, we must reclaim
991 * the space of the now empty record by adding the record size
992 * to the size of the previous entry.
993 */
d870be74
KM
994dirremove(ndp)
995 register struct nameidata *ndp;
6bd0bb92 996{
d870be74 997 register struct inode *dp = ndp->ni_pdir;
6bd0bb92
BJ
998 register struct buf *bp;
999 struct direct *ep;
1000
d870be74 1001 if (ndp->ni_count == 0) {
6bd0bb92
BJ
1002 /*
1003 * First entry in block: set d_ino to zero.
1004 */
d870be74
KM
1005 ndp->ni_dent.d_ino = 0;
1006 (void) rdwri(UIO_WRITE, dp, (caddr_t)&ndp->ni_dent,
1007 (int)DIRSIZ(&ndp->ni_dent), ndp->ni_offset, 1, (int *)0);
36d4ed87 1008 } else {
6bd0bb92
BJ
1009 /*
1010 * Collapse new free space into previous entry.
1011 */
8011f5df 1012 bp = blkatoff(dp, ndp->ni_offset - ndp->ni_count, (char **)&ep);
6bd0bb92
BJ
1013 if (bp == 0)
1014 return (0);
d870be74 1015 ep->d_reclen += ndp->ni_dent.d_reclen;
6bd0bb92
BJ
1016 bwrite(bp);
1017 dp->i_flag |= IUPD|ICHG;
1018 }
1019 return (1);
10873320 1020}
6459ebe0 1021
4f083fd7
SL
1022/*
1023 * Rewrite an existing directory entry to point at the inode
1024 * supplied. The parameters describing the directory entry are
1025 * set up by a call to namei.
1026 */
d870be74 1027dirrewrite(dp, ip, ndp)
4f083fd7 1028 struct inode *dp, *ip;
d870be74 1029 struct nameidata *ndp;
4f083fd7
SL
1030{
1031
d870be74
KM
1032 ndp->ni_dent.d_ino = ip->i_number;
1033 u.u_error = rdwri(UIO_WRITE, dp, (caddr_t)&ndp->ni_dent,
1034 (int)DIRSIZ(&ndp->ni_dent), ndp->ni_offset, 1, (int *)0);
4f083fd7
SL
1035 iput(dp);
1036}
1037
4a0415d6
SL
1038/*
1039 * Return buffer with contents of block "offset"
1040 * from the beginning of directory "ip". If "res"
1041 * is non-zero, fill it in with a pointer to the
1042 * remaining space in the directory.
1043 */
6bd0bb92 1044struct buf *
4a0415d6 1045blkatoff(ip, offset, res)
6bd0bb92
BJ
1046 struct inode *ip;
1047 off_t offset;
1048 char **res;
6459ebe0 1049{
6bd0bb92 1050 register struct fs *fs = ip->i_fs;
3fd23f5c 1051 daddr_t lbn = lblkno(fs, offset);
6bd0bb92 1052 int bsize = blksize(fs, ip, lbn);
6bd0bb92 1053 register struct buf *bp;
7e4f159c 1054 daddr_t bn;
6459ebe0 1055
7e4f159c 1056 bn = bmap(ip, lbn, B_READ, bsize);
6bd0bb92
BJ
1057 if (u.u_error)
1058 return (0);
7e4f159c
KM
1059 if (bn == (daddr_t)-1) {
1060 dirbad(ip, offset, "hole in dir");
1061 return (0);
1062 }
ec67a3ce
MK
1063#ifdef SECSIZE
1064 bp = bread(ip->i_dev, fsbtodb(fs, bn), bsize, fs->fs_dbsize);
1065#else SECSIZE
7e4f159c 1066 bp = bread(ip->i_dev, fsbtodb(fs, bn), bsize);
ec67a3ce 1067#endif SECSIZE
6bd0bb92
BJ
1068 if (bp->b_flags & B_ERROR) {
1069 brelse(bp);
1070 return (0);
1071 }
1072 if (res)
7e4f159c 1073 *res = bp->b_un.b_addr + blkoff(fs, offset);
6bd0bb92 1074 return (bp);
6459ebe0 1075}
4f083fd7
SL
1076
1077/*
1078 * Check if a directory is empty or not.
1079 * Inode supplied must be locked.
17d11193
SL
1080 *
1081 * Using a struct dirtemplate here is not precisely
1082 * what we want, but better than using a struct direct.
1083 *
1084 * NB: does not handle corrupted directories.
4f083fd7 1085 */
68f21562 1086dirempty(ip, parentino)
05d2bbce 1087 register struct inode *ip;
68f21562 1088 ino_t parentino;
4f083fd7
SL
1089{
1090 register off_t off;
17d11193
SL
1091 struct dirtemplate dbuf;
1092 register struct direct *dp = (struct direct *)&dbuf;
05d2bbce 1093 int error, count;
17d11193 1094#define MINDIRSIZ (sizeof (struct dirtemplate) / 2)
4f083fd7
SL
1095
1096 for (off = 0; off < ip->i_size; off += dp->d_reclen) {
17d11193
SL
1097 error = rdwri(UIO_READ, ip, (caddr_t)dp, MINDIRSIZ,
1098 off, 1, &count);
1099 /*
1100 * Since we read MINDIRSIZ, residual must
1101 * be 0 unless we're at end of file.
1102 */
1103 if (error || count != 0)
4f083fd7 1104 return (0);
d14b14c3 1105 /* avoid infinite loops */
a5e62f37 1106 if (dp->d_reclen == 0)
d14b14c3 1107 return (0);
17d11193 1108 /* skip empty entries */
4f083fd7
SL
1109 if (dp->d_ino == 0)
1110 continue;
17d11193
SL
1111 /* accept only "." and ".." */
1112 if (dp->d_namlen > 2)
1113 return (0);
4f083fd7
SL
1114 if (dp->d_name[0] != '.')
1115 return (0);
17d11193
SL
1116 /*
1117 * At this point d_namlen must be 1 or 2.
1118 * 1 implies ".", 2 implies ".." if second
1119 * char is also "."
1120 */
68f21562
KM
1121 if (dp->d_namlen == 1)
1122 continue;
1123 if (dp->d_name[1] == '.' && dp->d_ino == parentino)
4f083fd7
SL
1124 continue;
1125 return (0);
1126 }
1127 return (1);
1128}
b1aa93b9
KM
1129
1130/*
1131 * Check if source directory is in the path of the target directory.
1132 * Target is supplied locked, source is unlocked.
1133 * The target is always iput() before returning.
1134 */
1135checkpath(source, target)
1136 struct inode *source, *target;
1137{
1138 struct dirtemplate dirbuf;
1139 register struct inode *ip;
1140 int error = 0;
1141
1142 ip = target;
1143 if (ip->i_number == source->i_number) {
1144 error = EEXIST;
1145 goto out;
1146 }
1147 if (ip->i_number == ROOTINO)
1148 goto out;
1149
1150 for (;;) {
1151 if ((ip->i_mode&IFMT) != IFDIR) {
1152 error = ENOTDIR;
1153 break;
1154 }
1155 error = rdwri(UIO_READ, ip, (caddr_t)&dirbuf,
1156 sizeof (struct dirtemplate), (off_t)0, 1, (int *)0);
1157 if (error != 0)
1158 break;
1159 if (dirbuf.dotdot_namlen != 2 ||
4a287f19
KM
1160 dirbuf.dotdot_name[0] != '.' ||
1161 dirbuf.dotdot_name[1] != '.') {
b1aa93b9
KM
1162 error = ENOTDIR;
1163 break;
1164 }
1165 if (dirbuf.dotdot_ino == source->i_number) {
1166 error = EINVAL;
1167 break;
1168 }
1169 if (dirbuf.dotdot_ino == ROOTINO)
1170 break;
1171 iput(ip);
1172 ip = iget(ip->i_dev, ip->i_fs, dirbuf.dotdot_ino);
1173 if (ip == NULL) {
1174 error = u.u_error;
1175 break;
1176 }
1177 }
1178
1179out:
1180 if (error == ENOTDIR)
1181 printf("checkpath: .. not a directory\n");
1182 if (ip != NULL)
1183 iput(ip);
1184 return (error);
1185}
f93197fc
KM
1186
1187/*
1188 * Name cache initialization, from main() when we are booting
1189 */
1190nchinit()
1191{
1192 register union nchash *nchp;
7dba1c03 1193 register struct namecache *ncp;
f93197fc
KM
1194
1195 nchhead = 0;
1196 nchtail = &nchhead;
7dba1c03 1197 for (ncp = namecache; ncp < &namecache[nchsize]; ncp++) {
f93197fc
KM
1198 ncp->nc_forw = ncp; /* hash chain */
1199 ncp->nc_back = ncp;
f93197fc
KM
1200 ncp->nc_nxt = NULL; /* lru chain */
1201 *nchtail = ncp;
1202 ncp->nc_prev = nchtail;
1203 nchtail = &ncp->nc_nxt;
f93197fc
KM
1204 /* all else is zero already */
1205 }
f93197fc
KM
1206 for (nchp = nchash; nchp < &nchash[NCHHASH]; nchp++) {
1207 nchp->nch_head[0] = nchp;
1208 nchp->nch_head[1] = nchp;
1209 }
1210}
1211
1212/*
1213 * Cache flush, called when filesys is umounted to
1214 * remove entries that would now be invalid
1215 *
1216 * The line "nxtcp = nchhead" near the end is to avoid potential problems
1217 * if the cache lru chain is modified while we are dumping the
1218 * inode. This makes the algorithm O(n^2), but do you think I care?
1219 */
1220nchinval(dev)
1221 register dev_t dev;
1222{
7dba1c03 1223 register struct namecache *ncp, *nxtcp;
f93197fc
KM
1224
1225 for (ncp = nchhead; ncp; ncp = nxtcp) {
1226 nxtcp = ncp->nc_nxt;
f93197fc
KM
1227 if (ncp->nc_ip == NULL ||
1228 (ncp->nc_idev != dev && ncp->nc_dev != dev))
1229 continue;
a5e62f37 1230 /* free the resources we had */
f93197fc
KM
1231 ncp->nc_idev = NODEV;
1232 ncp->nc_dev = NODEV;
4a287f19 1233 ncp->nc_id = NULL;
f93197fc 1234 ncp->nc_ino = 0;
4a287f19 1235 ncp->nc_ip = NULL;
a5e62f37
MK
1236 remque(ncp); /* remove entry from its hash chain */
1237 ncp->nc_forw = ncp; /* and make a dummy one */
f93197fc 1238 ncp->nc_back = ncp;
a5e62f37 1239 /* delete this entry from LRU chain */
f93197fc
KM
1240 *ncp->nc_prev = nxtcp;
1241 if (nxtcp)
1242 nxtcp->nc_prev = ncp->nc_prev;
1243 else
1244 nchtail = ncp->nc_prev;
a5e62f37 1245 /* cause rescan of list, it may have altered */
f93197fc 1246 nxtcp = nchhead;
a5e62f37 1247 /* put the now-free entry at head of LRU */
f93197fc
KM
1248 ncp->nc_nxt = nxtcp;
1249 ncp->nc_prev = &nchhead;
1250 nxtcp->nc_prev = &ncp->nc_nxt;
1251 nchhead = ncp;
1252 }
1253}
9ffa8d54
KM
1254
1255/*
1256 * Name cache invalidation of all entries.
1257 */
1258cacheinvalall()
1259{
7dba1c03 1260 register struct namecache *ncp;
9ffa8d54 1261
7dba1c03 1262 for (ncp = namecache; ncp < &namecache[nchsize]; ncp++)
9ffa8d54 1263 ncp->nc_id = 0;
9ffa8d54 1264}