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