Sun Aug 9 03:28:35 2009 UTC ()
Begin splitting up namei into smaller pieces.


(dholland)
diff -r1.116 -r1.117 src/sys/kern/vfs_lookup.c

cvs diff -r1.116 -r1.117 src/sys/kern/vfs_lookup.c (expand / switch to unified diff)

--- src/sys/kern/vfs_lookup.c 2009/06/29 05:00:14 1.116
+++ src/sys/kern/vfs_lookup.c 2009/08/09 03:28:35 1.117
@@ -1,14 +1,14 @@ @@ -1,14 +1,14 @@
1/* $NetBSD: vfs_lookup.c,v 1.116 2009/06/29 05:00:14 dholland Exp $ */ 1/* $NetBSD: vfs_lookup.c,v 1.117 2009/08/09 03:28:35 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.116 2009/06/29 05:00:14 dholland Exp $"); 40__KERNEL_RCSID(0, "$NetBSD: vfs_lookup.c,v 1.117 2009/08/09 03:28:35 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>
@@ -206,262 +206,404 @@ symlink_magic(struct proc *p, char *cp,  @@ -206,262 +206,404 @@ symlink_magic(struct proc *p, char *cp,
206 * 206 *
207 * The segflg defines whether the name is to be copied from user 207 * The segflg defines whether the name is to be copied from user
208 * space or kernel space. 208 * space or kernel space.
209 * 209 *
210 * Overall outline of namei: 210 * Overall outline of namei:
211 * 211 *
212 * copy in name 212 * copy in name
213 * get starting directory 213 * get starting directory
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 */
219int 219
220namei(struct nameidata *ndp) 220/*
221{ 221 * Internal state for a namei operation.
222 struct cwdinfo *cwdi; /* pointer to cwd state */ 222 */
223 char *cp; /* pointer into pathname argument */ 223struct namei_state {
 224 struct nameidata *ndp;
 225 struct componentname *cnp;
 226
224 struct vnode *dp; /* the directory we are searching */ 227 struct vnode *dp; /* the directory we are searching */
225 struct iovec aiov; /* uio for reading symbolic links */ 228};
226 struct lwp *l = curlwp; /* thread doing namei() */ 229
227 struct uio auio; 230/*
228 int error; 231 * Initialize the namei working state.
229 size_t linklen; 232 */
230 struct componentname *cnp = &ndp->ni_cnd; 233static void
 234namei_init(struct namei_state *state, struct nameidata *ndp)
 235{
 236 state->ndp = ndp;
 237 state->cnp = &ndp->ni_cnd;
 238
 239 state->dp = NULL;
 240}
 241
 242/*
 243 * Clean up the working namei state, leaving things ready for return
 244 * from namei.
 245 */
 246static void
 247namei_cleanup(struct namei_state *state)
 248{
 249 KASSERT(state->cnp == &state->ndp->ni_cnd);
 250
 251 //KASSERT(state->dp == NULL); // not yet
 252
 253 /* nothing for now */
 254 (void)state;
 255}
 256
 257//////////////////////////////
 258
 259/*
 260 * Start up namei. Early portion.
 261 *
 262 * This is divided from namei_start2 by the emul_retry: point.
 263 */
 264static void
 265namei_start1(struct namei_state *state)
 266{
231 267
232#ifdef DIAGNOSTIC 268#ifdef DIAGNOSTIC
233 if (!cnp->cn_cred) 269 if (!state->cnp->cn_cred)
234 panic("namei: bad cred/proc"); 270 panic("namei: bad cred/proc");
235 if (cnp->cn_nameiop & (~OPMASK)) 271 if (state->cnp->cn_nameiop & (~OPMASK))
236 panic("namei: nameiop contaminated with flags"); 272 panic("namei: nameiop contaminated with flags");
237 if (cnp->cn_flags & OPMASK) 273 if (state->cnp->cn_flags & OPMASK)
238 panic("namei: flags contaminated with nameiops"); 274 panic("namei: flags contaminated with nameiops");
239#endif 275#endif
240 276
241 /* 277 /*
242 * Get a buffer for the name to be translated, and copy the 278 * Get a buffer for the name to be translated, and copy the
243 * name into the buffer. 279 * name into the buffer.
244 */ 280 */
245 if ((cnp->cn_flags & HASBUF) == 0) 281 if ((state->cnp->cn_flags & HASBUF) == 0)
246 cnp->cn_pnbuf = PNBUF_GET(); 282 state->cnp->cn_pnbuf = PNBUF_GET();
247 emul_retry: 283}
 284
 285/*
 286 * Start up namei. Copy the path, find the root dir and cwd, establish
 287 * the starting directory for lookup, and lock it.
 288 */
 289static int
 290namei_start2(struct namei_state *state)
 291{
 292 struct nameidata *ndp = state->ndp;
 293 struct componentname *cnp = state->cnp;
 294
 295 struct cwdinfo *cwdi; /* pointer to cwd state */
 296 struct lwp *self = curlwp; /* thread doing namei() */
 297 int error;
 298
248 if (ndp->ni_segflg == UIO_SYSSPACE) 299 if (ndp->ni_segflg == UIO_SYSSPACE)
249 error = copystr(ndp->ni_dirp, cnp->cn_pnbuf, 300 error = copystr(ndp->ni_dirp, cnp->cn_pnbuf,
250 MAXPATHLEN, &ndp->ni_pathlen); 301 MAXPATHLEN, &ndp->ni_pathlen);
251 else 302 else
252 error = copyinstr(ndp->ni_dirp, cnp->cn_pnbuf, 303 error = copyinstr(ndp->ni_dirp, cnp->cn_pnbuf,
253 MAXPATHLEN, &ndp->ni_pathlen); 304 MAXPATHLEN, &ndp->ni_pathlen);
254 305
255 /* 306 /*
256 * POSIX.1 requirement: "" is not a valid file name. 307 * POSIX.1 requirement: "" is not a valid file name.
257 */ 308 */
258 if (!error && ndp->ni_pathlen == 1) 309 if (!error && ndp->ni_pathlen == 1)
259 error = ENOENT; 310 error = ENOENT;
260 311
261 if (error) { 312 if (error) {
262 PNBUF_PUT(cnp->cn_pnbuf); 313 PNBUF_PUT(cnp->cn_pnbuf);
263 ndp->ni_vp = NULL; 314 ndp->ni_vp = NULL;
264 return (error); 315 return (error);
265 } 316 }
266 ndp->ni_loopcnt = 0; 317 ndp->ni_loopcnt = 0;
267 318
268 /* 319 /*
269 * Get root directory for the translation. 320 * Get root directory for the translation.
270 */ 321 */
271 cwdi = l->l_proc->p_cwdi; 322 cwdi = self->l_proc->p_cwdi;
272 rw_enter(&cwdi->cwdi_lock, RW_READER); 323 rw_enter(&cwdi->cwdi_lock, RW_READER);
273 dp = cwdi->cwdi_rdir; 324 state->dp = cwdi->cwdi_rdir;
274 if (dp == NULL) 325 if (state->dp == NULL)
275 dp = rootvnode; 326 state->dp = rootvnode;
276 ndp->ni_rootdir = dp; 327 ndp->ni_rootdir = state->dp;
277 328
278 /* 329 /*
279 * Check if starting from root directory or current directory. 330 * Check if starting from root directory or current directory.
280 */ 331 */
281 if (cnp->cn_pnbuf[0] == '/') { 332 if (cnp->cn_pnbuf[0] == '/') {
282 if (cnp->cn_flags & TRYEMULROOT) { 333 if (cnp->cn_flags & TRYEMULROOT) {
283 if (cnp->cn_flags & EMULROOTSET) { 334 if (cnp->cn_flags & EMULROOTSET) {
284 /* Called from (eg) emul_find_interp() */ 335 /* Called from (eg) emul_find_interp() */
285 dp = ndp->ni_erootdir; 336 state->dp = ndp->ni_erootdir;
286 } else { 337 } else {
287 if (cwdi->cwdi_edir == NULL 338 if (cwdi->cwdi_edir == NULL
288 || (cnp->cn_pnbuf[1] == '.'  339 || (cnp->cn_pnbuf[1] == '.'
289 && cnp->cn_pnbuf[2] == '.'  340 && cnp->cn_pnbuf[2] == '.'
290 && cnp->cn_pnbuf[3] == '/')) { 341 && cnp->cn_pnbuf[3] == '/')) {
291 ndp->ni_erootdir = NULL; 342 ndp->ni_erootdir = NULL;
292 } else { 343 } else {
293 dp = cwdi->cwdi_edir; 344 state->dp = cwdi->cwdi_edir;
294 ndp->ni_erootdir = dp; 345 ndp->ni_erootdir = state->dp;
295 } 346 }
296 } 347 }
297 } else { 348 } else {
298 ndp->ni_erootdir = NULL; 349 ndp->ni_erootdir = NULL;
299 if (cnp->cn_flags & NOCHROOT) 350 if (cnp->cn_flags & NOCHROOT)
300 dp = ndp->ni_rootdir = rootvnode; 351 state->dp = ndp->ni_rootdir = rootvnode;
301 } 352 }
302 } else { 353 } else {
303 dp = cwdi->cwdi_cdir; 354 state->dp = cwdi->cwdi_cdir;
304 ndp->ni_erootdir = NULL; 355 ndp->ni_erootdir = NULL;
305 } 356 }
306 VREF(dp); 357 VREF(state->dp);
307 rw_exit(&cwdi->cwdi_lock); 358 rw_exit(&cwdi->cwdi_lock);
308  359
 360 /*
 361 * Ktrace it.
 362 */
309 if (ktrpoint(KTR_NAMEI)) { 363 if (ktrpoint(KTR_NAMEI)) {
310 if (ndp->ni_erootdir != NULL) { 364 if (ndp->ni_erootdir != NULL) {
311 /* 365 /*
312 * To make any sense, the trace entry need to have the 366 * To make any sense, the trace entry need to have the
313 * text of the emulation path prepended. 367 * text of the emulation path prepended.
314 * Usually we can get this from the current process, 368 * Usually we can get this from the current process,
315 * but when called from emul_find_interp() it is only 369 * but when called from emul_find_interp() it is only
316 * in the exec_package - so we get it passed in ni_next 370 * in the exec_package - so we get it passed in ni_next
317 * (this is a hack). 371 * (this is a hack).
318 */ 372 */
319 const char *emul_path; 373 const char *emul_path;
320 if (cnp->cn_flags & EMULROOTSET) 374 if (cnp->cn_flags & EMULROOTSET)
321 emul_path = ndp->ni_next; 375 emul_path = ndp->ni_next;
322 else 376 else
323 emul_path = l->l_proc->p_emul->e_path; 377 emul_path = self->l_proc->p_emul->e_path;
324 ktrnamei2(emul_path, strlen(emul_path), 378 ktrnamei2(emul_path, strlen(emul_path),
325 cnp->cn_pnbuf, ndp->ni_pathlen); 379 cnp->cn_pnbuf, ndp->ni_pathlen);
326 } else 380 } else
327 ktrnamei(cnp->cn_pnbuf, ndp->ni_pathlen); 381 ktrnamei(cnp->cn_pnbuf, ndp->ni_pathlen);
328 } 382 }
329 383
330 vn_lock(dp, LK_EXCLUSIVE | LK_RETRY); 384 vn_lock(state->dp, LK_EXCLUSIVE | LK_RETRY);
 385
 386 return 0;
 387}
 388
 389/*
 390 * Undo namei_start: unlock and release the current lookup directory,
 391 * and discard the path buffer.
 392 */
 393static void
 394namei_end(struct namei_state *state)
 395{
 396 vput(state->dp);
 397 PNBUF_PUT(state->cnp->cn_pnbuf);
 398 //state->cnp->cn_pnbuf = NULL; // not yet (just in case) (XXX)
 399}
 400
 401/*
 402 * Check for being at a symlink.
 403 */
 404static inline int
 405namei_atsymlink(struct namei_state *state)
 406{
 407 return (state->cnp->cn_flags & ISSYMLINK) != 0;
 408}
 409
 410/*
 411 * Follow a symlink.
 412 */
 413static inline int
 414namei_follow(struct namei_state *state)
 415{
 416 struct nameidata *ndp = state->ndp;
 417 struct componentname *cnp = state->cnp;
 418
 419 struct lwp *self = curlwp; /* thread doing namei() */
 420 struct iovec aiov; /* uio for reading symbolic links */
 421 struct uio auio;
 422 char *cp; /* pointer into pathname argument */
 423 size_t linklen;
 424 int error;
 425
 426 if (ndp->ni_loopcnt++ >= MAXSYMLINKS) {
 427 return ELOOP;
 428 }
 429 if (ndp->ni_vp->v_mount->mnt_flag & MNT_SYMPERM) {
 430 error = VOP_ACCESS(ndp->ni_vp, VEXEC, cnp->cn_cred);
 431 if (error != 0)
 432 return error;
 433 }
 434 if (ndp->ni_pathlen > 1)
 435 cp = PNBUF_GET();
 436 else
 437 cp = cnp->cn_pnbuf;
 438 aiov.iov_base = cp;
 439 aiov.iov_len = MAXPATHLEN;
 440 auio.uio_iov = &aiov;
 441 auio.uio_iovcnt = 1;
 442 auio.uio_offset = 0;
 443 auio.uio_rw = UIO_READ;
 444 auio.uio_resid = MAXPATHLEN;
 445 UIO_SETUP_SYSSPACE(&auio);
 446 error = VOP_READLINK(ndp->ni_vp, &auio, cnp->cn_cred);
 447 if (error) {
 448badlink:
 449 if (ndp->ni_pathlen > 1)
 450 PNBUF_PUT(cp);
 451 return error;
 452 }
 453 linklen = MAXPATHLEN - auio.uio_resid;
 454 if (linklen == 0) {
 455 error = ENOENT;
 456 goto badlink;
 457 }
 458
 459 /*
 460 * Do symlink substitution, if appropriate, and
 461 * check length for potential overflow.
 462 */
 463 if ((vfs_magiclinks &&
 464 symlink_magic(self->l_proc, cp, &linklen)) ||
 465 (linklen + ndp->ni_pathlen >= MAXPATHLEN)) {
 466 error = ENAMETOOLONG;
 467 goto badlink;
 468 }
 469 if (ndp->ni_pathlen > 1) {
 470 memcpy(cp + linklen, ndp->ni_next, ndp->ni_pathlen);
 471 PNBUF_PUT(cnp->cn_pnbuf);
 472 cnp->cn_pnbuf = cp;
 473 } else
 474 cnp->cn_pnbuf[linklen] = '\0';
 475 ndp->ni_pathlen += linklen;
 476 vput(ndp->ni_vp);
 477 state->dp = ndp->ni_dvp;
 478
 479 /*
 480 * Check if root directory should replace current directory.
 481 */
 482 if (cnp->cn_pnbuf[0] == '/') {
 483 vput(state->dp);
 484 /* Keep absolute symbolic links inside emulation root */
 485 state->dp = ndp->ni_erootdir;
 486 if (state->dp == NULL || (cnp->cn_pnbuf[1] == '.'
 487 && cnp->cn_pnbuf[2] == '.'
 488 && cnp->cn_pnbuf[3] == '/')) {
 489 ndp->ni_erootdir = NULL;
 490 state->dp = ndp->ni_rootdir;
 491 }
 492 VREF(state->dp);
 493 vn_lock(state->dp, LK_EXCLUSIVE | LK_RETRY);
 494 }
 495
 496 return 0;
 497}
 498
 499//////////////////////////////
 500
 501static int
 502do_namei(struct namei_state *state)
 503{
 504 int error;
 505
 506 struct nameidata *ndp = state->ndp;
 507 struct componentname *cnp = state->cnp;
 508
 509 KASSERT(cnp == &ndp->ni_cnd);
 510
 511 namei_start1(state);
 512
 513 emul_retry:
 514
 515 error = namei_start2(state);
 516 if (error) {
 517 return error;
 518 }
 519
331 /* Loop through symbolic links */ 520 /* Loop through symbolic links */
332 for (;;) { 521 for (;;) {
333 if (!dp->v_mount) { 522 if (!state->dp->v_mount) {
334 /* Give up if the directory is no longer mounted */ 523 /* Give up if the directory is no longer mounted */
335 vput(dp); 524 namei_end(state);
336 PNBUF_PUT(cnp->cn_pnbuf); 
337 return (ENOENT); 525 return (ENOENT);
338 } 526 }
339 cnp->cn_nameptr = cnp->cn_pnbuf; 527 cnp->cn_nameptr = cnp->cn_pnbuf;
340 ndp->ni_startdir = dp; 528 ndp->ni_startdir = state->dp;
341 error = lookup(ndp); 529 error = lookup(ndp);
342 if (error != 0) { 530 if (error != 0) {
 531 /* XXX this should use namei_end() */
343 if (ndp->ni_dvp) { 532 if (ndp->ni_dvp) {
344 vput(ndp->ni_dvp); 533 vput(ndp->ni_dvp);
345 } 534 }
346 if (ndp->ni_erootdir != NULL) { 535 if (ndp->ni_erootdir != NULL) {
347 /* Retry the whole thing from the normal root */ 536 /* Retry the whole thing from the normal root */
348 cnp->cn_flags &= ~TRYEMULROOT; 537 cnp->cn_flags &= ~TRYEMULROOT;
349 goto emul_retry; 538 goto emul_retry;
350 } 539 }
351 PNBUF_PUT(cnp->cn_pnbuf); 540 PNBUF_PUT(cnp->cn_pnbuf);
352 return (error); 541 return (error);
353 } 542 }
354 543
355 /* 544 /*
356 * Check for symbolic link 545 * Check for symbolic link
357 */ 546 */
358 if ((cnp->cn_flags & ISSYMLINK) == 0) { 547 if (namei_atsymlink(state)) {
359 if ((cnp->cn_flags & LOCKPARENT) == 0 && ndp->ni_dvp) { 548 error = namei_follow(state);
360 if (ndp->ni_dvp == ndp->ni_vp) { 549 if (error) {
361 vrele(ndp->ni_dvp); 550 KASSERT(ndp->ni_dvp != ndp->ni_vp);
362 } else { 551 vput(ndp->ni_dvp);
363 vput(ndp->ni_dvp); 552 vput(ndp->ni_vp);
364 } 553 ndp->ni_vp = NULL;
365 } 
366 if ((cnp->cn_flags & (SAVENAME | SAVESTART)) == 0) { 
367 PNBUF_PUT(cnp->cn_pnbuf); 554 PNBUF_PUT(cnp->cn_pnbuf);
368#if defined(DIAGNOSTIC) 555 return error;
369 cnp->cn_pnbuf = NULL; 
370#endif /* defined(DIAGNOSTIC) */ 
371 } else { 
372 cnp->cn_flags |= HASBUF; 
373 } 556 }
374 return (0); 
375 } 557 }
376 558 else {
377 if (ndp->ni_loopcnt++ >= MAXSYMLINKS) { 
378 error = ELOOP; 
379 break; 559 break;
380 } 560 }
381 if (ndp->ni_vp->v_mount->mnt_flag & MNT_SYMPERM) { 561 }
382 error = VOP_ACCESS(ndp->ni_vp, VEXEC, cnp->cn_cred); 
383 if (error != 0) 
384 break; 
385 } 
386 if (ndp->ni_pathlen > 1) 
387 cp = PNBUF_GET(); 
388 else 
389 cp = cnp->cn_pnbuf; 
390 aiov.iov_base = cp; 
391 aiov.iov_len = MAXPATHLEN; 
392 auio.uio_iov = &aiov; 
393 auio.uio_iovcnt = 1; 
394 auio.uio_offset = 0; 
395 auio.uio_rw = UIO_READ; 
396 auio.uio_resid = MAXPATHLEN; 
397 UIO_SETUP_SYSSPACE(&auio); 
398 error = VOP_READLINK(ndp->ni_vp, &auio, cnp->cn_cred); 
399 if (error) { 
400badlink: 
401 if (ndp->ni_pathlen > 1) 
402 PNBUF_PUT(cp); 
403 break; 
404 } 
405 linklen = MAXPATHLEN - auio.uio_resid; 
406 if (linklen == 0) { 
407 error = ENOENT; 
408 goto badlink; 
409 } 
410 562
411 /* 563 /*
412 * Do symlink substitution, if appropriate, and 564 * Done
413 * check length for potential overflow. 565 */
414 */ 
415 if ((vfs_magiclinks && 
416 symlink_magic(l->l_proc, cp, &linklen)) || 
417 (linklen + ndp->ni_pathlen >= MAXPATHLEN)) { 
418 error = ENAMETOOLONG; 
419 goto badlink; 
420 } 
421 if (ndp->ni_pathlen > 1) { 
422 memcpy(cp + linklen, ndp->ni_next, ndp->ni_pathlen); 
423 PNBUF_PUT(cnp->cn_pnbuf); 
424 cnp->cn_pnbuf = cp; 
425 } else 
426 cnp->cn_pnbuf[linklen] = '\0'; 
427 ndp->ni_pathlen += linklen; 
428 vput(ndp->ni_vp); 
429 dp = ndp->ni_dvp; 
430 566
431 /* 567 if ((cnp->cn_flags & LOCKPARENT) == 0 && ndp->ni_dvp) {
432 * Check if root directory should replace current directory. 568 if (ndp->ni_dvp == ndp->ni_vp) {
433 */ 569 vrele(ndp->ni_dvp);
434 if (cnp->cn_pnbuf[0] == '/') { 570 } else {
435 vput(dp); 571 vput(ndp->ni_dvp);
436 /* Keep absolute symbolic links inside emulation root */ 
437 dp = ndp->ni_erootdir; 
438 if (dp == NULL || (cnp->cn_pnbuf[1] == '.'  
439 && cnp->cn_pnbuf[2] == '.' 
440 && cnp->cn_pnbuf[3] == '/')) { 
441 ndp->ni_erootdir = NULL; 
442 dp = ndp->ni_rootdir; 
443 } 
444 VREF(dp); 
445 vn_lock(dp, LK_EXCLUSIVE | LK_RETRY); 
446 } 572 }
447 } 573 }
448 /* Failed to process a symbolic link */ 574 if ((cnp->cn_flags & (SAVENAME | SAVESTART)) == 0) {
449 KASSERT(ndp->ni_dvp != ndp->ni_vp); 575 PNBUF_PUT(cnp->cn_pnbuf);
450 vput(ndp->ni_dvp); 576#if defined(DIAGNOSTIC)
451 vput(ndp->ni_vp); 577 cnp->cn_pnbuf = NULL;
452 ndp->ni_vp = NULL; 578#endif /* defined(DIAGNOSTIC) */
453 PNBUF_PUT(cnp->cn_pnbuf); 579 } else {
454 return (error); 580 cnp->cn_flags |= HASBUF;
 581 }
 582
 583 return 0;
 584}
 585
 586int
 587namei(struct nameidata *ndp)
 588{
 589 struct namei_state state;
 590 int error;
 591
 592 namei_init(&state, ndp);
 593 error = do_namei(&state);
 594 namei_cleanup(&state);
 595
 596 return error;
455} 597}
456 598
457/* 599/*
458 * Determine the namei hash (for cn_hash) for name. 600 * Determine the namei hash (for cn_hash) for name.
459 * If *ep != NULL, hash from name to ep-1. 601 * If *ep != NULL, hash from name to ep-1.
460 * If *ep == NULL, hash from name until the first NUL or '/', and 602 * If *ep == NULL, hash from name until the first NUL or '/', and
461 * return the location of this termination character in *ep. 603 * return the location of this termination character in *ep.
462 * 604 *
463 * This function returns an equivalent hash to the MI hash32_strn(). 605 * This function returns an equivalent hash to the MI hash32_strn().
464 * The latter isn't used because in the *ep == NULL case, determining 606 * The latter isn't used because in the *ep == NULL case, determining
465 * the length of the string to the first NUL or `/' and then calling 607 * the length of the string to the first NUL or `/' and then calling
466 * hash32_strn() involves unnecessary double-handling of the data. 608 * hash32_strn() involves unnecessary double-handling of the data.
467 */ 609 */