xref: /original-bsd/sys/kern/vfs_lookup.c (revision 55330032)
1 /*	vfs_lookup.c	4.2	11/09/80	*/
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 
11 /*
12  * Convert a pathname into a pointer to
13  * an inode. Note that the inode is locked.
14  *
15  * func = function called to get next char of name
16  *	&uchar if name is in user space
17  *	&schar if name is in system space
18  * flag = 0 if name is sought
19  *	1 if name is to be created
20  *	2 if name is to be deleted
21  */
22 struct inode *
23 namei(func, flag)
24 int (*func)();
25 {
26 	register struct inode *dp;
27 	register c;
28 	register char *cp;
29 	struct buf *bp;
30 	register struct direct *ep;
31 	int i;
32 	dev_t d;
33 	off_t eo;
34 
35 	/*
36 	 * If name starts with '/' start from
37 	 * root; otherwise start from current dir.
38 	 */
39 
40 	dp = u.u_cdir;
41 	if((c=(*func)()) == '/')
42 		if ((dp = u.u_rdir) == NULL)
43 			dp = rootdir;
44 	(void) iget(dp->i_dev, dp->i_number);
45 	while(c == '/')
46 		c = (*func)();
47 	if(c == '\0' && flag != 0)
48 		u.u_error = ENOENT;
49 
50 cloop:
51 	/*
52 	 * Here dp contains pointer
53 	 * to last component matched.
54 	 */
55 
56 	if(u.u_error)
57 		goto out;
58 	if(c == '\0')
59 		return(dp);
60 
61 	/*
62 	 * If there is another component,
63 	 * Gather up name into
64 	 * users' dir buffer.
65 	 */
66 
67 	cp = &u.u_dbuf[0];
68 	while (c != '/' && c != '\0' && u.u_error == 0 ) {
69 		if (mpxip!=NULL && c=='!')
70 			break;
71 		if (flag==1 && c == ('/'|0200)) {
72 			u.u_error = ENOENT;
73 			goto out;
74 		}
75 		if (cp < &u.u_dbuf[DIRSIZ])
76 			*cp++ = c;
77 		c = (*func)();
78 	}
79 	while(cp < &u.u_dbuf[DIRSIZ])
80 		*cp++ = '\0';
81 	while(c == '/')
82 		c = (*func)();
83 	if (c == '!' && mpxip != NULL) {
84 		iput(dp);
85 		plock(mpxip);
86 		mpxip->i_count++;
87 		return(mpxip);
88 	}
89 
90 seloop:
91 	/*
92 	 * dp must be a directory and
93 	 * must have X permission.
94 	 */
95 
96 	if((dp->i_mode&IFMT) != IFDIR)
97 		u.u_error = ENOTDIR;
98 	(void) access(dp, IEXEC);
99 	if(u.u_error)
100 		goto out;
101 
102 	/*
103 	 * set up to search a directory
104 	 */
105 	u.u_offset = 0;
106 	u.u_segflg = 1;
107 	eo = 0;
108 	bp = NULL;
109 
110 eloop:
111 
112 	/*
113 	 * If at the end of the directory,
114 	 * the search failed. Report what
115 	 * is appropriate as per flag.
116 	 */
117 
118 	if(u.u_offset >= dp->i_size) {
119 		if(bp != NULL)
120 			brelse(bp);
121 		if(flag==1 && c=='\0' && dp->i_nlink) {
122 			if(access(dp, IWRITE))
123 				goto out;
124 			u.u_pdir = dp;
125 			if(eo)
126 				u.u_offset = eo-sizeof(struct direct);
127 			else
128 				dp->i_flag |= IUPD|ICHG;
129 			return(NULL);
130 		}
131 		u.u_error = ENOENT;
132 		goto out;
133 	}
134 
135 	/*
136 	 * If offset is on a block boundary,
137 	 * read the next directory block.
138 	 * Release previous if it exists.
139 	 */
140 
141 	if((u.u_offset&BMASK) == 0) {
142 		if(bp != NULL)
143 			brelse(bp);
144 		bp = bread(dp->i_dev,
145 			bmap(dp, (daddr_t)(u.u_offset>>BSHIFT), B_READ));
146 		if (bp->b_flags & B_ERROR) {
147 			brelse(bp);
148 			goto out;
149 		}
150 		ep = (struct direct *)bp->b_un.b_addr;
151 	} else
152 		ep++;
153 
154 	/*
155 	 * Note first empty directory slot
156 	 * in eo for possible creat.
157 	 * String compare the directory entry
158 	 * and the current component.
159 	 * If they do not match, go back to eloop.
160 	 */
161 
162 	u.u_offset += sizeof(struct direct);
163 	if(ep->d_ino == 0) {
164 		if(eo == 0)
165 			eo = u.u_offset;
166 		goto eloop;
167 	}
168 	for(i=0; i<DIRSIZ; i++) {
169 		if(u.u_dbuf[i] != ep->d_name[i])
170 			goto eloop;
171 		if(u.u_dbuf[i] == 0)
172 			break;
173 	}
174 
175 	/*
176 	 * Here a component matched in a directory.
177 	 * If there is more pathname, go back to
178 	 * cloop, otherwise return.
179 	 */
180 	bcopy((caddr_t)ep, (caddr_t)&u.u_dent, sizeof(struct direct));
181 	if(bp != NULL)
182 		brelse(bp);
183 	if(flag==2 && c=='\0') {
184 		if(access(dp, IWRITE))
185 			goto out;
186 		return(dp);
187 	}
188 	d = dp->i_dev;
189 	if(u.u_dent.d_ino == ROOTINO)
190 	if(dp->i_number == ROOTINO)
191 	if(u.u_dent.d_name[1] == '.')
192 		for(i=1; i<NMOUNT; i++)
193 			if(mount[i].m_bufp != NULL)
194 			if(mount[i].m_dev == d) {
195 				iput(dp);
196 				dp = mount[i].m_inodp;
197 				dp->i_count++;
198 				plock(dp);
199 				goto seloop;
200 			}
201 	iput(dp);
202 	dp = iget(d, u.u_dent.d_ino);
203 	if(dp == NULL)
204 		return(NULL);
205 	goto cloop;
206 
207 out:
208 	iput(dp);
209 	return(NULL);
210 }
211 
212 /*
213  * Return the next character from the
214  * kernel string pointed at by dirp.
215  */
216 schar()
217 {
218 
219 	return(*u.u_dirp++ & 0377);
220 }
221 
222 /*
223  * Return the next character from the
224  * user string pointed at by dirp.
225  */
226 uchar()
227 {
228 	register c;
229 
230 	c = fubyte(u.u_dirp++);
231 	if(c == -1)
232 		u.u_error = EFAULT;
233 	return(c);
234 }
235