xref: /titanic_51/usr/src/uts/common/fs/pathname.c (revision 9985ed6f5fe5d1a32e5a5be21ad888ef5123a6d1)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
57c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
67c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
77c478bd9Sstevel@tonic-gate  * with the License.
87c478bd9Sstevel@tonic-gate  *
97c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
107c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
117c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
127c478bd9Sstevel@tonic-gate  * and limitations under the License.
137c478bd9Sstevel@tonic-gate  *
147c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
157c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
167c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
177c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
187c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
197c478bd9Sstevel@tonic-gate  *
207c478bd9Sstevel@tonic-gate  * CDDL HEADER END
217c478bd9Sstevel@tonic-gate  */
227c478bd9Sstevel@tonic-gate /*
237c478bd9Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate /*	Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T	*/
287c478bd9Sstevel@tonic-gate /*	  All Rights Reserved  	*/
297c478bd9Sstevel@tonic-gate 
307c478bd9Sstevel@tonic-gate /*
317c478bd9Sstevel@tonic-gate  * University Copyright- Copyright (c) 1982, 1986, 1988
327c478bd9Sstevel@tonic-gate  * The Regents of the University of California
337c478bd9Sstevel@tonic-gate  * All Rights Reserved
347c478bd9Sstevel@tonic-gate  *
357c478bd9Sstevel@tonic-gate  * University Acknowledgment- Portions of this document are derived from
367c478bd9Sstevel@tonic-gate  * software developed by the University of California, Berkeley, and its
377c478bd9Sstevel@tonic-gate  * contributors.
387c478bd9Sstevel@tonic-gate  */
397c478bd9Sstevel@tonic-gate 
407c478bd9Sstevel@tonic-gate 
417c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
427c478bd9Sstevel@tonic-gate 
437c478bd9Sstevel@tonic-gate #include <sys/types.h>
447c478bd9Sstevel@tonic-gate #include <sys/param.h>
457c478bd9Sstevel@tonic-gate #include <sys/systm.h>
467c478bd9Sstevel@tonic-gate #include <sys/uio.h>
477c478bd9Sstevel@tonic-gate #include <sys/errno.h>
487c478bd9Sstevel@tonic-gate #include <sys/pathname.h>
497c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
507c478bd9Sstevel@tonic-gate #include <sys/cred.h>
517c478bd9Sstevel@tonic-gate #include <sys/vnode.h>
527c478bd9Sstevel@tonic-gate #include <sys/debug.h>
537c478bd9Sstevel@tonic-gate 
547c478bd9Sstevel@tonic-gate /*
557c478bd9Sstevel@tonic-gate  * Pathname utilities.
567c478bd9Sstevel@tonic-gate  *
577c478bd9Sstevel@tonic-gate  * In translating file names we copy each argument file
587c478bd9Sstevel@tonic-gate  * name into a pathname structure where we operate on it.
597c478bd9Sstevel@tonic-gate  * Each pathname structure can hold "pn_bufsize" characters
607c478bd9Sstevel@tonic-gate  * including a terminating null, and operations here support
617c478bd9Sstevel@tonic-gate  * allocating and freeing pathname structures, fetching
627c478bd9Sstevel@tonic-gate  * strings from user space, getting the next character from
637c478bd9Sstevel@tonic-gate  * a pathname, combining two pathnames (used in symbolic
647c478bd9Sstevel@tonic-gate  * link processing), and peeling off the first component
657c478bd9Sstevel@tonic-gate  * of a pathname.
667c478bd9Sstevel@tonic-gate  */
677c478bd9Sstevel@tonic-gate 
687c478bd9Sstevel@tonic-gate /*
697c478bd9Sstevel@tonic-gate  * Allocate contents of pathname structure.  Structure is typically
707c478bd9Sstevel@tonic-gate  * an automatic variable in calling routine for convenience.
717c478bd9Sstevel@tonic-gate  *
727c478bd9Sstevel@tonic-gate  * May sleep in the call to kmem_alloc() and so must not be called
737c478bd9Sstevel@tonic-gate  * from interrupt level.
747c478bd9Sstevel@tonic-gate  */
757c478bd9Sstevel@tonic-gate void
767c478bd9Sstevel@tonic-gate pn_alloc(struct pathname *pnp)
777c478bd9Sstevel@tonic-gate {
787c478bd9Sstevel@tonic-gate 	pnp->pn_path = pnp->pn_buf = kmem_alloc(MAXPATHLEN, KM_SLEEP);
797c478bd9Sstevel@tonic-gate 	pnp->pn_pathlen = 0;
807c478bd9Sstevel@tonic-gate 	pnp->pn_bufsize = MAXPATHLEN;
817c478bd9Sstevel@tonic-gate }
827c478bd9Sstevel@tonic-gate 
837c478bd9Sstevel@tonic-gate /*
847c478bd9Sstevel@tonic-gate  * Free pathname resources.
857c478bd9Sstevel@tonic-gate  */
867c478bd9Sstevel@tonic-gate void
877c478bd9Sstevel@tonic-gate pn_free(struct pathname *pnp)
887c478bd9Sstevel@tonic-gate {
89*9985ed6fSdmick 	/* pn_bufsize is usually MAXPATHLEN, but may not be */
90*9985ed6fSdmick 	kmem_free(pnp->pn_buf, pnp->pn_bufsize);
917c478bd9Sstevel@tonic-gate 	pnp->pn_path = pnp->pn_buf = NULL;
927c478bd9Sstevel@tonic-gate 	pnp->pn_pathlen = pnp->pn_bufsize = 0;
937c478bd9Sstevel@tonic-gate }
947c478bd9Sstevel@tonic-gate 
957c478bd9Sstevel@tonic-gate /*
967c478bd9Sstevel@tonic-gate  * Pull a path name from user or kernel space.
977c478bd9Sstevel@tonic-gate  * Called from pn_get() after allocation of a MAXPATHLEN buffer.
987c478bd9Sstevel@tonic-gate  * Also called directly with a TYPICALMAXPATHLEN-size buffer
997c478bd9Sstevel@tonic-gate  * on the stack as a local optimization.
1007c478bd9Sstevel@tonic-gate  */
1017c478bd9Sstevel@tonic-gate int
1027c478bd9Sstevel@tonic-gate pn_get_buf(char *str, enum uio_seg seg, struct pathname *pnp,
1037c478bd9Sstevel@tonic-gate 	void *buf, size_t bufsize)
1047c478bd9Sstevel@tonic-gate {
1057c478bd9Sstevel@tonic-gate 	int error;
1067c478bd9Sstevel@tonic-gate 
1077c478bd9Sstevel@tonic-gate 	pnp->pn_path = pnp->pn_buf = buf;
1087c478bd9Sstevel@tonic-gate 	pnp->pn_bufsize = bufsize;
1097c478bd9Sstevel@tonic-gate 	if (seg == UIO_USERSPACE)
1107c478bd9Sstevel@tonic-gate 		error = copyinstr(str, pnp->pn_path, bufsize, &pnp->pn_pathlen);
1117c478bd9Sstevel@tonic-gate 	else
1127c478bd9Sstevel@tonic-gate 		error = copystr(str, pnp->pn_path, bufsize, &pnp->pn_pathlen);
1137c478bd9Sstevel@tonic-gate 	if (error)
1147c478bd9Sstevel@tonic-gate 		return (error);
1157c478bd9Sstevel@tonic-gate 	pnp->pn_pathlen--;		/* don't count null byte */
1167c478bd9Sstevel@tonic-gate 	return (0);
1177c478bd9Sstevel@tonic-gate }
1187c478bd9Sstevel@tonic-gate 
1197c478bd9Sstevel@tonic-gate /*
1207c478bd9Sstevel@tonic-gate  * Pull a path name from user or kernel space.
1217c478bd9Sstevel@tonic-gate  */
1227c478bd9Sstevel@tonic-gate int
1237c478bd9Sstevel@tonic-gate pn_get(char *str, enum uio_seg seg, struct pathname *pnp)
1247c478bd9Sstevel@tonic-gate {
1257c478bd9Sstevel@tonic-gate 	int error;
1267c478bd9Sstevel@tonic-gate 	void *buf;
1277c478bd9Sstevel@tonic-gate 
1287c478bd9Sstevel@tonic-gate 	buf = kmem_alloc(MAXPATHLEN, KM_SLEEP);
1297c478bd9Sstevel@tonic-gate 	if ((error = pn_get_buf(str, seg, pnp, buf, MAXPATHLEN)) != 0)
1307c478bd9Sstevel@tonic-gate 		pn_free(pnp);
1317c478bd9Sstevel@tonic-gate 	return (error);
1327c478bd9Sstevel@tonic-gate }
1337c478bd9Sstevel@tonic-gate 
1347c478bd9Sstevel@tonic-gate /*
1357c478bd9Sstevel@tonic-gate  * Set path name to argument string.  Storage has already been allocated
1367c478bd9Sstevel@tonic-gate  * and pn_buf points to it.
1377c478bd9Sstevel@tonic-gate  *
1387c478bd9Sstevel@tonic-gate  * On error, all fields except pn_buf will be undefined.
1397c478bd9Sstevel@tonic-gate  */
1407c478bd9Sstevel@tonic-gate int
1417c478bd9Sstevel@tonic-gate pn_set(struct pathname *pnp, char *path)
1427c478bd9Sstevel@tonic-gate {
1437c478bd9Sstevel@tonic-gate 	int error;
1447c478bd9Sstevel@tonic-gate 
1457c478bd9Sstevel@tonic-gate 	pnp->pn_path = pnp->pn_buf;
1467c478bd9Sstevel@tonic-gate 	error = copystr(path, pnp->pn_path, pnp->pn_bufsize, &pnp->pn_pathlen);
1477c478bd9Sstevel@tonic-gate 	pnp->pn_pathlen--;		/* don't count null byte */
1487c478bd9Sstevel@tonic-gate 	return (error);
1497c478bd9Sstevel@tonic-gate }
1507c478bd9Sstevel@tonic-gate 
1517c478bd9Sstevel@tonic-gate /*
1527c478bd9Sstevel@tonic-gate  * Combine two argument path names by putting the second argument
1537c478bd9Sstevel@tonic-gate  * before the first in the first's buffer.  This isn't very general;
1547c478bd9Sstevel@tonic-gate  * it is designed specifically for symbolic link processing.
1557c478bd9Sstevel@tonic-gate  * This function copies the symlink in-place in the pathname.  This is to
1567c478bd9Sstevel@tonic-gate  * ensure that vnode path caching remains correct.  At the point where this is
1577c478bd9Sstevel@tonic-gate  * called (from lookuppnvp), we have called pn_getcomponent(), found it is a
1587c478bd9Sstevel@tonic-gate  * symlink, and are now replacing the contents.  The complen parameter indicates
1597c478bd9Sstevel@tonic-gate  * how much of the pathname to replace.  If the symlink is an absolute path,
1607c478bd9Sstevel@tonic-gate  * then we overwrite the entire contents of the pathname.
1617c478bd9Sstevel@tonic-gate  */
1627c478bd9Sstevel@tonic-gate int
1637c478bd9Sstevel@tonic-gate pn_insert(struct pathname *pnp, struct pathname *sympnp, size_t complen)
1647c478bd9Sstevel@tonic-gate {
1657c478bd9Sstevel@tonic-gate 
1667c478bd9Sstevel@tonic-gate 	if (*sympnp->pn_path == '/') {
1677c478bd9Sstevel@tonic-gate 		/*
1687c478bd9Sstevel@tonic-gate 		 * Full path, replace everything
1697c478bd9Sstevel@tonic-gate 		 */
1707c478bd9Sstevel@tonic-gate 		if (pnp->pn_pathlen + sympnp->pn_pathlen >= pnp->pn_bufsize)
1717c478bd9Sstevel@tonic-gate 			return (ENAMETOOLONG);
1727c478bd9Sstevel@tonic-gate 		if (pnp->pn_pathlen != 0)
1737c478bd9Sstevel@tonic-gate 			ovbcopy(pnp->pn_path, pnp->pn_buf + sympnp->pn_pathlen,
1747c478bd9Sstevel@tonic-gate 			    pnp->pn_pathlen);
1757c478bd9Sstevel@tonic-gate 		bcopy(sympnp->pn_path, pnp->pn_buf, sympnp->pn_pathlen);
1767c478bd9Sstevel@tonic-gate 		pnp->pn_pathlen += sympnp->pn_pathlen;
1777c478bd9Sstevel@tonic-gate 		pnp->pn_buf[pnp->pn_pathlen] = '\0';
1787c478bd9Sstevel@tonic-gate 		pnp->pn_path = pnp->pn_buf;
1797c478bd9Sstevel@tonic-gate 	} else {
1807c478bd9Sstevel@tonic-gate 		/*
1817c478bd9Sstevel@tonic-gate 		 * Partial path, replace only last component
1827c478bd9Sstevel@tonic-gate 		 */
1837c478bd9Sstevel@tonic-gate 		if ((pnp->pn_path - pnp->pn_buf) - complen +
1847c478bd9Sstevel@tonic-gate 		    pnp->pn_pathlen + sympnp->pn_pathlen >= pnp->pn_bufsize)
1857c478bd9Sstevel@tonic-gate 			return (ENAMETOOLONG);
1867c478bd9Sstevel@tonic-gate 
1877c478bd9Sstevel@tonic-gate 		if (pnp->pn_pathlen != 0)
1887c478bd9Sstevel@tonic-gate 			ovbcopy(pnp->pn_path, pnp->pn_path - complen +
1897c478bd9Sstevel@tonic-gate 			    sympnp->pn_pathlen, pnp->pn_pathlen + 1);
1907c478bd9Sstevel@tonic-gate 		pnp->pn_path -= complen;
1917c478bd9Sstevel@tonic-gate 		bcopy(sympnp->pn_path, pnp->pn_path, sympnp->pn_pathlen);
1927c478bd9Sstevel@tonic-gate 		pnp->pn_pathlen += sympnp->pn_pathlen;
1937c478bd9Sstevel@tonic-gate 	}
1947c478bd9Sstevel@tonic-gate 
1957c478bd9Sstevel@tonic-gate 	return (0);
1967c478bd9Sstevel@tonic-gate }
1977c478bd9Sstevel@tonic-gate 
1987c478bd9Sstevel@tonic-gate int
1997c478bd9Sstevel@tonic-gate pn_getsymlink(vnode_t *vp, struct pathname *pnp, cred_t *crp)
2007c478bd9Sstevel@tonic-gate {
2017c478bd9Sstevel@tonic-gate 	struct iovec aiov;
2027c478bd9Sstevel@tonic-gate 	struct uio auio;
2037c478bd9Sstevel@tonic-gate 	int error;
2047c478bd9Sstevel@tonic-gate 
2057c478bd9Sstevel@tonic-gate 	aiov.iov_base = pnp->pn_path = pnp->pn_buf;
2067c478bd9Sstevel@tonic-gate 	aiov.iov_len = pnp->pn_bufsize;
2077c478bd9Sstevel@tonic-gate 	auio.uio_iov = &aiov;
2087c478bd9Sstevel@tonic-gate 	auio.uio_iovcnt = 1;
2097c478bd9Sstevel@tonic-gate 	auio.uio_loffset = 0;
2107c478bd9Sstevel@tonic-gate 	auio.uio_segflg = UIO_SYSSPACE;
2117c478bd9Sstevel@tonic-gate 	auio.uio_extflg = UIO_COPY_CACHED;
2127c478bd9Sstevel@tonic-gate 	auio.uio_resid = pnp->pn_bufsize;
2137c478bd9Sstevel@tonic-gate 	if ((error = VOP_READLINK(vp, &auio, crp)) == 0) {
2147c478bd9Sstevel@tonic-gate 		pnp->pn_pathlen = pnp->pn_bufsize - auio.uio_resid;
2157c478bd9Sstevel@tonic-gate 		if (pnp->pn_pathlen == pnp->pn_bufsize)
2167c478bd9Sstevel@tonic-gate 			error = ENAMETOOLONG;
2177c478bd9Sstevel@tonic-gate 		else
2187c478bd9Sstevel@tonic-gate 			pnp->pn_path[pnp->pn_pathlen] = '\0';
2197c478bd9Sstevel@tonic-gate 	}
2207c478bd9Sstevel@tonic-gate 	return (error);
2217c478bd9Sstevel@tonic-gate }
2227c478bd9Sstevel@tonic-gate 
2237c478bd9Sstevel@tonic-gate /*
2247c478bd9Sstevel@tonic-gate  * Get next component from a path name and leave in
2257c478bd9Sstevel@tonic-gate  * buffer "component" which should have room for
2267c478bd9Sstevel@tonic-gate  * MAXNAMELEN bytes (including a null terminator character).
2277c478bd9Sstevel@tonic-gate  */
2287c478bd9Sstevel@tonic-gate int
2297c478bd9Sstevel@tonic-gate pn_getcomponent(struct pathname *pnp, char *component)
2307c478bd9Sstevel@tonic-gate {
2317c478bd9Sstevel@tonic-gate 	char c, *cp, *path, saved;
2327c478bd9Sstevel@tonic-gate 	size_t pathlen;
2337c478bd9Sstevel@tonic-gate 
2347c478bd9Sstevel@tonic-gate 	path = pnp->pn_path;
2357c478bd9Sstevel@tonic-gate 	pathlen = pnp->pn_pathlen;
2367c478bd9Sstevel@tonic-gate 	if (pathlen >= MAXNAMELEN) {
2377c478bd9Sstevel@tonic-gate 		saved = path[MAXNAMELEN];
2387c478bd9Sstevel@tonic-gate 		path[MAXNAMELEN] = '/';	/* guarantees loop termination */
2397c478bd9Sstevel@tonic-gate 		for (cp = path; (c = *cp) != '/'; cp++)
2407c478bd9Sstevel@tonic-gate 			*component++ = c;
2417c478bd9Sstevel@tonic-gate 		path[MAXNAMELEN] = saved;
2427c478bd9Sstevel@tonic-gate 		if (cp - path == MAXNAMELEN)
2437c478bd9Sstevel@tonic-gate 			return (ENAMETOOLONG);
2447c478bd9Sstevel@tonic-gate 	} else {
2457c478bd9Sstevel@tonic-gate 		path[pathlen] = '/';	/* guarantees loop termination */
2467c478bd9Sstevel@tonic-gate 		for (cp = path; (c = *cp) != '/'; cp++)
2477c478bd9Sstevel@tonic-gate 			*component++ = c;
2487c478bd9Sstevel@tonic-gate 		path[pathlen] = '\0';
2497c478bd9Sstevel@tonic-gate 	}
2507c478bd9Sstevel@tonic-gate 
2517c478bd9Sstevel@tonic-gate 	pnp->pn_path = cp;
2527c478bd9Sstevel@tonic-gate 	pnp->pn_pathlen = pathlen - (cp - path);
2537c478bd9Sstevel@tonic-gate 	*component = '\0';
2547c478bd9Sstevel@tonic-gate 	return (0);
2557c478bd9Sstevel@tonic-gate }
2567c478bd9Sstevel@tonic-gate 
2577c478bd9Sstevel@tonic-gate /*
2587c478bd9Sstevel@tonic-gate  * Skip over consecutive slashes in the path name.
2597c478bd9Sstevel@tonic-gate  */
2607c478bd9Sstevel@tonic-gate void
2617c478bd9Sstevel@tonic-gate pn_skipslash(struct pathname *pnp)
2627c478bd9Sstevel@tonic-gate {
2637c478bd9Sstevel@tonic-gate 	while (pnp->pn_pathlen > 0 && *pnp->pn_path == '/') {
2647c478bd9Sstevel@tonic-gate 		pnp->pn_path++;
2657c478bd9Sstevel@tonic-gate 		pnp->pn_pathlen--;
2667c478bd9Sstevel@tonic-gate 	}
2677c478bd9Sstevel@tonic-gate }
2687c478bd9Sstevel@tonic-gate 
2697c478bd9Sstevel@tonic-gate /*
2707c478bd9Sstevel@tonic-gate  * Sets pn_path to the last component in the pathname, updating
2717c478bd9Sstevel@tonic-gate  * pn_pathlen.  If pathname is empty, or degenerate, leaves pn_path
2727c478bd9Sstevel@tonic-gate  * pointing at NULL char.  The pathname is explicitly null-terminated
2737c478bd9Sstevel@tonic-gate  * so that any trailing slashes are effectively removed.
2747c478bd9Sstevel@tonic-gate  */
2757c478bd9Sstevel@tonic-gate void
2767c478bd9Sstevel@tonic-gate pn_setlast(struct pathname *pnp)
2777c478bd9Sstevel@tonic-gate {
2787c478bd9Sstevel@tonic-gate 	char *buf = pnp->pn_buf;
2797c478bd9Sstevel@tonic-gate 	char *path = pnp->pn_path + pnp->pn_pathlen - 1;
2807c478bd9Sstevel@tonic-gate 	char *endpath;
2817c478bd9Sstevel@tonic-gate 
2827c478bd9Sstevel@tonic-gate 	while (path > buf && *path == '/')
2837c478bd9Sstevel@tonic-gate 		--path;
2847c478bd9Sstevel@tonic-gate 	endpath = path + 1;
2857c478bd9Sstevel@tonic-gate 	while (path > buf && *path != '/')
2867c478bd9Sstevel@tonic-gate 		--path;
2877c478bd9Sstevel@tonic-gate 	if (*path == '/')
2887c478bd9Sstevel@tonic-gate 		path++;
2897c478bd9Sstevel@tonic-gate 	*endpath = '\0';
2907c478bd9Sstevel@tonic-gate 	pnp->pn_path = path;
2917c478bd9Sstevel@tonic-gate 	pnp->pn_pathlen = endpath - path;
2927c478bd9Sstevel@tonic-gate }
2937c478bd9Sstevel@tonic-gate 
2947c478bd9Sstevel@tonic-gate /*
2957c478bd9Sstevel@tonic-gate  * Eliminate any trailing slashes in the pathname.
2967c478bd9Sstevel@tonic-gate  * Return non-zero iff there were any trailing slashes.
2977c478bd9Sstevel@tonic-gate  */
2987c478bd9Sstevel@tonic-gate int
2997c478bd9Sstevel@tonic-gate pn_fixslash(struct pathname *pnp)
3007c478bd9Sstevel@tonic-gate {
3017c478bd9Sstevel@tonic-gate 	char *start = pnp->pn_path;
3027c478bd9Sstevel@tonic-gate 	char *end = start + pnp->pn_pathlen;
3037c478bd9Sstevel@tonic-gate 
3047c478bd9Sstevel@tonic-gate 	while (end > start && *(end - 1) == '/')
3057c478bd9Sstevel@tonic-gate 		end--;
3067c478bd9Sstevel@tonic-gate 	if (pnp->pn_pathlen == end - start)
3077c478bd9Sstevel@tonic-gate 		return (0);
3087c478bd9Sstevel@tonic-gate 	*end = '\0';
3097c478bd9Sstevel@tonic-gate 	pnp->pn_pathlen = end - start;
3107c478bd9Sstevel@tonic-gate 	return (1);
3117c478bd9Sstevel@tonic-gate }
3127c478bd9Sstevel@tonic-gate 
3137c478bd9Sstevel@tonic-gate /*
3147c478bd9Sstevel@tonic-gate  * Add a slash to the end of the pathname, if it will fit.
3157c478bd9Sstevel@tonic-gate  * Return ENAMETOOLONG if it won't.
3167c478bd9Sstevel@tonic-gate  */
3177c478bd9Sstevel@tonic-gate int
3187c478bd9Sstevel@tonic-gate pn_addslash(struct pathname *pnp)
3197c478bd9Sstevel@tonic-gate {
3207c478bd9Sstevel@tonic-gate 	if (pnp->pn_path + pnp->pn_pathlen + 1 >=
3217c478bd9Sstevel@tonic-gate 	    pnp->pn_buf + pnp->pn_bufsize) {
3227c478bd9Sstevel@tonic-gate 		if (pnp->pn_pathlen + 1 >= pnp->pn_bufsize)	/* no room */
3237c478bd9Sstevel@tonic-gate 			return (ENAMETOOLONG);
3247c478bd9Sstevel@tonic-gate 		/*
3257c478bd9Sstevel@tonic-gate 		 * Move the component to the start of the buffer
3267c478bd9Sstevel@tonic-gate 		 * so we have room to add the trailing slash.
3277c478bd9Sstevel@tonic-gate 		 */
3287c478bd9Sstevel@tonic-gate 		ovbcopy(pnp->pn_path, pnp->pn_buf, pnp->pn_pathlen);
3297c478bd9Sstevel@tonic-gate 		pnp->pn_path = pnp->pn_buf;
3307c478bd9Sstevel@tonic-gate 	}
3317c478bd9Sstevel@tonic-gate 	pnp->pn_path[pnp->pn_pathlen++] = '/';
3327c478bd9Sstevel@tonic-gate 	pnp->pn_path[pnp->pn_pathlen] = '\0';
3337c478bd9Sstevel@tonic-gate 	return (0);
3347c478bd9Sstevel@tonic-gate }
335