xref: /original-bsd/sys/ufs/ffs/ufs_lookup.c (revision 31213361)
1 /*	ufs_lookup.c	4.11	82/03/06	*/
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&0377) == ('/'|0200)) {
45 			u.u_error = EPERM;
46 			break;
47 		}
48 #ifdef notdef
49 		if (*cp++&0200 && flag==1 || cp >= nbp->b_un.b_addr+BSIZE) {
50 #else
51 		cp++;
52 		if (cp >= nbp->b_un.b_addr+BSIZE) {
53 #endif
54 			u.u_error = ENOENT;
55 			break;
56 		}
57 	}
58 	if (u.u_error) {
59 		dp = NULL;
60 		goto out1;
61 	}
62 	cp = nbp->b_un.b_addr;
63 	/*
64 	 * If name starts with '/' start from
65 	 * root; otherwise start from current dir.
66 	 */
67 	dp = u.u_cdir;
68 	if (*cp == '/') {
69 		while (*cp == '/')
70 			cp++;
71 		if ((dp = u.u_rdir) == NULL)
72 			dp = rootdir;
73 	}
74 	ilock(dp);
75 	dp->i_count++;
76 
77 	/*
78 	 * dp must be a directory and
79 	 * must have X permission.
80 	 * cp is a path name relative to that directory.
81 	 */
82 
83 dirloop:
84 	if ((dp->i_mode&IFMT) != IFDIR)
85 		u.u_error = ENOTDIR;
86 	(void) access(dp, IEXEC);
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 dirloop;
179 					}
180 			}
181 		}
182 		d = dp->i_dev;
183 		ino = dp->i_number;
184 		irele(dp);
185 		pdp = dp;
186 		dp = iget(d, u.u_dent.d_ino);
187 		if (dp == NULL)  {
188 			iput(pdp);
189 			goto out1;
190 		}
191 		/*
192 		 * Check for symbolic link
193 		 */
194 		if ((dp->i_mode&IFMT)==IFLNK && (follow || *cp=='/')) {
195 			char *ocp;
196 
197 			ocp = cp;
198 			while (*cp++)
199 				;
200 			if (dp->i_size + (cp-ocp) >= BSIZE-1 || ++nlink>8) {
201 				u.u_error = ELOOP;
202 				iput(pdp);
203 				goto out;
204 			}
205 			bcopy(ocp, nbp->b_un.b_addr+dp->i_size, 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, 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