xref: /illumos-gate/usr/src/uts/common/os/move.c (revision 7c478bd9)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
28 /*	  All Rights Reserved  	*/
29 
30 /*
31  * University Copyright- Copyright (c) 1982, 1986, 1988
32  * The Regents of the University of California
33  * All Rights Reserved
34  *
35  * University Acknowledgment- Portions of this document are derived from
36  * software developed by the University of California, Berkeley, and its
37  * contributors.
38  */
39 
40 #pragma ident	"%Z%%M%	%I%	%E% SMI"
41 
42 #include <sys/types.h>
43 #include <sys/sysmacros.h>
44 #include <sys/param.h>
45 #include <sys/systm.h>
46 #include <sys/uio.h>
47 #include <sys/errno.h>
48 
49 /*
50  * Move "n" bytes at byte address "p"; "rw" indicates the direction
51  * of the move, and the I/O parameters are provided in "uio", which is
52  * update to reflect the data which was moved.  Returns 0 on success or
53  * a non-zero errno on failure.
54  */
55 int
56 uiomove(void *p, size_t n, enum uio_rw rw, struct uio *uio)
57 {
58 	struct iovec *iov;
59 	ulong_t cnt;
60 	int error;
61 
62 	while (n && uio->uio_resid) {
63 		iov = uio->uio_iov;
64 		cnt = MIN(iov->iov_len, n);
65 		if (cnt == 0l) {
66 			uio->uio_iov++;
67 			uio->uio_iovcnt--;
68 			continue;
69 		}
70 		switch (uio->uio_segflg) {
71 
72 		case UIO_USERSPACE:
73 		case UIO_USERISPACE:
74 			if (rw == UIO_READ) {
75 				error = xcopyout_nta(p, iov->iov_base, cnt,
76 				    (uio->uio_extflg & UIO_COPY_CACHED));
77 			} else {
78 				error = xcopyin_nta(iov->iov_base, p, cnt,
79 				    (uio->uio_extflg & UIO_COPY_CACHED));
80 			}
81 
82 			if (error)
83 				return (error);
84 			break;
85 
86 		case UIO_SYSSPACE:
87 			if (rw == UIO_READ)
88 				error = kcopy_nta(p, iov->iov_base, cnt,
89 				    (uio->uio_extflg & UIO_COPY_CACHED));
90 			else
91 				error = kcopy_nta(iov->iov_base, p, cnt,
92 				    (uio->uio_extflg & UIO_COPY_CACHED));
93 			if (error)
94 				return (error);
95 			break;
96 		}
97 		iov->iov_base += cnt;
98 		iov->iov_len -= cnt;
99 		uio->uio_resid -= cnt;
100 		uio->uio_loffset += cnt;
101 		p = (caddr_t)p + cnt;
102 		n -= cnt;
103 	}
104 	return (0);
105 }
106 
107 /*
108  * transfer a character value into the address space
109  * delineated by a uio and update fields within the
110  * uio for next character. Return 0 for success, EFAULT
111  * for error.
112  */
113 int
114 ureadc(int val, struct uio *uiop)
115 {
116 	struct iovec *iovp;
117 	unsigned char c;
118 
119 	/*
120 	 * first determine if uio is valid.  uiop should be
121 	 * non-NULL and the resid count > 0.
122 	 */
123 	if (!(uiop && uiop->uio_resid > 0))
124 		return (EFAULT);
125 
126 	/*
127 	 * scan through iovecs until one is found that is non-empty.
128 	 * Return EFAULT if none found.
129 	 */
130 	while (uiop->uio_iovcnt > 0) {
131 		iovp = uiop->uio_iov;
132 		if (iovp->iov_len <= 0) {
133 			uiop->uio_iovcnt--;
134 			uiop->uio_iov++;
135 		} else
136 			break;
137 	}
138 
139 	if (uiop->uio_iovcnt <= 0)
140 		return (EFAULT);
141 
142 	/*
143 	 * Transfer character to uio space.
144 	 */
145 
146 	c = (unsigned char) (val & 0xFF);
147 
148 	switch (uiop->uio_segflg) {
149 
150 	case UIO_USERISPACE:
151 	case UIO_USERSPACE:
152 		if (copyout(&c, iovp->iov_base, sizeof (unsigned char)))
153 			return (EFAULT);
154 		break;
155 
156 	case UIO_SYSSPACE: /* can do direct copy since kernel-kernel */
157 		*iovp->iov_base = c;
158 		break;
159 
160 	default:
161 		return (EFAULT); /* invalid segflg value */
162 	}
163 
164 	/*
165 	 * bump up/down iovec and uio members to reflect transfer.
166 	 */
167 	iovp->iov_base++;
168 	iovp->iov_len--;
169 	uiop->uio_resid--;
170 	uiop->uio_loffset++;
171 	return (0); /* success */
172 }
173 
174 /*
175  * return a character value from the address space
176  * delineated by a uio and update fields within the
177  * uio for next character. Return the character for success,
178  * -1 for error.
179  */
180 int
181 uwritec(struct uio *uiop)
182 {
183 	struct iovec *iovp;
184 	unsigned char c;
185 
186 	/*
187 	 * verify we were passed a valid uio structure.
188 	 * (1) non-NULL uiop, (2) positive resid count
189 	 * (3) there is an iovec with positive length
190 	 */
191 
192 	if (!(uiop && uiop->uio_resid > 0))
193 		return (-1);
194 
195 	while (uiop->uio_iovcnt > 0) {
196 		iovp = uiop->uio_iov;
197 		if (iovp->iov_len <= 0) {
198 			uiop->uio_iovcnt--;
199 			uiop->uio_iov++;
200 		} else
201 			break;
202 	}
203 
204 	if (uiop->uio_iovcnt <= 0)
205 		return (-1);
206 
207 	/*
208 	 * Get the character from the uio address space.
209 	 */
210 	switch (uiop->uio_segflg) {
211 
212 	case UIO_USERISPACE:
213 	case UIO_USERSPACE:
214 		if (copyin(iovp->iov_base, &c, sizeof (unsigned char)))
215 			return (-1);
216 		break;
217 
218 	case UIO_SYSSPACE:
219 		c = *iovp->iov_base;
220 		break;
221 
222 	default:
223 		return (-1); /* invalid segflg */
224 	}
225 
226 	/*
227 	 * Adjust fields of iovec and uio appropriately.
228 	 */
229 	iovp->iov_base++;
230 	iovp->iov_len--;
231 	uiop->uio_resid--;
232 	uiop->uio_loffset++;
233 	return ((int)c & 0xFF); /* success */
234 }
235 
236 /*
237  * Drop the next n chars out of *uiop.
238  */
239 void
240 uioskip(uio_t *uiop, size_t n)
241 {
242 	if (n > uiop->uio_resid)
243 		return;
244 	while (n != 0) {
245 		register iovec_t	*iovp = uiop->uio_iov;
246 		register size_t		niovb = MIN(iovp->iov_len, n);
247 
248 		if (niovb == 0) {
249 			uiop->uio_iov++;
250 			uiop->uio_iovcnt--;
251 			continue;
252 		}
253 		iovp->iov_base += niovb;
254 		uiop->uio_loffset += niovb;
255 		iovp->iov_len -= niovb;
256 		uiop->uio_resid -= niovb;
257 		n -= niovb;
258 	}
259 }
260 
261 /*
262  * Dup the suio into the duio and diovec of size diov_cnt. If diov
263  * is too small to dup suio then an error will be returned, else 0.
264  */
265 int
266 uiodup(uio_t *suio, uio_t *duio, iovec_t *diov, int diov_cnt)
267 {
268 	int ix;
269 	iovec_t *siov = suio->uio_iov;
270 
271 	*duio = *suio;
272 	for (ix = 0; ix < suio->uio_iovcnt; ix++) {
273 		diov[ix] = siov[ix];
274 		if (ix >= diov_cnt)
275 			return (1);
276 	}
277 	duio->uio_iov = diov;
278 	return (0);
279 }
280