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