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