xref: /original-bsd/sys/ufs/ffs/ufs_lookup.c (revision cc77da92)
1 /*	ufs_lookup.c	3.4	06/16/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 (cp < &u.u_dbuf[DIRSIZ])
72 			*cp++ = c;
73 		c = (*func)();
74 	}
75 	while(cp < &u.u_dbuf[DIRSIZ])
76 		*cp++ = '\0';
77 	while(c == '/')
78 		c = (*func)();
79 	if (c == '!' && mpxip != NULL) {
80 		iput(dp);
81 		plock(mpxip);
82 		mpxip->i_count++;
83 		return(mpxip);
84 	}
85 
86 seloop:
87 	/*
88 	 * dp must be a directory and
89 	 * must have X permission.
90 	 */
91 
92 	if((dp->i_mode&IFMT) != IFDIR)
93 		u.u_error = ENOTDIR;
94 	(void) access(dp, IEXEC);
95 	if(u.u_error)
96 		goto out;
97 
98 	/*
99 	 * set up to search a directory
100 	 */
101 	u.u_offset = 0;
102 	u.u_segflg = 1;
103 	eo = 0;
104 	bp = NULL;
105 
106 eloop:
107 
108 	/*
109 	 * If at the end of the directory,
110 	 * the search failed. Report what
111 	 * is appropriate as per flag.
112 	 */
113 
114 	if(u.u_offset >= dp->i_size) {
115 		if(bp != NULL)
116 			brelse(bp);
117 		if(flag==1 && c=='\0' && dp->i_nlink) {
118 			if(access(dp, IWRITE))
119 				goto out;
120 			u.u_pdir = dp;
121 			if(eo)
122 				u.u_offset = eo-sizeof(struct direct);
123 			else
124 				dp->i_flag |= IUPD|ICHG;
125 			return(NULL);
126 		}
127 		u.u_error = ENOENT;
128 		goto out;
129 	}
130 
131 	/*
132 	 * If offset is on a block boundary,
133 	 * read the next directory block.
134 	 * Release previous if it exists.
135 	 */
136 
137 	if((u.u_offset&BMASK) == 0) {
138 		if(bp != NULL)
139 			brelse(bp);
140 		bp = bread(dp->i_dev,
141 			bmap(dp, (daddr_t)(u.u_offset>>BSHIFT), B_READ));
142 		if (bp->b_flags & B_ERROR) {
143 			brelse(bp);
144 			goto out;
145 		}
146 		ep = (struct direct *)bp->b_un.b_addr;
147 	} else
148 		ep++;
149 
150 	/*
151 	 * Note first empty directory slot
152 	 * in eo for possible creat.
153 	 * String compare the directory entry
154 	 * and the current component.
155 	 * If they do not match, go back to eloop.
156 	 */
157 
158 	u.u_offset += sizeof(struct direct);
159 	if(ep->d_ino == 0) {
160 		if(eo == 0)
161 			eo = u.u_offset;
162 		goto eloop;
163 	}
164 	for(i=0; i<DIRSIZ; i++) {
165 		if(u.u_dbuf[i] != ep->d_name[i])
166 			goto eloop;
167 		if(u.u_dbuf[i] == 0)
168 			break;
169 	}
170 
171 	/*
172 	 * Here a component matched in a directory.
173 	 * If there is more pathname, go back to
174 	 * cloop, otherwise return.
175 	 */
176 	bcopy((caddr_t)ep, (caddr_t)&u.u_dent, sizeof(struct direct));
177 	if(bp != NULL)
178 		brelse(bp);
179 	if(flag==2 && c=='\0') {
180 		if(access(dp, IWRITE))
181 			goto out;
182 		return(dp);
183 	}
184 	d = dp->i_dev;
185 	if(u.u_dent.d_ino == ROOTINO)
186 	if(dp->i_number == ROOTINO)
187 	if(u.u_dent.d_name[1] == '.')
188 		for(i=1; i<NMOUNT; i++)
189 			if(mount[i].m_bufp != NULL)
190 			if(mount[i].m_dev == d) {
191 				iput(dp);
192 				dp = mount[i].m_inodp;
193 				dp->i_count++;
194 				plock(dp);
195 				goto seloop;
196 			}
197 	iput(dp);
198 	dp = iget(d, u.u_dent.d_ino);
199 	if(dp == NULL)
200 		return(NULL);
201 	goto cloop;
202 
203 out:
204 	iput(dp);
205 	return(NULL);
206 }
207 
208 /*
209  * Return the next character from the
210  * kernel string pointed at by dirp.
211  */
212 schar()
213 {
214 
215 	return(*u.u_dirp++ & 0377);
216 }
217 
218 /*
219  * Return the next character from the
220  * user string pointed at by dirp.
221  */
222 uchar()
223 {
224 	register c;
225 
226 	c = fubyte(u.u_dirp++);
227 	if(c == -1)
228 		u.u_error = EFAULT;
229 	return(c);
230 }
231