1
/* $Id: vfsstdfile.cpp $ */
3
* IPRT - Virtual File System, Standard File Implementation.
7
* Copyright (C) 2010-2011 Oracle Corporation
9
* This file is part of VirtualBox Open Source Edition (OSE), as
10
* available from http://www.virtualbox.org. This file is free software;
11
* you can redistribute it and/or modify it under the terms of the GNU
12
* General Public License (GPL) as published by the Free Software
13
* Foundation, in version 2 as it comes in the "COPYING" file of the
14
* VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15
* hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
17
* The contents of this file may alternatively be used under the terms
18
* of the Common Development and Distribution License Version 1.0
19
* (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20
* VirtualBox OSE distribution, in which case the provisions of the
21
* CDDL are applicable instead of those of the GPL.
23
* You may elect to license modified versions of this file under the
24
* terms and conditions of either the GPL or the CDDL or both.
28
/*******************************************************************************
30
*******************************************************************************/
32
#include <iprt/vfslowlevel.h>
35
#include <iprt/file.h>
36
#include <iprt/poll.h>
37
#include <iprt/thread.h>
40
/*******************************************************************************
41
* Structures and Typedefs *
42
*******************************************************************************/
44
* Private data of a standard file.
46
typedef struct RTVFSSTDFILE
48
/** The file handle. */
50
/** Whether to leave the handle open when the VFS handle is closed. */
53
/** Pointer to the private data of a standard file. */
54
typedef RTVFSSTDFILE *PRTVFSSTDFILE;
58
* @interface_method_impl{RTVFSOBJOPS,pfnClose}
60
static DECLCALLBACK(int) rtVfsStdFile_Close(void *pvThis)
62
PRTVFSSTDFILE pThis = (PRTVFSSTDFILE)pvThis;
65
if (!pThis->fLeaveOpen)
66
rc = RTFileClose(pThis->hFile);
69
pThis->hFile = NIL_RTFILE;
76
* @interface_method_impl{RTVFSOBJOPS,pfnQueryInfo}
78
static DECLCALLBACK(int) rtVfsStdFile_QueryInfo(void *pvThis, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr)
80
PRTVFSSTDFILE pThis = (PRTVFSSTDFILE)pvThis;
81
return RTFileQueryInfo(pThis->hFile, pObjInfo, enmAddAttr);
86
* RTFileRead and RTFileReadAt does not return VINF_EOF or VINF_TRY_AGAIN, this
87
* function tries to fix this as best as it can.
89
* This fixing can be subject to races if some other thread or process is
90
* modifying the file size between the read and our size query here.
92
* @returns VINF_SUCCESS, VINF_EOF or VINF_TRY_AGAIN.
93
* @param pThis The instance data.
94
* @param off The offset parameter.
95
* @param cbToRead The number of bytes attempted read .
96
* @param cbActuallyRead The number of bytes actually read.
98
DECLINLINE(int) rtVfsStdFile_ReadFixRC(PRTVFSSTDFILE pThis, RTFOFF off, size_t cbToRead, size_t cbActuallyRead)
100
/* If the read returned less bytes than requested, it means the end of the
101
file has been reached. */
102
if (cbToRead > cbActuallyRead)
105
/* The other case here is the very special zero byte read at the end of the
106
file, where we're supposed to indicate EOF. */
111
int rc = RTFileGetSize(pThis->hFile, &cbFile);
120
rc = RTFileSeek(pThis->hFile, 0, RTFILE_SEEK_CURRENT, &off2);
125
return off2 >= cbFile ? VINF_EOF : VINF_SUCCESS;
130
* @interface_method_impl{RTVFSIOSTREAMOPS,pfnRead}
132
static DECLCALLBACK(int) rtVfsStdFile_Read(void *pvThis, RTFOFF off, PCRTSGBUF pSgBuf, bool fBlocking, size_t *pcbRead)
134
PRTVFSSTDFILE pThis = (PRTVFSSTDFILE)pvThis;
138
if (pSgBuf->cSegs == 1)
141
rc = RTFileRead( pThis->hFile, pSgBuf->paSegs[0].pvSeg, pSgBuf->paSegs[0].cbSeg, pcbRead);
143
rc = RTFileReadAt(pThis->hFile, off, pSgBuf->paSegs[0].pvSeg, pSgBuf->paSegs[0].cbSeg, pcbRead);
144
if (rc == VINF_SUCCESS && pcbRead)
145
rc = rtVfsStdFile_ReadFixRC(pThis, off, pSgBuf->paSegs[0].cbSeg, *pcbRead);
151
size_t cbReadSeg = 0;
154
for (uint32_t iSeg = 0; iSeg < pSgBuf->cSegs; iSeg++)
156
void *pvSeg = pSgBuf->paSegs[iSeg].pvSeg;
157
cbSeg = pSgBuf->paSegs[iSeg].cbSeg;
161
rc = RTFileRead( pThis->hFile, pvSeg, cbSeg, pcbRead ? &cbReadSeg : NULL);
163
rc = RTFileReadAt(pThis->hFile, off, pvSeg, cbSeg, pcbRead ? &cbReadSeg : NULL);
169
if ((pcbRead && cbReadSeg != cbSeg) || rc != VINF_SUCCESS)
176
if (rc == VINF_SUCCESS)
177
rc = rtVfsStdFile_ReadFixRC(pThis, off, cbSeg, cbReadSeg);
186
* @interface_method_impl{RTVFSIOSTREAMOPS,pfnWrite}
188
static DECLCALLBACK(int) rtVfsStdFile_Write(void *pvThis, RTFOFF off, PCRTSGBUF pSgBuf, bool fBlocking, size_t *pcbWritten)
190
PRTVFSSTDFILE pThis = (PRTVFSSTDFILE)pvThis;
194
if (pSgBuf->cSegs == 1)
197
rc = RTFileWrite(pThis->hFile, pSgBuf->paSegs[0].pvSeg, pSgBuf->paSegs[0].cbSeg, pcbWritten);
199
rc = RTFileWriteAt(pThis->hFile, off, pSgBuf->paSegs[0].pvSeg, pSgBuf->paSegs[0].cbSeg, pcbWritten);
203
size_t cbWritten = 0;
205
size_t *pcbWrittenSeg = pcbWritten ? &cbWrittenSeg : NULL;
208
for (uint32_t iSeg = 0; iSeg < pSgBuf->cSegs; iSeg++)
210
void *pvSeg = pSgBuf->paSegs[iSeg].pvSeg;
211
size_t cbSeg = pSgBuf->paSegs[iSeg].cbSeg;
215
rc = RTFileWrite(pThis->hFile, pvSeg, cbSeg, pcbWrittenSeg);
218
rc = RTFileWriteAt(pThis->hFile, off, pvSeg, cbSeg, pcbWrittenSeg);
225
cbWritten += cbWrittenSeg;
226
if (cbWrittenSeg != cbSeg)
232
*pcbWritten = cbWritten;
240
* @interface_method_impl{RTVFSIOSTREAMOPS,pfnFlush}
242
static DECLCALLBACK(int) rtVfsStdFile_Flush(void *pvThis)
244
PRTVFSSTDFILE pThis = (PRTVFSSTDFILE)pvThis;
245
return RTFileFlush(pThis->hFile);
250
* @interface_method_impl{RTVFSIOSTREAMOPS,pfnPollOne}
252
static DECLCALLBACK(int) rtVfsStdFile_PollOne(void *pvThis, uint32_t fEvents, RTMSINTERVAL cMillies, bool fIntr,
253
uint32_t *pfRetEvents)
257
if (fEvents != RTPOLL_EVT_ERROR)
259
*pfRetEvents = fEvents & ~RTPOLL_EVT_ERROR;
263
rc = RTThreadSleep(cMillies);
266
uint64_t uMsStart = RTTimeMilliTS();
268
rc = RTThreadSleep(cMillies);
269
while ( rc == VERR_INTERRUPTED
271
&& RTTimeMilliTS() - uMsStart < cMillies);
272
if (rc == VERR_INTERRUPTED)
280
* @interface_method_impl{RTVFSIOSTREAMOPS,pfnTell}
282
static DECLCALLBACK(int) rtVfsStdFile_Tell(void *pvThis, PRTFOFF poffActual)
284
PRTVFSSTDFILE pThis = (PRTVFSSTDFILE)pvThis;
286
int rc = RTFileSeek(pThis->hFile, 0, RTFILE_SEEK_CURRENT, &offActual);
288
*poffActual = (RTFOFF)offActual;
294
* @interface_method_impl{RTVFSIOSTREAMOPS,pfnSkip}
296
static DECLCALLBACK(int) rtVfsStdFile_Skip(void *pvThis, RTFOFF cb)
298
PRTVFSSTDFILE pThis = (PRTVFSSTDFILE)pvThis;
300
return RTFileSeek(pThis->hFile, cb, RTFILE_SEEK_CURRENT, &offIgnore);
305
* @interface_method_impl{RTVFSOBJSETOPS,pfnMode}
307
static DECLCALLBACK(int) rtVfsStdFile_SetMode(void *pvThis, RTFMODE fMode, RTFMODE fMask)
309
PRTVFSSTDFILE pThis = (PRTVFSSTDFILE)pvThis;
310
if (fMask != ~RTFS_TYPE_MASK)
314
int rc = RTFileGetMode(pThis->hFile, &fCurMode);
317
fMode |= ~fMask & fCurMode;
320
int rc = RTFileQueryInfo(pThis->hFile, &ObjInfo, RTFSOBJATTRADD_NOTHING);
323
fMode |= ~fMask & ObjInfo.Attr.fMode;
326
return RTFileSetMode(pThis->hFile, fMode);
331
* @interface_method_impl{RTVFSOBJSETOPS,pfnSetTimes}
333
static DECLCALLBACK(int) rtVfsStdFile_SetTimes(void *pvThis, PCRTTIMESPEC pAccessTime, PCRTTIMESPEC pModificationTime,
334
PCRTTIMESPEC pChangeTime, PCRTTIMESPEC pBirthTime)
336
PRTVFSSTDFILE pThis = (PRTVFSSTDFILE)pvThis;
337
return RTFileSetTimes(pThis->hFile, pAccessTime, pModificationTime, pChangeTime, pBirthTime);
342
* @interface_method_impl{RTVFSOBJSETOPS,pfnSetOwner}
344
static DECLCALLBACK(int) rtVfsStdFile_SetOwner(void *pvThis, RTUID uid, RTGID gid)
347
PRTVFSSTDFILE pThis = (PRTVFSSTDFILE)pvThis;
348
return RTFileSetOwner(pThis->hFile, uid, gid);
350
NOREF(pvThis); NOREF(uid); NOREF(gid);
351
return VERR_NOT_IMPLEMENTED;
357
* @interface_method_impl{RTVFSFILEOPS,pfnSeek}
359
static DECLCALLBACK(int) rtVfsStdFile_Seek(void *pvThis, RTFOFF offSeek, unsigned uMethod, PRTFOFF poffActual)
361
PRTVFSSTDFILE pThis = (PRTVFSSTDFILE)pvThis;
362
uint64_t offActual = 0;
363
int rc = RTFileSeek(pThis->hFile, offSeek, uMethod, &offActual);
365
*poffActual = offActual;
371
* @interface_method_impl{RTVFSFILEOPS,pfnQuerySize}
373
static DECLCALLBACK(int) rtVfsStdFile_QuerySize(void *pvThis, uint64_t *pcbFile)
375
PRTVFSSTDFILE pThis = (PRTVFSSTDFILE)pvThis;
376
return RTFileGetSize(pThis->hFile, pcbFile);
381
* Standard file operations.
383
DECL_HIDDEN_CONST(const RTVFSFILEOPS) g_rtVfsStdFileOps =
391
rtVfsStdFile_QueryInfo,
394
RTVFSIOSTREAMOPS_VERSION,
399
rtVfsStdFile_PollOne,
403
RTVFSIOSTREAMOPS_VERSION,
405
RTVFSFILEOPS_VERSION,
408
RTVFSOBJSETOPS_VERSION,
409
RT_OFFSETOF(RTVFSFILEOPS, Stream.Obj) - RT_OFFSETOF(RTVFSFILEOPS, ObjSet),
410
rtVfsStdFile_SetMode,
411
rtVfsStdFile_SetTimes,
412
rtVfsStdFile_SetOwner,
413
RTVFSOBJSETOPS_VERSION
416
rtVfsStdFile_QuerySize,
422
* Internal worker for RTVfsFileFromRTFile and RTVfsFileOpenNormal.
424
* @returns IRPT status code.
425
* @param hFile The IPRT file handle.
426
* @param fOpen The RTFILE_O_XXX flags.
427
* @param fLeaveOpen Whether to leave it open or close it.
428
* @param phVfsFile Where to return the handle.
430
static int rtVfsFileFromRTFile(RTFILE hFile, uint64_t fOpen, bool fLeaveOpen, PRTVFSFILE phVfsFile)
434
int rc = RTVfsNewFile(&g_rtVfsStdFileOps, sizeof(RTVFSSTDFILE), fOpen, NIL_RTVFS, NIL_RTVFSLOCK,
435
&hVfsFile, (void **)&pThis);
439
pThis->hFile = hFile;
440
pThis->fLeaveOpen = fLeaveOpen;
441
*phVfsFile = hVfsFile;
446
RTDECL(int) RTVfsFileFromRTFile(RTFILE hFile, uint64_t fOpen, bool fLeaveOpen, PRTVFSFILE phVfsFile)
449
* Check the handle validity.
452
int rc = RTFileQueryInfo(hFile, &ObjInfo, RTFSOBJATTRADD_NOTHING);
457
* Set up some fake fOpen flags if necessary and create a VFS file handle.
460
fOpen = RTFILE_O_READWRITE | RTFILE_O_DENY_NONE | RTFILE_O_OPEN_CREATE;
462
return rtVfsFileFromRTFile(hFile, fOpen, fLeaveOpen, phVfsFile);
466
RTDECL(int) RTVfsFileOpenNormal(const char *pszFilename, uint64_t fOpen, PRTVFSFILE phVfsFile)
469
* Open the file the normal way and pass it to RTVfsFileFromRTFile.
472
int rc = RTFileOpen(&hFile, pszFilename, fOpen);
476
* Create a VFS file handle.
478
rc = rtVfsFileFromRTFile(hFile, fOpen, false /*fLeaveOpen*/, phVfsFile);
486
RTDECL(int) RTVfsIoStrmFromRTFile(RTFILE hFile, uint64_t fOpen, bool fLeaveOpen, PRTVFSIOSTREAM phVfsIos)
489
int rc = RTVfsFileFromRTFile(hFile, fOpen, fLeaveOpen, &hVfsFile);
492
*phVfsIos = RTVfsFileToIoStream(hVfsFile);
493
RTVfsFileRelease(hVfsFile);
499
RTDECL(int) RTVfsIoStrmOpenNormal(const char *pszFilename, uint64_t fOpen, PRTVFSIOSTREAM phVfsIos)
502
int rc = RTVfsFileOpenNormal(pszFilename, fOpen, &hVfsFile);
504
*phVfsIos = RTVfsFileToIoStream(hVfsFile);