This source file includes following definitions.
- namei
- lookup
- relookup
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40 #include <sys/param.h>
41 #include <sys/systm.h>
42 #include <sys/syslimits.h>
43 #include <sys/time.h>
44 #include <sys/namei.h>
45 #include <sys/vnode.h>
46 #include <sys/mount.h>
47 #include <sys/errno.h>
48 #include <sys/malloc.h>
49 #include <sys/pool.h>
50 #include <sys/filedesc.h>
51 #include <sys/proc.h>
52 #include <sys/hash.h>
53
54 #ifdef KTRACE
55 #include <sys/ktrace.h>
56 #endif
57
58 #include <dev/systrace.h>
59 #include "systrace.h"
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83 int
84 namei(struct nameidata *ndp)
85 {
86 struct filedesc *fdp;
87 char *cp;
88 struct vnode *dp;
89 struct iovec aiov;
90 struct uio auio;
91 int error, linklen;
92 struct componentname *cnp = &ndp->ni_cnd;
93 struct proc *p = cnp->cn_proc;
94
95 ndp->ni_cnd.cn_cred = ndp->ni_cnd.cn_proc->p_ucred;
96 #ifdef DIAGNOSTIC
97 if (!cnp->cn_cred || !cnp->cn_proc)
98 panic ("namei: bad cred/proc");
99 if (cnp->cn_nameiop & (~OPMASK))
100 panic ("namei: nameiop contaminated with flags");
101 if (cnp->cn_flags & OPMASK)
102 panic ("namei: flags contaminated with nameiops");
103 #endif
104 fdp = cnp->cn_proc->p_fd;
105
106
107
108
109
110 if ((cnp->cn_flags & HASBUF) == 0)
111 cnp->cn_pnbuf = pool_get(&namei_pool, PR_WAITOK);
112 if (ndp->ni_segflg == UIO_SYSSPACE)
113 error = copystr(ndp->ni_dirp, cnp->cn_pnbuf,
114 MAXPATHLEN, &ndp->ni_pathlen);
115 else
116 error = copyinstr(ndp->ni_dirp, cnp->cn_pnbuf,
117 MAXPATHLEN, &ndp->ni_pathlen);
118
119
120
121
122 if (error == 0 && ndp->ni_pathlen == 1)
123 error = ENOENT;
124
125 if (error) {
126 pool_put(&namei_pool, cnp->cn_pnbuf);
127 ndp->ni_vp = NULL;
128 return (error);
129 }
130
131 #ifdef KTRACE
132 if (KTRPOINT(cnp->cn_proc, KTR_NAMEI))
133 ktrnamei(cnp->cn_proc, cnp->cn_pnbuf);
134 #endif
135 #if NSYSTRACE > 0
136 if (ISSET(cnp->cn_proc->p_flag, P_SYSTRACE))
137 systrace_namei(ndp);
138 #endif
139
140
141
142
143 if (cnp->cn_flags & STRIPSLASHES) {
144 char *end = cnp->cn_pnbuf + ndp->ni_pathlen - 2;
145
146 cp = end;
147 while (cp >= cnp->cn_pnbuf && (*cp == '/'))
148 cp--;
149
150
151 if (cp >= cnp->cn_pnbuf) {
152 ndp->ni_pathlen -= (end - cp);
153 *(cp + 1) = '\0';
154 }
155 }
156
157 ndp->ni_loopcnt = 0;
158
159
160
161
162 if ((ndp->ni_rootdir = fdp->fd_rdir) == NULL)
163 ndp->ni_rootdir = rootvnode;
164
165
166
167 if (cnp->cn_pnbuf[0] == '/') {
168 dp = ndp->ni_rootdir;
169 VREF(dp);
170 } else {
171 dp = fdp->fd_cdir;
172 VREF(dp);
173 }
174 for (;;) {
175 if (!dp->v_mount) {
176
177 pool_put(&namei_pool, cnp->cn_pnbuf);
178 return (ENOENT);
179 }
180 cnp->cn_nameptr = cnp->cn_pnbuf;
181 ndp->ni_startdir = dp;
182 if ((error = lookup(ndp)) != 0) {
183 pool_put(&namei_pool, cnp->cn_pnbuf);
184 return (error);
185 }
186
187
188
189 if ((cnp->cn_flags & ISSYMLINK) == 0) {
190 if ((cnp->cn_flags & (SAVENAME | SAVESTART)) == 0)
191 pool_put(&namei_pool, cnp->cn_pnbuf);
192 else
193 cnp->cn_flags |= HASBUF;
194 return (0);
195 }
196 if ((cnp->cn_flags & LOCKPARENT) && (cnp->cn_flags & ISLASTCN))
197 VOP_UNLOCK(ndp->ni_dvp, 0, p);
198 if (ndp->ni_loopcnt++ >= MAXSYMLINKS) {
199 error = ELOOP;
200 break;
201 }
202 if (ndp->ni_pathlen > 1)
203 cp = pool_get(&namei_pool, PR_WAITOK);
204 else
205 cp = cnp->cn_pnbuf;
206 aiov.iov_base = cp;
207 aiov.iov_len = MAXPATHLEN;
208 auio.uio_iov = &aiov;
209 auio.uio_iovcnt = 1;
210 auio.uio_offset = 0;
211 auio.uio_rw = UIO_READ;
212 auio.uio_segflg = UIO_SYSSPACE;
213 auio.uio_procp = cnp->cn_proc;
214 auio.uio_resid = MAXPATHLEN;
215 error = VOP_READLINK(ndp->ni_vp, &auio, cnp->cn_cred);
216 if (error) {
217 badlink:
218 if (ndp->ni_pathlen > 1)
219 pool_put(&namei_pool, cp);
220 break;
221 }
222 linklen = MAXPATHLEN - auio.uio_resid;
223 if (linklen + ndp->ni_pathlen >= MAXPATHLEN) {
224 error = ENAMETOOLONG;
225 goto badlink;
226 }
227 if (ndp->ni_pathlen > 1) {
228 bcopy(ndp->ni_next, cp + linklen, ndp->ni_pathlen);
229 pool_put(&namei_pool, cnp->cn_pnbuf);
230 cnp->cn_pnbuf = cp;
231 } else
232 cnp->cn_pnbuf[linklen] = '\0';
233 ndp->ni_pathlen += linklen;
234 vput(ndp->ni_vp);
235 dp = ndp->ni_dvp;
236
237
238
239 if (cnp->cn_pnbuf[0] == '/') {
240 vrele(dp);
241 dp = ndp->ni_rootdir;
242 VREF(dp);
243 }
244 }
245 pool_put(&namei_pool, cnp->cn_pnbuf);
246 vrele(ndp->ni_dvp);
247 vput(ndp->ni_vp);
248 ndp->ni_vp = NULL;
249 return (error);
250 }
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290 int
291 lookup(struct nameidata *ndp)
292 {
293 char *cp;
294 struct vnode *dp = 0;
295 struct vnode *tdp;
296 struct mount *mp;
297 int docache;
298 int wantparent;
299 int rdonly;
300 int error = 0;
301 int dpunlocked = 0;
302 int slashes;
303 struct componentname *cnp = &ndp->ni_cnd;
304 struct proc *p = cnp->cn_proc;
305
306
307
308 wantparent = cnp->cn_flags & (LOCKPARENT | WANTPARENT);
309 docache = (cnp->cn_flags & NOCACHE) ^ NOCACHE;
310 if (cnp->cn_nameiop == DELETE ||
311 (wantparent && cnp->cn_nameiop != CREATE))
312 docache = 0;
313 rdonly = cnp->cn_flags & RDONLY;
314 ndp->ni_dvp = NULL;
315 cnp->cn_flags &= ~ISSYMLINK;
316 dp = ndp->ni_startdir;
317 ndp->ni_startdir = NULLVP;
318 vn_lock(dp, LK_EXCLUSIVE | LK_RETRY, p);
319
320
321
322
323
324 cp = cnp->cn_nameptr;
325 if (*cp == '/') {
326 do {
327 cp++;
328 } while (*cp == '/');
329 ndp->ni_pathlen -= cp - cnp->cn_nameptr;
330 cnp->cn_nameptr = cp;
331
332 if (dp->v_type != VDIR) {
333 error = ENOTDIR;
334 goto bad;
335 }
336
337
338
339
340
341
342
343 if (cnp->cn_nameptr[0] == '\0') {
344 if (ndp->ni_dvp == NULL && wantparent) {
345 error = EISDIR;
346 goto bad;
347 }
348 ndp->ni_vp = dp;
349 cnp->cn_flags |= ISLASTCN;
350 goto terminal;
351 }
352 }
353
354 dirloop:
355
356
357
358
359
360
361
362
363
364 cp = NULL;
365 cnp->cn_consume = 0;
366 cnp->cn_hash = hash32_stre(cnp->cn_nameptr, '/', &cp, HASHINIT);
367 cnp->cn_namelen = cp - cnp->cn_nameptr;
368 if (cnp->cn_namelen > NAME_MAX) {
369 error = ENAMETOOLONG;
370 goto bad;
371 }
372 #ifdef NAMEI_DIAGNOSTIC
373 { char c = *cp;
374 *cp = '\0';
375 printf("{%s}: ", cnp->cn_nameptr);
376 *cp = c; }
377 #endif
378 ndp->ni_pathlen -= cnp->cn_namelen;
379 ndp->ni_next = cp;
380
381
382
383
384
385 if (*cp == '/') {
386 do {
387 cp++;
388 } while (*cp == '/');
389 slashes = cp - ndp->ni_next;
390 ndp->ni_pathlen -= slashes;
391 ndp->ni_next = cp;
392 cnp->cn_flags |= REQUIREDIR;
393 } else {
394 slashes = 0;
395 cnp->cn_flags &= ~REQUIREDIR;
396 }
397
398
399
400
401 if (*cp == '\0') {
402 if (docache)
403 cnp->cn_flags |= MAKEENTRY;
404 else
405 cnp->cn_flags &= ~MAKEENTRY;
406 cnp->cn_flags |= ISLASTCN;
407 } else {
408 cnp->cn_flags |= MAKEENTRY;
409 cnp->cn_flags &= ~ISLASTCN;
410 }
411 if (cnp->cn_namelen == 2 &&
412 cnp->cn_nameptr[1] == '.' && cnp->cn_nameptr[0] == '.')
413 cnp->cn_flags |= ISDOTDOT;
414 else
415 cnp->cn_flags &= ~ISDOTDOT;
416
417
418
419
420
421
422
423
424
425
426
427 if (cnp->cn_flags & ISDOTDOT) {
428 for (;;) {
429 if (dp == ndp->ni_rootdir || dp == rootvnode) {
430 ndp->ni_dvp = dp;
431 ndp->ni_vp = dp;
432 VREF(dp);
433 goto nextname;
434 }
435 if ((dp->v_flag & VROOT) == 0 ||
436 (cnp->cn_flags & NOCROSSMOUNT))
437 break;
438 tdp = dp;
439 dp = dp->v_mount->mnt_vnodecovered;
440 vput(tdp);
441 VREF(dp);
442 vn_lock(dp, LK_EXCLUSIVE | LK_RETRY, p);
443 }
444 }
445
446
447
448
449 ndp->ni_dvp = dp;
450 ndp->ni_vp = NULL;
451 cnp->cn_flags &= ~PDIRUNLOCK;
452
453 if ((error = VOP_LOOKUP(dp, &ndp->ni_vp, cnp)) != 0) {
454 #ifdef DIAGNOSTIC
455 if (ndp->ni_vp != NULL)
456 panic("leaf should be empty");
457 #endif
458 #ifdef NAMEI_DIAGNOSTIC
459 printf("not found\n");
460 #endif
461 if (error != EJUSTRETURN)
462 goto bad;
463
464
465
466
467 if (cnp->cn_flags & REQUIREDIR) {
468 error = ENOENT;
469 goto bad;
470 }
471
472
473
474
475 if (rdonly || (ndp->ni_dvp->v_mount->mnt_flag & MNT_RDONLY)) {
476 error = EROFS;
477 goto bad;
478 }
479
480
481
482
483
484 if (cnp->cn_flags & SAVESTART) {
485 ndp->ni_startdir = ndp->ni_dvp;
486 VREF(ndp->ni_startdir);
487 }
488 return (0);
489 }
490 #ifdef NAMEI_DIAGNOSTIC
491 printf("found\n");
492 #endif
493
494
495
496
497
498
499 if (cnp->cn_consume > 0) {
500 if (cnp->cn_consume >= slashes) {
501 cnp->cn_flags &= ~REQUIREDIR;
502 }
503
504 ndp->ni_pathlen -= cnp->cn_consume - slashes;
505 ndp->ni_next += cnp->cn_consume - slashes;
506 cnp->cn_consume = 0;
507 if (ndp->ni_next[0] == '\0')
508 cnp->cn_flags |= ISLASTCN;
509 }
510
511 dp = ndp->ni_vp;
512
513
514
515
516 while (dp->v_type == VDIR && (mp = dp->v_mountedhere) &&
517 (cnp->cn_flags & NOCROSSMOUNT) == 0) {
518 if (vfs_busy(mp, VB_READ|VB_WAIT))
519 continue;
520 VOP_UNLOCK(dp, 0, p);
521 error = VFS_ROOT(mp, &tdp);
522 vfs_unbusy(mp);
523 if (error) {
524 dpunlocked = 1;
525 goto bad2;
526 }
527 vrele(dp);
528 ndp->ni_vp = dp = tdp;
529 }
530
531
532
533
534
535 if ((dp->v_type == VLNK) && (cnp->cn_flags & (FOLLOW|REQUIREDIR))) {
536 ndp->ni_pathlen += slashes;
537 ndp->ni_next -= slashes;
538 cnp->cn_flags |= ISSYMLINK;
539 return (0);
540 }
541
542
543
544
545
546 if ((dp->v_type != VDIR) && (cnp->cn_flags & REQUIREDIR)) {
547 error = ENOTDIR;
548 goto bad2;
549 }
550
551 nextname:
552
553
554
555
556 if (!(cnp->cn_flags & ISLASTCN)) {
557 cnp->cn_nameptr = ndp->ni_next;
558 vrele(ndp->ni_dvp);
559 goto dirloop;
560 }
561
562 terminal:
563
564
565
566 if (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME) {
567
568
569
570
571 if (rdonly || (dp->v_mount->mnt_flag & MNT_RDONLY) ||
572 (wantparent &&
573 (ndp->ni_dvp->v_mount->mnt_flag & MNT_RDONLY))) {
574 error = EROFS;
575 goto bad2;
576 }
577 }
578 if (ndp->ni_dvp != NULL) {
579 if (cnp->cn_flags & SAVESTART) {
580 ndp->ni_startdir = ndp->ni_dvp;
581 VREF(ndp->ni_startdir);
582 }
583 if (!wantparent)
584 vrele(ndp->ni_dvp);
585 }
586 if ((cnp->cn_flags & LOCKLEAF) == 0)
587 VOP_UNLOCK(dp, 0, p);
588 return (0);
589
590 bad2:
591 if ((cnp->cn_flags & LOCKPARENT) && (cnp->cn_flags & ISLASTCN) &&
592 ((cnp->cn_flags & PDIRUNLOCK) == 0))
593 VOP_UNLOCK(ndp->ni_dvp, 0, p);
594 vrele(ndp->ni_dvp);
595 bad:
596 if (dpunlocked)
597 vrele(dp);
598 else
599 vput(dp);
600 ndp->ni_vp = NULL;
601 return (error);
602 }
603
604
605
606
607 int
608 relookup(struct vnode *dvp, struct vnode **vpp, struct componentname *cnp)
609 {
610 struct proc *p = cnp->cn_proc;
611 struct vnode *dp = 0;
612 int wantparent;
613 int rdonly;
614 int error = 0;
615 #ifdef NAMEI_DIAGNOSTIC
616 u_int32_t newhash;
617 char *cp;
618 #endif
619
620
621
622
623 wantparent = cnp->cn_flags & (LOCKPARENT|WANTPARENT);
624 rdonly = cnp->cn_flags & RDONLY;
625 cnp->cn_flags &= ~ISSYMLINK;
626 dp = dvp;
627 vn_lock(dp, LK_EXCLUSIVE | LK_RETRY, p);
628
629
630
631
632
633
634
635
636
637
638
639 #ifdef NAMEI_DIAGNOSTIC
640 cp = NULL;
641 newhash = hash32_stre(cnp->cn_nameptr, '/', &cp, HASHINIT);
642 if (newhash != cnp->cn_hash)
643 panic("relookup: bad hash");
644 if (cnp->cn_namelen != cp - cnp->cn_nameptr)
645 panic ("relookup: bad len");
646 if (*cp != 0)
647 panic("relookup: not last component");
648 printf("{%s}: ", cnp->cn_nameptr);
649 #endif
650
651
652
653
654
655
656 if (cnp->cn_nameptr[0] == '\0')
657 panic("relookup: null name");
658
659 if (cnp->cn_flags & ISDOTDOT)
660 panic ("relookup: lookup on dot-dot");
661
662
663
664
665 if ((error = VOP_LOOKUP(dp, vpp, cnp)) != 0) {
666 #ifdef DIAGNOSTIC
667 if (*vpp != NULL)
668 panic("leaf should be empty");
669 #endif
670 if (error != EJUSTRETURN)
671 goto bad;
672
673
674
675
676 if (rdonly || (dvp->v_mount->mnt_flag & MNT_RDONLY)) {
677 error = EROFS;
678 goto bad;
679 }
680
681 if (cnp->cn_flags & SAVESTART)
682 VREF(dvp);
683
684
685
686
687
688 return (0);
689 }
690 dp = *vpp;
691
692 #ifdef DIAGNOSTIC
693
694
695
696 if (dp->v_type == VLNK && (cnp->cn_flags & FOLLOW))
697 panic ("relookup: symlink found.");
698 #endif
699
700
701
702
703 if (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME) {
704
705
706
707
708 if (rdonly || (dp->v_mount->mnt_flag & MNT_RDONLY) ||
709 (wantparent &&
710 (dvp->v_mount->mnt_flag & MNT_RDONLY))) {
711 error = EROFS;
712 goto bad2;
713 }
714 }
715
716 if (cnp->cn_flags & SAVESTART)
717 VREF(dvp);
718 if (!wantparent)
719 vrele(dvp);
720 if ((cnp->cn_flags & LOCKLEAF) == 0)
721 VOP_UNLOCK(dp, 0, p);
722 return (0);
723
724 bad2:
725 if ((cnp->cn_flags & LOCKPARENT) && (cnp->cn_flags & ISLASTCN))
726 VOP_UNLOCK(dvp, 0, p);
727 vrele(dvp);
728 bad:
729 vput(dp);
730 *vpp = NULL;
731 return (error);
732 }