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

« back to all changes in this revision

Viewing changes to src/VBox/Runtime/r3/isofs.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: isofs.cpp 34406 2010-11-26 16:45:34Z vboxsync $ */
 
2
/** @file
 
3
 * IPRT - ISO 9660 file system handling.
 
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/isofs.h>
 
32
 
 
33
#include <iprt/file.h>
 
34
#include <iprt/err.h>
 
35
#include <iprt/mem.h>
 
36
#include <iprt/path.h>
 
37
#include <iprt/string.h>
 
38
 
 
39
 
 
40
/**
 
41
 * Destroys the path cache.
 
42
 *
 
43
 * @param   pFile           ISO handle.
 
44
 */
 
45
static void rtIsoFsDestroyPathCache(PRTISOFSFILE pFile)
 
46
{
 
47
    PRTISOFSPATHTABLEENTRY pNode = RTListGetFirst(&pFile->listPaths, RTISOFSPATHTABLEENTRY, Node);
 
48
    while (pNode)
 
49
    {
 
50
        PRTISOFSPATHTABLEENTRY pNext = RTListNodeGetNext(&pNode->Node, RTISOFSPATHTABLEENTRY, Node);
 
51
        bool fLast = RTListNodeIsLast(&pFile->listPaths, &pNode->Node);
 
52
 
 
53
        if (pNode->path)
 
54
            RTStrFree(pNode->path);
 
55
        if (pNode->path_full)
 
56
            RTStrFree(pNode->path_full);
 
57
        RTListNodeRemove(&pNode->Node);
 
58
        RTMemFree(pNode);
 
59
 
 
60
        if (fLast)
 
61
            break;
 
62
 
 
63
        pNode = pNext;
 
64
    }
 
65
}
 
66
 
 
67
 
 
68
/**
 
69
 * Adds a path entry to the path table list.
 
70
 *
 
71
 * @return  IPRT status code.
 
72
 * @param   pList       Path table list to add the path entry to.
 
73
 * @param   pszPath     Path to add.
 
74
 * @param   pHeader     Path header information to add.
 
75
 */
 
76
static int rtIsoFsAddToPathCache(PRTLISTNODE pList, const char *pszPath,
 
77
                                 RTISOFSPATHTABLEHEADER *pHeader)
 
78
{
 
79
    AssertPtrReturn(pList, VERR_INVALID_PARAMETER);
 
80
    AssertPtrReturn(pszPath, VERR_INVALID_PARAMETER);
 
81
    AssertPtrReturn(pHeader, VERR_INVALID_PARAMETER);
 
82
 
 
83
    PRTISOFSPATHTABLEENTRY pNode = (PRTISOFSPATHTABLEENTRY)RTMemAlloc(sizeof(RTISOFSPATHTABLEENTRY));
 
84
    if (pNode == NULL)
 
85
        return VERR_NO_MEMORY;
 
86
 
 
87
    pNode->path = NULL;
 
88
    if (RT_SUCCESS(RTStrAAppend(&pNode->path, pszPath)))
 
89
    {
 
90
        memcpy((RTISOFSPATHTABLEHEADER*)&pNode->header,
 
91
               (RTISOFSPATHTABLEHEADER*)pHeader, sizeof(pNode->header));
 
92
 
 
93
        pNode->path_full = NULL;
 
94
        pNode->Node.pPrev = NULL;
 
95
        pNode->Node.pNext = NULL;
 
96
        RTListAppend(pList, &pNode->Node);
 
97
        return VINF_SUCCESS;
 
98
    }
 
99
    return VERR_NO_MEMORY;
 
100
}
 
101
 
 
102
 
 
103
/**
 
104
 * Retrieves the parent path of a given node, assuming that the path table
 
105
 * (still) is in sync with the node's index.
 
106
 *
 
107
 * @return  IPRT status code.
 
108
 * @param   pList           Path table list to use.
 
109
 * @param   pNode           Node of path table entry to lookup the full path for.
 
110
 * @param   pszPathNode     Current (partial) parent path; needed for recursion.
 
111
 * @param   ppszPath        Pointer to a pointer to store the retrieved full path to.
 
112
 */
 
113
static int rtIsoFsGetParentPathSub(PRTLISTNODE pList, PRTISOFSPATHTABLEENTRY pNode,
 
114
                                   char *pszPathNode, char **ppszPath)
 
115
{
 
116
    int rc = VINF_SUCCESS;
 
117
    /* Do we have a parent? */
 
118
    if (pNode->header.parent_index > 1)
 
119
    {
 
120
        uint16_t idx = 1;
 
121
        /* Get the parent of our current node (pNode) */
 
122
        PRTISOFSPATHTABLEENTRY pNodeParent = RTListGetFirst(pList, RTISOFSPATHTABLEENTRY, Node);
 
123
        while (idx++ < pNode->header.parent_index)
 
124
            pNodeParent =  RTListNodeGetNext(&pNodeParent->Node, RTISOFSPATHTABLEENTRY, Node);
 
125
        /* Construct intermediate path (parent + current path). */
 
126
        char *pszPath = RTPathJoinA(pNodeParent->path, pszPathNode);
 
127
        if (pszPath)
 
128
        {
 
129
            /* ... and do the same with the parent's parent until we reached the root. */
 
130
            rc = rtIsoFsGetParentPathSub(pList, pNodeParent, pszPath, ppszPath);
 
131
            RTStrFree(pszPath);
 
132
        }
 
133
        else
 
134
            rc = VERR_NO_STR_MEMORY;
 
135
    }
 
136
    else /* No parent (left), this must be the root path then. */
 
137
        *ppszPath = RTStrDup(pszPathNode);
 
138
    return rc;
 
139
}
 
140
 
 
141
 
 
142
/**
 
143
 * Updates the path table cache of an ISO file.
 
144
 *
 
145
 * @return  IPRT status code.
 
146
 * @param   pFile                   ISO handle.
 
147
 */
 
148
static int rtIsoFsUpdatePathCache(PRTISOFSFILE pFile)
 
149
{
 
150
    AssertPtrReturn(pFile, VERR_INVALID_PARAMETER);
 
151
    rtIsoFsDestroyPathCache(pFile);
 
152
 
 
153
    RTListInit(&pFile->listPaths);
 
154
 
 
155
    /* Seek to path tables. */
 
156
    int rc = VINF_SUCCESS;
 
157
    Assert(pFile->pvd.path_table_start_first > 16);
 
158
    uint64_t uTableStart = (pFile->pvd.path_table_start_first * RTISOFS_SECTOR_SIZE);
 
159
    Assert(uTableStart % RTISOFS_SECTOR_SIZE == 0); /* Make sure it's aligned. */
 
160
    if (RTFileTell(pFile->file) != uTableStart)
 
161
        rc = RTFileSeek(pFile->file, uTableStart, RTFILE_SEEK_BEGIN, &uTableStart);
 
162
 
 
163
    /*
 
164
     * Since this is a sequential format, for performance it's best to read the
 
165
     * complete path table (every entry can have its own level (directory depth) first
 
166
     * and the actual directories of the path table afterwards.
 
167
     */
 
168
 
 
169
    /* Read in the path table ... */
 
170
    size_t cbLeft = pFile->pvd.path_table_size;
 
171
    RTISOFSPATHTABLEHEADER header;
 
172
    while ((cbLeft > 0) && RT_SUCCESS(rc))
 
173
    {
 
174
        size_t cbRead;
 
175
        rc = RTFileRead(pFile->file, (RTISOFSPATHTABLEHEADER*)&header, sizeof(RTISOFSPATHTABLEHEADER), &cbRead);
 
176
        if (RT_FAILURE(rc))
 
177
            break;
 
178
        cbLeft -= cbRead;
 
179
        if (header.length)
 
180
        {
 
181
            Assert(cbLeft >= header.length);
 
182
            Assert(header.length <= 31);
 
183
            /* Allocate and read in the actual path name. */
 
184
            char *pszName = RTStrAlloc(header.length + 1);
 
185
            rc = RTFileRead(pFile->file, (char*)pszName, header.length, &cbRead);
 
186
            if (RT_SUCCESS(rc))
 
187
            {
 
188
                cbLeft -= cbRead;
 
189
                pszName[cbRead] = '\0'; /* Terminate string. */
 
190
                /* Add entry to cache ... */
 
191
                rc = rtIsoFsAddToPathCache(&pFile->listPaths, pszName, &header);
 
192
            }
 
193
            RTStrFree(pszName);
 
194
            /* Read padding if required ... */
 
195
            if ((header.length % 2) != 0) /* If we have an odd length, read/skip the padding byte. */
 
196
            {
 
197
                rc = RTFileSeek(pFile->file, 1, RTFILE_SEEK_CURRENT, NULL);
 
198
                cbLeft--;
 
199
            }
 
200
        }
 
201
    }
 
202
 
 
203
    /* Transform path names into full paths. This is a bit ugly right now. */
 
204
    PRTISOFSPATHTABLEENTRY pNode = RTListGetLast(&pFile->listPaths, RTISOFSPATHTABLEENTRY, Node);
 
205
    while (   pNode
 
206
           && !RTListNodeIsFirst(&pFile->listPaths, &pNode->Node)
 
207
           && RT_SUCCESS(rc))
 
208
    {
 
209
        rc = rtIsoFsGetParentPathSub(&pFile->listPaths, pNode,
 
210
                                     pNode->path, &pNode->path_full);
 
211
        if (RT_SUCCESS(rc))
 
212
            pNode = RTListNodeGetPrev(&pNode->Node, RTISOFSPATHTABLEENTRY, Node);
 
213
    }
 
214
 
 
215
    return rc;
 
216
}
 
217
 
 
218
 
 
219
RTR3DECL(int) RTIsoFsOpen(PRTISOFSFILE pFile, const char *pszFileName)
 
220
{
 
221
    AssertPtrReturn(pFile, VERR_INVALID_PARAMETER);
 
222
    AssertPtrReturn(pszFileName, VERR_INVALID_PARAMETER);
 
223
 
 
224
    RTListInit(&pFile->listPaths);
 
225
#if 0
 
226
    Assert(sizeof(RTISOFSDATESHORT) == 7);
 
227
    Assert(sizeof(RTISOFSDATELONG) == 17);
 
228
    int l = sizeof(RTISOFSDIRRECORD);
 
229
    RTPrintf("RTISOFSDIRRECORD=%ld\n", l);
 
230
    Assert(l == 33);
 
231
    /* Each volume descriptor exactly occupies one sector. */
 
232
    l = sizeof(RTISOFSPRIVOLDESC);
 
233
    RTPrintf("RTISOFSPRIVOLDESC=%ld\n", l);
 
234
    Assert(l == RTISOFS_SECTOR_SIZE);
 
235
#endif
 
236
    int rc = RTFileOpen(&pFile->file, pszFileName, RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_WRITE);
 
237
    if (RT_SUCCESS(rc))
 
238
    {
 
239
        uint64_t cbSize;
 
240
        rc = RTFileGetSize(pFile->file, &cbSize);
 
241
        if (   RT_SUCCESS(rc)
 
242
            && cbSize > 16 * RTISOFS_SECTOR_SIZE)
 
243
        {
 
244
            uint64_t cbOffset = 16 * RTISOFS_SECTOR_SIZE; /* Start reading at 32k. */
 
245
            size_t cbRead;
 
246
            RTISOFSPRIVOLDESC pvd;
 
247
            bool fFoundPrimary = false;
 
248
            bool fIsValid = false;
 
249
            while (cbOffset < _1M)
 
250
            {
 
251
                /* Get primary descriptor. */
 
252
                rc = RTFileRead(pFile->file, (PRTISOFSPRIVOLDESC)&pvd, sizeof(RTISOFSPRIVOLDESC), &cbRead);
 
253
                if (RT_FAILURE(rc) || cbRead < sizeof(RTISOFSPRIVOLDESC))
 
254
                    break;
 
255
                if (   RTStrStr((char*)pvd.name_id, RTISOFS_STANDARD_ID)
 
256
                    && pvd.type == 0x1 /* Primary Volume Descriptor */)
 
257
                {
 
258
                    memcpy((PRTISOFSPRIVOLDESC)&pFile->pvd,
 
259
                           (PRTISOFSPRIVOLDESC)&pvd, sizeof(RTISOFSPRIVOLDESC));
 
260
                    fFoundPrimary = true;
 
261
                }
 
262
                else if(pvd.type == 0xff /* Termination Volume Descriptor */)
 
263
                {
 
264
                    if (fFoundPrimary)
 
265
                        fIsValid = true;
 
266
                    break;
 
267
                }
 
268
                cbOffset += sizeof(RTISOFSPRIVOLDESC);
 
269
            }
 
270
 
 
271
            if (fIsValid)
 
272
                rc = rtIsoFsUpdatePathCache(pFile);
 
273
            else
 
274
                rc = VERR_INVALID_PARAMETER;
 
275
        }
 
276
        if (RT_FAILURE(rc))
 
277
            RTIsoFsClose(pFile);
 
278
    }
 
279
    return rc;
 
280
}
 
281
 
 
282
 
 
283
RTR3DECL(void) RTIsoFsClose(PRTISOFSFILE pFile)
 
284
{
 
285
    if (pFile)
 
286
    {
 
287
        rtIsoFsDestroyPathCache(pFile);
 
288
        RTFileClose(pFile->file);
 
289
    }
 
290
}
 
291
 
 
292
 
 
293
/**
 
294
 * Parses an extent given at the specified sector + size and
 
295
 * searches for a file name to return an allocated directory record.
 
296
 *
 
297
 * @return  IPRT status code.
 
298
 * @param   pFile                   ISO handle.
 
299
 * @param   pszFileName             Absolute file name to search for.
 
300
 * @param   uExtentSector           Sector of extent.
 
301
 * @param   cbExtent                Size (in bytes) of extent.
 
302
 * @param   ppRec                   Pointer to a pointer to return the
 
303
 *                                  directory record. Must be free'd with
 
304
 *                                  rtIsoFsFreeDirectoryRecord().
 
305
 */
 
306
static int rtIsoFsFindEntry(PRTISOFSFILE pFile, const char *pszFileName,
 
307
                            uint32_t uExtentSector, uint32_t cbExtent /* Bytes */,
 
308
                            PRTISOFSDIRRECORD *ppRec)
 
309
{
 
310
    AssertPtrReturn(pFile, VERR_INVALID_PARAMETER);
 
311
    Assert(uExtentSector > 16);
 
312
 
 
313
    int rc = RTFileSeek(pFile->file, uExtentSector * RTISOFS_SECTOR_SIZE,
 
314
                        RTFILE_SEEK_BEGIN, NULL);
 
315
    if (RT_SUCCESS(rc))
 
316
    {
 
317
        rc = VERR_FILE_NOT_FOUND;
 
318
 
 
319
        uint8_t uBuffer[RTISOFS_SECTOR_SIZE];
 
320
        size_t cbLeft = cbExtent;
 
321
        while (!RT_SUCCESS(rc) && cbLeft > 0)
 
322
        {
 
323
            size_t cbRead;
 
324
            int rc2 = RTFileRead(pFile->file, (void*)&uBuffer, sizeof(uBuffer), &cbRead);
 
325
            Assert(RT_SUCCESS(rc2) && cbRead == RTISOFS_SECTOR_SIZE);
 
326
            cbLeft -= cbRead;
 
327
 
 
328
            uint32_t idx = 0;
 
329
            while (idx < cbRead)
 
330
            {
 
331
                PRTISOFSDIRRECORD pCurRecord = (PRTISOFSDIRRECORD)&uBuffer[idx];
 
332
                if (pCurRecord->record_length == 0)
 
333
                    break;
 
334
 
 
335
                char *pszName = RTStrAlloc(pCurRecord->name_len + 1);
 
336
                AssertPtr(pszName);
 
337
                Assert(idx + sizeof(RTISOFSDIRRECORD) < cbRead);
 
338
                memcpy(pszName, &uBuffer[idx + sizeof(RTISOFSDIRRECORD)], pCurRecord->name_len);
 
339
                pszName[pCurRecord->name_len] = '\0'; /* Force string termination. */
 
340
 
 
341
                if (   pCurRecord->name_len == 1
 
342
                    && pszName[0] == 0x0)
 
343
                {
 
344
                    /* This is a "." directory (self). */
 
345
                }
 
346
                else if (   pCurRecord->name_len == 1
 
347
                         && pszName[0] == 0x1)
 
348
                {
 
349
                    /* This is a ".." directory (parent). */
 
350
                }
 
351
                else /* Regular directory or file */
 
352
                {
 
353
                    if (pCurRecord->flags & RT_BIT(1)) /* Directory */
 
354
                    {
 
355
                        /* We don't recursively go into directories
 
356
                         * because we already have the cached path table. */
 
357
                        pszName[pCurRecord->name_len] = 0;
 
358
                        /*rc = rtIsoFsParseDir(pFile, pszFileName,
 
359
                                                 pDirHdr->extent_location, pDirHdr->extent_data_length);*/
 
360
                    }
 
361
                    else /* File */
 
362
                    {
 
363
                        /* Get last occurrence of ";" and cut it off. */
 
364
                        char *pTerm = strrchr(pszName, ';');
 
365
                        if (pTerm)
 
366
                            pszName[pTerm - pszName] = 0;
 
367
 
 
368
                        /* Don't use case sensitive comparison here, in IS0 9660 all
 
369
                         * file / directory names are UPPERCASE. */
 
370
                        if (!RTStrICmp(pszName, pszFileName))
 
371
                        {
 
372
                            PRTISOFSDIRRECORD pRec = (PRTISOFSDIRRECORD)RTMemAlloc(sizeof(RTISOFSDIRRECORD));
 
373
                            if (pRec)
 
374
                            {
 
375
                                memcpy(pRec, pCurRecord, sizeof(RTISOFSDIRRECORD));
 
376
                                *ppRec = pRec;
 
377
                                rc = VINF_SUCCESS;
 
378
                            }
 
379
                            else
 
380
                                rc = VERR_NO_MEMORY;
 
381
                            break;
 
382
                        }
 
383
                    }
 
384
                }
 
385
                idx += pCurRecord->record_length;
 
386
            }
 
387
        }
 
388
    }
 
389
    return rc;
 
390
}
 
391
 
 
392
 
 
393
/**
 
394
 * Retrieves the sector of a file extent given by the
 
395
 * full file path within the ISO.
 
396
 *
 
397
 * @return  IPRT status code.
 
398
 * @param   pFile               ISO handle.
 
399
 * @param   pszPath             File path to resolve.
 
400
 * @param   puSector            Pointer where to store the found sector to.
 
401
 */
 
402
static int rtIsoFsResolvePath(PRTISOFSFILE pFile, const char *pszPath, uint32_t *puSector)
 
403
{
 
404
    AssertPtrReturn(pFile, VERR_INVALID_PARAMETER);
 
405
    AssertPtrReturn(pszPath, VERR_INVALID_PARAMETER);
 
406
    AssertPtrReturn(puSector, VERR_INVALID_PARAMETER);
 
407
 
 
408
    int rc = VERR_FILE_NOT_FOUND;
 
409
    char *pszTemp = RTStrDup(pszPath);
 
410
    if (pszTemp)
 
411
    {
 
412
        RTPathStripFilename(pszTemp);
 
413
 
 
414
        bool bFound = false;
 
415
        PRTISOFSPATHTABLEENTRY pNode;
 
416
        if (!RTStrCmp(pszTemp, ".")) /* Root directory? Use first node! */
 
417
        {
 
418
            pNode = RTListGetFirst(&pFile->listPaths, RTISOFSPATHTABLEENTRY, Node);
 
419
            if (pNode)
 
420
                bFound = true;
 
421
        }
 
422
        else
 
423
        {
 
424
            RTListForEach(&pFile->listPaths, pNode, RTISOFSPATHTABLEENTRY, Node)
 
425
            {
 
426
                if (   pNode->path_full != NULL /* Root does not have a path! */
 
427
                    && !RTStrICmp(pNode->path_full, pszTemp))
 
428
                {
 
429
                    bFound = true;
 
430
                    break;
 
431
                }
 
432
            }
 
433
        }
 
434
        if (bFound)
 
435
        {
 
436
            AssertPtr(pNode);
 
437
            *puSector = pNode->header.sector_dir_table;
 
438
            rc = VINF_SUCCESS;
 
439
        }
 
440
        else
 
441
            rc = VERR_FILE_NOT_FOUND;
 
442
        RTStrFree(pszTemp);
 
443
    }
 
444
    else
 
445
        rc = VERR_NO_MEMORY;
 
446
    return rc;
 
447
}
 
448
 
 
449
 
 
450
/**
 
451
 * Allocates a new directory record.
 
452
 *
 
453
 * @return  Pointer to the newly allocated directory record.
 
454
 */
 
455
static PRTISOFSDIRRECORD rtIsoFsCreateDirectoryRecord(void)
 
456
{
 
457
    PRTISOFSDIRRECORD pRecord = (PRTISOFSDIRRECORD)RTMemAlloc(sizeof(RTISOFSDIRRECORD));
 
458
    return pRecord;
 
459
}
 
460
 
 
461
 
 
462
/**
 
463
 * Frees a previously allocated directory record.
 
464
 *
 
465
 * @return  IPRT status code.
 
466
 */
 
467
static void rtIsoFsFreeDirectoryRecord(PRTISOFSDIRRECORD pRecord)
 
468
{
 
469
    RTMemFree(pRecord);
 
470
}
 
471
 
 
472
 
 
473
/**
 
474
 * Returns an allocated directory record for a given file.
 
475
 *
 
476
 * @return  IPRT status code.
 
477
 * @param   pFile                   ISO handle.
 
478
 * @param   pszPath                 File path to resolve.
 
479
 * @param   ppRecord                Pointer to a pointer to return the
 
480
 *                                  directory record. Must be free'd with
 
481
 *                                  rtIsoFsFreeDirectoryRecord().
 
482
 */
 
483
static int rtIsoFsGetDirectoryRecord(PRTISOFSFILE pFile, const char *pszPath,
 
484
                                     PRTISOFSDIRRECORD *ppRecord)
 
485
{
 
486
    AssertPtrReturn(pFile, VERR_INVALID_PARAMETER);
 
487
    AssertPtrReturn(pszPath, VERR_INVALID_PARAMETER);
 
488
    AssertPtrReturn(ppRecord, VERR_INVALID_PARAMETER);
 
489
 
 
490
    uint32_t uSector;
 
491
    int rc = rtIsoFsResolvePath(pFile, pszPath, &uSector);
 
492
    if (RT_SUCCESS(rc))
 
493
    {
 
494
        /* Seek and read the directory record of given file. */
 
495
        rc = RTFileSeek(pFile->file, uSector * RTISOFS_SECTOR_SIZE,
 
496
                        RTFILE_SEEK_BEGIN, NULL);
 
497
        if (RT_SUCCESS(rc))
 
498
        {
 
499
            size_t cbRead;
 
500
            PRTISOFSDIRRECORD pRecord = rtIsoFsCreateDirectoryRecord();
 
501
            if (pRecord)
 
502
            {
 
503
                rc = RTFileRead(pFile->file, (PRTISOFSDIRRECORD)pRecord, sizeof(RTISOFSDIRRECORD), &cbRead);
 
504
                if (RT_SUCCESS(rc))
 
505
                {
 
506
                    Assert(cbRead == sizeof(RTISOFSDIRRECORD));
 
507
                    *ppRecord = pRecord;
 
508
                }
 
509
                if (RT_FAILURE(rc))
 
510
                    rtIsoFsFreeDirectoryRecord(pRecord);
 
511
            }
 
512
            else
 
513
                rc = VERR_NO_MEMORY;
 
514
        }
 
515
    }
 
516
    return rc;
 
517
}
 
518
 
 
519
 
 
520
RTR3DECL(int) RTIsoFsGetFileInfo(PRTISOFSFILE pFile, const char *pszPath,
 
521
                                 uint32_t *pcbOffset, size_t *pcbLength)
 
522
{
 
523
    AssertPtrReturn(pFile, VERR_INVALID_PARAMETER);
 
524
    AssertPtrReturn(pszPath, VERR_INVALID_PARAMETER);
 
525
    AssertPtrReturn(pcbOffset, VERR_INVALID_PARAMETER);
 
526
 
 
527
    PRTISOFSDIRRECORD pDirRecord;
 
528
    int rc = rtIsoFsGetDirectoryRecord(pFile, pszPath, &pDirRecord);
 
529
    if (RT_SUCCESS(rc))
 
530
    {
 
531
        /* Get actual file record. */
 
532
        PRTISOFSDIRRECORD pFileRecord = NULL; /* shut up gcc*/
 
533
        rc = rtIsoFsFindEntry(pFile,
 
534
                              RTPathFilename(pszPath),
 
535
                              pDirRecord->extent_location,
 
536
                              pDirRecord->extent_data_length,
 
537
                              &pFileRecord);
 
538
        if (RT_SUCCESS(rc))
 
539
        {
 
540
            *pcbOffset = pFileRecord->extent_location * RTISOFS_SECTOR_SIZE;
 
541
            *pcbLength = pFileRecord->extent_data_length;
 
542
            rtIsoFsFreeDirectoryRecord(pFileRecord);
 
543
        }
 
544
        rtIsoFsFreeDirectoryRecord(pDirRecord);
 
545
    }
 
546
    return rc;
 
547
}
 
548
 
 
549
 
 
550
RTR3DECL(int) RTIsoFsExtractFile(PRTISOFSFILE pFile, const char *pszSource,
 
551
                                 const char *pszDest)
 
552
{
 
553
    AssertPtrReturn(pFile, VERR_INVALID_PARAMETER);
 
554
    AssertPtrReturn(pszSource, VERR_INVALID_PARAMETER);
 
555
    AssertPtrReturn(pszDest, VERR_INVALID_PARAMETER);
 
556
 
 
557
    uint32_t cbOffset;
 
558
    size_t cbLength;
 
559
    int rc = RTIsoFsGetFileInfo(pFile, pszSource, &cbOffset, &cbLength);
 
560
    if (RT_SUCCESS(rc))
 
561
    {
 
562
        rc = RTFileSeek(pFile->file, cbOffset, RTFILE_SEEK_BEGIN, NULL);
 
563
        if (RT_SUCCESS(rc))
 
564
        {
 
565
            RTFILE fileDest;
 
566
            rc = RTFileOpen(&fileDest, pszDest, RTFILE_O_CREATE | RTFILE_O_WRITE | RTFILE_O_DENY_WRITE);
 
567
            if (RT_SUCCESS(rc))
 
568
            {
 
569
                size_t cbToRead, cbRead, cbWritten;
 
570
                uint8_t byBuffer[_64K];
 
571
                while (   cbLength > 0
 
572
                       && RT_SUCCESS(rc))
 
573
                {
 
574
                    cbToRead = RT_MIN(cbLength, _64K);
 
575
                    rc = RTFileRead(pFile->file, (uint8_t*)byBuffer, cbToRead, &cbRead);
 
576
                    if (RT_FAILURE(rc))
 
577
                        break;
 
578
                    rc = RTFileWrite(fileDest, (uint8_t*)byBuffer, cbRead, &cbWritten);
 
579
                    if (RT_FAILURE(rc))
 
580
                        break;
 
581
                    cbLength -= cbRead;
 
582
                }
 
583
                RTFileClose(fileDest);
 
584
            }
 
585
        }
 
586
    }
 
587
    return rc;
 
588
}
 
589