~ubuntu-branches/ubuntu/trusty/virtualbox-lts-xenial/trusty-proposed

« back to all changes in this revision

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

  • Committer: Package Import Robot
  • Author(s): Gianfranco Costamagna
  • Date: 2016-02-23 14:28:26 UTC
  • Revision ID: package-import@ubuntu.com-20160223142826-bdu69el2z6wa2a44
Tags: upstream-4.3.36-dfsg
ImportĀ upstreamĀ versionĀ 4.3.36-dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* $Id: vfsstdfile.cpp $ */
 
2
/** @file
 
3
 * IPRT - Virtual File System, Standard File Implementation.
 
4
 */
 
5
 
 
6
/*
 
7
 * Copyright (C) 2010-2011 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
    NOREF(pvThis);
 
256
    int rc;
 
257
    if (fEvents != RTPOLL_EVT_ERROR)
 
258
    {
 
259
        *pfRetEvents = fEvents & ~RTPOLL_EVT_ERROR;
 
260
        rc = VINF_SUCCESS;
 
261
    }
 
262
    else if (fIntr)
 
263
        rc = RTThreadSleep(cMillies);
 
264
    else
 
265
    {
 
266
        uint64_t uMsStart = RTTimeMilliTS();
 
267
        do
 
268
            rc = RTThreadSleep(cMillies);
 
269
        while (   rc == VERR_INTERRUPTED
 
270
               && !fIntr
 
271
               && RTTimeMilliTS() - uMsStart < cMillies);
 
272
        if (rc == VERR_INTERRUPTED)
 
273
            rc = VERR_TIMEOUT;
 
274
    }
 
275
    return rc;
 
276
}
 
277
 
 
278
 
 
279
/**
 
280
 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnTell}
 
281
 */
 
282
static DECLCALLBACK(int) rtVfsStdFile_Tell(void *pvThis, PRTFOFF poffActual)
 
283
{
 
284
    PRTVFSSTDFILE pThis = (PRTVFSSTDFILE)pvThis;
 
285
    uint64_t offActual;
 
286
    int rc = RTFileSeek(pThis->hFile, 0, RTFILE_SEEK_CURRENT, &offActual);
 
287
    if (RT_SUCCESS(rc))
 
288
        *poffActual = (RTFOFF)offActual;
 
289
    return rc;
 
290
}
 
291
 
 
292
 
 
293
/**
 
294
 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnSkip}
 
295
 */
 
296
static DECLCALLBACK(int) rtVfsStdFile_Skip(void *pvThis, RTFOFF cb)
 
297
{
 
298
    PRTVFSSTDFILE pThis = (PRTVFSSTDFILE)pvThis;
 
299
    uint64_t offIgnore;
 
300
    return RTFileSeek(pThis->hFile, cb, RTFILE_SEEK_CURRENT, &offIgnore);
 
301
}
 
302
 
 
303
 
 
304
/**
 
305
 * @interface_method_impl{RTVFSOBJSETOPS,pfnMode}
 
306
 */
 
307
static DECLCALLBACK(int) rtVfsStdFile_SetMode(void *pvThis, RTFMODE fMode, RTFMODE fMask)
 
308
{
 
309
    PRTVFSSTDFILE pThis = (PRTVFSSTDFILE)pvThis;
 
310
    if (fMask != ~RTFS_TYPE_MASK)
 
311
    {
 
312
#if 0
 
313
        RTFMODE fCurMode;
 
314
        int rc = RTFileGetMode(pThis->hFile, &fCurMode);
 
315
        if (RT_FAILURE(rc))
 
316
            return rc;
 
317
        fMode |= ~fMask & fCurMode;
 
318
#else
 
319
        RTFSOBJINFO ObjInfo;
 
320
        int rc = RTFileQueryInfo(pThis->hFile, &ObjInfo, RTFSOBJATTRADD_NOTHING);
 
321
        if (RT_FAILURE(rc))
 
322
            return rc;
 
323
        fMode |= ~fMask & ObjInfo.Attr.fMode;
 
324
#endif
 
325
    }
 
326
    return RTFileSetMode(pThis->hFile, fMode);
 
327
}
 
328
 
 
329
 
 
330
/**
 
331
 * @interface_method_impl{RTVFSOBJSETOPS,pfnSetTimes}
 
332
 */
 
333
static DECLCALLBACK(int) rtVfsStdFile_SetTimes(void *pvThis, PCRTTIMESPEC pAccessTime, PCRTTIMESPEC pModificationTime,
 
334
                                               PCRTTIMESPEC pChangeTime, PCRTTIMESPEC pBirthTime)
 
335
{
 
336
    PRTVFSSTDFILE pThis = (PRTVFSSTDFILE)pvThis;
 
337
    return RTFileSetTimes(pThis->hFile, pAccessTime, pModificationTime, pChangeTime, pBirthTime);
 
338
}
 
339
 
 
340
 
 
341
/**
 
342
 * @interface_method_impl{RTVFSOBJSETOPS,pfnSetOwner}
 
343
 */
 
344
static DECLCALLBACK(int) rtVfsStdFile_SetOwner(void *pvThis, RTUID uid, RTGID gid)
 
345
{
 
346
#if 0
 
347
    PRTVFSSTDFILE pThis = (PRTVFSSTDFILE)pvThis;
 
348
    return RTFileSetOwner(pThis->hFile, uid, gid);
 
349
#else
 
350
    NOREF(pvThis); NOREF(uid); NOREF(gid);
 
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
DECL_HIDDEN_CONST(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
/**
 
422
 * Internal worker for RTVfsFileFromRTFile and RTVfsFileOpenNormal.
 
423
 *
 
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.
 
429
 */
 
430
static int rtVfsFileFromRTFile(RTFILE hFile, uint64_t fOpen, bool fLeaveOpen, PRTVFSFILE phVfsFile)
 
431
{
 
432
    PRTVFSSTDFILE   pThis;
 
433
    RTVFSFILE       hVfsFile;
 
434
    int rc = RTVfsNewFile(&g_rtVfsStdFileOps, sizeof(RTVFSSTDFILE), fOpen, NIL_RTVFS, NIL_RTVFSLOCK,
 
435
                          &hVfsFile, (void **)&pThis);
 
436
    if (RT_FAILURE(rc))
 
437
        return rc;
 
438
 
 
439
    pThis->hFile        = hFile;
 
440
    pThis->fLeaveOpen   = fLeaveOpen;
 
441
    *phVfsFile = hVfsFile;
 
442
    return VINF_SUCCESS;
 
443
}
 
444
 
 
445
 
 
446
RTDECL(int) RTVfsFileFromRTFile(RTFILE hFile, uint64_t fOpen, bool fLeaveOpen, PRTVFSFILE phVfsFile)
 
447
{
 
448
    /*
 
449
     * Check the handle validity.
 
450
     */
 
451
    RTFSOBJINFO ObjInfo;
 
452
    int rc = RTFileQueryInfo(hFile, &ObjInfo, RTFSOBJATTRADD_NOTHING);
 
453
    if (RT_FAILURE(rc))
 
454
        return rc;
 
455
 
 
456
    /*
 
457
     * Set up some fake fOpen flags if necessary and create a VFS file handle.
 
458
     */
 
459
    if (!fOpen)
 
460
        fOpen = RTFILE_O_READWRITE | RTFILE_O_DENY_NONE | RTFILE_O_OPEN_CREATE;
 
461
 
 
462
    return rtVfsFileFromRTFile(hFile, fOpen, fLeaveOpen, phVfsFile);
 
463
}
 
464
 
 
465
 
 
466
RTDECL(int) RTVfsFileOpenNormal(const char *pszFilename, uint64_t fOpen, PRTVFSFILE phVfsFile)
 
467
{
 
468
    /*
 
469
     * Open the file the normal way and pass it to RTVfsFileFromRTFile.
 
470
     */
 
471
    RTFILE hFile;
 
472
    int rc = RTFileOpen(&hFile, pszFilename, fOpen);
 
473
    if (RT_SUCCESS(rc))
 
474
    {
 
475
        /*
 
476
         * Create a VFS file handle.
 
477
         */
 
478
        rc = rtVfsFileFromRTFile(hFile, fOpen, false /*fLeaveOpen*/, phVfsFile);
 
479
        if (RT_FAILURE(rc))
 
480
            RTFileClose(hFile);
 
481
    }
 
482
    return rc;
 
483
}
 
484
 
 
485
 
 
486
RTDECL(int) RTVfsIoStrmFromRTFile(RTFILE hFile, uint64_t fOpen, bool fLeaveOpen, PRTVFSIOSTREAM phVfsIos)
 
487
{
 
488
    RTVFSFILE hVfsFile;
 
489
    int rc = RTVfsFileFromRTFile(hFile, fOpen, fLeaveOpen, &hVfsFile);
 
490
    if (RT_SUCCESS(rc))
 
491
    {
 
492
        *phVfsIos = RTVfsFileToIoStream(hVfsFile);
 
493
        RTVfsFileRelease(hVfsFile);
 
494
    }
 
495
    return rc;
 
496
}
 
497
 
 
498
 
 
499
RTDECL(int) RTVfsIoStrmOpenNormal(const char *pszFilename, uint64_t fOpen, PRTVFSIOSTREAM phVfsIos)
 
500
{
 
501
    RTVFSFILE hVfsFile;
 
502
    int rc = RTVfsFileOpenNormal(pszFilename, fOpen, &hVfsFile);
 
503
    if (RT_SUCCESS(rc))
 
504
        *phVfsIos = RTVfsFileToIoStream(hVfsFile);
 
505
    return rc;
 
506
}
 
507