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 #include <sys/types.h>
41 #include <sys/param.h>
42 #include <sys/systm.h>
44 #include <sys/errno.h>
45 #include <sys/pathname.h>
48 #include <sys/vnode.h>
49 #include <sys/debug.h>
54 * In translating file names we copy each argument file
55 * name into a pathname structure where we operate on it.
56 * Each pathname structure can hold "pn_bufsize" characters
57 * including a terminating null, and operations here support
58 * allocating and freeing pathname structures, fetching
59 * strings from user space, getting the next character from
60 * a pathname, combining two pathnames (used in symbolic
61 * link processing), and peeling off the first component
66 * Allocate contents of pathname structure. Structure is typically
67 * an automatic variable in calling routine for convenience.
69 * May sleep in the call to kmem_alloc() and so must not be called
70 * from interrupt level.
73 pn_alloc(struct pathname
*pnp
)
75 pn_alloc_sz(pnp
, MAXPATHLEN
);
78 pn_alloc_sz(struct pathname
*pnp
, size_t sz
)
80 pnp
->pn_path
= pnp
->pn_buf
= kmem_alloc(sz
, KM_SLEEP
);
86 * Free pathname resources.
89 pn_free(struct pathname
*pnp
)
91 /* pn_bufsize is usually MAXPATHLEN, but may not be */
92 kmem_free(pnp
->pn_buf
, pnp
->pn_bufsize
);
93 pnp
->pn_path
= pnp
->pn_buf
= NULL
;
94 pnp
->pn_pathlen
= pnp
->pn_bufsize
= 0;
98 * Pull a path name from user or kernel space.
99 * Called from pn_get() after allocation of a MAXPATHLEN buffer.
100 * Also called directly with a TYPICALMAXPATHLEN-size buffer
101 * on the stack as a local optimization.
104 pn_get_buf(char *str
, enum uio_seg seg
, struct pathname
*pnp
,
105 void *buf
, size_t bufsize
)
109 pnp
->pn_path
= pnp
->pn_buf
= buf
;
110 pnp
->pn_bufsize
= bufsize
;
111 if (seg
== UIO_USERSPACE
)
112 error
= copyinstr(str
, pnp
->pn_path
, bufsize
, &pnp
->pn_pathlen
);
114 error
= copystr(str
, pnp
->pn_path
, bufsize
, &pnp
->pn_pathlen
);
117 pnp
->pn_pathlen
--; /* don't count null byte */
122 * Pull a path name from user or kernel space.
125 pn_get(char *str
, enum uio_seg seg
, struct pathname
*pnp
)
130 buf
= kmem_alloc(MAXPATHLEN
, KM_SLEEP
);
131 if ((error
= pn_get_buf(str
, seg
, pnp
, buf
, MAXPATHLEN
)) != 0)
137 * Set path name to argument string. Storage has already been allocated
138 * and pn_buf points to it.
140 * On error, all fields except pn_buf will be undefined.
143 pn_set(struct pathname
*pnp
, char *path
)
147 pnp
->pn_path
= pnp
->pn_buf
;
148 error
= copystr(path
, pnp
->pn_path
, pnp
->pn_bufsize
, &pnp
->pn_pathlen
);
149 pnp
->pn_pathlen
--; /* don't count null byte */
154 * Combine two argument path names by putting the second argument
155 * before the first in the first's buffer. This isn't very general;
156 * it is designed specifically for symbolic link processing.
157 * This function copies the symlink in-place in the pathname. This is to
158 * ensure that vnode path caching remains correct. At the point where this is
159 * called (from lookuppnvp), we have called pn_getcomponent(), found it is a
160 * symlink, and are now replacing the contents. The complen parameter indicates
161 * how much of the pathname to replace. If the symlink is an absolute path,
162 * then we overwrite the entire contents of the pathname.
165 pn_insert(struct pathname
*pnp
, struct pathname
*sympnp
, size_t complen
)
168 if (*sympnp
->pn_path
== '/') {
170 * Full path, replace everything
172 if (pnp
->pn_pathlen
+ sympnp
->pn_pathlen
>= pnp
->pn_bufsize
)
173 return (ENAMETOOLONG
);
174 if (pnp
->pn_pathlen
!= 0)
175 ovbcopy(pnp
->pn_path
, pnp
->pn_buf
+ sympnp
->pn_pathlen
,
177 bcopy(sympnp
->pn_path
, pnp
->pn_buf
, sympnp
->pn_pathlen
);
178 pnp
->pn_pathlen
+= sympnp
->pn_pathlen
;
179 pnp
->pn_buf
[pnp
->pn_pathlen
] = '\0';
180 pnp
->pn_path
= pnp
->pn_buf
;
183 * Partial path, replace only last component
185 if ((pnp
->pn_path
- pnp
->pn_buf
) - complen
+
186 pnp
->pn_pathlen
+ sympnp
->pn_pathlen
>= pnp
->pn_bufsize
)
187 return (ENAMETOOLONG
);
189 if (pnp
->pn_pathlen
!= 0)
190 ovbcopy(pnp
->pn_path
, pnp
->pn_path
- complen
+
191 sympnp
->pn_pathlen
, pnp
->pn_pathlen
+ 1);
192 pnp
->pn_path
-= complen
;
193 bcopy(sympnp
->pn_path
, pnp
->pn_path
, sympnp
->pn_pathlen
);
194 pnp
->pn_pathlen
+= sympnp
->pn_pathlen
;
201 pn_getsymlink(vnode_t
*vp
, struct pathname
*pnp
, cred_t
*crp
)
207 aiov
.iov_base
= pnp
->pn_path
= pnp
->pn_buf
;
208 aiov
.iov_len
= pnp
->pn_bufsize
;
209 auio
.uio_iov
= &aiov
;
211 auio
.uio_loffset
= 0;
212 auio
.uio_segflg
= UIO_SYSSPACE
;
213 auio
.uio_extflg
= UIO_COPY_CACHED
;
214 auio
.uio_resid
= pnp
->pn_bufsize
;
215 if ((error
= fop_readlink(vp
, &auio
, crp
, NULL
)) == 0) {
216 pnp
->pn_pathlen
= pnp
->pn_bufsize
- auio
.uio_resid
;
217 if (pnp
->pn_pathlen
== pnp
->pn_bufsize
)
218 error
= ENAMETOOLONG
;
220 pnp
->pn_path
[pnp
->pn_pathlen
] = '\0';
226 * Get next component from a path name and leave in
227 * buffer "component" which should have room for
228 * MAXNAMELEN bytes (including a null terminator character).
231 pn_getcomponent(struct pathname
*pnp
, char *component
)
233 char c
, *cp
, *path
, saved
;
237 pathlen
= pnp
->pn_pathlen
;
238 if (pathlen
>= MAXNAMELEN
) {
239 saved
= path
[MAXNAMELEN
];
240 path
[MAXNAMELEN
] = '/'; /* guarantees loop termination */
241 for (cp
= path
; (c
= *cp
) != '/'; cp
++)
243 path
[MAXNAMELEN
] = saved
;
244 if (cp
- path
== MAXNAMELEN
)
245 return (ENAMETOOLONG
);
247 path
[pathlen
] = '/'; /* guarantees loop termination */
248 for (cp
= path
; (c
= *cp
) != '/'; cp
++)
250 path
[pathlen
] = '\0';
254 pnp
->pn_pathlen
= pathlen
- (cp
- path
);
260 * Skip over consecutive slashes in the path name.
263 pn_skipslash(struct pathname
*pnp
)
265 while (pnp
->pn_pathlen
> 0 && *pnp
->pn_path
== '/') {
272 * Sets pn_path to the last component in the pathname, updating
273 * pn_pathlen. If pathname is empty, or degenerate, leaves pn_path
274 * pointing at NULL char. The pathname is explicitly null-terminated
275 * so that any trailing slashes are effectively removed.
278 pn_setlast(struct pathname
*pnp
)
280 char *buf
= pnp
->pn_buf
;
281 char *path
= pnp
->pn_path
+ pnp
->pn_pathlen
- 1;
284 while (path
> buf
&& *path
== '/')
287 while (path
> buf
&& *path
!= '/')
293 pnp
->pn_pathlen
= endpath
- path
;
297 * Eliminate any trailing slashes in the pathname.
298 * Return non-zero iff there were any trailing slashes.
301 pn_fixslash(struct pathname
*pnp
)
303 char *start
= pnp
->pn_path
;
304 char *end
= start
+ pnp
->pn_pathlen
;
306 while (end
> start
&& *(end
- 1) == '/')
308 if (pnp
->pn_pathlen
== end
- start
)
311 pnp
->pn_pathlen
= end
- start
;
316 * Add a slash to the end of the pathname, if it will fit.
317 * Return ENAMETOOLONG if it won't.
320 pn_addslash(struct pathname
*pnp
)
322 if (pnp
->pn_path
+ pnp
->pn_pathlen
+ 1 >=
323 pnp
->pn_buf
+ pnp
->pn_bufsize
) {
324 if (pnp
->pn_pathlen
+ 1 >= pnp
->pn_bufsize
) /* no room */
325 return (ENAMETOOLONG
);
327 * Move the component to the start of the buffer
328 * so we have room to add the trailing slash.
330 ovbcopy(pnp
->pn_path
, pnp
->pn_buf
, pnp
->pn_pathlen
);
331 pnp
->pn_path
= pnp
->pn_buf
;
333 pnp
->pn_path
[pnp
->pn_pathlen
++] = '/';
334 pnp
->pn_path
[pnp
->pn_pathlen
] = '\0';