xref: /original-bsd/sys/ufs/ffs/ufs_lookup.c (revision b3b53e97)
1 /*	ufs_lookup.c	4.14	82/03/31	*/
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 dirloop2:
87 	for (i=0; *cp!='\0' && *cp!='/'; i++) {
88 #ifdef notdef
89 		if (i >= DIRSIZ) {
90 			u.u_error = ENOENT;
91 			break;
92 		}
93 		u.u_dbuf[i] = *cp++;
94 #else
95 		if (i < DIRSIZ)
96 			u.u_dbuf[i] = *cp;
97 		cp++;
98 #endif
99 	}
100 	if (u.u_error)
101 		goto out;
102 	u.u_pdir = dp;
103 	while (i < DIRSIZ)
104 		u.u_dbuf[i++] = '\0';
105 	if (u.u_dbuf[0] == '\0') {		/* null name, e.g. "/" or "" */
106 		if (flag) {
107 			u.u_error = ENOENT;
108 			goto out;
109 		}
110 		goto out1;
111 	}
112 	u.u_segflg = 1;
113 	eo = -1;
114 	bp = NULL;
115 
116 	for (u.u_offset=0; u.u_offset < dp->i_size;
117 	   u.u_offset += sizeof(struct direct), ep++) {
118 		/*
119 		 * If offset is on a block boundary,
120 		 * read the next directory block.
121 		 * Release previous if it exists.
122 		 */
123 		if ((u.u_offset&BMASK) == 0) {
124 			if (bp != NULL)
125 				brelse(bp);
126 			bp = bread(dp->i_dev,
127 				bmap(dp,(daddr_t)(u.u_offset>>BSHIFT), B_READ));
128 			if (bp->b_flags & B_ERROR) {
129 				brelse(bp);
130 				goto out;
131 			}
132 			ep = (struct direct *)bp->b_un.b_addr;
133 		}
134 		/*
135 		 * Note first empty directory slot
136 		 * in eo for possible creat.
137 		 * String compare the directory entry
138 		 * and the current component.
139 		 */
140 		if (ep->d_ino == 0) {
141 			if (eo < 0)
142 				eo = u.u_offset;
143 			continue;
144 		}
145 		if (strncmp(u.u_dbuf, ep->d_name, DIRSIZ) != 0)
146 			continue;
147 		/*
148 		 * Here a component matched in a directory.
149 		 * If there is more pathname, go back to
150 		 * dirloop, otherwise return.
151 		 */
152 		bcopy((caddr_t)ep, (caddr_t)&u.u_dent, sizeof(struct direct));
153 		brelse(bp);
154 		if (flag==2 && *cp=='\0') {
155 			if (access(dp, IWRITE))
156 				goto out;
157 			/* should fix unlink */
158 			u.u_offset += sizeof(struct direct);
159 			goto out1;
160 		}
161 		/*
162 		 * Special handling for ".."
163 		 */
164 		if (u.u_dent.d_name[0]=='.' && u.u_dent.d_name[1]=='.' &&
165 		    u.u_dent.d_name[2]=='\0') {
166 			if (dp == u.u_rdir)
167 				u.u_dent.d_ino = dp->i_number;
168 			else if (u.u_dent.d_ino==ROOTINO &&
169 			   dp->i_number == ROOTINO) {
170 				for(i=1; i<NMOUNT; i++)
171 					if (mount[i].m_bufp != NULL &&
172 					   mount[i].m_dev == dp->i_dev) {
173 						iput(dp);
174 						dp = mount[i].m_inodp;
175 						ilock(dp);
176 						dp->i_count++;
177 						cp -= 2;     /* back over .. */
178 						goto dirloop2;
179 					}
180 			}
181 		}
182 		d = dp->i_dev;
183 		irele(dp);
184 		pdp = dp;
185 		dp = iget(d, u.u_dent.d_ino);
186 		if (dp == NULL)  {
187 			iput(pdp);
188 			goto out1;
189 		}
190 		/*
191 		 * Check for symbolic link
192 		 */
193 		if ((dp->i_mode&IFMT)==IFLNK && (follow || *cp=='/')) {
194 			char *ocp;
195 
196 			ocp = cp;
197 			while (*cp++)
198 				;
199 			if (dp->i_size + (cp-ocp) >= BSIZE-1 || ++nlink>8) {
200 				u.u_error = ELOOP;
201 				iput(pdp);
202 				goto out;
203 			}
204 			bcopy(ocp, nbp->b_un.b_addr+dp->i_size,
205 			  (unsigned)(cp-ocp));
206 			bp = bread(dp->i_dev, bmap(dp, (daddr_t)0, B_READ));
207 			if (bp->b_flags & B_ERROR) {
208 				brelse(bp);
209 				iput(pdp);
210 				goto out;
211 			}
212 			bcopy(bp->b_un.b_addr, nbp->b_un.b_addr,
213 			  (unsigned)dp->i_size);
214 			brelse(bp);
215 			cp = nbp->b_un.b_addr;
216 			iput(dp);
217 			if (*cp == '/') {
218 				iput(pdp);
219 				while (*cp == '/')
220 					cp++;
221 				if ((dp = u.u_rdir) == NULL)
222 					dp = rootdir;
223 				ilock(dp);
224 				dp->i_count++;
225 			} else {
226 				dp = pdp;
227 				ilock(dp);
228 			}
229 			goto dirloop;
230 		}
231 		iput(pdp);
232 		if (*cp == '/') {
233 			while (*cp == '/')
234 				cp++;
235 			goto dirloop;
236 		}
237 		goto out1;
238 	}
239 	/*
240 	 * Search failed.
241 	 */
242 	if (bp != NULL)
243 		brelse(bp);
244 	if (flag==1 && *cp=='\0' && dp->i_nlink) {
245 		if (access(dp, IWRITE))
246 			goto out;
247 		if (eo>=0)
248 			u.u_offset = eo;
249 		dp->i_flag |= IUPD|ICHG;
250 		dp = NULL;
251 		goto out1;
252 	}
253 	u.u_error = ENOENT;
254 out:
255 	iput(dp);
256 	dp = NULL;
257 out1:
258 	brelse(nbp);
259 	return (dp);
260 }
261 
262 /*
263  * Return the next character from the
264  * kernel string pointed at by dirp.
265  */
266 schar()
267 {
268 
269 	return (*u.u_dirp++ & 0377);
270 }
271 
272 /*
273  * Return the next character from the
274  * user string pointed at by dirp.
275  */
276 uchar()
277 {
278 	register c;
279 
280 	c = fubyte(u.u_dirp++);
281 	if (c == -1) {
282 		u.u_error = EFAULT;
283 		c = 0;
284 	}
285 	return (c);
286 }
287 
288 #ifndef vax
289 strncmp(s1, s2, len)
290 	register char *s1, *s2;
291 	register len;
292 {
293 
294 	do {
295 		if (*s1 != *s2++)
296 			return (1);
297 		if (*s1++ == '\0')
298 			return (0);
299 	} while (--len);
300 	return (0);
301 }
302 #endif
303