xref: /original-bsd/sys/ufs/ufs/ufs_lookup.c (revision f4ab8a4c)
1 /*	ufs_lookup.c	4.13	82/03/13	*/
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,
204 			  (unsigned)(cp-ocp));
205 			bp = bread(dp->i_dev, bmap(dp, (daddr_t)0, B_READ));
206 			if (bp->b_flags & B_ERROR) {
207 				brelse(bp);
208 				iput(pdp);
209 				goto out;
210 			}
211 			bcopy(bp->b_un.b_addr, nbp->b_un.b_addr,
212 			  (unsigned)dp->i_size);
213 			brelse(bp);
214 			cp = nbp->b_un.b_addr;
215 			iput(dp);
216 			if (*cp == '/') {
217 				iput(pdp);
218 				while (*cp == '/')
219 					cp++;
220 				if ((dp = u.u_rdir) == NULL)
221 					dp = rootdir;
222 				ilock(dp);
223 				dp->i_count++;
224 			} else {
225 				dp = pdp;
226 				ilock(dp);
227 			}
228 			goto dirloop;
229 		}
230 		iput(pdp);
231 		if (*cp == '/') {
232 			while (*cp == '/')
233 				cp++;
234 			goto dirloop;
235 		}
236 		goto out1;
237 	}
238 	/*
239 	 * Search failed.
240 	 */
241 	if (bp != NULL)
242 		brelse(bp);
243 	if (flag==1 && *cp=='\0' && dp->i_nlink) {
244 		if (access(dp, IWRITE))
245 			goto out;
246 		if (eo>=0)
247 			u.u_offset = eo;
248 		dp->i_flag |= IUPD|ICHG;
249 		dp = NULL;
250 		goto out1;
251 	}
252 	u.u_error = ENOENT;
253 out:
254 	iput(dp);
255 	dp = NULL;
256 out1:
257 	brelse(nbp);
258 	return (dp);
259 }
260 
261 /*
262  * Return the next character from the
263  * kernel string pointed at by dirp.
264  */
265 schar()
266 {
267 
268 	return (*u.u_dirp++ & 0377);
269 }
270 
271 /*
272  * Return the next character from the
273  * user string pointed at by dirp.
274  */
275 uchar()
276 {
277 	register c;
278 
279 	c = fubyte(u.u_dirp++);
280 	if (c == -1) {
281 		u.u_error = EFAULT;
282 		c = 0;
283 	}
284 	return (c);
285 }
286 
287 #ifndef vax
288 strncmp(s1, s2, len)
289 	register char *s1, *s2;
290 	register len;
291 {
292 
293 	do {
294 		if (*s1 != *s2++)
295 			return (1);
296 		if (*s1++ == '\0')
297 			return (0);
298 	} while (--len);
299 	return (0);
300 }
301 #endif
302