xref: /csrg-svn/sys/kern/vfs_lookup.c (revision 3113)
1 /*	vfs_lookup.c	4.5	81/03/09	*/
2 
3 #include "../h/param.h"
4 #include "../h/systm.h"
5 #include "../h/inode.h"
6 #include "../h/mount.h"
7 #include "../h/dir.h"
8 #include "../h/user.h"
9 #include "../h/buf.h"
10 #include "../h/conf.h"
11 
12 /*
13  * Convert a pathname into a pointer to
14  * an inode. Note that the inode is locked.
15  *
16  * func = function called to get next char of name
17  *	&uchar if name is in user space
18  *	&schar if name is in system space
19  * flag = 0 if name is sought
20  *	1 if name is to be created
21  *	2 if name is to be deleted
22  */
23 struct inode *
24 namei(func, flag)
25 int (*func)();
26 {
27 	register struct inode *dp;
28 	register c;
29 	register char *cp;
30 	struct buf *bp;
31 	register struct direct *ep;
32 	int i;
33 	dev_t d;
34 	off_t eo;
35 
36 	/*
37 	 * If name starts with '/' start from
38 	 * root; otherwise start from current dir.
39 	 */
40 
41 	dp = u.u_cdir;
42 	if((c=(*func)()) == '/')
43 		if ((dp = u.u_rdir) == NULL)
44 			dp = rootdir;
45 	(void) iget(dp->i_dev, dp->i_number);
46 	while(c == '/')
47 		c = (*func)();
48 	if(c == '\0' && flag != 0)
49 		u.u_error = ENOENT;
50 
51 cloop:
52 	/*
53 	 * Here dp contains pointer
54 	 * to last component matched.
55 	 */
56 
57 	if(u.u_error)
58 		goto out;
59 	if(c == '\0')
60 		return(dp);
61 
62 	/*
63 	 * If there is another component,
64 	 * Gather up name into
65 	 * users' dir buffer.
66 	 */
67 
68 	cp = &u.u_dbuf[0];
69 	while (c != '/' && c != '\0' && u.u_error == 0 ) {
70 		if (mpxip!=NULL && c=='!')
71 			break;
72 		if (flag==1 && c == ('/'|0200)) {
73 			u.u_error = ENOENT;
74 			goto out;
75 		}
76 		if (cp < &u.u_dbuf[DIRSIZ])
77 			*cp++ = c;
78 		c = (*func)();
79 	}
80 	while(cp < &u.u_dbuf[DIRSIZ])
81 		*cp++ = '\0';
82 	while(c == '/')
83 		c = (*func)();
84 	if (c == '!' && mpxip != NULL) {
85 		iput(dp);
86 		plock(mpxip);
87 		mpxip->i_count++;
88 		return(mpxip);
89 	}
90 
91 seloop:
92 	/*
93 	 * dp must be a directory and
94 	 * must have X permission.
95 	 */
96 
97 	if((dp->i_mode&IFMT) != IFDIR)
98 		u.u_error = ENOTDIR;
99 	(void) access(dp, IEXEC);
100 	if(u.u_error)
101 		goto out;
102 
103 	/*
104 	 * set up to search a directory
105 	 */
106 	u.u_offset = 0;
107 	u.u_segflg = 1;
108 	eo = 0;
109 	bp = NULL;
110 	if (dp == u.u_rdir && u.u_dent.d_name[0] == '.' &&
111 	    u.u_dent.d_name[1] == '.' && u.u_dent.d_name[2] == 0)
112 		goto cloop;
113 
114 eloop:
115 
116 	/*
117 	 * If at the end of the directory,
118 	 * the search failed. Report what
119 	 * is appropriate as per flag.
120 	 */
121 
122 	if(u.u_offset >= dp->i_size) {
123 		if(bp != NULL)
124 			brelse(bp);
125 		if(flag==1 && c=='\0' && dp->i_nlink) {
126 			if(access(dp, IWRITE))
127 				goto out;
128 			u.u_pdir = dp;
129 			if(eo)
130 				u.u_offset = eo-sizeof(struct direct);
131 			else
132 				dp->i_flag |= IUPD|ICHG;
133 			return(NULL);
134 		}
135 		u.u_error = ENOENT;
136 		goto out;
137 	}
138 
139 	/*
140 	 * If offset is on a block boundary,
141 	 * read the next directory block.
142 	 * Release previous if it exists.
143 	 */
144 
145 	if((u.u_offset&BMASK) == 0) {
146 		if(bp != NULL)
147 			brelse(bp);
148 		bp = bread(dp->i_dev,
149 			bmap(dp, (daddr_t)(u.u_offset>>BSHIFT), B_READ));
150 		if (bp->b_flags & B_ERROR) {
151 			brelse(bp);
152 			goto out;
153 		}
154 		ep = (struct direct *)bp->b_un.b_addr;
155 	} else
156 		ep++;
157 
158 	/*
159 	 * Note first empty directory slot
160 	 * in eo for possible creat.
161 	 * String compare the directory entry
162 	 * and the current component.
163 	 * If they do not match, go back to eloop.
164 	 */
165 
166 	u.u_offset += sizeof(struct direct);
167 	if(ep->d_ino == 0) {
168 		if(eo == 0)
169 			eo = u.u_offset;
170 		goto eloop;
171 	}
172 	for(i=0; i<DIRSIZ; i++) {
173 		if(u.u_dbuf[i] != ep->d_name[i])
174 			goto eloop;
175 		if(u.u_dbuf[i] == 0)
176 			break;
177 	}
178 
179 	/*
180 	 * Here a component matched in a directory.
181 	 * If there is more pathname, go back to
182 	 * cloop, otherwise return.
183 	 */
184 	bcopy((caddr_t)ep, (caddr_t)&u.u_dent, sizeof(struct direct));
185 	if(bp != NULL)
186 		brelse(bp);
187 	if(flag==2 && c=='\0') {
188 		if(access(dp, IWRITE))
189 			goto out;
190 		return(dp);
191 	}
192 	d = dp->i_dev;
193 	if(u.u_dent.d_ino == ROOTINO)
194 	if(dp->i_number == ROOTINO)
195 	if(u.u_dent.d_name[1] == '.')
196 		for(i=1; i<NMOUNT; i++)
197 			if(mount[i].m_bufp != NULL)
198 			if(mount[i].m_dev == d) {
199 				iput(dp);
200 				dp = mount[i].m_inodp;
201 				dp->i_count++;
202 				plock(dp);
203 				goto seloop;
204 			}
205 	iput(dp);
206 	dp = iget(d, u.u_dent.d_ino);
207 	if(dp == NULL)
208 		return(NULL);
209 	goto cloop;
210 
211 out:
212 	iput(dp);
213 	return(NULL);
214 }
215 
216 /*
217  * Return the next character from the
218  * kernel string pointed at by dirp.
219  */
220 schar()
221 {
222 
223 	return(*u.u_dirp++ & 0377);
224 }
225 
226 /*
227  * Return the next character from the
228  * user string pointed at by dirp.
229  */
230 uchar()
231 {
232 	register c;
233 
234 	c = fubyte(u.u_dirp++);
235 	if(c == -1)
236 		u.u_error = EFAULT;
237 	return(c);
238 }
239