xref: /original-bsd/sys/kern/vfs_lookup.c (revision 73d5f1f4)
1 /*	vfs_lookup.c	4.12	82/03/12	*/
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  * a locked inode.
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  * follow = 1 if links are to be followed at the end of the name
23  */
24 struct inode *
25 namei(func, flag, follow)
26 	int (*func)(), flag, follow;
27 {
28 	register struct inode *dp;
29 	register char *cp;
30 	register struct buf *bp, *nbp;
31 	register struct direct *ep;
32 	struct inode *pdp;
33 	int i, nlink;
34 	dev_t d;
35 	off_t eo;
36 
37 	/*
38 	 * allocate name buffer; copy name
39 	 */
40 	nbp = geteblk();
41 	nlink = 0;
42 	for (i=0, cp = nbp->b_un.b_addr; *cp = (*func)(); i++) {
43 		if ((*cp&0377) == ('/'|0200)) {
44 			u.u_error = EPERM;
45 			break;
46 		}
47 #ifdef notdef
48 		if (*cp++&0200 && flag==1 || cp >= nbp->b_un.b_addr+BSIZE) {
49 #else
50 		cp++;
51 		if (cp >= nbp->b_un.b_addr+BSIZE) {
52 #endif
53 			u.u_error = ENOENT;
54 			break;
55 		}
56 	}
57 	if (u.u_error) {
58 		dp = NULL;
59 		goto out1;
60 	}
61 	cp = nbp->b_un.b_addr;
62 	/*
63 	 * If name starts with '/' start from
64 	 * root; otherwise start from current dir.
65 	 */
66 	dp = u.u_cdir;
67 	if (*cp == '/') {
68 		while (*cp == '/')
69 			cp++;
70 		if ((dp = u.u_rdir) == NULL)
71 			dp = rootdir;
72 	}
73 	ilock(dp);
74 	dp->i_count++;
75 
76 	/*
77 	 * dp must be a directory and
78 	 * must have X permission.
79 	 * cp is a path name relative to that directory.
80 	 */
81 
82 dirloop:
83 	if ((dp->i_mode&IFMT) != IFDIR)
84 		u.u_error = ENOTDIR;
85 	(void) access(dp, IEXEC);
86 	for (i=0; *cp!='\0' && *cp!='/'; i++) {
87 #ifdef notdef
88 		if (i >= DIRSIZ) {
89 			u.u_error = ENOENT;
90 			break;
91 		}
92 		u.u_dbuf[i] = *cp++;
93 #else
94 		if (i < DIRSIZ)
95 			u.u_dbuf[i] = *cp;
96 		cp++;
97 #endif
98 	}
99 	if (u.u_error)
100 		goto out;
101 	u.u_pdir = dp;
102 	while (i < DIRSIZ)
103 		u.u_dbuf[i++] = '\0';
104 	if (u.u_dbuf[0] == '\0') {		/* null name, e.g. "/" or "" */
105 		if (flag) {
106 			u.u_error = ENOENT;
107 			goto out;
108 		}
109 		goto out1;
110 	}
111 	u.u_segflg = 1;
112 	eo = -1;
113 	bp = NULL;
114 
115 	for (u.u_offset=0; u.u_offset < dp->i_size;
116 	   u.u_offset += sizeof(struct direct), ep++) {
117 		/*
118 		 * If offset is on a block boundary,
119 		 * read the next directory block.
120 		 * Release previous if it exists.
121 		 */
122 		if ((u.u_offset&BMASK) == 0) {
123 			if (bp != NULL)
124 				brelse(bp);
125 			bp = bread(dp->i_dev,
126 				bmap(dp,(daddr_t)(u.u_offset>>BSHIFT), B_READ));
127 			if (bp->b_flags & B_ERROR) {
128 				brelse(bp);
129 				goto out;
130 			}
131 			ep = (struct direct *)bp->b_un.b_addr;
132 		}
133 		/*
134 		 * Note first empty directory slot
135 		 * in eo for possible creat.
136 		 * String compare the directory entry
137 		 * and the current component.
138 		 */
139 		if (ep->d_ino == 0) {
140 			if (eo < 0)
141 				eo = u.u_offset;
142 			continue;
143 		}
144 		if (strncmp(u.u_dbuf, ep->d_name, DIRSIZ) != 0)
145 			continue;
146 		/*
147 		 * Here a component matched in a directory.
148 		 * If there is more pathname, go back to
149 		 * dirloop, otherwise return.
150 		 */
151 		bcopy((caddr_t)ep, (caddr_t)&u.u_dent, sizeof(struct direct));
152 		brelse(bp);
153 		if (flag==2 && *cp=='\0') {
154 			if (access(dp, IWRITE))
155 				goto out;
156 			/* should fix unlink */
157 			u.u_offset += sizeof(struct direct);
158 			goto out1;
159 		}
160 		/*
161 		 * Special handling for ".."
162 		 */
163 		if (u.u_dent.d_name[0]=='.' && u.u_dent.d_name[1]=='.' &&
164 		    u.u_dent.d_name[2]=='\0') {
165 			if (dp == u.u_rdir)
166 				u.u_dent.d_ino = dp->i_number;
167 			else if (u.u_dent.d_ino==ROOTINO &&
168 			   dp->i_number == ROOTINO) {
169 				for(i=1; i<NMOUNT; i++)
170 					if (mount[i].m_bufp != NULL &&
171 					   mount[i].m_dev == dp->i_dev) {
172 						iput(dp);
173 						dp = mount[i].m_inodp;
174 						ilock(dp);
175 						dp->i_count++;
176 						cp -= 2;     /* back over .. */
177 						goto dirloop;
178 					}
179 			}
180 		}
181 		d = dp->i_dev;
182 		irele(dp);
183 		pdp = dp;
184 		dp = iget(d, u.u_dent.d_ino);
185 		if (dp == NULL)  {
186 			iput(pdp);
187 			goto out1;
188 		}
189 		/*
190 		 * Check for symbolic link
191 		 */
192 		if ((dp->i_mode&IFMT)==IFLNK && (follow || *cp=='/')) {
193 			char *ocp;
194 
195 			ocp = cp;
196 			while (*cp++)
197 				;
198 			if (dp->i_size + (cp-ocp) >= BSIZE-1 || ++nlink>8) {
199 				u.u_error = ELOOP;
200 				iput(pdp);
201 				goto out;
202 			}
203 			bcopy(ocp, nbp->b_un.b_addr+dp->i_size, cp-ocp);
204 			bp = bread(dp->i_dev, bmap(dp, (daddr_t)0, B_READ));
205 			if (bp->b_flags & B_ERROR) {
206 				brelse(bp);
207 				iput(pdp);
208 				goto out;
209 			}
210 			bcopy(bp->b_un.b_addr, nbp->b_un.b_addr, dp->i_size);
211 			brelse(bp);
212 			cp = nbp->b_un.b_addr;
213 			iput(dp);
214 			if (*cp == '/') {
215 				iput(pdp);
216 				while (*cp == '/')
217 					cp++;
218 				if ((dp = u.u_rdir) == NULL)
219 					dp = rootdir;
220 				ilock(dp);
221 				dp->i_count++;
222 			} else {
223 				dp = pdp;
224 				ilock(dp);
225 			}
226 			goto dirloop;
227 		}
228 		iput(pdp);
229 		if (*cp == '/') {
230 			while (*cp == '/')
231 				cp++;
232 			goto dirloop;
233 		}
234 		goto out1;
235 	}
236 	/*
237 	 * Search failed.
238 	 */
239 	if (bp != NULL)
240 		brelse(bp);
241 	if (flag==1 && *cp=='\0' && dp->i_nlink) {
242 		if (access(dp, IWRITE))
243 			goto out;
244 		if (eo>=0)
245 			u.u_offset = eo;
246 		dp->i_flag |= IUPD|ICHG;
247 		dp = NULL;
248 		goto out1;
249 	}
250 	u.u_error = ENOENT;
251 out:
252 	iput(dp);
253 	dp = NULL;
254 out1:
255 	brelse(nbp);
256 	return (dp);
257 }
258 
259 /*
260  * Return the next character from the
261  * kernel string pointed at by dirp.
262  */
263 schar()
264 {
265 
266 	return (*u.u_dirp++ & 0377);
267 }
268 
269 /*
270  * Return the next character from the
271  * user string pointed at by dirp.
272  */
273 uchar()
274 {
275 	register c;
276 
277 	c = fubyte(u.u_dirp++);
278 	if (c == -1) {
279 		u.u_error = EFAULT;
280 		c = 0;
281 	}
282 	return (c);
283 }
284 
285 #ifndef vax
286 strncmp(s1, s2, len)
287 	register char *s1, *s2;
288 	register len;
289 {
290 
291 	do {
292 		if (*s1 != *s2++)
293 			return (1);
294 		if (*s1++ == '\0')
295 			return (0);
296 	} while (--len);
297 	return (0);
298 }
299 #endif
300