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