Home | History | Annotate | Download | only in fs
      1     0  stevel /*
      2     0  stevel  * CDDL HEADER START
      3     0  stevel  *
      4     0  stevel  * The contents of this file are subject to the terms of the
      5  5331     amw  * Common Development and Distribution License (the "License").
      6  5331     amw  * You may not use this file except in compliance with the License.
      7     0  stevel  *
      8     0  stevel  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9     0  stevel  * or http://www.opensolaris.org/os/licensing.
     10     0  stevel  * See the License for the specific language governing permissions
     11     0  stevel  * and limitations under the License.
     12     0  stevel  *
     13     0  stevel  * When distributing Covered Code, include this CDDL HEADER in each
     14     0  stevel  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15     0  stevel  * If applicable, add the following below this CDDL HEADER, with the
     16     0  stevel  * fields enclosed by brackets "[]" replaced with your own identifying
     17     0  stevel  * information: Portions Copyright [yyyy] [name of copyright owner]
     18     0  stevel  *
     19     0  stevel  * CDDL HEADER END
     20     0  stevel  */
     21     0  stevel /*
     22  5331     amw  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
     23     0  stevel  * Use is subject to license terms.
     24     0  stevel  */
     25     0  stevel 
     26     0  stevel /*	Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T	*/
     27     0  stevel /*	  All Rights Reserved  	*/
     28     0  stevel 
     29     0  stevel /*
     30     0  stevel  * University Copyright- Copyright (c) 1982, 1986, 1988
     31     0  stevel  * The Regents of the University of California
     32     0  stevel  * All Rights Reserved
     33     0  stevel  *
     34     0  stevel  * University Acknowledgment- Portions of this document are derived from
     35     0  stevel  * software developed by the University of California, Berkeley, and its
     36     0  stevel  * contributors.
     37     0  stevel  */
     38     0  stevel 
     39     0  stevel 
     40     0  stevel #pragma ident	"%Z%%M%	%I%	%E% SMI"
     41     0  stevel 
     42     0  stevel #include <sys/types.h>
     43     0  stevel #include <sys/param.h>
     44     0  stevel #include <sys/systm.h>
     45     0  stevel #include <sys/uio.h>
     46     0  stevel #include <sys/errno.h>
     47     0  stevel #include <sys/pathname.h>
     48     0  stevel #include <sys/kmem.h>
     49     0  stevel #include <sys/cred.h>
     50     0  stevel #include <sys/vnode.h>
     51     0  stevel #include <sys/debug.h>
     52     0  stevel 
     53     0  stevel /*
     54     0  stevel  * Pathname utilities.
     55     0  stevel  *
     56     0  stevel  * In translating file names we copy each argument file
     57     0  stevel  * name into a pathname structure where we operate on it.
     58     0  stevel  * Each pathname structure can hold "pn_bufsize" characters
     59     0  stevel  * including a terminating null, and operations here support
     60     0  stevel  * allocating and freeing pathname structures, fetching
     61     0  stevel  * strings from user space, getting the next character from
     62     0  stevel  * a pathname, combining two pathnames (used in symbolic
     63     0  stevel  * link processing), and peeling off the first component
     64     0  stevel  * of a pathname.
     65     0  stevel  */
     66     0  stevel 
     67     0  stevel /*
     68     0  stevel  * Allocate contents of pathname structure.  Structure is typically
     69     0  stevel  * an automatic variable in calling routine for convenience.
     70     0  stevel  *
     71     0  stevel  * May sleep in the call to kmem_alloc() and so must not be called
     72     0  stevel  * from interrupt level.
     73     0  stevel  */
     74     0  stevel void
     75     0  stevel pn_alloc(struct pathname *pnp)
     76     0  stevel {
     77     0  stevel 	pnp->pn_path = pnp->pn_buf = kmem_alloc(MAXPATHLEN, KM_SLEEP);
     78     0  stevel 	pnp->pn_pathlen = 0;
     79     0  stevel 	pnp->pn_bufsize = MAXPATHLEN;
     80     0  stevel }
     81     0  stevel 
     82     0  stevel /*
     83     0  stevel  * Free pathname resources.
     84     0  stevel  */
     85     0  stevel void
     86     0  stevel pn_free(struct pathname *pnp)
     87     0  stevel {
     88   274   dmick 	/* pn_bufsize is usually MAXPATHLEN, but may not be */
     89   274   dmick 	kmem_free(pnp->pn_buf, pnp->pn_bufsize);
     90     0  stevel 	pnp->pn_path = pnp->pn_buf = NULL;
     91     0  stevel 	pnp->pn_pathlen = pnp->pn_bufsize = 0;
     92     0  stevel }
     93     0  stevel 
     94     0  stevel /*
     95     0  stevel  * Pull a path name from user or kernel space.
     96     0  stevel  * Called from pn_get() after allocation of a MAXPATHLEN buffer.
     97     0  stevel  * Also called directly with a TYPICALMAXPATHLEN-size buffer
     98     0  stevel  * on the stack as a local optimization.
     99     0  stevel  */
    100     0  stevel int
    101     0  stevel pn_get_buf(char *str, enum uio_seg seg, struct pathname *pnp,
    102     0  stevel 	void *buf, size_t bufsize)
    103     0  stevel {
    104     0  stevel 	int error;
    105     0  stevel 
    106     0  stevel 	pnp->pn_path = pnp->pn_buf = buf;
    107     0  stevel 	pnp->pn_bufsize = bufsize;
    108     0  stevel 	if (seg == UIO_USERSPACE)
    109     0  stevel 		error = copyinstr(str, pnp->pn_path, bufsize, &pnp->pn_pathlen);
    110     0  stevel 	else
    111     0  stevel 		error = copystr(str, pnp->pn_path, bufsize, &pnp->pn_pathlen);
    112     0  stevel 	if (error)
    113     0  stevel 		return (error);
    114     0  stevel 	pnp->pn_pathlen--;		/* don't count null byte */
    115     0  stevel 	return (0);
    116     0  stevel }
    117     0  stevel 
    118     0  stevel /*
    119     0  stevel  * Pull a path name from user or kernel space.
    120     0  stevel  */
    121     0  stevel int
    122     0  stevel pn_get(char *str, enum uio_seg seg, struct pathname *pnp)
    123     0  stevel {
    124     0  stevel 	int error;
    125     0  stevel 	void *buf;
    126     0  stevel 
    127     0  stevel 	buf = kmem_alloc(MAXPATHLEN, KM_SLEEP);
    128     0  stevel 	if ((error = pn_get_buf(str, seg, pnp, buf, MAXPATHLEN)) != 0)
    129     0  stevel 		pn_free(pnp);
    130     0  stevel 	return (error);
    131     0  stevel }
    132     0  stevel 
    133     0  stevel /*
    134     0  stevel  * Set path name to argument string.  Storage has already been allocated
    135     0  stevel  * and pn_buf points to it.
    136     0  stevel  *
    137     0  stevel  * On error, all fields except pn_buf will be undefined.
    138     0  stevel  */
    139     0  stevel int
    140     0  stevel pn_set(struct pathname *pnp, char *path)
    141     0  stevel {
    142     0  stevel 	int error;
    143     0  stevel 
    144     0  stevel 	pnp->pn_path = pnp->pn_buf;
    145     0  stevel 	error = copystr(path, pnp->pn_path, pnp->pn_bufsize, &pnp->pn_pathlen);
    146     0  stevel 	pnp->pn_pathlen--;		/* don't count null byte */
    147     0  stevel 	return (error);
    148     0  stevel }
    149     0  stevel 
    150     0  stevel /*
    151     0  stevel  * Combine two argument path names by putting the second argument
    152     0  stevel  * before the first in the first's buffer.  This isn't very general;
    153     0  stevel  * it is designed specifically for symbolic link processing.
    154     0  stevel  * This function copies the symlink in-place in the pathname.  This is to
    155     0  stevel  * ensure that vnode path caching remains correct.  At the point where this is
    156     0  stevel  * called (from lookuppnvp), we have called pn_getcomponent(), found it is a
    157     0  stevel  * symlink, and are now replacing the contents.  The complen parameter indicates
    158     0  stevel  * how much of the pathname to replace.  If the symlink is an absolute path,
    159     0  stevel  * then we overwrite the entire contents of the pathname.
    160     0  stevel  */
    161     0  stevel int
    162     0  stevel pn_insert(struct pathname *pnp, struct pathname *sympnp, size_t complen)
    163     0  stevel {
    164     0  stevel 
    165     0  stevel 	if (*sympnp->pn_path == '/') {
    166     0  stevel 		/*
    167     0  stevel 		 * Full path, replace everything
    168     0  stevel 		 */
    169     0  stevel 		if (pnp->pn_pathlen + sympnp->pn_pathlen >= pnp->pn_bufsize)
    170     0  stevel 			return (ENAMETOOLONG);
    171     0  stevel 		if (pnp->pn_pathlen != 0)
    172     0  stevel 			ovbcopy(pnp->pn_path, pnp->pn_buf + sympnp->pn_pathlen,
    173     0  stevel 			    pnp->pn_pathlen);
    174     0  stevel 		bcopy(sympnp->pn_path, pnp->pn_buf, sympnp->pn_pathlen);
    175     0  stevel 		pnp->pn_pathlen += sympnp->pn_pathlen;
    176     0  stevel 		pnp->pn_buf[pnp->pn_pathlen] = '\0';
    177     0  stevel 		pnp->pn_path = pnp->pn_buf;
    178     0  stevel 	} else {
    179     0  stevel 		/*
    180     0  stevel 		 * Partial path, replace only last component
    181     0  stevel 		 */
    182     0  stevel 		if ((pnp->pn_path - pnp->pn_buf) - complen +
    183     0  stevel 		    pnp->pn_pathlen + sympnp->pn_pathlen >= pnp->pn_bufsize)
    184     0  stevel 			return (ENAMETOOLONG);
    185     0  stevel 
    186     0  stevel 		if (pnp->pn_pathlen != 0)
    187     0  stevel 			ovbcopy(pnp->pn_path, pnp->pn_path - complen +
    188     0  stevel 			    sympnp->pn_pathlen, pnp->pn_pathlen + 1);
    189     0  stevel 		pnp->pn_path -= complen;
    190     0  stevel 		bcopy(sympnp->pn_path, pnp->pn_path, sympnp->pn_pathlen);
    191     0  stevel 		pnp->pn_pathlen += sympnp->pn_pathlen;
    192     0  stevel 	}
    193     0  stevel 
    194     0  stevel 	return (0);
    195     0  stevel }
    196     0  stevel 
    197     0  stevel int
    198     0  stevel pn_getsymlink(vnode_t *vp, struct pathname *pnp, cred_t *crp)
    199     0  stevel {
    200     0  stevel 	struct iovec aiov;
    201     0  stevel 	struct uio auio;
    202     0  stevel 	int error;
    203     0  stevel 
    204     0  stevel 	aiov.iov_base = pnp->pn_path = pnp->pn_buf;
    205     0  stevel 	aiov.iov_len = pnp->pn_bufsize;
    206     0  stevel 	auio.uio_iov = &aiov;
    207     0  stevel 	auio.uio_iovcnt = 1;
    208     0  stevel 	auio.uio_loffset = 0;
    209     0  stevel 	auio.uio_segflg = UIO_SYSSPACE;
    210     0  stevel 	auio.uio_extflg = UIO_COPY_CACHED;
    211     0  stevel 	auio.uio_resid = pnp->pn_bufsize;
    212  5331     amw 	if ((error = VOP_READLINK(vp, &auio, crp, NULL)) == 0) {
    213     0  stevel 		pnp->pn_pathlen = pnp->pn_bufsize - auio.uio_resid;
    214     0  stevel 		if (pnp->pn_pathlen == pnp->pn_bufsize)
    215     0  stevel 			error = ENAMETOOLONG;
    216     0  stevel 		else
    217     0  stevel 			pnp->pn_path[pnp->pn_pathlen] = '\0';
    218     0  stevel 	}
    219     0  stevel 	return (error);
    220     0  stevel }
    221     0  stevel 
    222     0  stevel /*
    223     0  stevel  * Get next component from a path name and leave in
    224     0  stevel  * buffer "component" which should have room for
    225     0  stevel  * MAXNAMELEN bytes (including a null terminator character).
    226     0  stevel  */
    227     0  stevel int
    228     0  stevel pn_getcomponent(struct pathname *pnp, char *component)
    229     0  stevel {
    230     0  stevel 	char c, *cp, *path, saved;
    231     0  stevel 	size_t pathlen;
    232     0  stevel 
    233     0  stevel 	path = pnp->pn_path;
    234     0  stevel 	pathlen = pnp->pn_pathlen;
    235     0  stevel 	if (pathlen >= MAXNAMELEN) {
    236     0  stevel 		saved = path[MAXNAMELEN];
    237     0  stevel 		path[MAXNAMELEN] = '/';	/* guarantees loop termination */
    238     0  stevel 		for (cp = path; (c = *cp) != '/'; cp++)
    239     0  stevel 			*component++ = c;
    240     0  stevel 		path[MAXNAMELEN] = saved;
    241     0  stevel 		if (cp - path == MAXNAMELEN)
    242     0  stevel 			return (ENAMETOOLONG);
    243     0  stevel 	} else {
    244     0  stevel 		path[pathlen] = '/';	/* guarantees loop termination */
    245     0  stevel 		for (cp = path; (c = *cp) != '/'; cp++)
    246     0  stevel 			*component++ = c;
    247     0  stevel 		path[pathlen] = '\0';
    248     0  stevel 	}
    249     0  stevel 
    250     0  stevel 	pnp->pn_path = cp;
    251     0  stevel 	pnp->pn_pathlen = pathlen - (cp - path);
    252     0  stevel 	*component = '\0';
    253     0  stevel 	return (0);
    254     0  stevel }
    255     0  stevel 
    256     0  stevel /*
    257     0  stevel  * Skip over consecutive slashes in the path name.
    258     0  stevel  */
    259     0  stevel void
    260     0  stevel pn_skipslash(struct pathname *pnp)
    261     0  stevel {
    262     0  stevel 	while (pnp->pn_pathlen > 0 && *pnp->pn_path == '/') {
    263     0  stevel 		pnp->pn_path++;
    264     0  stevel 		pnp->pn_pathlen--;
    265     0  stevel 	}
    266     0  stevel }
    267     0  stevel 
    268     0  stevel /*
    269     0  stevel  * Sets pn_path to the last component in the pathname, updating
    270     0  stevel  * pn_pathlen.  If pathname is empty, or degenerate, leaves pn_path
    271     0  stevel  * pointing at NULL char.  The pathname is explicitly null-terminated
    272     0  stevel  * so that any trailing slashes are effectively removed.
    273     0  stevel  */
    274     0  stevel void
    275     0  stevel pn_setlast(struct pathname *pnp)
    276     0  stevel {
    277     0  stevel 	char *buf = pnp->pn_buf;
    278     0  stevel 	char *path = pnp->pn_path + pnp->pn_pathlen - 1;
    279     0  stevel 	char *endpath;
    280     0  stevel 
    281     0  stevel 	while (path > buf && *path == '/')
    282     0  stevel 		--path;
    283     0  stevel 	endpath = path + 1;
    284     0  stevel 	while (path > buf && *path != '/')
    285     0  stevel 		--path;
    286     0  stevel 	if (*path == '/')
    287     0  stevel 		path++;
    288     0  stevel 	*endpath = '\0';
    289     0  stevel 	pnp->pn_path = path;
    290     0  stevel 	pnp->pn_pathlen = endpath - path;
    291     0  stevel }
    292     0  stevel 
    293     0  stevel /*
    294     0  stevel  * Eliminate any trailing slashes in the pathname.
    295     0  stevel  * Return non-zero iff there were any trailing slashes.
    296     0  stevel  */
    297     0  stevel int
    298     0  stevel pn_fixslash(struct pathname *pnp)
    299     0  stevel {
    300     0  stevel 	char *start = pnp->pn_path;
    301     0  stevel 	char *end = start + pnp->pn_pathlen;
    302     0  stevel 
    303     0  stevel 	while (end > start && *(end - 1) == '/')
    304     0  stevel 		end--;
    305     0  stevel 	if (pnp->pn_pathlen == end - start)
    306     0  stevel 		return (0);
    307     0  stevel 	*end = '\0';
    308     0  stevel 	pnp->pn_pathlen = end - start;
    309     0  stevel 	return (1);
    310     0  stevel }
    311     0  stevel 
    312     0  stevel /*
    313     0  stevel  * Add a slash to the end of the pathname, if it will fit.
    314     0  stevel  * Return ENAMETOOLONG if it won't.
    315     0  stevel  */
    316     0  stevel int
    317     0  stevel pn_addslash(struct pathname *pnp)
    318     0  stevel {
    319     0  stevel 	if (pnp->pn_path + pnp->pn_pathlen + 1 >=
    320     0  stevel 	    pnp->pn_buf + pnp->pn_bufsize) {
    321     0  stevel 		if (pnp->pn_pathlen + 1 >= pnp->pn_bufsize)	/* no room */
    322     0  stevel 			return (ENAMETOOLONG);
    323     0  stevel 		/*
    324     0  stevel 		 * Move the component to the start of the buffer
    325     0  stevel 		 * so we have room to add the trailing slash.
    326     0  stevel 		 */
    327     0  stevel 		ovbcopy(pnp->pn_path, pnp->pn_buf, pnp->pn_pathlen);
    328     0  stevel 		pnp->pn_path = pnp->pn_buf;
    329     0  stevel 	}
    330     0  stevel 	pnp->pn_path[pnp->pn_pathlen++] = '/';
    331     0  stevel 	pnp->pn_path[pnp->pn_pathlen] = '\0';
    332     0  stevel 	return (0);
    333     0  stevel }
    334