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