4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
27 /* All Rights Reserved */
30 * University Copyright- Copyright (c) 1982, 1986, 1988
31 * The Regents of the University of California
34 * University Acknowledgment- Portions of this document are derived from
35 * software developed by the University of California, Berkeley, and its
40 #pragma ident "%Z%%M% %I% %E% SMI"
42 #include <sys/types.h>
43 #include <sys/param.h>
44 #include <sys/systm.h>
46 #include <sys/errno.h>
47 #include <sys/pathname.h>
50 #include <sys/vnode.h>
51 #include <sys/debug.h>
56 * In translating file names we copy each argument file
57 * name into a pathname structure where we operate on it.
58 * Each pathname structure can hold "pn_bufsize" characters
59 * including a terminating null, and operations here support
60 * allocating and freeing pathname structures, fetching
61 * strings from user space, getting the next character from
62 * a pathname, combining two pathnames (used in symbolic
63 * link processing), and peeling off the first component
68 * Allocate contents of pathname structure. Structure is typically
69 * an automatic variable in calling routine for convenience.
71 * May sleep in the call to kmem_alloc() and so must not be called
72 * from interrupt level.
75 pn_alloc(struct pathname
*pnp
)
77 pnp
->pn_path
= pnp
->pn_buf
= kmem_alloc(MAXPATHLEN
, KM_SLEEP
);
79 pnp
->pn_bufsize
= MAXPATHLEN
;
83 * Free pathname resources.
86 pn_free(struct pathname
*pnp
)
88 /* pn_bufsize is usually MAXPATHLEN, but may not be */
89 kmem_free(pnp
->pn_buf
, pnp
->pn_bufsize
);
90 pnp
->pn_path
= pnp
->pn_buf
= NULL
;
91 pnp
->pn_pathlen
= pnp
->pn_bufsize
= 0;
95 * Pull a path name from user or kernel space.
96 * Called from pn_get() after allocation of a MAXPATHLEN buffer.
97 * Also called directly with a TYPICALMAXPATHLEN-size buffer
98 * on the stack as a local optimization.
101 pn_get_buf(char *str
, enum uio_seg seg
, struct pathname
*pnp
,
102 void *buf
, size_t bufsize
)
106 pnp
->pn_path
= pnp
->pn_buf
= buf
;
107 pnp
->pn_bufsize
= bufsize
;
108 if (seg
== UIO_USERSPACE
)
109 error
= copyinstr(str
, pnp
->pn_path
, bufsize
, &pnp
->pn_pathlen
);
111 error
= copystr(str
, pnp
->pn_path
, bufsize
, &pnp
->pn_pathlen
);
114 pnp
->pn_pathlen
--; /* don't count null byte */
119 * Pull a path name from user or kernel space.
122 pn_get(char *str
, enum uio_seg seg
, struct pathname
*pnp
)
127 buf
= kmem_alloc(MAXPATHLEN
, KM_SLEEP
);
128 if ((error
= pn_get_buf(str
, seg
, pnp
, buf
, MAXPATHLEN
)) != 0)
134 * Set path name to argument string. Storage has already been allocated
135 * and pn_buf points to it.
137 * On error, all fields except pn_buf will be undefined.
140 pn_set(struct pathname
*pnp
, char *path
)
144 pnp
->pn_path
= pnp
->pn_buf
;
145 error
= copystr(path
, pnp
->pn_path
, pnp
->pn_bufsize
, &pnp
->pn_pathlen
);
146 pnp
->pn_pathlen
--; /* don't count null byte */
151 * Combine two argument path names by putting the second argument
152 * before the first in the first's buffer. This isn't very general;
153 * it is designed specifically for symbolic link processing.
154 * This function copies the symlink in-place in the pathname. This is to
155 * ensure that vnode path caching remains correct. At the point where this is
156 * called (from lookuppnvp), we have called pn_getcomponent(), found it is a
157 * symlink, and are now replacing the contents. The complen parameter indicates
158 * how much of the pathname to replace. If the symlink is an absolute path,
159 * then we overwrite the entire contents of the pathname.
162 pn_insert(struct pathname
*pnp
, struct pathname
*sympnp
, size_t complen
)
165 if (*sympnp
->pn_path
== '/') {
167 * Full path, replace everything
169 if (pnp
->pn_pathlen
+ sympnp
->pn_pathlen
>= pnp
->pn_bufsize
)
170 return (ENAMETOOLONG
);
171 if (pnp
->pn_pathlen
!= 0)
172 ovbcopy(pnp
->pn_path
, pnp
->pn_buf
+ sympnp
->pn_pathlen
,
174 bcopy(sympnp
->pn_path
, pnp
->pn_buf
, sympnp
->pn_pathlen
);
175 pnp
->pn_pathlen
+= sympnp
->pn_pathlen
;
176 pnp
->pn_buf
[pnp
->pn_pathlen
] = '\0';
177 pnp
->pn_path
= pnp
->pn_buf
;
180 * Partial path, replace only last component
182 if ((pnp
->pn_path
- pnp
->pn_buf
) - complen
+
183 pnp
->pn_pathlen
+ sympnp
->pn_pathlen
>= pnp
->pn_bufsize
)
184 return (ENAMETOOLONG
);
186 if (pnp
->pn_pathlen
!= 0)
187 ovbcopy(pnp
->pn_path
, pnp
->pn_path
- complen
+
188 sympnp
->pn_pathlen
, pnp
->pn_pathlen
+ 1);
189 pnp
->pn_path
-= complen
;
190 bcopy(sympnp
->pn_path
, pnp
->pn_path
, sympnp
->pn_pathlen
);
191 pnp
->pn_pathlen
+= sympnp
->pn_pathlen
;
198 pn_getsymlink(vnode_t
*vp
, struct pathname
*pnp
, cred_t
*crp
)
204 aiov
.iov_base
= pnp
->pn_path
= pnp
->pn_buf
;
205 aiov
.iov_len
= pnp
->pn_bufsize
;
206 auio
.uio_iov
= &aiov
;
208 auio
.uio_loffset
= 0;
209 auio
.uio_segflg
= UIO_SYSSPACE
;
210 auio
.uio_extflg
= UIO_COPY_CACHED
;
211 auio
.uio_resid
= pnp
->pn_bufsize
;
212 if ((error
= VOP_READLINK(vp
, &auio
, crp
, NULL
)) == 0) {
213 pnp
->pn_pathlen
= pnp
->pn_bufsize
- auio
.uio_resid
;
214 if (pnp
->pn_pathlen
== pnp
->pn_bufsize
)
215 error
= ENAMETOOLONG
;
217 pnp
->pn_path
[pnp
->pn_pathlen
] = '\0';
223 * Get next component from a path name and leave in
224 * buffer "component" which should have room for
225 * MAXNAMELEN bytes (including a null terminator character).
228 pn_getcomponent(struct pathname
*pnp
, char *component
)
230 char c
, *cp
, *path
, saved
;
234 pathlen
= pnp
->pn_pathlen
;
235 if (pathlen
>= MAXNAMELEN
) {
236 saved
= path
[MAXNAMELEN
];
237 path
[MAXNAMELEN
] = '/'; /* guarantees loop termination */
238 for (cp
= path
; (c
= *cp
) != '/'; cp
++)
240 path
[MAXNAMELEN
] = saved
;
241 if (cp
- path
== MAXNAMELEN
)
242 return (ENAMETOOLONG
);
244 path
[pathlen
] = '/'; /* guarantees loop termination */
245 for (cp
= path
; (c
= *cp
) != '/'; cp
++)
247 path
[pathlen
] = '\0';
251 pnp
->pn_pathlen
= pathlen
- (cp
- path
);
257 * Skip over consecutive slashes in the path name.
260 pn_skipslash(struct pathname
*pnp
)
262 while (pnp
->pn_pathlen
> 0 && *pnp
->pn_path
== '/') {
269 * Sets pn_path to the last component in the pathname, updating
270 * pn_pathlen. If pathname is empty, or degenerate, leaves pn_path
271 * pointing at NULL char. The pathname is explicitly null-terminated
272 * so that any trailing slashes are effectively removed.
275 pn_setlast(struct pathname
*pnp
)
277 char *buf
= pnp
->pn_buf
;
278 char *path
= pnp
->pn_path
+ pnp
->pn_pathlen
- 1;
281 while (path
> buf
&& *path
== '/')
284 while (path
> buf
&& *path
!= '/')
290 pnp
->pn_pathlen
= endpath
- path
;
294 * Eliminate any trailing slashes in the pathname.
295 * Return non-zero iff there were any trailing slashes.
298 pn_fixslash(struct pathname
*pnp
)
300 char *start
= pnp
->pn_path
;
301 char *end
= start
+ pnp
->pn_pathlen
;
303 while (end
> start
&& *(end
- 1) == '/')
305 if (pnp
->pn_pathlen
== end
- start
)
308 pnp
->pn_pathlen
= end
- start
;
313 * Add a slash to the end of the pathname, if it will fit.
314 * Return ENAMETOOLONG if it won't.
317 pn_addslash(struct pathname
*pnp
)
319 if (pnp
->pn_path
+ pnp
->pn_pathlen
+ 1 >=
320 pnp
->pn_buf
+ pnp
->pn_bufsize
) {
321 if (pnp
->pn_pathlen
+ 1 >= pnp
->pn_bufsize
) /* no room */
322 return (ENAMETOOLONG
);
324 * Move the component to the start of the buffer
325 * so we have room to add the trailing slash.
327 ovbcopy(pnp
->pn_path
, pnp
->pn_buf
, pnp
->pn_pathlen
);
328 pnp
->pn_path
= pnp
->pn_buf
;
330 pnp
->pn_path
[pnp
->pn_pathlen
++] = '/';
331 pnp
->pn_path
[pnp
->pn_pathlen
] = '\0';