VirtualBox

source: vbox/trunk/src/VBox/Runtime/r3/posix/fileio-sg-posix.cpp@ 103914

Last change on this file since 103914 was 98103, checked in by vboxsync, 2 years ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 8.4 KB
Line 
1/* $Id: fileio-sg-posix.cpp 98103 2023-01-17 14:15:46Z vboxsync $ */
2/** @file
3 * IPRT - File I/O, RTFileSgRead & RTFileSgWrite, posixy.
4 */
5
6/*
7 * Copyright (C) 2006-2023 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * The contents of this file may alternatively be used under the terms
26 * of the Common Development and Distribution License Version 1.0
27 * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
28 * in the VirtualBox distribution, in which case the provisions of the
29 * CDDL are applicable instead of those of the GPL.
30 *
31 * You may elect to license modified versions of this file under the
32 * terms and conditions of either the GPL or the CDDL or both.
33 *
34 * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
35 */
36
37
38/*********************************************************************************************************************************
39* Header Files *
40*********************************************************************************************************************************/
41#include <iprt/cdefs.h>
42#include <errno.h>
43#include <sys/types.h>
44#include <sys/uio.h>
45#include <unistd.h>
46#include <limits.h>
47#if defined(RT_OS_DARWIN) || defined(RT_OS_FREEBSD) || defined(RT_OS_NETBSD) || defined(RT_OS_OPENBSD)
48# include <sys/syslimits.h>
49#endif
50
51#include "internal/iprt.h"
52#include <iprt/file.h>
53
54#include <iprt/assert.h>
55#include <iprt/err.h>
56#include <iprt/log.h>
57
58#ifndef UIO_MAXIOV
59# ifdef IOV_MAX
60# define UIO_MAXIOV IOV_MAX
61# else
62# error "UIO_MAXIOV and IOV_MAX are undefined"
63# endif
64#endif
65
66
67/* These assumptions simplifies things a lot here. */
68AssertCompileMembersSameSizeAndOffset(struct iovec, iov_base, RTSGSEG, pvSeg);
69AssertCompileMembersSameSizeAndOffset(struct iovec, iov_len, RTSGSEG, cbSeg);
70
71
72RTDECL(int) RTFileSgRead(RTFILE hFile, PRTSGBUF pSgBuf, size_t cbToRead, size_t *pcbRead)
73{
74 /*
75 * Make sure we set pcbRead.
76 */
77 if (pcbRead)
78 *pcbRead = 0;
79
80 /*
81 * Special case: Zero read == nop.
82 */
83 if (cbToRead == 0)
84 return VINF_SUCCESS;
85
86 /*
87 * We can use the segment array directly if we're at the start of the
88 * current S/G segment and cbToRead matches the remainder exactly.
89 */
90 size_t cbTotalRead = 0;
91
92 size_t const cbSgBufLeft = RTSgBufCalcLengthLeft(pSgBuf);
93 AssertMsgReturn(cbSgBufLeft >= cbToRead, ("%#zx vs %#zx\n", cbSgBufLeft, cbToRead), VERR_INVALID_PARAMETER);
94
95 if (cbToRead == cbSgBufLeft)
96 while (RTSgBufIsAtStartOfSegment(pSgBuf))
97 {
98 size_t const cSegsLeft = pSgBuf->cSegs - pSgBuf->idxSeg;
99 ssize_t cbThisRead = readv(RTFileToNative(hFile), (const struct iovec *)&pSgBuf->paSegs[pSgBuf->idxSeg],
100 RT_MIN(cSegsLeft, UIO_MAXIOV));
101 if (cbThisRead >= 0)
102 {
103 AssertStmt((size_t)cbThisRead <= cbToRead, cbThisRead = cbToRead);
104
105 RTSgBufAdvance(pSgBuf, cbThisRead);
106 cbTotalRead += cbThisRead;
107 cbToRead -= cbThisRead;
108 if (cbToRead == 0)
109 {
110 if (pcbRead)
111 *pcbRead = cbTotalRead;
112 return VINF_SUCCESS;
113 }
114
115 if ( pcbRead
116 && ( cSegsLeft <= UIO_MAXIOV
117 || cbThisRead == 0 /* typically EOF */ ))
118 {
119 *pcbRead = cbTotalRead;
120 return VINF_SUCCESS;
121 }
122 if (cbThisRead == 0)
123 return VERR_EOF;
124 }
125 else if (cbTotalRead > 0 && pcbRead)
126 {
127 *pcbRead = cbTotalRead;
128 return VINF_SUCCESS;
129 }
130 else
131 return RTErrConvertFromErrno(errno);
132 }
133
134 /*
135 * Unaligned start or not reading the whole buffer. For reasons of
136 * simplicity, we work the input segment by segment like the generic code.
137 */
138 int rc = VINF_SUCCESS;
139 while (cbToRead > 0)
140 {
141 size_t cbSeg;
142 void *pvSeg = RTSgBufGetCurrentSegment(pSgBuf, cbToRead, &cbSeg);
143 size_t cbThisRead = cbSeg;
144 rc = RTFileRead(hFile, pvSeg, cbSeg, pcbRead ? &cbThisRead : NULL);
145 if (RT_SUCCESS(rc))
146 {
147 RTSgBufAdvance(pSgBuf, cbThisRead);
148 cbTotalRead += cbThisRead;
149 }
150 else
151 break;
152 if ((size_t)cbThisRead < cbSeg)
153 {
154 AssertStmt(pcbRead, rc = VERR_INTERNAL_ERROR_2);
155 break;
156 }
157
158 Assert(cbSeg == cbThisRead);
159 cbToRead -= cbSeg;
160 }
161 if (pcbRead)
162 *pcbRead = cbTotalRead;
163 return rc;
164}
165
166
167RTDECL(int) RTFileSgWrite(RTFILE hFile, PRTSGBUF pSgBuf, size_t cbToWrite, size_t *pcbWritten)
168{
169 /*
170 * Make sure we set pcbWritten.
171 */
172 if (pcbWritten)
173 *pcbWritten = 0;
174
175 /*
176 * Special case: Zero write == nop.
177 */
178 if (cbToWrite == 0)
179 return VINF_SUCCESS;
180
181 /*
182 * We can use the segment array directly if we're at the start of the
183 * current S/G segment and cbToWrite matches the remainder exactly.
184 */
185 size_t cbTotalWritten = 0;
186
187 size_t const cbSgBufLeft = RTSgBufCalcLengthLeft(pSgBuf);
188 AssertMsgReturn(cbSgBufLeft >= cbToWrite, ("%#zx vs %#zx\n", cbSgBufLeft, cbToWrite), VERR_INVALID_PARAMETER);
189
190 if (cbToWrite == cbSgBufLeft)
191 while (RTSgBufIsAtStartOfSegment(pSgBuf))
192 {
193 size_t const cSegsLeft = pSgBuf->cSegs - pSgBuf->idxSeg;
194 ssize_t cbThisWritten = writev(RTFileToNative(hFile), (const struct iovec *)&pSgBuf->paSegs[pSgBuf->idxSeg],
195 RT_MIN(cSegsLeft, UIO_MAXIOV));
196 if (cbThisWritten >= 0)
197 {
198 AssertStmt((size_t)cbThisWritten <= cbToWrite, cbThisWritten = cbToWrite);
199
200 RTSgBufAdvance(pSgBuf, cbThisWritten);
201 cbTotalWritten += cbThisWritten;
202 cbToWrite -= cbThisWritten;
203 if (cbToWrite == 0)
204 {
205 if (pcbWritten)
206 *pcbWritten = cbTotalWritten;
207 return VINF_SUCCESS;
208 }
209
210 if ( pcbWritten
211 && ( cSegsLeft <= UIO_MAXIOV
212 || cbThisWritten == 0 /* non-file, full buffer/whatever */ ))
213 {
214 *pcbWritten = cbTotalWritten;
215 return VINF_SUCCESS;
216 }
217 if (cbThisWritten == 0)
218 return VERR_TRY_AGAIN;
219 }
220 else if (cbTotalWritten > 0 && pcbWritten)
221 {
222 *pcbWritten = cbTotalWritten;
223 return VINF_SUCCESS;
224 }
225 else
226 return RTErrConvertFromErrno(errno);
227 }
228
229 /*
230 * Unaligned start or not writing the whole buffer. For reasons of
231 * simplicity, we work the input segment by segment like the generic code.
232 */
233 int rc = VINF_SUCCESS;
234 while (cbToWrite > 0)
235 {
236 size_t cbSeg;
237 void *pvSeg = RTSgBufGetCurrentSegment(pSgBuf, cbToWrite, &cbSeg);
238 size_t cbThisWritten = cbSeg;
239 rc = RTFileWrite(hFile, pvSeg, cbSeg, pcbWritten ? &cbThisWritten : NULL);
240 if (RT_SUCCESS(rc))
241 {
242 RTSgBufAdvance(pSgBuf, cbThisWritten);
243 cbTotalWritten += cbThisWritten;
244 }
245 else
246 break;
247 if ((size_t)cbThisWritten < cbSeg)
248 {
249 AssertStmt(pcbWritten, rc = VERR_INTERNAL_ERROR_2);
250 break;
251 }
252
253 Assert(cbSeg == cbThisWritten);
254 cbToWrite -= cbSeg;
255 }
256 if (pcbWritten)
257 *pcbWritten = cbTotalWritten;
258 return rc;
259}
260
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette