Commit | Line | Data |
---|---|---|
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 | */ |
27 | struct inode * | |
f5039631 BJ |
28 | namei(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; | |
87 | dirloop: | |
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 | 96 | dirloop2: |
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 | */ | |
390 | schar() | |
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 | */ | |
400 | uchar() | |
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 | 413 | bcmp(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 | |
424 | strlen(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 |