bring up to version 4.1
[unix-history] / usr / src / sys / ufs / ffs / ufs_lookup.c
CommitLineData
6f004ab5 1/* ufs_lookup.c 4.14 82/03/31 */
10873320
BJ
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"
3cbbbe12 10#include "../h/conf.h"
10873320
BJ
11
12/*
13 * Convert a pathname into a pointer to
f5039631 14 * a locked inode.
10873320
BJ
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
f5039631 22 * follow = 1 if links are to be followed at the end of the name
10873320
BJ
23 */
24struct inode *
f5039631
BJ
25namei(func, flag, follow)
26 int (*func)(), flag, follow;
10873320
BJ
27{
28 register struct inode *dp;
10873320 29 register char *cp;
f5039631 30 register struct buf *bp, *nbp;
cee4ba58 31 register struct direct *ep;
5485e062 32 struct inode *pdp;
f5039631 33 int i, nlink;
10873320
BJ
34 dev_t d;
35 off_t eo;
36
f5039631
BJ
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++) {
a21ae242
BJ
43 if ((*cp&0377) == ('/'|0200)) {
44 u.u_error = EPERM;
45 break;
46 }
47#ifdef notdef
f5039631 48 if (*cp++&0200 && flag==1 || cp >= nbp->b_un.b_addr+BSIZE) {
a21ae242
BJ
49#else
50 cp++;
51 if (cp >= nbp->b_un.b_addr+BSIZE) {
52#endif
f5039631
BJ
53 u.u_error = ENOENT;
54 break;
55 }
56 }
57 if (u.u_error) {
58 dp = NULL;
59 goto out1;
60 }
61 cp = nbp->b_un.b_addr;
10873320
BJ
62 /*
63 * If name starts with '/' start from
64 * root; otherwise start from current dir.
65 */
10873320 66 dp = u.u_cdir;
f5039631
BJ
67 if (*cp == '/') {
68 while (*cp == '/')
69 cp++;
10873320
BJ
70 if ((dp = u.u_rdir) == NULL)
71 dp = rootdir;
10873320 72 }
f5039631
BJ
73 ilock(dp);
74 dp->i_count++;
10873320 75
10873320
BJ
76 /*
77 * dp must be a directory and
78 * must have X permission.
f5039631 79 * cp is a path name relative to that directory.
10873320
BJ
80 */
81
f5039631 82dirloop:
aa064819 83 if ((dp->i_mode&IFMT) != IFDIR)
10873320 84 u.u_error = ENOTDIR;
cee4ba58 85 (void) access(dp, IEXEC);
6f004ab5 86dirloop2:
f5039631 87 for (i=0; *cp!='\0' && *cp!='/'; i++) {
a21ae242 88#ifdef notdef
f5039631
BJ
89 if (i >= DIRSIZ) {
90 u.u_error = ENOENT;
91 break;
92 }
93 u.u_dbuf[i] = *cp++;
a21ae242
BJ
94#else
95 if (i < DIRSIZ)
96 u.u_dbuf[i] = *cp;
97 cp++;
98#endif
f5039631 99 }
aa064819 100 if (u.u_error)
10873320 101 goto out;
5485e062 102 u.u_pdir = dp;
f5039631
BJ
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 }
10873320 112 u.u_segflg = 1;
f5039631 113 eo = -1;
10873320
BJ
114 bp = NULL;
115
f5039631
BJ
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') {
aa064819 155 if (access(dp, IWRITE))
10873320 156 goto out;
f5039631
BJ
157 /* should fix unlink */
158 u.u_offset += sizeof(struct direct);
159 goto out1;
10873320 160 }
f5039631
BJ
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 .. */
6f004ab5 178 goto dirloop2;
f5039631
BJ
179 }
180 }
181 }
182 d = dp->i_dev;
5485e062
BJ
183 irele(dp);
184 pdp = dp;
f5039631 185 dp = iget(d, u.u_dent.d_ino);
5485e062
BJ
186 if (dp == NULL) {
187 iput(pdp);
f5039631 188 goto out1;
5485e062 189 }
f5039631
BJ
190 /*
191 * Check for symbolic link
192 */
193 if ((dp->i_mode&IFMT)==IFLNK && (follow || *cp=='/')) {
194 char *ocp;
10873320 195
f5039631
BJ
196 ocp = cp;
197 while (*cp++)
198 ;
199 if (dp->i_size + (cp-ocp) >= BSIZE-1 || ++nlink>8) {
200 u.u_error = ELOOP;
5485e062 201 iput(pdp);
f5039631
BJ
202 goto out;
203 }
668cc26d
SL
204 bcopy(ocp, nbp->b_un.b_addr+dp->i_size,
205 (unsigned)(cp-ocp));
f5039631
BJ
206 bp = bread(dp->i_dev, bmap(dp, (daddr_t)0, B_READ));
207 if (bp->b_flags & B_ERROR) {
208 brelse(bp);
5485e062 209 iput(pdp);
f5039631
BJ
210 goto out;
211 }
668cc26d
SL
212 bcopy(bp->b_un.b_addr, nbp->b_un.b_addr,
213 (unsigned)dp->i_size);
10873320 214 brelse(bp);
f5039631
BJ
215 cp = nbp->b_un.b_addr;
216 iput(dp);
217 if (*cp == '/') {
5485e062 218 iput(pdp);
f5039631
BJ
219 while (*cp == '/')
220 cp++;
221 if ((dp = u.u_rdir) == NULL)
222 dp = rootdir;
223 ilock(dp);
224 dp->i_count++;
225 } else {
5485e062
BJ
226 dp = pdp;
227 ilock(dp);
f5039631
BJ
228 }
229 goto dirloop;
10873320 230 }
5485e062 231 iput(pdp);
f5039631
BJ
232 if (*cp == '/') {
233 while (*cp == '/')
234 cp++;
235 goto dirloop;
236 }
237 goto out1;
10873320 238 }
10873320 239 /*
f5039631 240 * Search failed.
10873320 241 */
aa064819 242 if (bp != NULL)
10873320 243 brelse(bp);
f5039631 244 if (flag==1 && *cp=='\0' && dp->i_nlink) {
aa064819 245 if (access(dp, IWRITE))
10873320 246 goto out;
f5039631
BJ
247 if (eo>=0)
248 u.u_offset = eo;
249 dp->i_flag |= IUPD|ICHG;
250 dp = NULL;
251 goto out1;
10873320 252 }
f5039631 253 u.u_error = ENOENT;
10873320
BJ
254out:
255 iput(dp);
f5039631
BJ
256 dp = NULL;
257out1:
258 brelse(nbp);
259 return (dp);
10873320
BJ
260}
261
262/*
263 * Return the next character from the
264 * kernel string pointed at by dirp.
265 */
266schar()
267{
268
f5039631 269 return (*u.u_dirp++ & 0377);
10873320
BJ
270}
271
272/*
273 * Return the next character from the
274 * user string pointed at by dirp.
275 */
276uchar()
277{
278 register c;
279
280 c = fubyte(u.u_dirp++);
f5039631 281 if (c == -1) {
10873320 282 u.u_error = EFAULT;
f5039631
BJ
283 c = 0;
284 }
285 return (c);
286}
287
288#ifndef vax
289strncmp(s1, s2, len)
290 register char *s1, *s2;
291 register len;
292{
293
294 do {
295 if (*s1 != *s2++)
296 return (1);
297 if (*s1++ == '\0')
298 return (0);
299 } while (--len);
300 return (0);
10873320 301}
f5039631 302#endif