VirtualBox

source: vbox/trunk/src/VBox/Runtime/r0drv/darwin/fileio-r0drv-darwin.cpp@ 98032

Last change on this file since 98032 was 96407, checked in by vboxsync, 2 years ago

scm copyright and license note update

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 10.6 KB
Line 
1/* $Id: fileio-r0drv-darwin.cpp 96407 2022-08-22 17:43:14Z vboxsync $ */
2/** @file
3 * IPRT - File I/O, R0 Driver, Darwin.
4 */
5
6/*
7 * Copyright (C) 2011-2022 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 "the-darwin-kernel.h"
42
43#include <iprt/file.h>
44#include "internal/iprt.h"
45
46#include <iprt/asm.h>
47#include <iprt/assert.h>
48#include <iprt/err.h>
49#include <iprt/log.h>
50#include <iprt/mem.h>
51#include <iprt/string.h>
52#include "internal/magics.h"
53
54
55/*********************************************************************************************************************************
56* Global Variables *
57*********************************************************************************************************************************/
58/** Default file permissions for newly created files. */
59#if defined(S_IRUSR) && defined(S_IWUSR)
60# define RT_FILE_PERMISSION (S_IRUSR | S_IWUSR)
61#else
62# define RT_FILE_PERMISSION (00600)
63#endif
64
65
66/*********************************************************************************************************************************
67* Structures and Typedefs *
68*********************************************************************************************************************************/
69/**
70 * Darwin kernel file handle data.
71 */
72typedef struct RTFILEINT
73{
74 /** Magic value (RTFILE_MAGIC). */
75 uint32_t u32Magic;
76 /** The open mode flags passed to the kernel API. */
77 int fOpenMode;
78 /** The open flags passed to RTFileOpen. */
79 uint64_t fOpen;
80 /** The VFS context in which the file was opened. */
81 vfs_context_t hVfsCtx;
82 /** The vnode returned by vnode_open. */
83 vnode_t hVnode;
84 /** The current file offset. */
85 uint64_t offFile;
86} RTFILEINT;
87/** Magic number for RTFILEINT::u32Magic (To Be Determined). */
88#define RTFILE_MAGIC UINT32_C(0x01020304)
89
90
91RTDECL(int) RTFileOpen(PRTFILE phFile, const char *pszFilename, uint64_t fOpen)
92{
93 AssertReturn(!(fOpen & RTFILE_O_TEMP_AUTO_DELETE), VERR_NOT_SUPPORTED);
94
95 RTFILEINT *pThis = (RTFILEINT *)RTMemAllocZ(sizeof(*pThis));
96 if (!pThis)
97 return VERR_NO_MEMORY;
98 IPRT_DARWIN_SAVE_EFL_AC();
99
100 errno_t rc;
101 pThis->u32Magic = RTFILE_MAGIC;
102 pThis->fOpen = fOpen;
103 pThis->hVfsCtx = vfs_context_current();
104 if (pThis->hVfsCtx != NULL)
105 {
106 int fCMode = (fOpen & RTFILE_O_CREATE_MODE_MASK)
107 ? (fOpen & RTFILE_O_CREATE_MODE_MASK) >> RTFILE_O_CREATE_MODE_SHIFT
108 : RT_FILE_PERMISSION;
109 int fVnFlags = 0; /* VNODE_LOOKUP_XXX */
110 int fOpenMode = 0;
111 if (fOpen & RTFILE_O_NON_BLOCK)
112 fOpenMode |= O_NONBLOCK;
113 if (fOpen & RTFILE_O_WRITE_THROUGH)
114 fOpenMode |= O_SYNC;
115
116 /* create/truncate file */
117 switch (fOpen & RTFILE_O_ACTION_MASK)
118 {
119 case RTFILE_O_OPEN: break;
120 case RTFILE_O_OPEN_CREATE: fOpenMode |= O_CREAT; break;
121 case RTFILE_O_CREATE: fOpenMode |= O_CREAT | O_EXCL; break;
122 case RTFILE_O_CREATE_REPLACE: fOpenMode |= O_CREAT | O_TRUNC; break; /** @todo replacing needs fixing, this is *not* a 1:1 mapping! */
123 }
124 if (fOpen & RTFILE_O_TRUNCATE)
125 fOpenMode |= O_TRUNC;
126
127 switch (fOpen & RTFILE_O_ACCESS_MASK)
128 {
129 case RTFILE_O_READ:
130 fOpenMode |= FREAD;
131 break;
132 case RTFILE_O_WRITE:
133 fOpenMode |= fOpen & RTFILE_O_APPEND ? O_APPEND | FWRITE : FWRITE;
134 break;
135 case RTFILE_O_READWRITE:
136 fOpenMode |= fOpen & RTFILE_O_APPEND ? O_APPEND | FWRITE | FREAD : FWRITE | FREAD;
137 break;
138 default:
139 AssertMsgFailed(("RTFileOpen received an invalid RW value, fOpen=%#x\n", fOpen));
140 IPRT_DARWIN_RESTORE_EFL_AC();
141 return VERR_INVALID_PARAMETER;
142 }
143
144 pThis->fOpenMode = fOpenMode;
145 rc = vnode_open(pszFilename, fOpenMode, fCMode, fVnFlags, &pThis->hVnode, pThis->hVfsCtx);
146 if (rc == 0)
147 {
148 *phFile = pThis;
149 IPRT_DARWIN_RESTORE_EFL_AC();
150 return VINF_SUCCESS;
151 }
152
153 rc = RTErrConvertFromErrno(rc);
154 }
155 else
156 rc = VERR_INTERNAL_ERROR_5;
157 RTMemFree(pThis);
158
159 IPRT_DARWIN_RESTORE_EFL_AC();
160 return rc;
161}
162
163
164RTDECL(int) RTFileClose(RTFILE hFile)
165{
166 if (hFile == NIL_RTFILE)
167 return VINF_SUCCESS;
168
169 RTFILEINT *pThis = hFile;
170 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
171 AssertReturn(pThis->u32Magic == RTFILE_MAGIC, VERR_INVALID_HANDLE);
172 pThis->u32Magic = ~RTFILE_MAGIC;
173
174 IPRT_DARWIN_SAVE_EFL_AC();
175 errno_t rc = vnode_close(pThis->hVnode, pThis->fOpenMode & (FREAD | FWRITE), pThis->hVfsCtx);
176 IPRT_DARWIN_RESTORE_EFL_AC();
177
178 RTMemFree(pThis);
179 return RTErrConvertFromErrno(rc);
180}
181
182
183RTDECL(int) RTFileReadAt(RTFILE hFile, RTFOFF off, void *pvBuf, size_t cbToRead, size_t *pcbRead)
184{
185 RTFILEINT *pThis = hFile;
186 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
187 AssertReturn(pThis->u32Magic == RTFILE_MAGIC, VERR_INVALID_HANDLE);
188
189 off_t offNative = (off_t)off;
190 AssertReturn((RTFOFF)offNative == off, VERR_OUT_OF_RANGE);
191 IPRT_DARWIN_SAVE_EFL_AC();
192
193#if 0 /* Added in 10.6, grr. */
194 errno_t rc;
195 if (!pcbRead)
196 rc = vn_rdwr(UIO_READ, pThis->hVnode, (char *)pvBuf, cbToRead, offNative, UIO_SYSSPACE, 0 /*ioflg*/,
197 vfs_context_ucred(pThis->hVfsCtx), NULL, vfs_context_proc(pThis->hVfsCtx));
198 else
199 {
200 int cbLeft = 0;
201 rc = vn_rdwr(UIO_READ, pThis->hVnode, (char *)pvBuf, cbToRead, offNative, UIO_SYSSPACE, 0 /*ioflg*/,
202 vfs_context_ucred(pThis->hVfsCtx), &cbLeft, vfs_context_proc(pThis->hVfsCtx));
203 *pcbRead = cbToRead - cbLeft;
204 }
205 IPRT_DARWIN_RESTORE_EFL_AC();
206 return !rc ? VINF_SUCCESS : RTErrConvertFromErrno(rc);
207
208#else
209 uio_t hUio = uio_create(1, offNative, UIO_SYSSPACE, UIO_READ);
210 if (!hUio)
211 {
212 IPRT_DARWIN_RESTORE_EFL_AC();
213 return VERR_NO_MEMORY;
214 }
215 errno_t rc;
216 if (uio_addiov(hUio, (user_addr_t)(uintptr_t)pvBuf, cbToRead) == 0)
217 {
218 rc = VNOP_READ(pThis->hVnode, hUio, 0 /*ioflg*/, pThis->hVfsCtx);
219 off_t const cbActual = cbToRead - uio_resid(hUio);
220 if (pcbRead)
221 *pcbRead = cbActual;
222 if (rc == 0)
223 {
224 pThis->offFile += (uint64_t)cbActual;
225 if (cbToRead != (uint64_t)cbActual)
226 rc = VERR_FILE_IO_ERROR;
227 }
228 else
229 rc = RTErrConvertFromErrno(rc);
230 }
231 else
232 rc = VERR_INTERNAL_ERROR_3;
233 uio_free(hUio);
234 IPRT_DARWIN_RESTORE_EFL_AC();
235 return rc;
236#endif
237}
238
239
240RTDECL(int) RTFileRead(RTFILE hFile, void *pvBuf, size_t cbToRead, size_t *pcbRead)
241{
242 RTFILEINT *pThis = hFile;
243 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
244 AssertReturn(pThis->u32Magic == RTFILE_MAGIC, VERR_INVALID_HANDLE);
245
246 return RTFileReadAt(hFile, pThis->offFile, pvBuf, cbToRead, pcbRead);
247}
248
249
250RTDECL(int) RTFileQuerySize(RTFILE hFile, uint64_t *pcbSize)
251{
252 RTFILEINT *pThis = hFile;
253 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
254 AssertReturn(pThis->u32Magic == RTFILE_MAGIC, VERR_INVALID_HANDLE);
255
256 /*
257 * Query the data size attribute.
258 * Note! Allocate extra attribute buffer space to be on the safe side.
259 */
260 union
261 {
262 struct vnode_attr VAttr;
263 uint8_t abPadding[sizeof(struct vnode_attr) * 2];
264 } uBuf;
265 RT_ZERO(uBuf);
266 struct vnode_attr *pVAttr = &uBuf.VAttr;
267
268 VATTR_INIT(pVAttr);
269 VATTR_WANTED(pVAttr, va_data_size);
270
271 errno_t rc = vnode_getattr(pThis->hVnode, pVAttr, pThis->hVfsCtx);
272 if (!rc)
273 {
274 *pcbSize = pVAttr->va_data_size;
275 return VINF_SUCCESS;
276 }
277 return RTErrConvertFromErrno(rc);
278}
279
280
281RTDECL(int) RTFileSeek(RTFILE hFile, int64_t offSeek, unsigned uMethod, uint64_t *poffActual)
282{
283 RTFILEINT *pThis = hFile;
284 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
285 AssertReturn(pThis->u32Magic == RTFILE_MAGIC, VERR_INVALID_HANDLE);
286
287 uint64_t offNew;
288 switch (uMethod)
289 {
290 case RTFILE_SEEK_BEGIN:
291 AssertReturn(offSeek >= 0, VERR_NEGATIVE_SEEK);
292 offNew = offSeek;
293 break;
294
295 case RTFILE_SEEK_CURRENT:
296 offNew = pThis->offFile + offSeek;
297 break;
298
299 case RTFILE_SEEK_END:
300 {
301 uint64_t cbFile = 0;
302 int rc = RTFileQuerySize(hFile, &cbFile);
303 if (RT_SUCCESS(rc))
304 offNew = cbFile + offSeek;
305 else
306 return rc;
307 break;
308 }
309
310 default:
311 return VERR_INVALID_PARAMETER;
312 }
313
314 if ((RTFOFF)offNew >= 0)
315 {
316 pThis->offFile = offNew;
317 if (poffActual)
318 *poffActual = offNew;
319 return VINF_SUCCESS;
320 }
321 return VERR_NEGATIVE_SEEK;
322}
323
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