merge into new file system
[unix-history] / usr / src / sys / ufs / ufs / ufs_lookup.c
CommitLineData
6459ebe0
KM
1/* ufs_lookup.c 4.15 82/04/19 */
2
3/* merged into kernel: @(#)nami.c 2.3 4/8/82 */
10873320
BJ
4
5#include "../h/param.h"
6#include "../h/systm.h"
7#include "../h/inode.h"
6459ebe0 8#include "../h/fs.h"
10873320
BJ
9#include "../h/mount.h"
10#include "../h/dir.h"
11#include "../h/user.h"
12#include "../h/buf.h"
3cbbbe12 13#include "../h/conf.h"
10873320
BJ
14
15/*
16 * Convert a pathname into a pointer to
f5039631 17 * a locked inode.
10873320
BJ
18 *
19 * func = function called to get next char of name
20 * &uchar if name is in user space
21 * &schar if name is in system space
22 * flag = 0 if name is sought
23 * 1 if name is to be created
24 * 2 if name is to be deleted
f5039631 25 * follow = 1 if links are to be followed at the end of the name
10873320
BJ
26 */
27struct inode *
f5039631
BJ
28namei(func, flag, follow)
29 int (*func)(), flag, follow;
10873320
BJ
30{
31 register struct inode *dp;
10873320 32 register char *cp;
f5039631 33 register struct buf *bp, *nbp;
cee4ba58 34 register struct direct *ep;
6459ebe0 35 register struct fs *fs;
5485e062 36 struct inode *pdp;
6459ebe0
KM
37 enum {NONE, COMPACT, FOUND} slot;
38 int entryfree, entrysize;
39 int spccnt, size, newsize;
40 int loc, prevoff, curoff;
41 int i, nlink, bsize;
42 unsigned pathlen;
43 daddr_t lbn, bn;
10873320 44 dev_t d;
10873320 45
f5039631
BJ
46 /*
47 * allocate name buffer; copy name
48 */
6459ebe0 49 nbp = geteblk(MAXPATHLEN);
f5039631 50 nlink = 0;
6459ebe0
KM
51 for (i = 0, cp = nbp->b_un.b_addr; *cp = (*func)(); i++) {
52 if ((*cp & 0377) == ('/'|0200)) {
a21ae242
BJ
53 u.u_error = EPERM;
54 break;
55 }
56#ifdef notdef
6459ebe0
KM
57 if (*cp++ & 0200 && flag == 1 ||
58 cp >= nbp->b_un.b_addr + MAXPATHLEN) {
a21ae242
BJ
59#else
60 cp++;
6459ebe0 61 if (cp >= nbp->b_un.b_addr + MAXPATHLEN) {
a21ae242 62#endif
f5039631
BJ
63 u.u_error = ENOENT;
64 break;
65 }
66 }
67 if (u.u_error) {
6459ebe0
KM
68 brelse(nbp);
69 return (NULL);
f5039631
BJ
70 }
71 cp = nbp->b_un.b_addr;
10873320
BJ
72 /*
73 * If name starts with '/' start from
74 * root; otherwise start from current dir.
75 */
10873320 76 dp = u.u_cdir;
f5039631
BJ
77 if (*cp == '/') {
78 while (*cp == '/')
79 cp++;
10873320
BJ
80 if ((dp = u.u_rdir) == NULL)
81 dp = rootdir;
10873320 82 }
f5039631
BJ
83 ilock(dp);
84 dp->i_count++;
6459ebe0
KM
85 fs = dp->i_fs;
86 newsize = 0;
87dirloop:
10873320
BJ
88 /*
89 * dp must be a directory and
90 * must have X permission.
f5039631 91 * cp is a path name relative to that directory.
10873320 92 */
aa064819 93 if ((dp->i_mode&IFMT) != IFDIR)
10873320 94 u.u_error = ENOTDIR;
cee4ba58 95 (void) access(dp, IEXEC);
6f004ab5 96dirloop2:
6459ebe0 97 for (i = 0; *cp != '\0' && *cp != '/'; cp++) {
a21ae242 98#ifdef notdef
6459ebe0 99 if (i >= MAXNAMLEN) {
f5039631
BJ
100 u.u_error = ENOENT;
101 break;
102 }
6459ebe0 103 u.u_dent.d_name[i] = *cp;
a21ae242 104#else
6459ebe0
KM
105 if (i < MAXNAMLEN) {
106 u.u_dent.d_name[i] = *cp;
107 i++;
108 }
a21ae242 109#endif
f5039631 110 }
6459ebe0
KM
111 if (u.u_error) {
112 iput(dp);
113 brelse(nbp);
114 return (NULL);
115 }
116 u.u_dent.d_namlen = i;
117 u.u_dent.d_name[i] = '\0';
118 newsize = DIRSIZ(&u.u_dent);
5485e062 119 u.u_pdir = dp;
6459ebe0
KM
120 if (u.u_dent.d_name[0] == '\0') { /* null name, e.g. "/" or "" */
121 if (flag != 0) {
f5039631 122 u.u_error = ENOENT;
6459ebe0
KM
123 iput(dp);
124 dp = NULL;
f5039631 125 }
6459ebe0
KM
126 u.u_offset = 0;
127 u.u_count = newsize;
128 brelse(nbp);
129 return (dp);
f5039631 130 }
6459ebe0
KM
131 /*
132 * set up to search a directory
133 */
134 if (flag == 1)
135 slot = NONE;
136 else
137 slot = FOUND;
138 u.u_offset = 0;
10873320 139 u.u_segflg = 1;
10873320 140 bp = NULL;
6459ebe0
KM
141 spccnt = 0;
142 loc = 0;
143 while (u.u_offset < dp->i_size) {
144 /*
145 * check to see if enough space has been accumulated to make
146 * an entry by compaction. Reset the free space counter each
147 * time a directory block is crossed.
148 */
149 if (slot == NONE) {
150 if (spccnt >= newsize) {
151 slot = COMPACT;
152 entrysize = u.u_offset - entryfree;
153 } else if (loc % DIRBLKSIZ == 0) {
154 entryfree = NULL;
155 spccnt = 0;
156 }
157 }
f5039631
BJ
158 /*
159 * If offset is on a block boundary,
160 * read the next directory block.
161 * Release previous if it exists.
162 */
6459ebe0 163 if (blkoff(fs, u.u_offset) == 0) {
f5039631
BJ
164 if (bp != NULL)
165 brelse(bp);
6459ebe0
KM
166 lbn = (daddr_t)lblkno(fs, u.u_offset);
167 bsize = blksize(fs, dp, lbn);
168 if ((bn = bmap(dp, lbn, B_READ)) < 0) {
169 printf("hole in dir: %s i = %d\n",
170 fs->fs_fsmnt, dp->i_number);
171 if (fs->fs_ronly != 0 ||
172 (bn = bmap(dp, lbn, B_WRITE, bsize)) < 0) {
173 u.u_offset += bsize;
174 bp = NULL;
175 continue;
176 }
177 }
178 bp = bread(dp->i_dev, fsbtodb(fs, bn), bsize);
f5039631
BJ
179 if (bp->b_flags & B_ERROR) {
180 brelse(bp);
6459ebe0
KM
181 iput(dp);
182 brelse(nbp);
183 return (NULL);
184 }
185 loc = 0;
186 } else {
187 loc += ep->d_reclen;
188 }
189 /*
190 * calculate the next directory entry and run
191 * some rudimentary bounds checks to make sure
192 * that it is reasonable. If the check fails
193 * resync at the beginning of the next directory
194 * block.
195 */
196 ep = (struct direct *)(bp->b_un.b_addr + loc);
197 i = DIRBLKSIZ - (loc & (DIRBLKSIZ - 1));
198 if (ep->d_reclen <= 0 || ep->d_reclen > i) {
199 loc += i;
200 u.u_offset += i;
201 continue;
202 }
203 /*
204 * If an appropriate sized hole has not yet been found,
205 * check to see if one is available. Also accumulate space
206 * in the current block so that we can determine if
207 * compaction is viable.
208 */
209 if (slot != FOUND) {
210 size = ep->d_reclen;
211 if (ep->d_ino != 0)
212 size -= DIRSIZ(ep);
213 if (size > 0) {
214 if (size >= newsize) {
215 slot = FOUND;
216 entryfree = u.u_offset;
217 entrysize = DIRSIZ(ep) + newsize;
218 }
219 if (entryfree == NULL)
220 entryfree = u.u_offset;
221 spccnt += size;
f5039631 222 }
f5039631
BJ
223 }
224 /*
f5039631
BJ
225 * String compare the directory entry
226 * and the current component.
6459ebe0 227 * If they do not match, continue to the next entry.
f5039631 228 */
6459ebe0
KM
229 prevoff = curoff;
230 curoff = u.u_offset;
231 u.u_offset += ep->d_reclen;
232 if (ep->d_ino == 0)
f5039631 233 continue;
6459ebe0
KM
234 if (ep->d_namlen != u.u_dent.d_namlen)
235 continue;
236 if (bcmp(u.u_dent.d_name, ep->d_name, ep->d_namlen))
f5039631
BJ
237 continue;
238 /*
239 * Here a component matched in a directory.
240 * If there is more pathname, go back to
241 * dirloop, otherwise return.
242 */
6459ebe0 243 bcopy((caddr_t)ep, (caddr_t)&u.u_dent, DIRSIZ(ep));
f5039631 244 brelse(bp);
6459ebe0
KM
245 if (flag == 2 && *cp == '\0') {
246 brelse(nbp);
247 if (access(dp, IWRITE)) {
248 iput(dp);
249 return (NULL);
250 }
251 if (curoff % DIRBLKSIZ == 0) {
252 u.u_offset = curoff;
253 u.u_count = 0;
254 return (dp);
255 }
256 u.u_offset = prevoff;
257 u.u_count = DIRSIZ((struct direct *)
258 (bp->b_un.b_addr + blkoff(fs, prevoff)));
259 return (dp);
10873320 260 }
f5039631
BJ
261 /*
262 * Special handling for ".."
263 */
6459ebe0
KM
264 if (u.u_dent.d_name[0] == '.' && u.u_dent.d_name[1] == '.' &&
265 u.u_dent.d_name[2] == '\0') {
f5039631
BJ
266 if (dp == u.u_rdir)
267 u.u_dent.d_ino = dp->i_number;
6459ebe0 268 else if (u.u_dent.d_ino == ROOTINO &&
f5039631 269 dp->i_number == ROOTINO) {
6459ebe0 270 for (i = 1; i < NMOUNT; i++)
f5039631
BJ
271 if (mount[i].m_bufp != NULL &&
272 mount[i].m_dev == dp->i_dev) {
273 iput(dp);
274 dp = mount[i].m_inodp;
275 ilock(dp);
276 dp->i_count++;
6459ebe0 277 fs = dp->i_fs;
f5039631 278 cp -= 2; /* back over .. */
6f004ab5 279 goto dirloop2;
f5039631
BJ
280 }
281 }
282 }
283 d = dp->i_dev;
5485e062
BJ
284 irele(dp);
285 pdp = dp;
6459ebe0 286 dp = iget(d, fs, u.u_dent.d_ino);
5485e062
BJ
287 if (dp == NULL) {
288 iput(pdp);
6459ebe0
KM
289 brelse(nbp);
290 return (NULL);
5485e062 291 }
6459ebe0 292 fs = dp->i_fs;
f5039631
BJ
293 /*
294 * Check for symbolic link
295 */
6459ebe0
KM
296 if ((dp->i_mode & IFMT) == IFLNK && (follow || *cp == '/')) {
297 pathlen = strlen(cp) + 1;
298 if (dp->i_size + pathlen >= MAXPATHLEN - 1 ||
299 ++nlink > MAXSYMLINKS) {
f5039631 300 u.u_error = ELOOP;
5485e062 301 iput(pdp);
6459ebe0
KM
302 iput(dp);
303 brelse(nbp);
304 return (NULL);
f5039631 305 }
6459ebe0
KM
306 bcopy(cp, nbp->b_un.b_addr + dp->i_size, pathlen);
307 bn = bmap(dp, (daddr_t)0, B_READ);
308 if (bn < 0) {
309 printf("hole in symlink: %s i = %d\n",
310 fs->fs_fsmnt, dp->i_number);
311 iput(pdp);
312 iput(dp);
313 brelse(nbp);
314 return (NULL);
315 }
316 bp = bread(dp->i_dev, fsbtodb(fs, bn),
317 (int)blksize(fs, dp, (daddr_t)0));
f5039631
BJ
318 if (bp->b_flags & B_ERROR) {
319 brelse(bp);
5485e062 320 iput(pdp);
6459ebe0
KM
321 iput(dp);
322 brelse(nbp);
323 return (NULL);
f5039631 324 }
668cc26d
SL
325 bcopy(bp->b_un.b_addr, nbp->b_un.b_addr,
326 (unsigned)dp->i_size);
10873320 327 brelse(bp);
f5039631
BJ
328 cp = nbp->b_un.b_addr;
329 iput(dp);
330 if (*cp == '/') {
5485e062 331 iput(pdp);
f5039631
BJ
332 while (*cp == '/')
333 cp++;
334 if ((dp = u.u_rdir) == NULL)
335 dp = rootdir;
336 ilock(dp);
337 dp->i_count++;
338 } else {
5485e062
BJ
339 dp = pdp;
340 ilock(dp);
f5039631 341 }
6459ebe0 342 fs = dp->i_fs;
f5039631 343 goto dirloop;
10873320 344 }
5485e062 345 iput(pdp);
f5039631
BJ
346 if (*cp == '/') {
347 while (*cp == '/')
348 cp++;
349 goto dirloop;
350 }
6459ebe0
KM
351 /*
352 * End of path, so return name matched.
353 */
354 u.u_offset -= ep->d_reclen;
355 u.u_count = newsize;
356 brelse(nbp);
357 return (dp);
10873320 358 }
10873320 359 /*
f5039631 360 * Search failed.
6459ebe0 361 * Report what is appropriate as per flag.
10873320 362 */
aa064819 363 if (bp != NULL)
10873320 364 brelse(bp);
6459ebe0
KM
365 if (flag == 1 && *cp == '\0' && dp->i_nlink != 0) {
366 brelse(nbp);
367 if (access(dp, IWRITE)) {
368 iput(dp);
369 return (NULL);
370 }
371 if (slot == NONE) {
372 u.u_count = 0;
373 } else {
374 u.u_offset = entryfree;
375 u.u_count = entrysize;
376 }
f5039631 377 dp->i_flag |= IUPD|ICHG;
6459ebe0 378 return (NULL);
10873320 379 }
f5039631 380 u.u_error = ENOENT;
10873320 381 iput(dp);
f5039631 382 brelse(nbp);
6459ebe0 383 return (NULL);
10873320
BJ
384}
385
386/*
387 * Return the next character from the
388 * kernel string pointed at by dirp.
389 */
390schar()
391{
392
f5039631 393 return (*u.u_dirp++ & 0377);
10873320
BJ
394}
395
396/*
397 * Return the next character from the
398 * user string pointed at by dirp.
399 */
400uchar()
401{
402 register c;
403
404 c = fubyte(u.u_dirp++);
f5039631 405 if (c == -1) {
10873320 406 u.u_error = EFAULT;
f5039631
BJ
407 c = 0;
408 }
409 return (c);
410}
411
412#ifndef vax
6459ebe0 413bcmp(s1, s2, len)
f5039631 414 register char *s1, *s2;
6459ebe0 415 register int len;
f5039631
BJ
416{
417
6459ebe0
KM
418 while (--len)
419 if (*s1++ != *s2++)
f5039631 420 return (1);
f5039631 421 return (0);
10873320 422}
6459ebe0
KM
423
424strlen(s1)
425 register char *s1;
426{
427 register int len;
428
429 for (len = 0; *s1++ != '\0'; len++)
430 /* void */;
431 return (len);
432}
f5039631 433#endif