xref: /original-bsd/sys/kern/vfs_lookup.c (revision de655a82)
1 /*	vfs_lookup.c	4.7	81/05/18	*/
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 #ifdef CHAOS
63 	/*
64 	 *      If the current node is a character
65 	 *      special file with the SUID bit set, return anyway.
66 	 *	This lets the Chaos open decode the rest of the name in its own
67 	 *      peculiar way.  jrl 3/81
68 	 */
69 	if((dp->i_mode&(IFMT|ISUID)) == (IFCHR|ISUID)) {
70 		u.u_dirp--;     /* back up to the slash or null */
71 		return(dp);
72 	}
73 #endif
74 
75 	/*
76 	 * If there is another component,
77 	 * Gather up name into
78 	 * users' dir buffer.
79 	 */
80 
81 	cp = &u.u_dbuf[0];
82 	while (c != '/' && c != '\0' && u.u_error == 0 ) {
83 		if (mpxip!=NULL && c=='!')
84 			break;
85 		if (flag==1 && c == ('/'|0200)) {
86 			u.u_error = ENOENT;
87 			goto out;
88 		}
89 		if (cp < &u.u_dbuf[DIRSIZ])
90 			*cp++ = c;
91 		c = (*func)();
92 	}
93 	while(cp < &u.u_dbuf[DIRSIZ])
94 		*cp++ = '\0';
95 	while(c == '/')
96 		c = (*func)();
97 	if (c == '!' && mpxip != NULL) {
98 		iput(dp);
99 		plock(mpxip);
100 		mpxip->i_count++;
101 		return(mpxip);
102 	}
103 
104 seloop:
105 	/*
106 	 * dp must be a directory and
107 	 * must have X permission.
108 	 */
109 
110 	if((dp->i_mode&IFMT) != IFDIR)
111 		u.u_error = ENOTDIR;
112 	(void) access(dp, IEXEC);
113 	if(u.u_error)
114 		goto out;
115 
116 	/*
117 	 * set up to search a directory
118 	 */
119 	u.u_offset = 0;
120 	u.u_segflg = 1;
121 	eo = 0;
122 	bp = NULL;
123 	if (dp == u.u_rdir && u.u_dbuf[0] == '.' &&
124 	    u.u_dbuf[1] == '.' && u.u_dbuf[2] == 0)
125 		goto cloop;
126 
127 eloop:
128 
129 	/*
130 	 * If at the end of the directory,
131 	 * the search failed. Report what
132 	 * is appropriate as per flag.
133 	 */
134 
135 	if(u.u_offset >= dp->i_size) {
136 		if(bp != NULL)
137 			brelse(bp);
138 		if(flag==1 && c=='\0' && dp->i_nlink) {
139 			if(access(dp, IWRITE))
140 				goto out;
141 			u.u_pdir = dp;
142 			if(eo)
143 				u.u_offset = eo-sizeof(struct direct);
144 			else
145 				dp->i_flag |= IUPD|ICHG;
146 			return(NULL);
147 		}
148 		u.u_error = ENOENT;
149 		goto out;
150 	}
151 
152 	/*
153 	 * If offset is on a block boundary,
154 	 * read the next directory block.
155 	 * Release previous if it exists.
156 	 */
157 
158 	if((u.u_offset&BMASK) == 0) {
159 		if(bp != NULL)
160 			brelse(bp);
161 		bp = bread(dp->i_dev,
162 			bmap(dp, (daddr_t)(u.u_offset>>BSHIFT), B_READ));
163 		if (bp->b_flags & B_ERROR) {
164 			brelse(bp);
165 			goto out;
166 		}
167 		ep = (struct direct *)bp->b_un.b_addr;
168 	} else
169 		ep++;
170 
171 	/*
172 	 * Note first empty directory slot
173 	 * in eo for possible creat.
174 	 * String compare the directory entry
175 	 * and the current component.
176 	 * If they do not match, go back to eloop.
177 	 */
178 
179 	u.u_offset += sizeof(struct direct);
180 	if(ep->d_ino == 0) {
181 		if(eo == 0)
182 			eo = u.u_offset;
183 		goto eloop;
184 	}
185 	for(i=0; i<DIRSIZ; i++) {
186 		if(u.u_dbuf[i] != ep->d_name[i])
187 			goto eloop;
188 		if(u.u_dbuf[i] == 0)
189 			break;
190 	}
191 
192 	/*
193 	 * Here a component matched in a directory.
194 	 * If there is more pathname, go back to
195 	 * cloop, otherwise return.
196 	 */
197 	bcopy((caddr_t)ep, (caddr_t)&u.u_dent, sizeof(struct direct));
198 	if(bp != NULL)
199 		brelse(bp);
200 	if(flag==2 && c=='\0') {
201 		if(access(dp, IWRITE))
202 			goto out;
203 		return(dp);
204 	}
205 	d = dp->i_dev;
206 	if(u.u_dent.d_ino == ROOTINO)
207 	if(dp->i_number == ROOTINO)
208 	if(u.u_dent.d_name[1] == '.')
209 		for(i=1; i<NMOUNT; i++)
210 			if(mount[i].m_bufp != NULL)
211 			if(mount[i].m_dev == d) {
212 				iput(dp);
213 				dp = mount[i].m_inodp;
214 				dp->i_count++;
215 				plock(dp);
216 				goto seloop;
217 			}
218 	iput(dp);
219 	dp = iget(d, u.u_dent.d_ino);
220 	if(dp == NULL)
221 		return(NULL);
222 	goto cloop;
223 
224 out:
225 	iput(dp);
226 	return(NULL);
227 }
228 
229 /*
230  * Return the next character from the
231  * kernel string pointed at by dirp.
232  */
233 schar()
234 {
235 
236 	return(*u.u_dirp++ & 0377);
237 }
238 
239 /*
240  * Return the next character from the
241  * user string pointed at by dirp.
242  */
243 uchar()
244 {
245 	register c;
246 
247 	c = fubyte(u.u_dirp++);
248 	if(c == -1)
249 		u.u_error = EFAULT;
250 	return(c);
251 }
252