| @@ -1,14 +1,14 @@ | | | @@ -1,14 +1,14 @@ |
1 | /* $NetBSD: vfs_lookup.c,v 1.117 2009/08/09 03:28:35 dholland Exp $ */ | | 1 | /* $NetBSD: vfs_lookup.c,v 1.118 2009/08/09 07:27:54 dholland Exp $ */ |
2 | | | 2 | |
3 | /* | | 3 | /* |
4 | * Copyright (c) 1982, 1986, 1989, 1993 | | 4 | * Copyright (c) 1982, 1986, 1989, 1993 |
5 | * The Regents of the University of California. All rights reserved. | | 5 | * The Regents of the University of California. All rights reserved. |
6 | * (c) UNIX System Laboratories, Inc. | | 6 | * (c) UNIX System Laboratories, Inc. |
7 | * All or some portions of this file are derived from material licensed | | 7 | * All or some portions of this file are derived from material licensed |
8 | * to the University of California by American Telephone and Telegraph | | 8 | * to the University of California by American Telephone and Telegraph |
9 | * Co. or Unix System Laboratories, Inc. and are reproduced herein with | | 9 | * Co. or Unix System Laboratories, Inc. and are reproduced herein with |
10 | * the permission of UNIX System Laboratories, Inc. | | 10 | * the permission of UNIX System Laboratories, Inc. |
11 | * | | 11 | * |
12 | * Redistribution and use in source and binary forms, with or without | | 12 | * Redistribution and use in source and binary forms, with or without |
13 | * modification, are permitted provided that the following conditions | | 13 | * modification, are permitted provided that the following conditions |
14 | * are met: | | 14 | * are met: |
| @@ -27,27 +27,27 @@ | | | @@ -27,27 +27,27 @@ |
27 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | | 27 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
28 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | | 28 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
29 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | | 29 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
30 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | | 30 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
31 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | | 31 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
32 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | | 32 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
33 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | | 33 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
34 | * SUCH DAMAGE. | | 34 | * SUCH DAMAGE. |
35 | * | | 35 | * |
36 | * @(#)vfs_lookup.c 8.10 (Berkeley) 5/27/95 | | 36 | * @(#)vfs_lookup.c 8.10 (Berkeley) 5/27/95 |
37 | */ | | 37 | */ |
38 | | | 38 | |
39 | #include <sys/cdefs.h> | | 39 | #include <sys/cdefs.h> |
40 | __KERNEL_RCSID(0, "$NetBSD: vfs_lookup.c,v 1.117 2009/08/09 03:28:35 dholland Exp $"); | | 40 | __KERNEL_RCSID(0, "$NetBSD: vfs_lookup.c,v 1.118 2009/08/09 07:27:54 dholland Exp $"); |
41 | | | 41 | |
42 | #include "opt_magiclinks.h" | | 42 | #include "opt_magiclinks.h" |
43 | | | 43 | |
44 | #include <sys/param.h> | | 44 | #include <sys/param.h> |
45 | #include <sys/systm.h> | | 45 | #include <sys/systm.h> |
46 | #include <sys/kernel.h> | | 46 | #include <sys/kernel.h> |
47 | #include <sys/syslimits.h> | | 47 | #include <sys/syslimits.h> |
48 | #include <sys/time.h> | | 48 | #include <sys/time.h> |
49 | #include <sys/namei.h> | | 49 | #include <sys/namei.h> |
50 | #include <sys/vnode.h> | | 50 | #include <sys/vnode.h> |
51 | #include <sys/mount.h> | | 51 | #include <sys/mount.h> |
52 | #include <sys/errno.h> | | 52 | #include <sys/errno.h> |
53 | #include <sys/filedesc.h> | | 53 | #include <sys/filedesc.h> |
| @@ -214,51 +214,71 @@ symlink_magic(struct proc *p, char *cp, | | | @@ -214,51 +214,71 @@ symlink_magic(struct proc *p, char *cp, |
214 | * while (!done && !error) { | | 214 | * while (!done && !error) { |
215 | * call lookup to search path. | | 215 | * call lookup to search path. |
216 | * if symbolic link, massage name in buffer and continue | | 216 | * if symbolic link, massage name in buffer and continue |
217 | * } | | 217 | * } |
218 | */ | | 218 | */ |
219 | | | 219 | |
220 | /* | | 220 | /* |
221 | * Internal state for a namei operation. | | 221 | * Internal state for a namei operation. |
222 | */ | | 222 | */ |
223 | struct namei_state { | | 223 | struct namei_state { |
224 | struct nameidata *ndp; | | 224 | struct nameidata *ndp; |
225 | struct componentname *cnp; | | 225 | struct componentname *cnp; |
226 | | | 226 | |
| | | 227 | /* used by the pieces of namei */ |
| | | 228 | struct vnode *namei_startdir; /* The directory namei() starts from. */ |
| | | 229 | |
| | | 230 | /* used by the pieces of lookup */ |
| | | 231 | int lookup_alldone; |
| | | 232 | |
| | | 233 | int docache; /* == 0 do not cache last component */ |
| | | 234 | int rdonly; /* lookup read-only flag bit */ |
227 | struct vnode *dp; /* the directory we are searching */ | | 235 | struct vnode *dp; /* the directory we are searching */ |
| | | 236 | int slashes; |
228 | }; | | 237 | }; |
229 | | | 238 | |
| | | 239 | /* XXX reorder things to make this decl unnecessary */ |
| | | 240 | static int do_lookup(struct namei_state *state); |
| | | 241 | |
| | | 242 | |
230 | /* | | 243 | /* |
231 | * Initialize the namei working state. | | 244 | * Initialize the namei working state. |
232 | */ | | 245 | */ |
233 | static void | | 246 | static void |
234 | namei_init(struct namei_state *state, struct nameidata *ndp) | | 247 | namei_init(struct namei_state *state, struct nameidata *ndp) |
235 | { | | 248 | { |
236 | state->ndp = ndp; | | 249 | state->ndp = ndp; |
237 | state->cnp = &ndp->ni_cnd; | | 250 | state->cnp = &ndp->ni_cnd; |
238 | | | 251 | |
| | | 252 | state->namei_startdir = NULL; |
| | | 253 | |
| | | 254 | state->lookup_alldone = 0; |
| | | 255 | |
| | | 256 | state->docache = 0; |
| | | 257 | state->rdonly = 0; |
239 | state->dp = NULL; | | 258 | state->dp = NULL; |
| | | 259 | state->slashes = 0; |
240 | } | | 260 | } |
241 | | | 261 | |
242 | /* | | 262 | /* |
243 | * Clean up the working namei state, leaving things ready for return | | 263 | * Clean up the working namei state, leaving things ready for return |
244 | * from namei. | | 264 | * from namei. |
245 | */ | | 265 | */ |
246 | static void | | 266 | static void |
247 | namei_cleanup(struct namei_state *state) | | 267 | namei_cleanup(struct namei_state *state) |
248 | { | | 268 | { |
249 | KASSERT(state->cnp == &state->ndp->ni_cnd); | | 269 | KASSERT(state->cnp == &state->ndp->ni_cnd); |
250 | | | 270 | |
251 | //KASSERT(state->dp == NULL); // not yet | | 271 | //KASSERT(state->namei_startdir == NULL); // not yet |
252 | | | 272 | |
253 | /* nothing for now */ | | 273 | /* nothing for now */ |
254 | (void)state; | | 274 | (void)state; |
255 | } | | 275 | } |
256 | | | 276 | |
257 | ////////////////////////////// | | 277 | ////////////////////////////// |
258 | | | 278 | |
259 | /* | | 279 | /* |
260 | * Start up namei. Early portion. | | 280 | * Start up namei. Early portion. |
261 | * | | 281 | * |
262 | * This is divided from namei_start2 by the emul_retry: point. | | 282 | * This is divided from namei_start2 by the emul_retry: point. |
263 | */ | | 283 | */ |
264 | static void | | 284 | static void |
| @@ -311,99 +331,99 @@ namei_start2(struct namei_state *state) | | | @@ -311,99 +331,99 @@ namei_start2(struct namei_state *state) |
311 | | | 331 | |
312 | if (error) { | | 332 | if (error) { |
313 | PNBUF_PUT(cnp->cn_pnbuf); | | 333 | PNBUF_PUT(cnp->cn_pnbuf); |
314 | ndp->ni_vp = NULL; | | 334 | ndp->ni_vp = NULL; |
315 | return (error); | | 335 | return (error); |
316 | } | | 336 | } |
317 | ndp->ni_loopcnt = 0; | | 337 | ndp->ni_loopcnt = 0; |
318 | | | 338 | |
319 | /* | | 339 | /* |
320 | * Get root directory for the translation. | | 340 | * Get root directory for the translation. |
321 | */ | | 341 | */ |
322 | cwdi = self->l_proc->p_cwdi; | | 342 | cwdi = self->l_proc->p_cwdi; |
323 | rw_enter(&cwdi->cwdi_lock, RW_READER); | | 343 | rw_enter(&cwdi->cwdi_lock, RW_READER); |
324 | state->dp = cwdi->cwdi_rdir; | | 344 | state->namei_startdir = cwdi->cwdi_rdir; |
325 | if (state->dp == NULL) | | 345 | if (state->namei_startdir == NULL) |
326 | state->dp = rootvnode; | | 346 | state->namei_startdir = rootvnode; |
327 | ndp->ni_rootdir = state->dp; | | 347 | ndp->ni_rootdir = state->namei_startdir; |
328 | | | 348 | |
329 | /* | | 349 | /* |
330 | * Check if starting from root directory or current directory. | | 350 | * Check if starting from root directory or current directory. |
331 | */ | | 351 | */ |
332 | if (cnp->cn_pnbuf[0] == '/') { | | 352 | if (cnp->cn_pnbuf[0] == '/') { |
333 | if (cnp->cn_flags & TRYEMULROOT) { | | 353 | if (cnp->cn_flags & TRYEMULROOT) { |
334 | if (cnp->cn_flags & EMULROOTSET) { | | 354 | if (cnp->cn_flags & EMULROOTSET) { |
335 | /* Called from (eg) emul_find_interp() */ | | 355 | /* Called from (eg) emul_find_interp() */ |
336 | state->dp = ndp->ni_erootdir; | | 356 | state->namei_startdir = ndp->ni_erootdir; |
337 | } else { | | 357 | } else { |
338 | if (cwdi->cwdi_edir == NULL | | 358 | if (cwdi->cwdi_edir == NULL |
339 | || (cnp->cn_pnbuf[1] == '.' | | 359 | || (cnp->cn_pnbuf[1] == '.' |
340 | && cnp->cn_pnbuf[2] == '.' | | 360 | && cnp->cn_pnbuf[2] == '.' |
341 | && cnp->cn_pnbuf[3] == '/')) { | | 361 | && cnp->cn_pnbuf[3] == '/')) { |
342 | ndp->ni_erootdir = NULL; | | 362 | ndp->ni_erootdir = NULL; |
343 | } else { | | 363 | } else { |
344 | state->dp = cwdi->cwdi_edir; | | 364 | state->namei_startdir = cwdi->cwdi_edir; |
345 | ndp->ni_erootdir = state->dp; | | 365 | ndp->ni_erootdir = state->namei_startdir; |
346 | } | | 366 | } |
347 | } | | 367 | } |
348 | } else { | | 368 | } else { |
349 | ndp->ni_erootdir = NULL; | | 369 | ndp->ni_erootdir = NULL; |
350 | if (cnp->cn_flags & NOCHROOT) | | 370 | if (cnp->cn_flags & NOCHROOT) |
351 | state->dp = ndp->ni_rootdir = rootvnode; | | 371 | state->namei_startdir = ndp->ni_rootdir = rootvnode; |
352 | } | | 372 | } |
353 | } else { | | 373 | } else { |
354 | state->dp = cwdi->cwdi_cdir; | | 374 | state->namei_startdir = cwdi->cwdi_cdir; |
355 | ndp->ni_erootdir = NULL; | | 375 | ndp->ni_erootdir = NULL; |
356 | } | | 376 | } |
357 | VREF(state->dp); | | 377 | VREF(state->namei_startdir); |
358 | rw_exit(&cwdi->cwdi_lock); | | 378 | rw_exit(&cwdi->cwdi_lock); |
359 | | | 379 | |
360 | /* | | 380 | /* |
361 | * Ktrace it. | | 381 | * Ktrace it. |
362 | */ | | 382 | */ |
363 | if (ktrpoint(KTR_NAMEI)) { | | 383 | if (ktrpoint(KTR_NAMEI)) { |
364 | if (ndp->ni_erootdir != NULL) { | | 384 | if (ndp->ni_erootdir != NULL) { |
365 | /* | | 385 | /* |
366 | * To make any sense, the trace entry need to have the | | 386 | * To make any sense, the trace entry need to have the |
367 | * text of the emulation path prepended. | | 387 | * text of the emulation path prepended. |
368 | * Usually we can get this from the current process, | | 388 | * Usually we can get this from the current process, |
369 | * but when called from emul_find_interp() it is only | | 389 | * but when called from emul_find_interp() it is only |
370 | * in the exec_package - so we get it passed in ni_next | | 390 | * in the exec_package - so we get it passed in ni_next |
371 | * (this is a hack). | | 391 | * (this is a hack). |
372 | */ | | 392 | */ |
373 | const char *emul_path; | | 393 | const char *emul_path; |
374 | if (cnp->cn_flags & EMULROOTSET) | | 394 | if (cnp->cn_flags & EMULROOTSET) |
375 | emul_path = ndp->ni_next; | | 395 | emul_path = ndp->ni_next; |
376 | else | | 396 | else |
377 | emul_path = self->l_proc->p_emul->e_path; | | 397 | emul_path = self->l_proc->p_emul->e_path; |
378 | ktrnamei2(emul_path, strlen(emul_path), | | 398 | ktrnamei2(emul_path, strlen(emul_path), |
379 | cnp->cn_pnbuf, ndp->ni_pathlen); | | 399 | cnp->cn_pnbuf, ndp->ni_pathlen); |
380 | } else | | 400 | } else |
381 | ktrnamei(cnp->cn_pnbuf, ndp->ni_pathlen); | | 401 | ktrnamei(cnp->cn_pnbuf, ndp->ni_pathlen); |
382 | } | | 402 | } |
383 | | | 403 | |
384 | vn_lock(state->dp, LK_EXCLUSIVE | LK_RETRY); | | 404 | vn_lock(state->namei_startdir, LK_EXCLUSIVE | LK_RETRY); |
385 | | | 405 | |
386 | return 0; | | 406 | return 0; |
387 | } | | 407 | } |
388 | | | 408 | |
389 | /* | | 409 | /* |
390 | * Undo namei_start: unlock and release the current lookup directory, | | 410 | * Undo namei_start: unlock and release the current lookup directory, |
391 | * and discard the path buffer. | | 411 | * and discard the path buffer. |
392 | */ | | 412 | */ |
393 | static void | | 413 | static void |
394 | namei_end(struct namei_state *state) | | 414 | namei_end(struct namei_state *state) |
395 | { | | 415 | { |
396 | vput(state->dp); | | 416 | vput(state->namei_startdir); |
397 | PNBUF_PUT(state->cnp->cn_pnbuf); | | 417 | PNBUF_PUT(state->cnp->cn_pnbuf); |
398 | //state->cnp->cn_pnbuf = NULL; // not yet (just in case) (XXX) | | 418 | //state->cnp->cn_pnbuf = NULL; // not yet (just in case) (XXX) |
399 | } | | 419 | } |
400 | | | 420 | |
401 | /* | | 421 | /* |
402 | * Check for being at a symlink. | | 422 | * Check for being at a symlink. |
403 | */ | | 423 | */ |
404 | static inline int | | 424 | static inline int |
405 | namei_atsymlink(struct namei_state *state) | | 425 | namei_atsymlink(struct namei_state *state) |
406 | { | | 426 | { |
407 | return (state->cnp->cn_flags & ISSYMLINK) != 0; | | 427 | return (state->cnp->cn_flags & ISSYMLINK) != 0; |
408 | } | | 428 | } |
409 | | | 429 | |
| @@ -464,43 +484,43 @@ badlink: | | | @@ -464,43 +484,43 @@ badlink: |
464 | symlink_magic(self->l_proc, cp, &linklen)) || | | 484 | symlink_magic(self->l_proc, cp, &linklen)) || |
465 | (linklen + ndp->ni_pathlen >= MAXPATHLEN)) { | | 485 | (linklen + ndp->ni_pathlen >= MAXPATHLEN)) { |
466 | error = ENAMETOOLONG; | | 486 | error = ENAMETOOLONG; |
467 | goto badlink; | | 487 | goto badlink; |
468 | } | | 488 | } |
469 | if (ndp->ni_pathlen > 1) { | | 489 | if (ndp->ni_pathlen > 1) { |
470 | memcpy(cp + linklen, ndp->ni_next, ndp->ni_pathlen); | | 490 | memcpy(cp + linklen, ndp->ni_next, ndp->ni_pathlen); |
471 | PNBUF_PUT(cnp->cn_pnbuf); | | 491 | PNBUF_PUT(cnp->cn_pnbuf); |
472 | cnp->cn_pnbuf = cp; | | 492 | cnp->cn_pnbuf = cp; |
473 | } else | | 493 | } else |
474 | cnp->cn_pnbuf[linklen] = '\0'; | | 494 | cnp->cn_pnbuf[linklen] = '\0'; |
475 | ndp->ni_pathlen += linklen; | | 495 | ndp->ni_pathlen += linklen; |
476 | vput(ndp->ni_vp); | | 496 | vput(ndp->ni_vp); |
477 | state->dp = ndp->ni_dvp; | | 497 | state->namei_startdir = ndp->ni_dvp; |
478 | | | 498 | |
479 | /* | | 499 | /* |
480 | * Check if root directory should replace current directory. | | 500 | * Check if root directory should replace current directory. |
481 | */ | | 501 | */ |
482 | if (cnp->cn_pnbuf[0] == '/') { | | 502 | if (cnp->cn_pnbuf[0] == '/') { |
483 | vput(state->dp); | | 503 | vput(state->namei_startdir); |
484 | /* Keep absolute symbolic links inside emulation root */ | | 504 | /* Keep absolute symbolic links inside emulation root */ |
485 | state->dp = ndp->ni_erootdir; | | 505 | state->namei_startdir = ndp->ni_erootdir; |
486 | if (state->dp == NULL || (cnp->cn_pnbuf[1] == '.' | | 506 | if (state->namei_startdir == NULL || (cnp->cn_pnbuf[1] == '.' |
487 | && cnp->cn_pnbuf[2] == '.' | | 507 | && cnp->cn_pnbuf[2] == '.' |
488 | && cnp->cn_pnbuf[3] == '/')) { | | 508 | && cnp->cn_pnbuf[3] == '/')) { |
489 | ndp->ni_erootdir = NULL; | | 509 | ndp->ni_erootdir = NULL; |
490 | state->dp = ndp->ni_rootdir; | | 510 | state->namei_startdir = ndp->ni_rootdir; |
491 | } | | 511 | } |
492 | VREF(state->dp); | | 512 | VREF(state->namei_startdir); |
493 | vn_lock(state->dp, LK_EXCLUSIVE | LK_RETRY); | | 513 | vn_lock(state->namei_startdir, LK_EXCLUSIVE | LK_RETRY); |
494 | } | | 514 | } |
495 | | | 515 | |
496 | return 0; | | 516 | return 0; |
497 | } | | 517 | } |
498 | | | 518 | |
499 | ////////////////////////////// | | 519 | ////////////////////////////// |
500 | | | 520 | |
501 | static int | | 521 | static int |
502 | do_namei(struct namei_state *state) | | 522 | do_namei(struct namei_state *state) |
503 | { | | 523 | { |
504 | int error; | | 524 | int error; |
505 | | | 525 | |
506 | struct nameidata *ndp = state->ndp; | | 526 | struct nameidata *ndp = state->ndp; |
| @@ -509,33 +529,33 @@ do_namei(struct namei_state *state) | | | @@ -509,33 +529,33 @@ do_namei(struct namei_state *state) |
509 | KASSERT(cnp == &ndp->ni_cnd); | | 529 | KASSERT(cnp == &ndp->ni_cnd); |
510 | | | 530 | |
511 | namei_start1(state); | | 531 | namei_start1(state); |
512 | | | 532 | |
513 | emul_retry: | | 533 | emul_retry: |
514 | | | 534 | |
515 | error = namei_start2(state); | | 535 | error = namei_start2(state); |
516 | if (error) { | | 536 | if (error) { |
517 | return error; | | 537 | return error; |
518 | } | | 538 | } |
519 | | | 539 | |
520 | /* Loop through symbolic links */ | | 540 | /* Loop through symbolic links */ |
521 | for (;;) { | | 541 | for (;;) { |
522 | if (!state->dp->v_mount) { | | 542 | if (state->namei_startdir->v_mount == NULL) { |
523 | /* Give up if the directory is no longer mounted */ | | 543 | /* Give up if the directory is no longer mounted */ |
524 | namei_end(state); | | 544 | namei_end(state); |
525 | return (ENOENT); | | 545 | return (ENOENT); |
526 | } | | 546 | } |
527 | cnp->cn_nameptr = cnp->cn_pnbuf; | | 547 | cnp->cn_nameptr = cnp->cn_pnbuf; |
528 | ndp->ni_startdir = state->dp; | | 548 | ndp->ni_startdir = state->namei_startdir; |
529 | error = lookup(ndp); | | 549 | error = lookup(ndp); |
530 | if (error != 0) { | | 550 | if (error != 0) { |
531 | /* XXX this should use namei_end() */ | | 551 | /* XXX this should use namei_end() */ |
532 | if (ndp->ni_dvp) { | | 552 | if (ndp->ni_dvp) { |
533 | vput(ndp->ni_dvp); | | 553 | vput(ndp->ni_dvp); |
534 | } | | 554 | } |
535 | if (ndp->ni_erootdir != NULL) { | | 555 | if (ndp->ni_erootdir != NULL) { |
536 | /* Retry the whole thing from the normal root */ | | 556 | /* Retry the whole thing from the normal root */ |
537 | cnp->cn_flags &= ~TRYEMULROOT; | | 557 | cnp->cn_flags &= ~TRYEMULROOT; |
538 | goto emul_retry; | | 558 | goto emul_retry; |
539 | } | | 559 | } |
540 | PNBUF_PUT(cnp->cn_pnbuf); | | 560 | PNBUF_PUT(cnp->cn_pnbuf); |
541 | return (error); | | 561 | return (error); |
| @@ -650,427 +670,512 @@ namei_hash(const char *name, const char | | | @@ -650,427 +670,512 @@ namei_hash(const char *name, const char |
650 | * dirloop: | | 670 | * dirloop: |
651 | * identify next component of name at ndp->ni_ptr | | 671 | * identify next component of name at ndp->ni_ptr |
652 | * handle degenerate case where name is null string | | 672 | * handle degenerate case where name is null string |
653 | * if .. and crossing mount points and on mounted filesys, find parent | | 673 | * if .. and crossing mount points and on mounted filesys, find parent |
654 | * call VOP_LOOKUP routine for next component name | | 674 | * call VOP_LOOKUP routine for next component name |
655 | * directory vnode returned in ni_dvp, locked. | | 675 | * directory vnode returned in ni_dvp, locked. |
656 | * component vnode returned in ni_vp (if it exists), locked. | | 676 | * component vnode returned in ni_vp (if it exists), locked. |
657 | * if result vnode is mounted on and crossing mount points, | | 677 | * if result vnode is mounted on and crossing mount points, |
658 | * find mounted on vnode | | 678 | * find mounted on vnode |
659 | * if more components of name, do next level at dirloop | | 679 | * if more components of name, do next level at dirloop |
660 | * return the answer in ni_vp, locked if LOCKLEAF set | | 680 | * return the answer in ni_vp, locked if LOCKLEAF set |
661 | * if LOCKPARENT set, return locked parent in ni_dvp | | 681 | * if LOCKPARENT set, return locked parent in ni_dvp |
662 | */ | | 682 | */ |
663 | int | | 683 | |
664 | lookup(struct nameidata *ndp) | | 684 | /* |
| | | 685 | * Begin lookup(). |
| | | 686 | */ |
| | | 687 | static int |
| | | 688 | lookup_start(struct namei_state *state) |
665 | { | | 689 | { |
666 | const char *cp; /* pointer into pathname argument */ | | 690 | const char *cp; /* pointer into pathname argument */ |
667 | struct vnode *dp = 0; /* the directory we are searching */ | | 691 | |
668 | struct vnode *tdp; /* saved dp */ | | 692 | struct componentname *cnp = state->cnp; |
669 | struct mount *mp; /* mount table entry */ | | 693 | struct nameidata *ndp = state->ndp; |
670 | int docache; /* == 0 do not cache last component */ | | 694 | |
671 | int rdonly; /* lookup read-only flag bit */ | | 695 | KASSERT(cnp == &ndp->ni_cnd); |
672 | int error = 0; | | 696 | |
673 | int slashes; | | 697 | state->lookup_alldone = 0; |
674 | struct componentname *cnp = &ndp->ni_cnd; | | 698 | state->dp = NULL; |
675 | struct lwp *l = curlwp; | | | |
676 | | | 699 | |
677 | /* | | 700 | /* |
678 | * Setup: break out flag bits into variables. | | 701 | * Setup: break out flag bits into variables. |
679 | */ | | 702 | */ |
680 | docache = (cnp->cn_flags & NOCACHE) ^ NOCACHE; | | 703 | state->docache = (cnp->cn_flags & NOCACHE) ^ NOCACHE; |
681 | if (cnp->cn_nameiop == DELETE) | | 704 | if (cnp->cn_nameiop == DELETE) |
682 | docache = 0; | | 705 | state->docache = 0; |
683 | rdonly = cnp->cn_flags & RDONLY; | | 706 | state->rdonly = cnp->cn_flags & RDONLY; |
684 | ndp->ni_dvp = NULL; | | 707 | ndp->ni_dvp = NULL; |
685 | cnp->cn_flags &= ~ISSYMLINK; | | 708 | cnp->cn_flags &= ~ISSYMLINK; |
686 | dp = ndp->ni_startdir; | | 709 | state->dp = ndp->ni_startdir; |
687 | ndp->ni_startdir = NULLVP; | | 710 | ndp->ni_startdir = NULLVP; |
688 | | | 711 | |
689 | /* | | 712 | /* |
690 | * If we have a leading string of slashes, remove them, and just make | | 713 | * If we have a leading string of slashes, remove them, and just make |
691 | * sure the current node is a directory. | | 714 | * sure the current node is a directory. |
692 | */ | | 715 | */ |
693 | cp = cnp->cn_nameptr; | | 716 | cp = cnp->cn_nameptr; |
694 | if (*cp == '/') { | | 717 | if (*cp == '/') { |
695 | do { | | 718 | do { |
696 | cp++; | | 719 | cp++; |
697 | } while (*cp == '/'); | | 720 | } while (*cp == '/'); |
698 | ndp->ni_pathlen -= cp - cnp->cn_nameptr; | | 721 | ndp->ni_pathlen -= cp - cnp->cn_nameptr; |
699 | cnp->cn_nameptr = cp; | | 722 | cnp->cn_nameptr = cp; |
700 | | | 723 | |
701 | if (dp->v_type != VDIR) { | | 724 | if (state->dp->v_type != VDIR) { |
702 | error = ENOTDIR; | | 725 | vput(state->dp); |
703 | vput(dp); | | 726 | return ENOTDIR; |
704 | goto bad; | | | |
705 | } | | 727 | } |
706 | | | 728 | |
707 | /* | | 729 | /* |
708 | * If we've exhausted the path name, then just return the | | 730 | * If we've exhausted the path name, then just return the |
709 | * current node. | | 731 | * current node. |
710 | */ | | 732 | */ |
711 | if (cnp->cn_nameptr[0] == '\0') { | | 733 | if (cnp->cn_nameptr[0] == '\0') { |
712 | ndp->ni_vp = dp; | | 734 | ndp->ni_vp = state->dp; |
713 | cnp->cn_flags |= ISLASTCN; | | 735 | cnp->cn_flags |= ISLASTCN; |
714 | goto terminal; | | 736 | |
| | | 737 | /* bleh */ |
| | | 738 | state->lookup_alldone = 1; |
| | | 739 | return 0; |
715 | } | | 740 | } |
716 | } | | 741 | } |
717 | | | 742 | |
718 | dirloop: | | 743 | return 0; |
| | | 744 | } |
| | | 745 | |
| | | 746 | static int |
| | | 747 | lookup_parsepath(struct namei_state *state) |
| | | 748 | { |
| | | 749 | const char *cp; /* pointer into pathname argument */ |
| | | 750 | |
| | | 751 | struct componentname *cnp = state->cnp; |
| | | 752 | struct nameidata *ndp = state->ndp; |
| | | 753 | |
| | | 754 | KASSERT(cnp == &ndp->ni_cnd); |
| | | 755 | |
719 | /* | | 756 | /* |
720 | * Search a new directory. | | 757 | * Search a new directory. |
721 | * | | 758 | * |
722 | * The cn_hash value is for use by vfs_cache. | | 759 | * The cn_hash value is for use by vfs_cache. |
723 | * The last component of the filename is left accessible via | | 760 | * The last component of the filename is left accessible via |
724 | * cnp->cn_nameptr for callers that need the name. Callers needing | | 761 | * cnp->cn_nameptr for callers that need the name. Callers needing |
725 | * the name set the SAVENAME flag. When done, they assume | | 762 | * the name set the SAVENAME flag. When done, they assume |
726 | * responsibility for freeing the pathname buffer. | | 763 | * responsibility for freeing the pathname buffer. |
727 | * | | 764 | * |
728 | * At this point, our only vnode state is that "dp" is held and locked. | | 765 | * At this point, our only vnode state is that "dp" is held and locked. |
729 | */ | | 766 | */ |
730 | cnp->cn_consume = 0; | | 767 | cnp->cn_consume = 0; |
731 | cp = NULL; | | 768 | cp = NULL; |
732 | cnp->cn_hash = namei_hash(cnp->cn_nameptr, &cp); | | 769 | cnp->cn_hash = namei_hash(cnp->cn_nameptr, &cp); |
733 | cnp->cn_namelen = cp - cnp->cn_nameptr; | | 770 | cnp->cn_namelen = cp - cnp->cn_nameptr; |
734 | if (cnp->cn_namelen > NAME_MAX) { | | 771 | if (cnp->cn_namelen > NAME_MAX) { |
735 | vput(dp); | | 772 | vput(state->dp); |
736 | error = ENAMETOOLONG; | | | |
737 | ndp->ni_dvp = NULL; | | 773 | ndp->ni_dvp = NULL; |
738 | goto bad; | | 774 | return ENAMETOOLONG; |
739 | } | | 775 | } |
740 | #ifdef NAMEI_DIAGNOSTIC | | 776 | #ifdef NAMEI_DIAGNOSTIC |
741 | { char c = *cp; | | 777 | { char c = *cp; |
742 | *(char *)cp = '\0'; | | 778 | *(char *)cp = '\0'; |
743 | printf("{%s}: ", cnp->cn_nameptr); | | 779 | printf("{%s}: ", cnp->cn_nameptr); |
744 | *(char *)cp = c; } | | 780 | *(char *)cp = c; } |
745 | #endif /* NAMEI_DIAGNOSTIC */ | | 781 | #endif /* NAMEI_DIAGNOSTIC */ |
746 | ndp->ni_pathlen -= cnp->cn_namelen; | | 782 | ndp->ni_pathlen -= cnp->cn_namelen; |
747 | ndp->ni_next = cp; | | 783 | ndp->ni_next = cp; |
748 | /* | | 784 | /* |
749 | * If this component is followed by a slash, then move the pointer to | | 785 | * If this component is followed by a slash, then move the pointer to |
750 | * the next component forward, and remember that this component must be | | 786 | * the next component forward, and remember that this component must be |
751 | * a directory. | | 787 | * a directory. |
752 | */ | | 788 | */ |
753 | if (*cp == '/') { | | 789 | if (*cp == '/') { |
754 | do { | | 790 | do { |
755 | cp++; | | 791 | cp++; |
756 | } while (*cp == '/'); | | 792 | } while (*cp == '/'); |
757 | slashes = cp - ndp->ni_next; | | 793 | state->slashes = cp - ndp->ni_next; |
758 | ndp->ni_pathlen -= slashes; | | 794 | ndp->ni_pathlen -= state->slashes; |
759 | ndp->ni_next = cp; | | 795 | ndp->ni_next = cp; |
760 | cnp->cn_flags |= REQUIREDIR; | | 796 | cnp->cn_flags |= REQUIREDIR; |
761 | } else { | | 797 | } else { |
762 | slashes = 0; | | 798 | state->slashes = 0; |
763 | cnp->cn_flags &= ~REQUIREDIR; | | 799 | cnp->cn_flags &= ~REQUIREDIR; |
764 | } | | 800 | } |
765 | /* | | 801 | /* |
766 | * We do special processing on the last component, whether or not it's | | 802 | * We do special processing on the last component, whether or not it's |
767 | * a directory. Cache all intervening lookups, but not the final one. | | 803 | * a directory. Cache all intervening lookups, but not the final one. |
768 | */ | | 804 | */ |
769 | if (*cp == '\0') { | | 805 | if (*cp == '\0') { |
770 | if (docache) | | 806 | if (state->docache) |
771 | cnp->cn_flags |= MAKEENTRY; | | 807 | cnp->cn_flags |= MAKEENTRY; |
772 | else | | 808 | else |
773 | cnp->cn_flags &= ~MAKEENTRY; | | 809 | cnp->cn_flags &= ~MAKEENTRY; |
774 | cnp->cn_flags |= ISLASTCN; | | 810 | cnp->cn_flags |= ISLASTCN; |
775 | } else { | | 811 | } else { |
776 | cnp->cn_flags |= MAKEENTRY; | | 812 | cnp->cn_flags |= MAKEENTRY; |
777 | cnp->cn_flags &= ~ISLASTCN; | | 813 | cnp->cn_flags &= ~ISLASTCN; |
778 | } | | 814 | } |
779 | if (cnp->cn_namelen == 2 && | | 815 | if (cnp->cn_namelen == 2 && |
780 | cnp->cn_nameptr[1] == '.' && cnp->cn_nameptr[0] == '.') | | 816 | cnp->cn_nameptr[1] == '.' && cnp->cn_nameptr[0] == '.') |
781 | cnp->cn_flags |= ISDOTDOT; | | 817 | cnp->cn_flags |= ISDOTDOT; |
782 | else | | 818 | else |
783 | cnp->cn_flags &= ~ISDOTDOT; | | 819 | cnp->cn_flags &= ~ISDOTDOT; |
784 | | | 820 | |
| | | 821 | return 0; |
| | | 822 | } |
| | | 823 | |
| | | 824 | static int |
| | | 825 | lookup_once(struct namei_state *state) |
| | | 826 | { |
| | | 827 | struct vnode *tdp; /* saved dp */ |
| | | 828 | struct mount *mp; /* mount table entry */ |
| | | 829 | struct lwp *l = curlwp; |
| | | 830 | int error; |
| | | 831 | |
| | | 832 | struct componentname *cnp = state->cnp; |
| | | 833 | struct nameidata *ndp = state->ndp; |
| | | 834 | |
| | | 835 | KASSERT(cnp == &ndp->ni_cnd); |
| | | 836 | |
785 | /* | | 837 | /* |
786 | * Handle "..": two special cases. | | 838 | * Handle "..": two special cases. |
787 | * 1. If at root directory (e.g. after chroot) | | 839 | * 1. If at root directory (e.g. after chroot) |
788 | * or at absolute root directory | | 840 | * or at absolute root directory |
789 | * then ignore it so can't get out. | | 841 | * then ignore it so can't get out. |
790 | * 1a. If at the root of the emulation filesystem go to the real | | 842 | * 1a. If at the root of the emulation filesystem go to the real |
791 | * root. So "/../<path>" is always absolute. | | 843 | * root. So "/../<path>" is always absolute. |
792 | * 1b. If we have somehow gotten out of a jail, warn | | 844 | * 1b. If we have somehow gotten out of a jail, warn |
793 | * and also ignore it so we can't get farther out. | | 845 | * and also ignore it so we can't get farther out. |
794 | * 2. If this vnode is the root of a mounted | | 846 | * 2. If this vnode is the root of a mounted |
795 | * filesystem, then replace it with the | | 847 | * filesystem, then replace it with the |
796 | * vnode which was mounted on so we take the | | 848 | * vnode which was mounted on so we take the |
797 | * .. in the other file system. | | 849 | * .. in the other file system. |
798 | */ | | 850 | */ |
799 | if (cnp->cn_flags & ISDOTDOT) { | | 851 | if (cnp->cn_flags & ISDOTDOT) { |
800 | struct proc *p = l->l_proc; | | 852 | struct proc *p = l->l_proc; |
801 | | | 853 | |
802 | for (;;) { | | 854 | for (;;) { |
803 | if (dp == ndp->ni_rootdir || dp == rootvnode) { | | 855 | if (state->dp == ndp->ni_rootdir || state->dp == rootvnode) { |
804 | ndp->ni_dvp = dp; | | 856 | ndp->ni_dvp = state->dp; |
805 | ndp->ni_vp = dp; | | 857 | ndp->ni_vp = state->dp; |
806 | VREF(dp); | | 858 | VREF(state->dp); |
807 | goto nextname; | | 859 | return 0; |
808 | } | | 860 | } |
809 | if (ndp->ni_rootdir != rootvnode) { | | 861 | if (ndp->ni_rootdir != rootvnode) { |
810 | int retval; | | 862 | int retval; |
811 | | | 863 | |
812 | VOP_UNLOCK(dp, 0); | | 864 | VOP_UNLOCK(state->dp, 0); |
813 | retval = vn_isunder(dp, ndp->ni_rootdir, l); | | 865 | retval = vn_isunder(state->dp, ndp->ni_rootdir, l); |
814 | vn_lock(dp, LK_EXCLUSIVE | LK_RETRY); | | 866 | vn_lock(state->dp, LK_EXCLUSIVE | LK_RETRY); |
815 | if (!retval) { | | 867 | if (!retval) { |
816 | /* Oops! We got out of jail! */ | | 868 | /* Oops! We got out of jail! */ |
817 | log(LOG_WARNING, | | 869 | log(LOG_WARNING, |
818 | "chrooted pid %d uid %d (%s) " | | 870 | "chrooted pid %d uid %d (%s) " |
819 | "detected outside of its chroot\n", | | 871 | "detected outside of its chroot\n", |
820 | p->p_pid, kauth_cred_geteuid(l->l_cred), | | 872 | p->p_pid, kauth_cred_geteuid(l->l_cred), |
821 | p->p_comm); | | 873 | p->p_comm); |
822 | /* Put us at the jail root. */ | | 874 | /* Put us at the jail root. */ |
823 | vput(dp); | | 875 | vput(state->dp); |
824 | dp = ndp->ni_rootdir; | | 876 | state->dp = ndp->ni_rootdir; |
825 | ndp->ni_dvp = dp; | | 877 | ndp->ni_dvp = state->dp; |
826 | ndp->ni_vp = dp; | | 878 | ndp->ni_vp = state->dp; |
827 | VREF(dp); | | 879 | VREF(state->dp); |
828 | VREF(dp); | | 880 | VREF(state->dp); |
829 | vn_lock(dp, LK_EXCLUSIVE | LK_RETRY); | | 881 | vn_lock(state->dp, LK_EXCLUSIVE | LK_RETRY); |
830 | goto nextname; | | 882 | return 0; |
831 | } | | 883 | } |
832 | } | | 884 | } |
833 | if ((dp->v_vflag & VV_ROOT) == 0 || | | 885 | if ((state->dp->v_vflag & VV_ROOT) == 0 || |
834 | (cnp->cn_flags & NOCROSSMOUNT)) | | 886 | (cnp->cn_flags & NOCROSSMOUNT)) |
835 | break; | | 887 | break; |
836 | tdp = dp; | | 888 | tdp = state->dp; |
837 | dp = dp->v_mount->mnt_vnodecovered; | | 889 | state->dp = state->dp->v_mount->mnt_vnodecovered; |
838 | vput(tdp); | | 890 | vput(tdp); |
839 | VREF(dp); | | 891 | VREF(state->dp); |
840 | vn_lock(dp, LK_EXCLUSIVE | LK_RETRY); | | 892 | vn_lock(state->dp, LK_EXCLUSIVE | LK_RETRY); |
841 | } | | 893 | } |
842 | } | | 894 | } |
843 | | | 895 | |
844 | /* | | 896 | /* |
845 | * We now have a segment name to search for, and a directory to search. | | 897 | * We now have a segment name to search for, and a directory to search. |
846 | * Again, our only vnode state is that "dp" is held and locked. | | 898 | * Again, our only vnode state is that "dp" is held and locked. |
847 | */ | | 899 | */ |
848 | unionlookup: | | 900 | unionlookup: |
849 | ndp->ni_dvp = dp; | | 901 | ndp->ni_dvp = state->dp; |
850 | ndp->ni_vp = NULL; | | 902 | ndp->ni_vp = NULL; |
851 | error = VOP_LOOKUP(dp, &ndp->ni_vp, cnp); | | 903 | error = VOP_LOOKUP(state->dp, &ndp->ni_vp, cnp); |
852 | if (error != 0) { | | 904 | if (error != 0) { |
853 | #ifdef DIAGNOSTIC | | 905 | #ifdef DIAGNOSTIC |
854 | if (ndp->ni_vp != NULL) | | 906 | if (ndp->ni_vp != NULL) |
855 | panic("leaf `%s' should be empty", cnp->cn_nameptr); | | 907 | panic("leaf `%s' should be empty", cnp->cn_nameptr); |
856 | #endif /* DIAGNOSTIC */ | | 908 | #endif /* DIAGNOSTIC */ |
857 | #ifdef NAMEI_DIAGNOSTIC | | 909 | #ifdef NAMEI_DIAGNOSTIC |
858 | printf("not found\n"); | | 910 | printf("not found\n"); |
859 | #endif /* NAMEI_DIAGNOSTIC */ | | 911 | #endif /* NAMEI_DIAGNOSTIC */ |
860 | if ((error == ENOENT) && | | 912 | if ((error == ENOENT) && |
861 | (dp->v_vflag & VV_ROOT) && | | 913 | (state->dp->v_vflag & VV_ROOT) && |
862 | (dp->v_mount->mnt_flag & MNT_UNION)) { | | 914 | (state->dp->v_mount->mnt_flag & MNT_UNION)) { |
863 | tdp = dp; | | 915 | tdp = state->dp; |
864 | dp = dp->v_mount->mnt_vnodecovered; | | 916 | state->dp = state->dp->v_mount->mnt_vnodecovered; |
865 | vput(tdp); | | 917 | vput(tdp); |
866 | VREF(dp); | | 918 | VREF(state->dp); |
867 | vn_lock(dp, LK_EXCLUSIVE | LK_RETRY); | | 919 | vn_lock(state->dp, LK_EXCLUSIVE | LK_RETRY); |
868 | goto unionlookup; | | 920 | goto unionlookup; |
869 | } | | 921 | } |
870 | | | 922 | |
871 | if (error != EJUSTRETURN) | | 923 | if (error != EJUSTRETURN) |
872 | goto bad; | | 924 | return error; |
873 | | | 925 | |
874 | /* | | 926 | /* |
875 | * If this was not the last component, or there were trailing | | 927 | * If this was not the last component, or there were trailing |
876 | * slashes, and we are not going to create a directory, | | 928 | * slashes, and we are not going to create a directory, |
877 | * then the name must exist. | | 929 | * then the name must exist. |
878 | */ | | 930 | */ |
879 | if ((cnp->cn_flags & (REQUIREDIR | CREATEDIR)) == REQUIREDIR) { | | 931 | if ((cnp->cn_flags & (REQUIREDIR | CREATEDIR)) == REQUIREDIR) { |
880 | error = ENOENT; | | 932 | return ENOENT; |
881 | goto bad; | | | |
882 | } | | 933 | } |
883 | | | 934 | |
884 | /* | | 935 | /* |
885 | * If creating and at end of pathname, then can consider | | 936 | * If creating and at end of pathname, then can consider |
886 | * allowing file to be created. | | 937 | * allowing file to be created. |
887 | */ | | 938 | */ |
888 | if (rdonly) { | | 939 | if (state->rdonly) { |
889 | error = EROFS; | | 940 | return EROFS; |
890 | goto bad; | | | |
891 | } | | 941 | } |
892 | | | 942 | |
893 | /* | | 943 | /* |
894 | * We return with ni_vp NULL to indicate that the entry | | 944 | * We return with ni_vp NULL to indicate that the entry |
895 | * doesn't currently exist, leaving a pointer to the | | 945 | * doesn't currently exist, leaving a pointer to the |
896 | * (possibly locked) directory vnode in ndp->ni_dvp. | | 946 | * (possibly locked) directory vnode in ndp->ni_dvp. |
897 | */ | | 947 | */ |
898 | if (cnp->cn_flags & SAVESTART) { | | 948 | if (cnp->cn_flags & SAVESTART) { |
899 | ndp->ni_startdir = ndp->ni_dvp; | | 949 | ndp->ni_startdir = ndp->ni_dvp; |
900 | VREF(ndp->ni_startdir); | | 950 | VREF(ndp->ni_startdir); |
901 | } | | 951 | } |
| | | 952 | state->lookup_alldone = 1; |
902 | return (0); | | 953 | return (0); |
903 | } | | 954 | } |
904 | #ifdef NAMEI_DIAGNOSTIC | | 955 | #ifdef NAMEI_DIAGNOSTIC |
905 | printf("found\n"); | | 956 | printf("found\n"); |
906 | #endif /* NAMEI_DIAGNOSTIC */ | | 957 | #endif /* NAMEI_DIAGNOSTIC */ |
907 | | | 958 | |
908 | /* | | 959 | /* |
909 | * Take into account any additional components consumed by the | | 960 | * Take into account any additional components consumed by the |
910 | * underlying filesystem. This will include any trailing slashes after | | 961 | * underlying filesystem. This will include any trailing slashes after |
911 | * the last component consumed. | | 962 | * the last component consumed. |
912 | */ | | 963 | */ |
913 | if (cnp->cn_consume > 0) { | | 964 | if (cnp->cn_consume > 0) { |
914 | ndp->ni_pathlen -= cnp->cn_consume - slashes; | | 965 | ndp->ni_pathlen -= cnp->cn_consume - state->slashes; |
915 | ndp->ni_next += cnp->cn_consume - slashes; | | 966 | ndp->ni_next += cnp->cn_consume - state->slashes; |
916 | cnp->cn_consume = 0; | | 967 | cnp->cn_consume = 0; |
917 | if (ndp->ni_next[0] == '\0') | | 968 | if (ndp->ni_next[0] == '\0') |
918 | cnp->cn_flags |= ISLASTCN; | | 969 | cnp->cn_flags |= ISLASTCN; |
919 | } | | 970 | } |
920 | | | 971 | |
921 | dp = ndp->ni_vp; | | 972 | state->dp = ndp->ni_vp; |
922 | | | 973 | |
923 | /* | | 974 | /* |
924 | * "dp" and "ndp->ni_dvp" are both locked and held, | | 975 | * "state->dp" and "ndp->ni_dvp" are both locked and held, |
925 | * and may be the same vnode. | | 976 | * and may be the same vnode. |
926 | */ | | 977 | */ |
927 | | | 978 | |
928 | /* | | 979 | /* |
929 | * Check to see if the vnode has been mounted on; | | 980 | * Check to see if the vnode has been mounted on; |
930 | * if so find the root of the mounted file system. | | 981 | * if so find the root of the mounted file system. |
931 | */ | | 982 | */ |
932 | while (dp->v_type == VDIR && (mp = dp->v_mountedhere) && | | 983 | while (state->dp->v_type == VDIR && (mp = state->dp->v_mountedhere) && |
933 | (cnp->cn_flags & NOCROSSMOUNT) == 0) { | | 984 | (cnp->cn_flags & NOCROSSMOUNT) == 0) { |
934 | error = vfs_busy(mp, NULL); | | 985 | error = vfs_busy(mp, NULL); |
935 | if (error != 0) { | | 986 | if (error != 0) { |
936 | vput(dp); | | 987 | vput(state->dp); |
937 | goto bad; | | 988 | return error; |
938 | } | | 989 | } |
939 | KASSERT(ndp->ni_dvp != dp); | | 990 | KASSERT(ndp->ni_dvp != state->dp); |
940 | VOP_UNLOCK(ndp->ni_dvp, 0); | | 991 | VOP_UNLOCK(ndp->ni_dvp, 0); |
941 | vput(dp); | | 992 | vput(state->dp); |
942 | error = VFS_ROOT(mp, &tdp); | | 993 | error = VFS_ROOT(mp, &tdp); |
943 | vfs_unbusy(mp, false, NULL); | | 994 | vfs_unbusy(mp, false, NULL); |
944 | if (error) { | | 995 | if (error) { |
945 | vn_lock(ndp->ni_dvp, LK_EXCLUSIVE | LK_RETRY); | | 996 | vn_lock(ndp->ni_dvp, LK_EXCLUSIVE | LK_RETRY); |
946 | goto bad; | | 997 | return error; |
947 | } | | 998 | } |
948 | VOP_UNLOCK(tdp, 0); | | 999 | VOP_UNLOCK(tdp, 0); |
949 | ndp->ni_vp = dp = tdp; | | 1000 | ndp->ni_vp = state->dp = tdp; |
950 | vn_lock(ndp->ni_dvp, LK_EXCLUSIVE | LK_RETRY); | | 1001 | vn_lock(ndp->ni_dvp, LK_EXCLUSIVE | LK_RETRY); |
951 | vn_lock(ndp->ni_vp, LK_EXCLUSIVE | LK_RETRY); | | 1002 | vn_lock(ndp->ni_vp, LK_EXCLUSIVE | LK_RETRY); |
952 | } | | 1003 | } |
953 | | | 1004 | |
| | | 1005 | return 0; |
| | | 1006 | } |
| | | 1007 | |
| | | 1008 | static int |
| | | 1009 | do_lookup(struct namei_state *state) |
| | | 1010 | { |
| | | 1011 | int error = 0; |
| | | 1012 | |
| | | 1013 | struct componentname *cnp = state->cnp; |
| | | 1014 | struct nameidata *ndp = state->ndp; |
| | | 1015 | |
| | | 1016 | KASSERT(cnp == &ndp->ni_cnd); |
| | | 1017 | |
| | | 1018 | error = lookup_start(state); |
| | | 1019 | if (error) { |
| | | 1020 | goto bad; |
| | | 1021 | } |
| | | 1022 | // XXX: this case should not be necessary given proper handling |
| | | 1023 | // of slashes elsewhere. |
| | | 1024 | if (state->lookup_alldone) { |
| | | 1025 | goto terminal; |
| | | 1026 | } |
| | | 1027 | |
| | | 1028 | dirloop: |
| | | 1029 | error = lookup_parsepath(state); |
| | | 1030 | if (error) { |
| | | 1031 | goto bad; |
| | | 1032 | } |
| | | 1033 | |
| | | 1034 | error = lookup_once(state); |
| | | 1035 | if (error) { |
| | | 1036 | goto bad; |
| | | 1037 | } |
| | | 1038 | // XXX ought to be able to avoid this case too |
| | | 1039 | if (state->lookup_alldone) { |
| | | 1040 | /* this should NOT be "goto terminal;" */ |
| | | 1041 | return 0; |
| | | 1042 | } |
| | | 1043 | |
954 | /* | | 1044 | /* |
955 | * Check for symbolic link. Back up over any slashes that we skipped, | | 1045 | * Check for symbolic link. Back up over any slashes that we skipped, |
956 | * as we will need them again. | | 1046 | * as we will need them again. |
957 | */ | | 1047 | */ |
958 | if ((dp->v_type == VLNK) && (cnp->cn_flags & (FOLLOW|REQUIREDIR))) { | | 1048 | if ((state->dp->v_type == VLNK) && (cnp->cn_flags & (FOLLOW|REQUIREDIR))) { |
959 | ndp->ni_pathlen += slashes; | | 1049 | ndp->ni_pathlen += state->slashes; |
960 | ndp->ni_next -= slashes; | | 1050 | ndp->ni_next -= state->slashes; |
961 | cnp->cn_flags |= ISSYMLINK; | | 1051 | cnp->cn_flags |= ISSYMLINK; |
962 | return (0); | | 1052 | return (0); |
963 | } | | 1053 | } |
964 | | | 1054 | |
965 | /* | | 1055 | /* |
966 | * Check for directory, if the component was followed by a series of | | 1056 | * Check for directory, if the component was followed by a series of |
967 | * slashes. | | 1057 | * slashes. |
968 | */ | | 1058 | */ |
969 | if ((dp->v_type != VDIR) && (cnp->cn_flags & REQUIREDIR)) { | | 1059 | if ((state->dp->v_type != VDIR) && (cnp->cn_flags & REQUIREDIR)) { |
970 | error = ENOTDIR; | | 1060 | error = ENOTDIR; |
971 | KASSERT(dp != ndp->ni_dvp); | | 1061 | KASSERT(state->dp != ndp->ni_dvp); |
972 | vput(dp); | | 1062 | vput(state->dp); |
973 | goto bad; | | 1063 | goto bad; |
974 | } | | 1064 | } |
975 | | | 1065 | |
976 | nextname: | | | |
977 | | | | |
978 | /* | | 1066 | /* |
979 | * Not a symbolic link. If this was not the last component, then | | 1067 | * Not a symbolic link. If this was not the last component, then |
980 | * continue at the next component, else return. | | 1068 | * continue at the next component, else return. |
981 | */ | | 1069 | */ |
982 | if (!(cnp->cn_flags & ISLASTCN)) { | | 1070 | if (!(cnp->cn_flags & ISLASTCN)) { |
983 | cnp->cn_nameptr = ndp->ni_next; | | 1071 | cnp->cn_nameptr = ndp->ni_next; |
984 | if (ndp->ni_dvp == dp) { | | 1072 | if (ndp->ni_dvp == state->dp) { |
985 | vrele(ndp->ni_dvp); | | 1073 | vrele(ndp->ni_dvp); |
986 | } else { | | 1074 | } else { |
987 | vput(ndp->ni_dvp); | | 1075 | vput(ndp->ni_dvp); |
988 | } | | 1076 | } |
989 | goto dirloop; | | 1077 | goto dirloop; |
990 | } | | 1078 | } |
991 | | | 1079 | |
992 | terminal: | | 1080 | terminal: |
993 | if (dp == ndp->ni_erootdir) { | | 1081 | if (state->dp == ndp->ni_erootdir) { |
994 | /* | | 1082 | /* |
995 | * We are about to return the emulation root. | | 1083 | * We are about to return the emulation root. |
996 | * This isn't a good idea because code might repeatedly | | 1084 | * This isn't a good idea because code might repeatedly |
997 | * lookup ".." until the file matches that returned | | 1085 | * lookup ".." until the file matches that returned |
998 | * for "/" and loop forever. | | 1086 | * for "/" and loop forever. |
999 | * So convert it to the real root. | | 1087 | * So convert it to the real root. |
1000 | */ | | 1088 | */ |
1001 | if (ndp->ni_dvp == dp) | | 1089 | if (ndp->ni_dvp == state->dp) |
1002 | vrele(dp); | | 1090 | vrele(state->dp); |
1003 | else | | 1091 | else |
1004 | if (ndp->ni_dvp != NULL) | | 1092 | if (ndp->ni_dvp != NULL) |
1005 | vput(ndp->ni_dvp); | | 1093 | vput(ndp->ni_dvp); |
1006 | ndp->ni_dvp = NULL; | | 1094 | ndp->ni_dvp = NULL; |
1007 | vput(dp); | | 1095 | vput(state->dp); |
1008 | dp = ndp->ni_rootdir; | | 1096 | state->dp = ndp->ni_rootdir; |
1009 | VREF(dp); | | 1097 | VREF(state->dp); |
1010 | vn_lock(dp, LK_EXCLUSIVE | LK_RETRY); | | 1098 | vn_lock(state->dp, LK_EXCLUSIVE | LK_RETRY); |
1011 | ndp->ni_vp = dp; | | 1099 | ndp->ni_vp = state->dp; |
1012 | } | | 1100 | } |
1013 | | | 1101 | |
1014 | /* | | 1102 | /* |
1015 | * If the caller requested the parent node (i.e. | | 1103 | * If the caller requested the parent node (i.e. |
1016 | * it's a CREATE, DELETE, or RENAME), and we don't have one | | 1104 | * it's a CREATE, DELETE, or RENAME), and we don't have one |
1017 | * (because this is the root directory), then we must fail. | | 1105 | * (because this is the root directory), then we must fail. |
1018 | */ | | 1106 | */ |
1019 | if (ndp->ni_dvp == NULL && cnp->cn_nameiop != LOOKUP) { | | 1107 | if (ndp->ni_dvp == NULL && cnp->cn_nameiop != LOOKUP) { |
1020 | switch (cnp->cn_nameiop) { | | 1108 | switch (cnp->cn_nameiop) { |
1021 | case CREATE: | | 1109 | case CREATE: |
1022 | error = EEXIST; | | 1110 | error = EEXIST; |
1023 | break; | | 1111 | break; |
1024 | case DELETE: | | 1112 | case DELETE: |
1025 | case RENAME: | | 1113 | case RENAME: |
1026 | error = EBUSY; | | 1114 | error = EBUSY; |
1027 | break; | | 1115 | break; |
1028 | default: | | 1116 | default: |
1029 | KASSERT(0); | | 1117 | KASSERT(0); |
1030 | } | | 1118 | } |
1031 | vput(dp); | | 1119 | vput(state->dp); |
1032 | goto bad; | | 1120 | goto bad; |
1033 | } | | 1121 | } |
1034 | | | 1122 | |
1035 | /* | | 1123 | /* |
1036 | * Disallow directory write attempts on read-only lookups. | | 1124 | * Disallow directory write attempts on read-only lookups. |
1037 | * Prefers EEXIST over EROFS for the CREATE case. | | 1125 | * Prefers EEXIST over EROFS for the CREATE case. |
1038 | */ | | 1126 | */ |
1039 | if (rdonly && | | 1127 | if (state->rdonly && |
1040 | (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)) { | | 1128 | (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)) { |
1041 | error = EROFS; | | 1129 | error = EROFS; |
1042 | if (dp != ndp->ni_dvp) { | | 1130 | if (state->dp != ndp->ni_dvp) { |
1043 | vput(dp); | | 1131 | vput(state->dp); |
1044 | } | | 1132 | } |
1045 | goto bad; | | 1133 | goto bad; |
1046 | } | | 1134 | } |
1047 | if (ndp->ni_dvp != NULL) { | | 1135 | if (ndp->ni_dvp != NULL) { |
1048 | if (cnp->cn_flags & SAVESTART) { | | 1136 | if (cnp->cn_flags & SAVESTART) { |
1049 | ndp->ni_startdir = ndp->ni_dvp; | | 1137 | ndp->ni_startdir = ndp->ni_dvp; |
1050 | VREF(ndp->ni_startdir); | | 1138 | VREF(ndp->ni_startdir); |
1051 | } | | 1139 | } |
1052 | } | | 1140 | } |
1053 | if ((cnp->cn_flags & LOCKLEAF) == 0) { | | 1141 | if ((cnp->cn_flags & LOCKLEAF) == 0) { |
1054 | VOP_UNLOCK(dp, 0); | | 1142 | VOP_UNLOCK(state->dp, 0); |
1055 | } | | 1143 | } |
1056 | return (0); | | 1144 | return (0); |
1057 | | | 1145 | |
1058 | bad: | | 1146 | bad: |
1059 | ndp->ni_vp = NULL; | | 1147 | ndp->ni_vp = NULL; |
1060 | return (error); | | 1148 | return (error); |
1061 | } | | 1149 | } |
1062 | | | 1150 | |
1063 | /* | | 1151 | /* |
| | | 1152 | * Externally visible interface used by nfsd (bletch, yuk, XXX) |
| | | 1153 | */ |
| | | 1154 | int |
| | | 1155 | lookup(struct nameidata *ndp) |
| | | 1156 | { |
| | | 1157 | struct namei_state state; |
| | | 1158 | int error; |
| | | 1159 | |
| | | 1160 | /* For now at least we don't have to frob the state */ |
| | | 1161 | namei_init(&state, ndp); |
| | | 1162 | error = do_lookup(&state); |
| | | 1163 | namei_cleanup(&state); |
| | | 1164 | |
| | | 1165 | return error; |
| | | 1166 | } |
| | | 1167 | |
| | | 1168 | /* |
1064 | * Reacquire a path name component. | | 1169 | * Reacquire a path name component. |
1065 | * dvp is locked on entry and exit. | | 1170 | * dvp is locked on entry and exit. |
1066 | * *vpp is locked on exit unless it's NULL. | | 1171 | * *vpp is locked on exit unless it's NULL. |
1067 | */ | | 1172 | */ |
1068 | int | | 1173 | int |
1069 | relookup(struct vnode *dvp, struct vnode **vpp, struct componentname *cnp) | | 1174 | relookup(struct vnode *dvp, struct vnode **vpp, struct componentname *cnp) |
1070 | { | | 1175 | { |
1071 | int rdonly; /* lookup read-only flag bit */ | | 1176 | int rdonly; /* lookup read-only flag bit */ |
1072 | int error = 0; | | 1177 | int error = 0; |
1073 | #ifdef DEBUG | | 1178 | #ifdef DEBUG |
1074 | uint32_t newhash; /* DEBUG: check name hash */ | | 1179 | uint32_t newhash; /* DEBUG: check name hash */ |
1075 | const char *cp; /* DEBUG: check name ptr/len */ | | 1180 | const char *cp; /* DEBUG: check name ptr/len */ |
1076 | #endif /* DEBUG */ | | 1181 | #endif /* DEBUG */ |