xref: /csrg-svn/sys/kern/vfs_lookup.c (revision 7867)
1 /*	vfs_lookup.c	4.24	82/08/24	*/
2 
3 #include "../h/param.h"
4 #include "../h/systm.h"
5 #include "../h/inode.h"
6 #include "../h/fs.h"
7 #include "../h/mount.h"
8 #include "../h/dir.h"
9 #include "../h/user.h"
10 #include "../h/buf.h"
11 #include "../h/conf.h"
12 #include "../h/uio.h"
13 
14 struct	buf *blkatoff();
15 int	dirchk = 1;
16 /*
17  * Convert a pathname into a pointer to a locked inode,
18  * with side effects usable in creating and removing files.
19  * This is a very central and rather complicated routine.
20  *
21  * The func argument gives the routine which returns successive
22  * characters of the name to be translated.  The flag
23  * argument is (0, 1, 2) depending on whether the name is to be
24  * (looked up, created, deleted).  The follow argument is 1 when
25  * symbolic links are to be followed when they occur at the end of
26  * the name translation process.
27  *
28  * Overall outline:
29  *
30  *	copy in name
31  *	get starting directory
32  * dirloop:
33  *	check accessibility of directory
34  * dirloop2:
35  *	copy next component of name to u.u_dent
36  *	handle degenerate case where name is null string
37  *	search for name in directory, to found or notfound
38  * notfound:
39  *	if creating, return locked inode, leaving information on avail. slots
40  *	else return error
41  * found:
42  *	if at end of path and deleting, return information to allow delete
43  *	if .. and on mounted filesys, look in mount table for parent
44  *	if symbolic link, massage name in buffer and continue at dirloop
45  *	if more components of name, do next level at dirloop
46  *	return the answer as locked inode
47  */
48 struct inode *
49 namei(func, flag, follow)
50 	int (*func)(), flag, follow;
51 {
52 	register char *cp;		/* pointer into pathname argument */
53 /* these variables refer to things which must be freed or unlocked */
54 	register struct inode *dp = 0;	/* the directory we are searching */
55 	register struct fs *fs;		/* file system that directory is in */
56 	register struct buf *bp = 0;	/* a buffer of directory entries */
57 	register struct direct *ep;	/* the current directory entry */
58 	int entryoffsetinblock;		/* offset of ep in bp's buffer */
59 	register struct buf *nbp;	/* buffer storing path name argument */
60 /* these variables hold information about the search for a slot */
61 	enum {NONE, COMPACT, FOUND} slotstatus;
62 	int slotoffset = -1;		/* offset of area with free space */
63 	int slotsize;			/* size of area at slotoffset */
64 	int slotfreespace;		/* amount of space free in slot */
65 	int slotneeded;			/* size of the entry we're seeking */
66 /* */
67 	int dirsize;
68 	int prevoff;			/* u.u_offset of previous entry */
69 	int nlink = 0;			/* number of symbolic links taken */
70 	struct inode *pdp;		/* saved dp during symlink work */
71 	int i;
72 
73 	/*
74 	 * Get a buffer for the name to be translated, and copy the
75 	 * name into the buffer.
76 	 */
77 	nbp = geteblk(MAXPATHLEN);
78 	for (cp = nbp->b_un.b_addr; *cp = (*func)(); ) {
79 		if ((*cp&0377) == ('/'|0200) || (*cp&0200) && flag != 2) {
80 			u.u_error = EPERM;
81 			goto bad;
82 		}
83 		cp++;
84 		if (cp >= nbp->b_un.b_addr + MAXPATHLEN) {
85 			u.u_error = ENOENT;
86 			goto bad;
87 		}
88 	}
89 	if (u.u_error)
90 		goto bad;
91 
92 	/*
93 	 * Get starting directory.
94 	 */
95 	cp = nbp->b_un.b_addr;
96 	if (*cp == '/') {
97 		while (*cp == '/')
98 			cp++;
99 		if ((dp = u.u_rdir) == NULL)
100 			dp = rootdir;
101 	} else
102 		dp = u.u_cdir;
103 	fs = dp->i_fs;
104 	ilock(dp);
105 	dp->i_count++;
106 	u.u_pdir = (struct inode *)0xc0000000;		/* illegal */
107 
108 	/*
109 	 * We come to dirloop to search a new directory.
110 	 * The directory must be locked so that it can be
111 	 * iput, and fs must be already set to dp->i_fs.
112 	 */
113 dirloop:
114 	/*
115 	 * Check accessiblity of directory.
116 	 */
117 	if ((dp->i_mode&IFMT) != IFDIR) {
118 		u.u_error = ENOTDIR;
119 		goto bad;
120 	}
121 	if (access(dp, IEXEC))
122 		goto bad;
123 
124 dirloop2:
125 	/*
126 	 * Copy next component of name to u.u_dent.
127 	 */
128 	for (i = 0; *cp != 0 && *cp != '/'; cp++) {
129 		if (i >= MAXNAMLEN) {
130 			u.u_error = ENOENT;
131 			goto bad;
132 		}
133 		u.u_dent.d_name[i++] = *cp;
134 	}
135 	u.u_dent.d_namlen = i;
136 	u.u_dent.d_name[i] = 0;
137 
138 	/*
139 	 * Check for degenerate name (e.g. / or "")
140 	 * which is a way of talking about a directory,
141 	 * e.g. like "/." or ".".
142 	 */
143 	if (u.u_dent.d_name[0] == 0) {
144 		if (flag) {
145 			u.u_error = ENOENT;
146 			goto bad;
147 		}
148 		brelse(nbp);
149 		return (dp);
150 	}
151 
152 	/*
153 	 * Suppress search for slots unless creating
154 	 * file and at end of pathname, in which case
155 	 * we watch for a place to put the new file in
156 	 * case it doesn't already exist.
157 	 */
158 	slotstatus = FOUND;
159 	if (flag == 1 && *cp == 0) {
160 		slotstatus = NONE;
161 		slotfreespace = 0;
162 		slotneeded = DIRSIZ(&u.u_dent);
163 	}
164 
165 	dirsize = roundup(dp->i_size, DIRBLKSIZ);
166 	u.u_offset = 0;
167 	while (u.u_offset < dirsize) {
168 		/*
169 		 * If offset is on a block boundary,
170 		 * read the next directory block.
171 		 * Release previous if it exists.
172 		 */
173 		if (blkoff(fs, u.u_offset) == 0) {
174 			if (bp != NULL)
175 				brelse(bp);
176 			bp = blkatoff(dp, u.u_offset, (char **)0);
177 			if (bp == 0)
178 				goto bad;
179 			entryoffsetinblock = 0;
180 		}
181 
182 		/*
183 		 * If still looking for a slot, and at a DIRBLKSIZE
184 		 * boundary, have to start looking for free space
185 		 * again.
186 		 */
187 		if (slotstatus == NONE &&
188 		    (entryoffsetinblock&(DIRBLKSIZ-1)) == 0) {
189 			slotoffset = -1;
190 			slotfreespace = 0;
191 		}
192 
193 		/*
194 		 * Get pointer to next entry, and do consistency checking:
195 		 *	record length must be multiple of 4
196 		 *	record length must not be zero
197 		 *	entry must fit in rest of this DIRBLKSIZ block
198 		 *	record must be large enough to contain name
199 		 * When dirchk is set we also check:
200 		 *	name is not longer than MAXNAMLEN
201 		 *	name must be as long as advertised, and null terminated
202 		 * Checking last two conditions is done only when dirchk is
203 		 * set, to save time.
204 		 */
205 		ep = (struct direct *)(bp->b_un.b_addr + entryoffsetinblock);
206 		i = DIRBLKSIZ - (entryoffsetinblock & (DIRBLKSIZ - 1));
207 		if ((ep->d_reclen & 0x3) || ep->d_reclen == 0 ||
208 		    ep->d_reclen > i || DIRSIZ(ep) > ep->d_reclen ||
209 		    dirchk && (ep->d_namlen > MAXNAMLEN || dirbadname(ep))) {
210 			dirbad(dp, "mangled entry");
211 			u.u_offset += i;
212 			entryoffsetinblock += i;
213 			continue;
214 		}
215 
216 		/*
217 		 * If an appropriate sized slot has not yet been found,
218 		 * check to see if one is available. Also accumulate space
219 		 * in the current block so that we can determine if
220 		 * compaction is viable.
221 		 */
222 		if (slotstatus != FOUND) {
223 			int size = ep->d_reclen;
224 
225 			if (ep->d_ino != 0)
226 				size -= DIRSIZ(ep);
227 			if (size > 0) {
228 				if (size >= slotneeded) {
229 					slotstatus = FOUND;
230 					slotoffset = u.u_offset;
231 					slotsize = ep->d_reclen;
232 				} else if (slotstatus == NONE) {
233 					slotfreespace += size;
234 					if (slotoffset == -1)
235 						slotoffset = u.u_offset;
236 					if (slotfreespace >= slotneeded) {
237 						slotstatus = COMPACT;
238 						slotsize =
239 						    u.u_offset+ep->d_reclen -
240 						      slotoffset;
241 					}
242 				}
243 			}
244 		}
245 
246 		/*
247 		 * Check for a name match.
248 		 */
249 		if (ep->d_ino) {
250 			if (ep->d_namlen == u.u_dent.d_namlen &&
251 			    !bcmp(u.u_dent.d_name, ep->d_name, ep->d_namlen))
252 				goto found;
253 		}
254 		prevoff = u.u_offset;
255 		u.u_offset += ep->d_reclen;
256 		entryoffsetinblock += ep->d_reclen;
257 	}
258 /* notfound: */
259 	/*
260 	 * If creating, and at end of pathname and current
261 	 * directory has not been removed, then can consider allowing
262 	 * file to be created.
263 	 */
264 	if (flag == 1 && *cp == 0 && dp->i_nlink != 0) {
265 		/*
266 		 * Access for write is interpreted as allowing
267 		 * creation of files in the directory.
268 		 */
269 		if (access(dp, IWRITE))
270 			goto bad;
271 		/*
272 		 * Return an indication of where the new directory
273 		 * entry should be put.  If we didn't find a slot,
274 		 * then set u.u_count to 0 indicating that the
275 		 * new slot belongs at the end of the directory.
276 		 * If we found a slot, then the new entry can be
277 		 * put in the range [u.u_offset..u.u_offset+u.u_count)
278 		 */
279 		if (slotstatus == NONE)
280 			u.u_count = 0;
281 		else {
282 			u.u_offset = slotoffset;
283 			u.u_count = slotsize;
284 		}
285 		dp->i_flag |= IUPD|ICHG;
286 		if (bp)
287 			brelse(bp);
288 		brelse(nbp);
289 		/*
290 		 * We return with the directory locked, so that
291 		 * the parameters we set up above will still be
292 		 * valid if we actually decide to do a direnter().
293 		 * We return NULL to indicate that the entry doesn't
294 		 * currently exist, leaving a pointer to the (locked)
295 		 * directory inode in u.u_pdir.
296 		 */
297 		u.u_pdir = dp;
298 		return (NULL);
299 	}
300 	u.u_error = ENOENT;
301 	goto bad;
302 found:
303 	/*
304 	 * Check that directory length properly reflects presence
305 	 * of this entry.
306 	 */
307 	if (entryoffsetinblock + DIRSIZ(ep) > dp->i_size) {
308 		dirbad(dp, "i_size too small");
309 		dp->i_size = entryoffsetinblock + DIRSIZ(ep);
310 		dp->i_flag |= IUPD|ICHG;
311 	}
312 
313 	/*
314 	 * Found component in pathname; save directory
315 	 * entry in u.u_dent, and release directory buffer.
316 	 */
317 	bcopy((caddr_t)ep, (caddr_t)&u.u_dent, (u_int)DIRSIZ(ep));
318 	brelse(bp);
319 	bp = NULL;
320 
321 	/*
322 	 * If deleting, and at end of pathname, return
323 	 * parameters which can be used to remove file.
324 	 * Note that in this case we return the directory
325 	 * inode, not the inode of the file being deleted.
326 	 */
327 	if (flag == 2 && *cp == 0) {
328 		/*
329 		 * Write access to directory required to delete files.
330 		 */
331 		if (access(dp, IWRITE))
332 			goto bad;
333 		/*
334 		 * Return pointer to current entry in u.u_offset,
335 		 * and distance past previous entry (if there
336 		 * is a previous entry in this block) in u.u_count.
337 		 * Save directory inode pointer in u.u_pdir for dirremove().
338 		 */
339 		if ((u.u_offset&(DIRBLKSIZ-1)) == 0)
340 			u.u_count = 0;
341 		else
342 			u.u_count = u.u_offset - prevoff;
343 		brelse(nbp);
344 		u.u_pdir = dp;		/* for dirremove() */
345 		return (dp);
346 	}
347 
348 	/*
349 	 * Special handling for ".." allowing chdir out of mounted
350 	 * file system: indirect .. in root inode to reevaluate
351 	 * in directory file system was mounted on.
352 	 */
353 	if (u.u_dent.d_name[0] == '.' && u.u_dent.d_name[1] == '.' &&
354 	    u.u_dent.d_name[2] == '\0') {
355 		if (dp == u.u_rdir)
356 			u.u_dent.d_ino = dp->i_number;
357 		else if (u.u_dent.d_ino == ROOTINO &&
358 		   dp->i_number == ROOTINO) {
359 			for (i = 1; i < NMOUNT; i++)
360 			if (mount[i].m_bufp != NULL &&
361 			   mount[i].m_dev == dp->i_dev) {
362 				iput(dp);
363 				dp = mount[i].m_inodp;
364 				ilock(dp);
365 				dp->i_count++;
366 				fs = dp->i_fs;
367 				cp -= 2;     /* back over .. */
368 				goto dirloop2;
369 			}
370 		}
371 	}
372 
373 	/*
374 	 * Check for symbolic link, which may require us
375 	 * to massage the name before we continue translation.
376 	 * To avoid deadlock have to unlock the current directory,
377 	 * but don't iput it because we may need it again (if
378 	 * the symbolic link is relative to .).  Instead save
379 	 * it (unlocked) as pdp.
380 	 */
381 	pdp = dp;
382 	iunlock(pdp);
383 	dp = iget(dp->i_dev, fs, u.u_dent.d_ino);
384 	if (dp == NULL)
385 		goto bad2;
386 	fs = dp->i_fs;
387 
388 	/*
389 	 * Check for symbolic link
390 	 */
391 	if ((dp->i_mode & IFMT) == IFLNK && (follow || *cp == '/')) {
392 		u_int pathlen = strlen(cp) + 1;
393 
394 		if (dp->i_size + pathlen >= MAXPATHLEN - 1 ||
395 		    ++nlink > MAXSYMLINKS) {
396 			u.u_error = ELOOP;
397 			goto bad2;
398 		}
399 		bcopy(cp, nbp->b_un.b_addr + dp->i_size, pathlen);
400 		u.u_error =
401 		    rdwri(UIO_READ, dp, nbp->b_un.b_addr, dp->i_size,
402 			0, 1, (int *)0);
403 		if (u.u_error)
404 			goto bad2;
405 		cp = nbp->b_un.b_addr;
406 		iput(dp);
407 		if (*cp == '/') {
408 			irele(pdp);
409 			while (*cp == '/')
410 				cp++;
411 			if ((dp = u.u_rdir) == NULL)
412 				dp = rootdir;
413 			ilock(dp);
414 			dp->i_count++;
415 		} else {
416 			dp = pdp;
417 			ilock(dp);
418 		}
419 		fs = dp->i_fs;
420 		goto dirloop;
421 	}
422 	irele(pdp);
423 
424 	/*
425 	 * Not a symbolic link.  If more pathname,
426 	 * continue at next component, else return.
427 	 */
428 	if (*cp == '/') {
429 		while (*cp == '/')
430 			cp++;
431 		goto dirloop;
432 	}
433 	brelse(nbp);
434 	return (dp);
435 bad2:
436 	irele(pdp);
437 bad:
438 	if (bp)
439 		brelse(bp);
440 	if (dp)
441 		iput(dp);
442 	brelse(nbp);
443 	return (NULL);
444 }
445 
446 dirbad(ip, how)
447 	struct inode *ip;
448 	char *how;
449 {
450 
451 	printf("%s: bad dir ino %d at offset %d: %s\n",
452 	    ip->i_fs->fs_fsmnt, ip->i_number, u.u_offset, how);
453 }
454 
455 dirbadname(ep)
456 	register struct direct *ep;
457 {
458 	register int i;
459 
460 	for (i = 0; i < ep->d_namlen; i++)
461 		if (ep->d_name[i] == 0)
462 			return (1);
463 	return (ep->d_name[i]);
464 }
465 
466 /*
467  * Write a directory entry after a call to namei, using the parameters
468  * which it left in the u. area.  The argument ip is the inode which
469  * the new directory entry will refer to.  The u. area field u.u_pdir is
470  * a pointer to the directory to be written, which was left locked by
471  * namei.  Remaining parameters (u.u_offset, u.u_count) indicate
472  * how the space for the new entry is to be gotten.
473  */
474 direnter(ip)
475 	struct inode *ip;
476 {
477 	register struct direct *ep, *nep;
478 	struct buf *bp;
479 	int loc, freespace;
480 	u_int dsize, newentrysize;
481 	char *dirbuf;
482 
483 	u.u_dent.d_ino = ip->i_number;
484 	u.u_segflg = 1;
485 	newentrysize = DIRSIZ(&u.u_dent);
486 	if (u.u_count == 0) {
487 		/*
488 		 * If u.u_count is 0, then namei could find no space in the
489 		 * directory.  In this case u.u_offset will be on a directory
490 		 * block boundary and we will write the new entry into a fresh
491 		 * block.
492 		 */
493 		if (u.u_offset&(DIRBLKSIZ-1))
494 			panic("wdir: newblk");
495 		u.u_dent.d_reclen = DIRBLKSIZ;
496 		(void) rdwri(UIO_WRITE, u.u_pdir, (caddr_t)&u.u_dent, newentrysize,
497 		    u.u_offset, 1, (int *)0);
498 		iput(u.u_pdir);
499 		return;
500 	}
501 
502 	/*
503 	 * If u.u_count is non-zero, then namei found space for the
504 	 * new entry in the range u.u_offset to u.u_offset+u.u_count.
505 	 * in the directory.  To use this space, we may have to compact
506 	 * the entries located there, by copying them together towards
507 	 * the beginning of the block, leaving the free space in
508 	 * one usable chunk at the end.
509 	 */
510 
511 	/*
512 	 * Increase size of directory if entry eats into new space.
513 	 * This should never push the size past a new multiple of
514 	 * DIRBLKSIZE.
515 	 */
516 	if (u.u_offset+u.u_count > u.u_pdir->i_size) {
517 /*ZZ*/		if (((u.u_offset+u.u_count-1)&~(DIRBLKSIZ-1)) !=
518 /*ZZ*/		    ((u.u_pdir->i_size-1)&~(DIRBLKSIZ-1))) {
519 /*ZZ*/			panic("wdir: span");
520 /*ZZ*/		}
521 		u.u_pdir->i_size = u.u_offset + u.u_count;
522 	}
523 
524 	/*
525 	 * Get the block containing the space for the new directory
526 	 * entry.
527 	 */
528 	bp = blkatoff(u.u_pdir, u.u_offset, (char **)&dirbuf);
529 	if (bp == 0)
530 		return;
531 
532 	/*
533 	 * Find space for the new entry.  In the simple case, the
534 	 * entry at offset base will have the space.  If it does
535 	 * not, then namei arranged that compacting the region
536 	 * u.u_offset to u.u_offset+u.u_count would yield the space.
537 	 */
538 	ep = (struct direct *)dirbuf;
539 	dsize = DIRSIZ(ep);
540 	freespace = ep->d_reclen - dsize;
541 	for (loc = ep->d_reclen; loc < u.u_count; ) {
542 		nep = (struct direct *)(dirbuf + loc);
543 		if (ep->d_ino) {
544 			/* trim the existing slot */
545 			ep->d_reclen = dsize;
546 			ep = (struct direct *)((char *)ep + dsize);
547 		} else {
548 			/* overwrite; nothing there; header is ours */
549 			freespace += dsize;
550 		}
551 		dsize = DIRSIZ(nep);
552 		freespace += nep->d_reclen - dsize;
553 		loc += nep->d_reclen;
554 /*ZZ*/if((loc&~0x1ff)!=(loc+nep->d_reclen-1&~0x1ff))
555 /*ZZ*/printf("wdir: compact loc %d reclen %d (dir %s/%d)\n",loc,nep->d_reclen,
556 /*ZZ*/u.u_pdir->i_fs->fs_fsmnt,u.u_pdir->i_number);
557 		bcopy((caddr_t)nep, (caddr_t)ep, dsize);
558 	}
559 	/*
560 	 * Update the pointer fields in the previous entry (if any),
561 	 * copy in the new entry, and write out the block.
562 	 */
563 	if (ep->d_ino == 0) {
564 		if (freespace + dsize < newentrysize)
565 			panic("wdir: compact1");
566 /*ZZ*/if(freespace+dsize>512)panic("wdir: compact screwup");
567 		u.u_dent.d_reclen = freespace + dsize;
568 	} else {
569 		if (freespace < newentrysize)
570 			panic("wdir: compact2");
571 		u.u_dent.d_reclen = freespace;
572 /*ZZ*/if ((((char *)ep-bp->b_un.b_addr)&0x1ff)+dsize>512) panic("wdir: reclen");
573 		ep->d_reclen = dsize;
574 		ep = (struct direct *)((char *)ep + dsize);
575 	}
576 /*ZZ*/if((((char*)ep-bp->b_un.b_addr)&0x1ff)+u.u_dent.d_reclen>512)panic("wdir: botch");
577 	bcopy(&u.u_dent, ep, newentrysize);
578 	bwrite(bp);
579 	u.u_pdir->i_flag |= IUPD|ICHG;
580 	iput(u.u_pdir);
581 }
582 
583 dirremove()
584 {
585 	register struct inode *dp = u.u_pdir;
586 	register struct buf *bp;
587 	struct direct *ep;
588 
589 	if (u.u_count == 0) {
590 		/*
591 		 * First entry in block: set d_ino to zero.
592 		 */
593 /*ZZ*/if(u.u_offset&0x1ff)printf("missed dir compact dir %s/%d off %d file %s\n"
594 /*ZZ*/,dp->i_fs->fs_fsmnt,dp->i_number,u.u_offset,u.u_dent.d_name);
595 		u.u_dent.d_ino = 0;
596 		(void) rdwri(UIO_WRITE, dp, (caddr_t)&u.u_dent, DIRSIZ(&u.u_dent),
597 		    u.u_offset, 1, (int *)0);
598 	} else {
599 		/*
600 		 * Collapse new free space into previous entry.
601 		 */
602 		bp = blkatoff(dp, (int)(u.u_offset - u.u_count), (char **)&ep);
603 		if (bp == 0)
604 			return (0);
605 		ep->d_reclen += u.u_dent.d_reclen;
606 /*ZZ*/if((((char *)ep - bp->b_un.b_addr)&0x1ff)+u.u_dent.d_reclen > 512)
607 /*ZZ*/	panic("unlink: reclen");
608 		bwrite(bp);
609 		dp->i_flag |= IUPD|ICHG;
610 	}
611 	return (1);
612 }
613 
614 /*
615  * Return buffer with contents of block "offset"
616  * from the beginning of directory "ip".  If "res"
617  * is non-zero, fill it in with a pointer to the
618  * remaining space in the directory.
619  */
620 struct buf *
621 blkatoff(ip, offset, res)
622 	struct inode *ip;
623 	off_t offset;
624 	char **res;
625 {
626 	register struct fs *fs = ip->i_fs;
627 	int lbn = lblkno(fs, offset);
628 	int base = blkoff(fs, offset);
629 	int bsize = blksize(fs, ip, lbn);
630 	int bn = fsbtodb(fs, bmap(ip, lbn, B_WRITE, base, bsize));
631 	register struct buf *bp;
632 
633 	if (u.u_error)
634 		return (0);
635 	bp = bread(ip->i_dev, bn, bsize);
636 	if (bp->b_flags & B_ERROR) {
637 		brelse(bp);
638 		return (0);
639 	}
640 	if (res)
641 		*res = bp->b_un.b_addr + base;
642 	return (bp);
643 }
644