~ubuntu-branches/ubuntu/raring/virtualbox-ose/raring

« back to all changes in this revision

Viewing changes to src/VBox/Runtime/common/vfs/vfsstdfile.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Felix Geyer
  • Date: 2011-01-30 23:27:25 UTC
  • mfrom: (0.3.12 upstream)
  • Revision ID: james.westby@ubuntu.com-20110130232725-2ouajjd2ggdet0zd
Tags: 4.0.2-dfsg-1ubuntu1
* Merge from Debian unstable, remaining changes:
  - Add Apport hook.
    - debian/virtualbox-ose.files/source_virtualbox-ose.py
    - debian/virtualbox-ose.install
  - Drop *-source packages.
* Drop ubuntu-01-fix-build-gcc45.patch, fixed upstream.
* Drop ubuntu-02-as-needed.patch, added to the Debian package.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* $Id: vfsstdfile.cpp 34405 2010-11-26 16:43:26Z vboxsync $ */
 
2
/** @file
 
3
 * IPRT - Virtual File System, Standard File Implementation.
 
4
 */
 
5
 
 
6
/*
 
7
 * Copyright (C) 2010 Oracle Corporation
 
8
 *
 
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.
 
16
 *
 
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.
 
22
 *
 
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.
 
25
 */
 
26
 
 
27
 
 
28
/*******************************************************************************
 
29
*   Header Files                                                               *
 
30
*******************************************************************************/
 
31
#include <iprt/vfs.h>
 
32
#include <iprt/vfslowlevel.h>
 
33
 
 
34
#include <iprt/err.h>
 
35
#include <iprt/file.h>
 
36
#include <iprt/poll.h>
 
37
#include <iprt/thread.h>
 
38
 
 
39
 
 
40
/*******************************************************************************
 
41
*   Structures and Typedefs                                                    *
 
42
*******************************************************************************/
 
43
/**
 
44
 * Private data of a standard file.
 
45
 */
 
46
typedef struct RTVFSSTDFILE
 
47
{
 
48
    /** The file handle. */
 
49
    RTFILE          hFile;
 
50
    /** Whether to leave the handle open when the VFS handle is closed. */
 
51
    bool            fLeaveOpen;
 
52
} RTVFSSTDFILE;
 
53
/** Pointer to the private data of a standard file. */
 
54
typedef RTVFSSTDFILE *PRTVFSSTDFILE;
 
55
 
 
56
 
 
57
/**
 
58
 * @interface_method_impl{RTVFSOBJOPS,pfnClose}
 
59
 */
 
60
static DECLCALLBACK(int) rtVfsStdFile_Close(void *pvThis)
 
61
{
 
62
    PRTVFSSTDFILE pThis = (PRTVFSSTDFILE)pvThis;
 
63
 
 
64
    int rc;
 
65
    if (!pThis->fLeaveOpen)
 
66
        rc = RTFileClose(pThis->hFile);
 
67
    else
 
68
        rc = VINF_SUCCESS;
 
69
    pThis->hFile = NIL_RTFILE;
 
70
 
 
71
    return rc;
 
72
}
 
73
 
 
74
 
 
75
/**
 
76
 * @interface_method_impl{RTVFSOBJOPS,pfnQueryInfo}
 
77
 */
 
78
static DECLCALLBACK(int) rtVfsStdFile_QueryInfo(void *pvThis, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr)
 
79
{
 
80
    PRTVFSSTDFILE pThis = (PRTVFSSTDFILE)pvThis;
 
81
    return RTFileQueryInfo(pThis->hFile, pObjInfo, enmAddAttr);
 
82
}
 
83
 
 
84
 
 
85
/**
 
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.
 
88
 *
 
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.
 
91
 *
 
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.
 
97
 */
 
98
DECLINLINE(int) rtVfsStdFile_ReadFixRC(PRTVFSSTDFILE pThis, RTFOFF off, size_t cbToRead, size_t cbActuallyRead)
 
99
{
 
100
    /* If the read returned less bytes than requested, it means the end of the
 
101
       file has been reached. */
 
102
    if (cbToRead > cbActuallyRead)
 
103
        return VINF_EOF;
 
104
 
 
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. */
 
107
    if (cbToRead > 0)
 
108
        return VINF_SUCCESS;
 
109
 
 
110
    uint64_t cbFile;
 
111
    int rc = RTFileGetSize(pThis->hFile, &cbFile);
 
112
    if (RT_FAILURE(rc))
 
113
        return rc;
 
114
 
 
115
    uint64_t off2;
 
116
    if (off >= 0)
 
117
        off2 = off;
 
118
    else
 
119
    {
 
120
        rc = RTFileSeek(pThis->hFile, 0, RTFILE_SEEK_CURRENT, &off2);
 
121
        if (RT_FAILURE(rc))
 
122
            return rc;
 
123
    }
 
124
 
 
125
    return off2 >= cbFile ? VINF_EOF : VINF_SUCCESS;
 
126
}
 
127
 
 
128
 
 
129
/**
 
130
 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnRead}
 
131
 */
 
132
static DECLCALLBACK(int) rtVfsStdFile_Read(void *pvThis, RTFOFF off, PCRTSGBUF pSgBuf, bool fBlocking, size_t *pcbRead)
 
133
{
 
134
    PRTVFSSTDFILE pThis = (PRTVFSSTDFILE)pvThis;
 
135
    int           rc;
 
136
 
 
137
    NOREF(fBlocking);
 
138
    if (pSgBuf->cSegs == 1)
 
139
    {
 
140
        if (off < 0)
 
141
            rc = RTFileRead(  pThis->hFile,      pSgBuf->paSegs[0].pvSeg, pSgBuf->paSegs[0].cbSeg, pcbRead);
 
142
        else
 
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);
 
146
    }
 
147
    else
 
148
    {
 
149
        size_t  cbSeg      = 0;
 
150
        size_t  cbRead     = 0;
 
151
        size_t  cbReadSeg  = 0;
 
152
        rc = VINF_SUCCESS;
 
153
 
 
154
        for (uint32_t iSeg = 0; iSeg < pSgBuf->cSegs; iSeg++)
 
155
        {
 
156
            void *pvSeg = pSgBuf->paSegs[iSeg].pvSeg;
 
157
            cbSeg       = pSgBuf->paSegs[iSeg].cbSeg;
 
158
 
 
159
            cbReadSeg = cbSeg;
 
160
            if (off < 0)
 
161
                rc = RTFileRead(  pThis->hFile,      pvSeg, cbSeg, pcbRead ? &cbReadSeg : NULL);
 
162
            else
 
163
                rc = RTFileReadAt(pThis->hFile, off, pvSeg, cbSeg, pcbRead ? &cbReadSeg : NULL);
 
164
            if (RT_FAILURE(rc))
 
165
                break;
 
166
            if (off >= 0)
 
167
                off += cbReadSeg;
 
168
            cbRead  += cbReadSeg;
 
169
            if ((pcbRead && cbReadSeg != cbSeg) || rc != VINF_SUCCESS)
 
170
                break;
 
171
        }
 
172
 
 
173
        if (pcbRead)
 
174
        {
 
175
            *pcbRead = cbRead;
 
176
            if (rc == VINF_SUCCESS)
 
177
                rc = rtVfsStdFile_ReadFixRC(pThis, off, cbSeg, cbReadSeg);
 
178
        }
 
179
    }
 
180
 
 
181
    return rc;
 
182
}
 
183
 
 
184
 
 
185
/**
 
186
 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnWrite}
 
187
 */
 
188
static DECLCALLBACK(int) rtVfsStdFile_Write(void *pvThis, RTFOFF off, PCRTSGBUF pSgBuf, bool fBlocking, size_t *pcbWritten)
 
189
{
 
190
    PRTVFSSTDFILE pThis = (PRTVFSSTDFILE)pvThis;
 
191
    int           rc;
 
192
 
 
193
    NOREF(fBlocking);
 
194
    if (pSgBuf->cSegs == 1)
 
195
    {
 
196
        if (off < 0)
 
197
            rc = RTFileWrite(pThis->hFile, pSgBuf->paSegs[0].pvSeg, pSgBuf->paSegs[0].cbSeg, pcbWritten);
 
198
        else
 
199
            rc = RTFileWriteAt(pThis->hFile, off, pSgBuf->paSegs[0].pvSeg, pSgBuf->paSegs[0].cbSeg, pcbWritten);
 
200
    }
 
201
    else
 
202
    {
 
203
        size_t  cbWritten     = 0;
 
204
        size_t  cbWrittenSeg;
 
205
        size_t *pcbWrittenSeg = pcbWritten ? &cbWrittenSeg : NULL;
 
206
        rc = VINF_SUCCESS;
 
207
 
 
208
        for (uint32_t iSeg = 0; iSeg < pSgBuf->cSegs; iSeg++)
 
209
        {
 
210
            void   *pvSeg  = pSgBuf->paSegs[iSeg].pvSeg;
 
211
            size_t  cbSeg  = pSgBuf->paSegs[iSeg].cbSeg;
 
212
 
 
213
            cbWrittenSeg = 0;
 
214
            if (off < 0)
 
215
                rc = RTFileWrite(pThis->hFile, pvSeg, cbSeg, pcbWrittenSeg);
 
216
            else
 
217
            {
 
218
                rc = RTFileWriteAt(pThis->hFile, off, pvSeg, cbSeg, pcbWrittenSeg);
 
219
                off += cbSeg;
 
220
            }
 
221
            if (RT_FAILURE(rc))
 
222
                break;
 
223
            if (pcbWritten)
 
224
            {
 
225
                cbWritten += cbWrittenSeg;
 
226
                if (cbWrittenSeg != cbSeg)
 
227
                    break;
 
228
            }
 
229
        }
 
230
 
 
231
        if (pcbWritten)
 
232
            *pcbWritten = cbWritten;
 
233
    }
 
234
 
 
235
    return rc;
 
236
}
 
237
 
 
238
 
 
239
/**
 
240
 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnFlush}
 
241
 */
 
242
static DECLCALLBACK(int) rtVfsStdFile_Flush(void *pvThis)
 
243
{
 
244
    PRTVFSSTDFILE pThis = (PRTVFSSTDFILE)pvThis;
 
245
    return RTFileFlush(pThis->hFile);
 
246
}
 
247
 
 
248
 
 
249
/**
 
250
 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnPollOne}
 
251
 */
 
252
static DECLCALLBACK(int) rtVfsStdFile_PollOne(void *pvThis, uint32_t fEvents, RTMSINTERVAL cMillies, bool fIntr,
 
253
                                              uint32_t *pfRetEvents)
 
254
{
 
255
    PRTVFSSTDFILE pThis = (PRTVFSSTDFILE)pvThis;
 
256
    int           rc;
 
257
 
 
258
    if (fEvents != RTPOLL_EVT_ERROR)
 
259
    {
 
260
        *pfRetEvents = fEvents & ~RTPOLL_EVT_ERROR;
 
261
        rc = VINF_SUCCESS;
 
262
    }
 
263
    else if (fIntr)
 
264
        rc = RTThreadSleep(cMillies);
 
265
    else
 
266
    {
 
267
        uint64_t uMsStart = RTTimeMilliTS();
 
268
        do
 
269
            rc = RTThreadSleep(cMillies);
 
270
        while (   rc == VERR_INTERRUPTED
 
271
               && !fIntr
 
272
               && RTTimeMilliTS() - uMsStart < cMillies);
 
273
        if (rc == VERR_INTERRUPTED)
 
274
            rc = VERR_TIMEOUT;
 
275
    }
 
276
    return rc;
 
277
}
 
278
 
 
279
 
 
280
/**
 
281
 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnTell}
 
282
 */
 
283
static DECLCALLBACK(int) rtVfsStdFile_Tell(void *pvThis, PRTFOFF poffActual)
 
284
{
 
285
    PRTVFSSTDFILE pThis = (PRTVFSSTDFILE)pvThis;
 
286
    uint64_t offActual;
 
287
    int rc = RTFileSeek(pThis->hFile, 0, RTFILE_SEEK_CURRENT, &offActual);
 
288
    if (RT_SUCCESS(rc))
 
289
        *poffActual = (RTFOFF)offActual;
 
290
    return rc;
 
291
}
 
292
 
 
293
 
 
294
/**
 
295
 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnSkip}
 
296
 */
 
297
static DECLCALLBACK(int) rtVfsStdFile_Skip(void *pvThis, RTFOFF cb)
 
298
{
 
299
    PRTVFSSTDFILE pThis = (PRTVFSSTDFILE)pvThis;
 
300
    uint64_t offIgnore;
 
301
    return RTFileSeek(pThis->hFile, cb, RTFILE_SEEK_CURRENT, &offIgnore);
 
302
}
 
303
 
 
304
 
 
305
/**
 
306
 * @interface_method_impl{RTVFSOBJSETOPS,pfnMode}
 
307
 */
 
308
static DECLCALLBACK(int) rtVfsStdFile_SetMode(void *pvThis, RTFMODE fMode, RTFMODE fMask)
 
309
{
 
310
    PRTVFSSTDFILE pThis = (PRTVFSSTDFILE)pvThis;
 
311
    if (fMask != ~RTFS_TYPE_MASK)
 
312
    {
 
313
#if 0
 
314
        RTFMODE fCurMode;
 
315
        int rc = RTFileGetMode(pThis->hFile, &fCurMode);
 
316
        if (RT_FAILURE(rc))
 
317
            return rc;
 
318
        fMode |= ~fMask & fCurMode;
 
319
#else
 
320
        RTFSOBJINFO ObjInfo;
 
321
        int rc = RTFileQueryInfo(pThis->hFile, &ObjInfo, RTFSOBJATTRADD_NOTHING);
 
322
        if (RT_FAILURE(rc))
 
323
            return rc;
 
324
        fMode |= ~fMask & ObjInfo.Attr.fMode;
 
325
#endif
 
326
    }
 
327
    return RTFileSetMode(pThis->hFile, fMode);
 
328
}
 
329
 
 
330
 
 
331
/**
 
332
 * @interface_method_impl{RTVFSOBJSETOPS,pfnSetTimes}
 
333
 */
 
334
static DECLCALLBACK(int) rtVfsStdFile_SetTimes(void *pvThis, PCRTTIMESPEC pAccessTime, PCRTTIMESPEC pModificationTime,
 
335
                                               PCRTTIMESPEC pChangeTime, PCRTTIMESPEC pBirthTime)
 
336
{
 
337
    PRTVFSSTDFILE pThis = (PRTVFSSTDFILE)pvThis;
 
338
    return RTFileSetTimes(pThis->hFile, pAccessTime, pModificationTime, pChangeTime, pBirthTime);
 
339
}
 
340
 
 
341
 
 
342
/**
 
343
 * @interface_method_impl{RTVFSOBJSETOPS,pfnSetOwner}
 
344
 */
 
345
static DECLCALLBACK(int) rtVfsStdFile_SetOwner(void *pvThis, RTUID uid, RTGID gid)
 
346
{
 
347
    PRTVFSSTDFILE pThis = (PRTVFSSTDFILE)pvThis;
 
348
#if 0
 
349
    return RTFileSetOwner(pThis->hFile, uid, gid);
 
350
#else
 
351
    return VERR_NOT_IMPLEMENTED;
 
352
#endif
 
353
}
 
354
 
 
355
 
 
356
/**
 
357
 * @interface_method_impl{RTVFSFILEOPS,pfnSeek}
 
358
 */
 
359
static DECLCALLBACK(int) rtVfsStdFile_Seek(void *pvThis, RTFOFF offSeek, unsigned uMethod, PRTFOFF poffActual)
 
360
{
 
361
    PRTVFSSTDFILE pThis     = (PRTVFSSTDFILE)pvThis;
 
362
    uint64_t      offActual = 0;
 
363
    int rc = RTFileSeek(pThis->hFile, offSeek, uMethod, &offActual);
 
364
    if (RT_SUCCESS(rc))
 
365
        *poffActual = offActual;
 
366
    return rc;
 
367
}
 
368
 
 
369
 
 
370
/**
 
371
 * @interface_method_impl{RTVFSFILEOPS,pfnQuerySize}
 
372
 */
 
373
static DECLCALLBACK(int) rtVfsStdFile_QuerySize(void *pvThis, uint64_t *pcbFile)
 
374
{
 
375
    PRTVFSSTDFILE pThis = (PRTVFSSTDFILE)pvThis;
 
376
    return RTFileGetSize(pThis->hFile, pcbFile);
 
377
}
 
378
 
 
379
 
 
380
/**
 
381
 * Standard file operations.
 
382
 */
 
383
DECLHIDDEN(const RTVFSFILEOPS) g_rtVfsStdFileOps =
 
384
{
 
385
    { /* Stream */
 
386
        { /* Obj */
 
387
            RTVFSOBJOPS_VERSION,
 
388
            RTVFSOBJTYPE_FILE,
 
389
            "StdFile",
 
390
            rtVfsStdFile_Close,
 
391
            rtVfsStdFile_QueryInfo,
 
392
            RTVFSOBJOPS_VERSION
 
393
        },
 
394
        RTVFSIOSTREAMOPS_VERSION,
 
395
        0,
 
396
        rtVfsStdFile_Read,
 
397
        rtVfsStdFile_Write,
 
398
        rtVfsStdFile_Flush,
 
399
        rtVfsStdFile_PollOne,
 
400
        rtVfsStdFile_Tell,
 
401
        rtVfsStdFile_Skip,
 
402
        NULL /*ZeroFill*/,
 
403
        RTVFSIOSTREAMOPS_VERSION,
 
404
    },
 
405
    RTVFSFILEOPS_VERSION,
 
406
    0,
 
407
    { /* ObjSet */
 
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
 
414
    },
 
415
    rtVfsStdFile_Seek,
 
416
    rtVfsStdFile_QuerySize,
 
417
    RTVFSFILEOPS_VERSION
 
418
};
 
419
 
 
420
 
 
421
RTDECL(int) RTVfsFileFromRTFile(RTFILE hFile, uint32_t fOpen, bool fLeaveOpen, PRTVFSFILE phVfsFile)
 
422
{
 
423
    /*
 
424
     * Check the handle validity.
 
425
     */
 
426
    RTFSOBJINFO ObjInfo;
 
427
    int rc = RTFileQueryInfo(hFile, &ObjInfo, RTFSOBJATTRADD_NOTHING);
 
428
    if (RT_FAILURE(rc))
 
429
        return rc;
 
430
 
 
431
    /*
 
432
     * Set up some fake fOpen flags.
 
433
     */
 
434
    if (!fOpen)
 
435
        fOpen = RTFILE_O_READWRITE | RTFILE_O_DENY_NONE | RTFILE_O_OPEN_CREATE;
 
436
 
 
437
    /*
 
438
     * Create the handle.
 
439
     */
 
440
    PRTVFSSTDFILE   pThis;
 
441
    RTVFSFILE       hVfsFile;
 
442
    rc = RTVfsNewFile(&g_rtVfsStdFileOps, sizeof(RTVFSSTDFILE), fOpen, NIL_RTVFS, NIL_RTVFSLOCK, &hVfsFile, (void **)&pThis);
 
443
    if (RT_FAILURE(rc))
 
444
        return rc;
 
445
 
 
446
    pThis->hFile        = hFile;
 
447
    pThis->fLeaveOpen   = fLeaveOpen;
 
448
    *phVfsFile = hVfsFile;
 
449
    return VINF_SUCCESS;
 
450
}
 
451
 
 
452
 
 
453
RTDECL(int)         RTVfsIoStrmFromRTFile(RTFILE hFile, uint32_t fOpen, bool fLeaveOpen, PRTVFSIOSTREAM phVfsIos)
 
454
{
 
455
    RTVFSFILE hVfsFile;
 
456
    int rc = RTVfsFileFromRTFile(hFile, fOpen, fLeaveOpen, &hVfsFile);
 
457
    if (RT_SUCCESS(rc))
 
458
        *phVfsIos = RTVfsFileToIoStream(hVfsFile);
 
459
    return rc;
 
460
}
 
461