Index: /trunk/include/iprt/isofs.h
===================================================================
--- /trunk/include/iprt/isofs.h	(revision 32997)
+++ /trunk/include/iprt/isofs.h	(revision 32997)
@@ -0,0 +1,222 @@
+/** @file
+ * IPRT - ISO 9660 file system handling.
+ */
+
+/*
+ * Copyright (C) 2010 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+#ifndef ___iprt_isofs_h
+#define ___iprt_isofs_h
+
+#include <iprt/file.h>
+#include <iprt/mem.h>
+#include <iprt/list.h>
+#include <iprt/string.h>
+
+RT_C_DECLS_BEGIN
+
+/** @defgroup grp_rt_isofs    RTIsoFs - ISO 9660 Filesystem
+ * @ingroup grp_rt
+ * @{
+ */
+
+#define RTISOFS_MAX_SYSTEM_ID      32
+#define RTISOFS_MAX_VOLUME_ID      32
+#define RTISOFS_MAX_PUBLISHER_ID   128
+#define RTISOFS_MAX_VOLUME_ID      32
+#define RTISOFS_MAX_VOLUMESET_ID   128
+#define RTISOFS_MAX_PREPARER_ID    128
+#define RTISOFS_MAX_APPLICATION_ID 128
+
+/** Standard ID of volume descriptors. */
+#define RTISOFS_STANDARD_ID        "CD001"
+
+/** Default sector size. */
+#define RTISOFS_SECTOR_SIZE        2048
+
+
+#pragma pack(1)
+typedef struct RTISOFSDATESHORT
+{
+    uint8_t year;
+    uint8_t month;
+    uint8_t day;
+    uint8_t hour;
+    uint8_t minute;
+    uint8_t second;
+    int8_t 	gmt_offset;
+} RTISOFSDATESHORT, *PRTISOFSDATESHORT;
+
+typedef struct RTISOFSDATELONG
+{
+    char year[4];
+    char month[2];
+    char day[2];
+    char hour[2];
+    char minute[2];
+    char second[2];
+    char hseconds[2];
+    int8_t gmt_offset;
+} RTISOFSDATELONG, *PRTISOFSDATELONG;
+
+/* Directory Record. */
+typedef struct RTISOFSDIRRECORD
+{
+	uint8_t record_length;
+	uint8_t extented_attr_length;
+	uint32_t extent_location;
+    uint32_t extent_location_big;
+	uint32_t extent_data_length; /* Number of bytes (file) / len (directory). */
+    uint32_t extent_data_length_big;
+    RTISOFSDATESHORT date;
+	uint8_t flags;
+	uint8_t interleave_unit_size;
+    uint8_t interleave_gap_size;
+	uint16_t volume_sequence_number;
+    uint16_t volume_sequence_number_big;
+	uint8_t name_len;
+    /* Starting here there will be the actual directory entry name
+     * and a padding of 1 byte if name_len is odd. */
+} RTISOFSDIRRECORD, *PRTISOFSDIRRECORD;
+
+/* Primary Volume Descriptor. */
+typedef struct RTISOFSPRIVOLDESC
+{
+	uint8_t type;
+	char name_id[6];
+	uint8_t version;
+	char system_id[RTISOFS_MAX_SYSTEM_ID];
+	char volume_id[RTISOFS_MAX_VOLUME_ID];
+	uint8_t unused2[8];
+	uint32_t volume_space_size; /* Number of sectors, Little Endian. */
+	uint32_t volume_space_size_big; /* Number of sectors Big Endian. */
+    uint8_t unused3[32];
+	uint16_t volume_set_size;
+    uint16_t volume_set_size_big;
+    uint16_t volume_sequence_number;
+    uint16_t volume_sequence_number_big;
+    uint16_t logical_block_size; /* 2048. */
+    uint16_t logical_block_size_big;
+	uint32_t path_table_size; /* Size in bytes. */
+	uint32_t path_table_size_big; /* Size in bytes. */
+    uint32_t path_table_start_first;
+    uint32_t path_table_start_second;
+    uint32_t path_table_start_first_big;
+    uint32_t path_table_start_second_big;
+    RTISOFSDIRRECORD root_directory_record;
+    uint8_t directory_padding;
+    char volume_set_id[RTISOFS_MAX_VOLUMESET_ID];
+    char publisher_id[RTISOFS_MAX_PUBLISHER_ID];
+    char preparer_id[RTISOFS_MAX_PREPARER_ID];
+    char application_id[RTISOFS_MAX_APPLICATION_ID];
+    char copyright_file_id[37];
+    char abstract_file_id[37];
+    char bibliographic_file_id[37];
+    RTISOFSDATELONG creation_date;
+    RTISOFSDATELONG modification_date;
+    RTISOFSDATELONG expiration_date;
+    RTISOFSDATELONG effective_date;
+    uint8_t file_structure_version;
+    uint8_t unused4[1];
+    char application_data[512];
+    uint8_t unused5[653];
+} RTISOFSPRIVOLDESC, *PRTISOFSPRIVOLDESC;
+
+typedef struct RTISOFSPATHTABLEHEADER
+{
+    uint8_t length;
+    uint8_t extended_attr_sectors;
+    /** Sector of starting directory table. */
+    uint32_t sector_dir_table;
+    /** Index of parent directory (1 for the root). */
+    uint16_t parent_index;
+    /* Starting here there will be the name of the directory,
+     * specified by length above. */
+} RTISOFSPATHTABLEHEADER, *PRTISOFSPATHTABLEHEADER;
+
+typedef struct RTISOFSPATHTABLEENTRY
+{
+    char       *path;
+    char       *path_full;
+    RTISOFSPATHTABLEHEADER header;
+    RTLISTNODE  Node;
+} RTISOFSPATHTABLEENTRY, *PRTISOFSPATHTABLEENTRY;
+
+typedef struct RTISOFSFILE
+{
+    RTFILE file;
+    RTLISTNODE listPaths;
+    RTISOFSPRIVOLDESC pvd;
+} RTISOFSFILE, *PRTISOFSFILE;
+#pragma pack()
+
+
+#ifdef IN_RING3
+/**
+ *
+ *
+ * @return  int
+ *
+ * @param   pszFileName
+ * @param   pFile
+ */
+RTR3DECL(int) RTIsoFsOpen(PRTISOFSFILE pFile, const char *pszFileName);
+
+/**
+ *
+ *
+ *
+ * @param   pFile
+ */
+RTR3DECL(void) RTIsoFsClose(PRTISOFSFILE pFile);
+
+/**
+ *
+ *
+ * @return  int
+ *
+ * @param   pFile
+ * @param   pszPath
+ * @param   pcbOffset
+ * @param   pcbLength
+ */
+RTR3DECL(int) RTIsoFsGetFileInfo(PRTISOFSFILE pFile, const char *pszPath,
+                                 uint32_t *pcbOffset, size_t *pcbLength);
+
+/**
+ *
+ *
+ * @return  int
+ *
+ * @param   pFile
+ * @param   pszSource
+ * @param   pszDest
+ */
+RTR3DECL(int) RTIsoFsExtractFile(PRTISOFSFILE pFile, const char *pszSource,
+                                 const char *pszDest);
+#endif /* IN_RING3 */
+
+/** @} */
+
+RT_C_DECLS_END
+
+#endif /* ___iprt_isofs_h */
+
Index: /trunk/src/VBox/Frontends/VBoxManage/VBoxManageGuestCtrl.cpp
===================================================================
--- /trunk/src/VBox/Frontends/VBoxManage/VBoxManageGuestCtrl.cpp	(revision 32996)
+++ /trunk/src/VBox/Frontends/VBoxManage/VBoxManageGuestCtrl.cpp	(revision 32997)
@@ -35,15 +35,7 @@
 #include <VBox/HostServices/GuestControlSvc.h> /* for PROC_STS_XXX */
 
-#include <VBox/log.h>
 #include <iprt/asm.h>
-#include <iprt/assert.h>
-#include <iprt/file.h>
+#include <iprt/isofs.h>
 #include <iprt/getopt.h>
-#include <iprt/list.h>
-#include <iprt/path.h>
-#include <iprt/stream.h>
-#include <iprt/string.h>
-#include <iprt/time.h>
-#include <iprt/thread.h>
 
 #ifdef USE_XPCOM_QUEUE
@@ -558,588 +550,14 @@
 }
 
-#ifdef VBOX_WITH_COPYTOGUEST
-
-#define VBOX_ISO9660_MAX_SYSTEM_ID 32
-#define VBOX_ISO9660_MAX_VOLUME_ID 32
-#define VBOX_ISO9660_MAX_PUBLISHER_ID   128
-#define VBOX_ISO9660_MAX_VOLUME_ID   32
-#define VBOX_ISO9660_MAX_VOLUMESET_ID   128
-#define VBOX_ISO9660_MAX_PREPARER_ID   128
-#define VBOX_ISO9660_MAX_APPLICATION_ID   128
-#define VBOX_ISO9660_STANDARD_ID "CD001"
-#define VBOX_ISO9660_SECTOR_SIZE 2048
-
-#pragma pack(1)
-typedef struct VBoxISO9660DateShort
-{
-    uint8_t year;
-    uint8_t month;
-    uint8_t day;
-    uint8_t hour;
-    uint8_t minute;
-    uint8_t second;
-    int8_t 	gmt_offset;
-} VBoxISO9660DateShort;
-
-typedef struct VBoxISO9660DateLong
-{
-    char year[4];
-    char month[2];
-    char day[2];
-    char hour[2];
-    char minute[2];
-    char second[2];
-    char hseconds[2];
-    int8_t gmt_offset;
-} VBoxISO9660DateLong;
-
-typedef struct VBoxISO9660DirRecord
-{
-	uint8_t record_length;
-	uint8_t extented_attr_length;
-	uint32_t extent_location;
-    uint32_t extent_location_big;
-	uint32_t extent_data_length; /* Number of bytes (file) / len (directory). */
-    uint32_t extent_data_length_big;
-    VBoxISO9660DateShort date;
-	uint8_t flags;
-	uint8_t interleave_unit_size;
-    uint8_t interleave_gap_size;
-	uint16_t volume_sequence_number;
-    uint16_t volume_sequence_number_big;
-	uint8_t name_len;
-    /* Starting here there will be the actual directory entry name
-     * and a padding of 1 byte if name_len is odd. */
-} VBoxISO9660DirRecord;
-
-typedef struct VBoxISO9660PriVolDesc
-{
-	uint8_t type;
-	char name_id[6];
-	uint8_t version;
-	char system_id[VBOX_ISO9660_MAX_SYSTEM_ID];
-	char volume_id[VBOX_ISO9660_MAX_VOLUME_ID];
-	uint8_t unused2[8];
-	uint32_t volume_space_size; /* Number of sectors, Little Endian. */
-	uint32_t volume_space_size_big; /* Number of sectors Big Endian. */
-    uint8_t unused3[32];
-	uint16_t volume_set_size;
-    uint16_t volume_set_size_big;
-    uint16_t volume_sequence_number;
-    uint16_t volume_sequence_number_big;
-    uint16_t logical_block_size; /* 2048. */
-    uint16_t logical_block_size_big;
-	uint32_t path_table_size; /* Size in bytes. */
-	uint32_t path_table_size_big; /* Size in bytes. */
-    uint32_t path_table_start_first;
-    uint32_t path_table_start_second;
-    uint32_t path_table_start_first_big;
-    uint32_t path_table_start_second_big;
-    VBoxISO9660DirRecord root_directory_record;
-    uint8_t directory_padding;
-    char volume_set_id[VBOX_ISO9660_MAX_VOLUMESET_ID];
-    char publisher_id[VBOX_ISO9660_MAX_PUBLISHER_ID];
-    char preparer_id[VBOX_ISO9660_MAX_PREPARER_ID];
-    char application_id[VBOX_ISO9660_MAX_APPLICATION_ID];
-    char copyright_file_id[37];
-    char abstract_file_id[37];
-    char bibliographic_file_id[37];
-    VBoxISO9660DateLong creation_date;
-    VBoxISO9660DateLong modification_date;
-    VBoxISO9660DateLong expiration_date;
-    VBoxISO9660DateLong effective_date;
-    uint8_t file_structure_version;
-    uint8_t unused4[1];
-    char application_data[512];
-    uint8_t unused5[653];
-} VBoxISO9660PriVolDesc;
-
-typedef struct VBoxISO9660PathTableHeader
-{
-    uint8_t length;
-    uint8_t extended_attr_sectors;
-    /** Sector of starting directory table. */
-    uint32_t sector_dir_table;
-    /** Index of parent directory (1 for the root). */
-    uint16_t parent_index;
-    /* Starting here there will be the name of the directory,
-     * specified by length above. */
-} VBoxISO9660PathTableHeader;
-
-typedef struct VBoxISO9660PathTableEntry
-{
-    char       *path;
-    char       *path_full;
-    VBoxISO9660PathTableHeader header;
-    RTLISTNODE  Node;
-} VBoxISO9660PathTableEntry;
-
-typedef struct VBoxISO9660File
-{
-    RTFILE file;
-    RTLISTNODE listPaths;
-    VBoxISO9660PriVolDesc priVolDesc;
-} VBoxISO9660File;
-#pragma pack()
-
-void rtISO9660DestroyPathCache(VBoxISO9660File *pFile)
-{
-    VBoxISO9660PathTableEntry *pNode = RTListNodeGetFirst(&pFile->listPaths, VBoxISO9660PathTableEntry, Node);
-    while (pNode)
-    {
-        VBoxISO9660PathTableEntry *pNext = RTListNodeGetNext(&pNode->Node, VBoxISO9660PathTableEntry, Node);
-        bool fLast = RTListNodeIsLast(&pFile->listPaths, &pNode->Node);
-
-        if (pNode->path)
-            RTStrFree(pNode->path);
-        if (pNode->path_full)
-            RTStrFree(pNode->path_full);
-        RTListNodeRemove(&pNode->Node);
-        RTMemFree(pNode);
-
-        if (fLast)
-            break;
-
-        pNode = pNext;
-    }
-}
-
-void RTISO9660Close(VBoxISO9660File *pFile)
-{
-    if (pFile)
-    {
-        rtISO9660DestroyPathCache(pFile);
-        RTFileClose(pFile->file);
-    }
-}
-
-int rtISO9660AddToPathCache(PRTLISTNODE pList, const char *pszPath,
-                            VBoxISO9660PathTableHeader *pHeader)
-{
-    AssertPtrReturn(pList, VERR_INVALID_PARAMETER);
-    AssertPtrReturn(pszPath, VERR_INVALID_PARAMETER);
-    AssertPtrReturn(pHeader, VERR_INVALID_PARAMETER);
-
-    VBoxISO9660PathTableEntry *pNode = (VBoxISO9660PathTableEntry*)RTMemAlloc(sizeof(VBoxISO9660PathTableEntry));
-    if (pNode == NULL)
-        return VERR_NO_MEMORY;
-
-    pNode->path = NULL;
-    if (RT_SUCCESS(RTStrAAppend(&pNode->path, pszPath)))
-    {
-        memcpy((VBoxISO9660PathTableHeader*)&pNode->header,
-               (VBoxISO9660PathTableHeader*)pHeader, sizeof(pNode->header));
-
-        pNode->path_full = NULL;
-        pNode->Node.pPrev = NULL;
-        pNode->Node.pNext = NULL;
-        RTListAppend(pList, &pNode->Node);
-        return VINF_SUCCESS;
-    }
-    return VERR_NO_MEMORY;
-}
-
-int rtISO9660GetParentPathSub(PRTLISTNODE pList, VBoxISO9660PathTableEntry *pNode,
-                              char *pszPathNode, char **ppszPath)
-{
-    int rc = VINF_SUCCESS;
-    if (pNode->header.parent_index > 1)
-    {
-        uint16_t idx = 1;
-        VBoxISO9660PathTableEntry *pNodeParent = RTListNodeGetFirst(pList, VBoxISO9660PathTableEntry, Node);
-        while (idx++ < pNode->header.parent_index)
-            pNodeParent =  RTListNodeGetNext(&pNodeParent->Node, VBoxISO9660PathTableEntry, Node);
-        char *pszPath;
-        if (RTStrAPrintf(&pszPath, "%s/%s", pNodeParent->path, pszPathNode))
-        {
-            rc = rtISO9660GetParentPathSub(pList, pNodeParent, pszPath, ppszPath);
-            RTStrFree(pszPath);
-        }
-        else
-            rc = VERR_NO_MEMORY;
-    }
-    else
-    {
-        char *pszPath = RTStrDup(pszPathNode);
-        *ppszPath = pszPath;
-    }
-    return rc;
-}
-
-/* Is a *flat* structure! */
-int rtISO9660UpdatePathCache(VBoxISO9660File *pFile)
-{
-    AssertPtrReturn(pFile, VERR_INVALID_PARAMETER);
-    rtISO9660DestroyPathCache(pFile);
-
-    RTListInit(&pFile->listPaths);
-
-    /* Seek to path tables. */
-    int rc = VINF_SUCCESS;
-    Assert(pFile->priVolDesc.path_table_start_first > 16);
-    uint64_t uTableStart = (pFile->priVolDesc.path_table_start_first * VBOX_ISO9660_SECTOR_SIZE);
-    Assert(uTableStart % VBOX_ISO9660_SECTOR_SIZE == 0); /* Make sure it's aligned. */
-    if (RTFileTell(pFile->file) != uTableStart)
-        rc = RTFileSeek(pFile->file, uTableStart, RTFILE_SEEK_BEGIN, &uTableStart);
-
-    /*
-     * Since this is a sequential format, for performance it's best to read the
-     * complete path table (every entry can have its own level (directory depth) first
-     * and the actual directories of the path table afterwards.
-     */
-
-    /* Read in the path table ... */
-    uint32_t cbLeft = pFile->priVolDesc.path_table_size;
-    VBoxISO9660PathTableHeader header;
-    while ((cbLeft > 0) && RT_SUCCESS(rc))
-    {
-        size_t cbRead;
-        rc = RTFileRead(pFile->file, (VBoxISO9660PathTableHeader*)&header, sizeof(VBoxISO9660PathTableHeader), &cbRead);
-        if (RT_FAILURE(rc))
-            break;
-        cbLeft -= cbRead;
-        if (header.length)
-        {
-            Assert(cbLeft >= header.length);
-            Assert(header.length <= 31);
-            /* Allocate and read in the actual path name. */
-            char *pszName = RTStrAlloc(header.length + 1);
-            rc = RTFileRead(pFile->file, (char*)pszName, header.length, &cbRead);
-            if (RT_SUCCESS(rc))
-            {
-                cbLeft -= cbRead;
-                pszName[cbRead] = '\0'; /* Terminate string. */
-                /* Add entry to cache ... */
-                rc = rtISO9660AddToPathCache(&pFile->listPaths, pszName, &header);
-            }
-            RTStrFree(pszName);
-            /* Read padding if required ... */
-            if ((header.length % 2) != 0) /* If we have an odd length, read/skip the padding byte. */
-            {
-                rc = RTFileSeek(pFile->file, 1, RTFILE_SEEK_CURRENT, NULL);
-                cbLeft--;
-            }
-        }
-    }
-
-    /* Transform path names into full paths. This is a bit ugly right now. */
-    VBoxISO9660PathTableEntry *pNode = RTListNodeGetLast(&pFile->listPaths, VBoxISO9660PathTableEntry, Node);
-    while (   pNode
-           && !RTListNodeIsFirst(&pFile->listPaths, &pNode->Node)
-           && RT_SUCCESS(rc))
-    {
-        rc = rtISO9660GetParentPathSub(&pFile->listPaths, pNode,
-                                       pNode->path, &pNode->path_full);
-        if (RT_SUCCESS(rc))
-            pNode = RTListNodeGetPrev(&pNode->Node, VBoxISO9660PathTableEntry, Node);
-    }
-
-    return rc;
-}
-
-int RTISO9660Open(const char *pszFileName, VBoxISO9660File *pFile)
-{
-    AssertPtrReturn(pszFileName, VERR_INVALID_PARAMETER);
-    AssertPtrReturn(pFile, VERR_INVALID_PARAMETER);
-
-    RTListInit(&pFile->listPaths);
-#if 1
-    Assert(sizeof(VBoxISO9660DateShort) == 7);
-    Assert(sizeof(VBoxISO9660DateLong) == 17);
-    int l = sizeof(VBoxISO9660DirRecord);
-    RTPrintf("VBoxISO9660DirRecord=%ld\n", l);
-    Assert(l == 33);
-    /* Each volume descriptor exactly occupies one sector. */
-    l = sizeof(VBoxISO9660PriVolDesc);
-    RTPrintf("VBoxISO9660PriVolDesc=%ld\n", l);
-    Assert(l == VBOX_ISO9660_SECTOR_SIZE);
-#endif
-    int rc = RTFileOpen(&pFile->file, pszFileName, RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_WRITE);
-    if (RT_SUCCESS(rc))
-    {
-        uint64_t cbSize;
-        rc = RTFileGetSize(pFile->file, &cbSize);
-        if (   RT_SUCCESS(rc)
-            && cbSize > 16 * VBOX_ISO9660_SECTOR_SIZE)
-        {
-            uint64_t cbOffset = 16 * VBOX_ISO9660_SECTOR_SIZE; /* Start reading at 32k. */
-            size_t cbRead;
-            VBoxISO9660PriVolDesc volDesc;
-            bool fFoundPrimary = false;
-            bool fIsValid = false;
-            while (cbOffset < _1M)
-            {
-                /* Get primary descriptor. */
-                rc = RTFileRead(pFile->file, (VBoxISO9660PriVolDesc*)&volDesc, sizeof(VBoxISO9660PriVolDesc), &cbRead);
-                if (RT_FAILURE(rc) || cbRead < sizeof(VBoxISO9660PriVolDesc))
-                    break;
-                if (   RTStrStr((char*)volDesc.name_id, VBOX_ISO9660_STANDARD_ID)
-                    && volDesc.type    == 0x1 /* Primary Volume Descriptor */)
-                {
-                    memcpy((VBoxISO9660PriVolDesc*)&pFile->priVolDesc,
-                           (VBoxISO9660PriVolDesc*)&volDesc, sizeof(VBoxISO9660PriVolDesc));
-                    fFoundPrimary = true;
-                }
-                else if(volDesc.type == 0xff /* Termination Volume Descriptor */)
-                {
-                    if (fFoundPrimary)
-                        fIsValid = true;
-                    break;
-                }
-                cbOffset += sizeof(VBoxISO9660PriVolDesc);
-            }
-
-            if (fIsValid)
-                rc = rtISO9660UpdatePathCache(pFile);
-            else
-                rc = VERR_INVALID_PARAMETER;
-        }
-        if (RT_FAILURE(rc))
-            RTISO9660Close(pFile);
-    }
-    return rc;
-}
-
-/* Parses the extent content given at a specified sector. */
-int rtISO9660FindEntry(VBoxISO9660File *pFile, const char *pszFileName,
-                       uint32_t uExtentSector, uint32_t cbExtent /* Bytes */,
-                       VBoxISO9660DirRecord **ppRec)
-{
-    AssertPtrReturn(pFile, VERR_INVALID_PARAMETER);
-    Assert(uExtentSector > 16);
-
-    int rc = RTFileSeek(pFile->file, uExtentSector * VBOX_ISO9660_SECTOR_SIZE,
-                        RTFILE_SEEK_BEGIN, NULL);
-    if (RT_SUCCESS(rc))
-    {
-        rc = VERR_FILE_NOT_FOUND;
-
-        uint8_t uBuffer[VBOX_ISO9660_SECTOR_SIZE];
-        uint32_t cbLeft = cbExtent;
-        while (!RT_SUCCESS(rc) && cbLeft > 0)
-        {
-            size_t cbRead;
-            int rc2 = RTFileRead(pFile->file, (void*)&uBuffer, sizeof(uBuffer), &cbRead);
-            Assert(RT_SUCCESS(rc2) && cbRead == VBOX_ISO9660_SECTOR_SIZE);
-            cbLeft -= cbRead;
-
-            uint32_t idx = 0;
-            while (idx < cbRead)
-            {
-                VBoxISO9660DirRecord *pCurRecord = (VBoxISO9660DirRecord*)&uBuffer[idx];
-                if (pCurRecord->record_length == 0)
-                    break;
-
-                Assert(pCurRecord->name_len > 0);
-                char *pszName = RTStrAlloc(pCurRecord->name_len + 1);
-                AssertPtr(pszName);
-                Assert(idx + sizeof(VBoxISO9660DirRecord) < cbRead);
-                memcpy(pszName, &uBuffer[idx + sizeof(VBoxISO9660DirRecord)], pCurRecord->name_len);
-
-                if (   pCurRecord->name_len == 1
-                    && pszName[0] == 0x0)
-                {
-                    /* This is a "." directory (self). */
-                }
-                else if (   pCurRecord->name_len == 1
-                         && pszName[0] == 0x1)
-                {
-                    /* This is a ".." directory (parent). */
-                }
-                else /* Regular directory or file */
-                {
-                    if (pCurRecord->flags & RT_BIT(1)) /* Directory */
-                    {
-                        /* We don't recursively go into directories
-                         * because we already have the cached path table. */
-                        pszName[pCurRecord->name_len] = 0;
-                        /*rc = rtISO9660ParseDir(pFile, pszFileName,
-                                                 pDirHdr->extent_location, pDirHdr->extent_data_length);*/
-                    }
-                    else /* File */
-                    {
-                        /* Get last occurence of ";" and cut it off. */
-                        char *pTerm = strrchr(pszName, ';');
-                        if (pTerm)
-                            pszName[pTerm - pszName] = 0;
-
-                        /* Don't use case sensitive comparison here, in IS0 9660 all
-                         * file / directory names are UPPERCASE. */
-                        if (!RTStrICmp(pszName, pszFileName))
-                        {
-                            VBoxISO9660DirRecord *pRec = (VBoxISO9660DirRecord*)RTMemAlloc(sizeof(VBoxISO9660DirRecord));
-                            if (pRec)
-                            {
-                                memcpy(pRec, pCurRecord, sizeof(VBoxISO9660DirRecord));
-                                *ppRec = pRec;
-                                rc = VINF_SUCCESS;
-                                break;
-                            }
-                            else
-                                rc = VERR_NO_MEMORY;
-                        }
-                    }
-                }
-                idx += pCurRecord->record_length;
-            }
-        }
-    }
-    return rc;
-}
-
-int rtISO9660ResolvePath(VBoxISO9660File *pFile, const char *pszPath, uint32_t *puSector)
-{
-    AssertPtrReturn(pFile, VERR_INVALID_PARAMETER);
-    AssertPtrReturn(pszPath, VERR_INVALID_PARAMETER);
-    AssertPtrReturn(puSector, VERR_INVALID_PARAMETER);
-
-    int rc = VERR_FILE_NOT_FOUND;
-    char *pszTemp = RTStrDup(pszPath);
-    if (pszTemp)
-    {
-        RTPathStripFilename(pszTemp);
-
-        bool bFound = false;
-        VBoxISO9660PathTableEntry *pNode;
-        if (!RTStrCmp(pszTemp, ".")) /* Root directory? Use first node! */
-        {
-            pNode = RTListNodeGetFirst(&pFile->listPaths, VBoxISO9660PathTableEntry, Node);
-            bFound = true;
-        }
-        else
-        {
-            RTListForEach(&pFile->listPaths, pNode, VBoxISO9660PathTableEntry, Node)
-            {
-                if (   pNode->path_full != NULL /* Root does not have a path! */
-                    && !RTStrICmp(pNode->path_full, pszTemp))
-                {
-                    bFound = true;
-                    break;
-                }
-            }
-        }
-        if (bFound)
-        {
-            *puSector = pNode->header.sector_dir_table;
-            rc = VINF_SUCCESS;
-        }
-        RTStrFree(pszTemp);
-    }
-    else
-        rc = VERR_NO_MEMORY;
-    return rc;
-}
-
-int rtISO9660GetDirectoryRecord(VBoxISO9660File *pFile, const char *pszPath,
-                                VBoxISO9660DirRecord **ppRecord)
-{
-    AssertPtrReturn(pFile, VERR_INVALID_PARAMETER);
-    AssertPtrReturn(pszPath, VERR_INVALID_PARAMETER);
-    AssertPtrReturn(ppRecord, VERR_INVALID_PARAMETER);
-
-    uint32_t uSector;
-    int rc = rtISO9660ResolvePath(pFile, pszPath, &uSector);
-    if (RT_SUCCESS(rc))
-    {
-        /* Seek and read the directory record of given file. */
-        rc = RTFileSeek(pFile->file, uSector * VBOX_ISO9660_SECTOR_SIZE,
-                        RTFILE_SEEK_BEGIN, NULL);
-        if (RT_SUCCESS(rc))
-        {
-            size_t cbRead;
-            VBoxISO9660DirRecord *pRecord = (VBoxISO9660DirRecord*)RTMemAlloc(sizeof(VBoxISO9660DirRecord));
-            if (pRecord)
-            {
-                rc = RTFileRead(pFile->file, (VBoxISO9660DirRecord*)pRecord, sizeof(VBoxISO9660DirRecord), &cbRead);
-                if (RT_SUCCESS(rc))
-                {
-                    Assert(cbRead == sizeof(VBoxISO9660DirRecord));
-                    *ppRecord = pRecord;
-                }
-                if (RT_FAILURE(rc))
-                    RTMemFree(pRecord);
-            }
-            else
-                rc = VERR_NO_MEMORY;
-        }
-    }
-    return rc;
-}
-
-int RTISO9660GetFileInfo(VBoxISO9660File *pFile, const char *pszPath,
-                         uint32_t *pcbOffset, uint32_t *pcbLength)
-{
-    AssertPtrReturn(pFile, VERR_INVALID_PARAMETER);
-    AssertPtrReturn(pszPath, VERR_INVALID_PARAMETER);
-    AssertPtrReturn(pcbOffset, VERR_INVALID_PARAMETER);
-
-    VBoxISO9660DirRecord *pDirRecord;
-    int rc = rtISO9660GetDirectoryRecord(pFile, pszPath, &pDirRecord);
-    if (RT_SUCCESS(rc))
-    {
-        /* Get actual file record. */
-        VBoxISO9660DirRecord *pFileRecord;
-        rc = rtISO9660FindEntry(pFile,
-                                RTPathFilename(pszPath),
-                                pDirRecord->extent_location,
-                                pDirRecord->extent_data_length,
-                                &pFileRecord);
-        if (RT_SUCCESS(rc))
-        {
-            *pcbOffset = pFileRecord->extent_location * VBOX_ISO9660_SECTOR_SIZE;
-            *pcbLength = pFileRecord->extent_data_length;
-            RTMemFree(pFileRecord);
-        }
-        RTMemFree(pDirRecord);
-    }
-    return rc;
-}
-
-int RTISO9660ExtractFile(VBoxISO9660File *pFile, const char *pszSource,
-                         const char *pszDest)
-{
-    uint32_t cbOffset, cbLength;
-    int rc = RTISO9660GetFileInfo(pFile, pszSource, &cbOffset, &cbLength);
-    if (RT_SUCCESS(rc))
-    {
-        rc = RTFileSeek(pFile->file, cbOffset, RTFILE_SEEK_BEGIN, NULL);
-        if (RT_SUCCESS(rc))
-        {
-            RTFILE fileDest;
-            rc = RTFileOpen(&fileDest, pszDest, RTFILE_O_CREATE | RTFILE_O_WRITE | RTFILE_O_DENY_WRITE);
-            if (RT_SUCCESS(rc))
-            {
-                size_t cbToRead, cbRead, cbWritten;
-                uint8_t byBuffer[_4K];
-                while (   cbLength > 0
-                       && RT_SUCCESS(rc))
-                {
-                    cbToRead = RT_MIN(cbLength, _4K);
-                    rc = RTFileRead(pFile->file, (uint8_t*)byBuffer, cbToRead, &cbRead);
-                    if (RT_FAILURE(rc))
-                        break;
-                    rc = RTFileWrite(fileDest, (uint8_t*)byBuffer, cbRead, &cbWritten);
-                    if (RT_FAILURE(rc))
-                        break;
-                    cbLength -= cbRead;
-                }
-                RTFileClose(fileDest);
-            }
-        }
-    }
-    return rc;
-}
-
-#endif
-
 static int handleCtrlCopyTo(HandlerArg *a)
 {
-    VBoxISO9660File file;
-    int vrc = RTISO9660Open("c:\\Downloads\\VBoxGuestAdditions_3.2.8.iso", &file);
+    RTISOFSFILE file;
+    int vrc = RTIsoFsOpen(&file, "c:\\Downloads\\VBoxGuestAdditions_3.2.8.iso");
     if (RT_SUCCESS(vrc))
     {
-        //vrc = RTISO9660ExtractFile(&file, "VBOXWINDOWSADDITIONS_X86.EXE", "C:\\VBOXWINDOWSADDITIONS_X86.EXE");
-        vrc = RTISO9660ExtractFile(&file, "32BIT/OS2/README.TXT", "C:\\OS2-Readme.txt");
-        RTISO9660Close(&file);
+        vrc = RTIsoFsExtractFile(&file, "VBOXWINDOWSADDITIONS_X86.EXE", "C:\\VBOXWINDOWSADDITIONS_X86.EXE");
+        vrc = RTIsoFsExtractFile(&file, "FOO.EXE", "C:\\FOO.EXE");
+        vrc = RTIsoFsExtractFile(&file, "32BIT/OS2/README.TXT", "C:\\OS2-Readme.txt");
+        RTIsoFsClose(&file);
     }
     return vrc;
Index: /trunk/src/VBox/Runtime/Makefile.kmk
===================================================================
--- /trunk/src/VBox/Runtime/Makefile.kmk	(revision 32996)
+++ /trunk/src/VBox/Runtime/Makefile.kmk	(revision 32997)
@@ -387,4 +387,5 @@
 	r3/fs.cpp \
 	r3/init.cpp \
+	r3/isofs.cpp \
 	r3/path.cpp \
 	r3/process.cpp \
Index: /trunk/src/VBox/Runtime/r3/isofs.cpp
===================================================================
--- /trunk/src/VBox/Runtime/r3/isofs.cpp	(revision 32997)
+++ /trunk/src/VBox/Runtime/r3/isofs.cpp	(revision 32997)
@@ -0,0 +1,570 @@
+/* $Id$ */
+/** @file
+ * IPRT - ISO 9660 file system handling.
+ */
+
+/*
+ * Copyright (C) 2010 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*******************************************************************************
+*   Header Files                                                               *
+*******************************************************************************/
+#include <iprt/isofs.h>
+#include <iprt/path.h>
+
+
+/**
+ * Destroys the patch cache.
+ *
+ * @param   pFile
+ */
+RTR3DECL(void) rtIsoFsDestroyPathCache(PRTISOFSFILE pFile)
+{
+    PRTISOFSPATHTABLEENTRY pNode = RTListNodeGetFirst(&pFile->listPaths, RTISOFSPATHTABLEENTRY, Node);
+    while (pNode)
+    {
+        PRTISOFSPATHTABLEENTRY pNext = RTListNodeGetNext(&pNode->Node, RTISOFSPATHTABLEENTRY, Node);
+        bool fLast = RTListNodeIsLast(&pFile->listPaths, &pNode->Node);
+
+        if (pNode->path)
+            RTStrFree(pNode->path);
+        if (pNode->path_full)
+            RTStrFree(pNode->path_full);
+        RTListNodeRemove(&pNode->Node);
+        RTMemFree(pNode);
+
+        if (fLast)
+            break;
+
+        pNode = pNext;
+    }
+}
+
+
+/**
+ *
+ *
+ * @return  int
+ *
+ * @param   pList
+ * @param   pszPath
+ * @param   pHeader
+ */
+RTR3DECL(int) rtIsoFsAddToPathCache(PRTLISTNODE pList, const char *pszPath,
+                                    RTISOFSPATHTABLEHEADER *pHeader)
+{
+    AssertPtrReturn(pList, VERR_INVALID_PARAMETER);
+    AssertPtrReturn(pszPath, VERR_INVALID_PARAMETER);
+    AssertPtrReturn(pHeader, VERR_INVALID_PARAMETER);
+
+    PRTISOFSPATHTABLEENTRY pNode = (PRTISOFSPATHTABLEENTRY)RTMemAlloc(sizeof(RTISOFSPATHTABLEENTRY));
+    if (pNode == NULL)
+        return VERR_NO_MEMORY;
+
+    pNode->path = NULL;
+    if (RT_SUCCESS(RTStrAAppend(&pNode->path, pszPath)))
+    {
+        memcpy((RTISOFSPATHTABLEHEADER*)&pNode->header,
+               (RTISOFSPATHTABLEHEADER*)pHeader, sizeof(pNode->header));
+
+        pNode->path_full = NULL;
+        pNode->Node.pPrev = NULL;
+        pNode->Node.pNext = NULL;
+        RTListAppend(pList, &pNode->Node);
+        return VINF_SUCCESS;
+    }
+    return VERR_NO_MEMORY;
+}
+
+
+/**
+ *
+ *
+ * @return  int
+ *
+ * @param   pList
+ * @param   pNode
+ * @param   pszPathNode
+ * @param   ppszPath
+ */
+RTR3DECL(int) rtIsoFsGetParentPathSub(PRTLISTNODE pList, PRTISOFSPATHTABLEENTRY pNode,
+                                      char *pszPathNode, char **ppszPath)
+{
+    int rc = VINF_SUCCESS;
+    if (pNode->header.parent_index > 1)
+    {
+        uint16_t idx = 1;
+        PRTISOFSPATHTABLEENTRY pNodeParent = RTListNodeGetFirst(pList, RTISOFSPATHTABLEENTRY, Node);
+        while (idx++ < pNode->header.parent_index)
+            pNodeParent =  RTListNodeGetNext(&pNodeParent->Node, RTISOFSPATHTABLEENTRY, Node);
+        char *pszPath;
+        if (RTStrAPrintf(&pszPath, "%s/%s", pNodeParent->path, pszPathNode))
+        {
+            rc = rtIsoFsGetParentPathSub(pList, pNodeParent, pszPath, ppszPath);
+            RTStrFree(pszPath);
+        }
+        else
+            rc = VERR_NO_MEMORY;
+    }
+    else
+    {
+        char *pszPath = RTStrDup(pszPathNode);
+        *ppszPath = pszPath;
+    }
+    return rc;
+}
+
+
+/**
+ *
+ *
+ * @return  int
+ *
+ * @param   pFile
+ */
+RTR3DECL(int) rtIsoFsUpdatePathCache(PRTISOFSFILE pFile)
+{
+    AssertPtrReturn(pFile, VERR_INVALID_PARAMETER);
+    rtIsoFsDestroyPathCache(pFile);
+
+    RTListInit(&pFile->listPaths);
+
+    /* Seek to path tables. */
+    int rc = VINF_SUCCESS;
+    Assert(pFile->pvd.path_table_start_first > 16);
+    uint64_t uTableStart = (pFile->pvd.path_table_start_first * RTISOFS_SECTOR_SIZE);
+    Assert(uTableStart % RTISOFS_SECTOR_SIZE == 0); /* Make sure it's aligned. */
+    if (RTFileTell(pFile->file) != uTableStart)
+        rc = RTFileSeek(pFile->file, uTableStart, RTFILE_SEEK_BEGIN, &uTableStart);
+
+    /*
+     * Since this is a sequential format, for performance it's best to read the
+     * complete path table (every entry can have its own level (directory depth) first
+     * and the actual directories of the path table afterwards.
+     */
+
+    /* Read in the path table ... */
+    size_t cbLeft = pFile->pvd.path_table_size;
+    RTISOFSPATHTABLEHEADER header;
+    while ((cbLeft > 0) && RT_SUCCESS(rc))
+    {
+        size_t cbRead;
+        rc = RTFileRead(pFile->file, (RTISOFSPATHTABLEHEADER*)&header, sizeof(RTISOFSPATHTABLEHEADER), &cbRead);
+        if (RT_FAILURE(rc))
+            break;
+        cbLeft -= cbRead;
+        if (header.length)
+        {
+            Assert(cbLeft >= header.length);
+            Assert(header.length <= 31);
+            /* Allocate and read in the actual path name. */
+            char *pszName = RTStrAlloc(header.length + 1);
+            rc = RTFileRead(pFile->file, (char*)pszName, header.length, &cbRead);
+            if (RT_SUCCESS(rc))
+            {
+                cbLeft -= cbRead;
+                pszName[cbRead] = '\0'; /* Terminate string. */
+                /* Add entry to cache ... */
+                rc = rtIsoFsAddToPathCache(&pFile->listPaths, pszName, &header);
+            }
+            RTStrFree(pszName);
+            /* Read padding if required ... */
+            if ((header.length % 2) != 0) /* If we have an odd length, read/skip the padding byte. */
+            {
+                rc = RTFileSeek(pFile->file, 1, RTFILE_SEEK_CURRENT, NULL);
+                cbLeft--;
+            }
+        }
+    }
+
+    /* Transform path names into full paths. This is a bit ugly right now. */
+    PRTISOFSPATHTABLEENTRY pNode = RTListNodeGetLast(&pFile->listPaths, RTISOFSPATHTABLEENTRY, Node);
+    while (   pNode
+           && !RTListNodeIsFirst(&pFile->listPaths, &pNode->Node)
+           && RT_SUCCESS(rc))
+    {
+        rc = rtIsoFsGetParentPathSub(&pFile->listPaths, pNode,
+                                       pNode->path, &pNode->path_full);
+        if (RT_SUCCESS(rc))
+            pNode = RTListNodeGetPrev(&pNode->Node, RTISOFSPATHTABLEENTRY, Node);
+    }
+
+    return rc;
+}
+
+
+/**
+ *
+ *
+ * @return  int
+ *
+ * @param   pszFileName
+ * @param   pFile
+ */
+RTR3DECL(int) RTIsoFsOpen(PRTISOFSFILE pFile, const char *pszFileName)
+{
+    AssertPtrReturn(pFile, VERR_INVALID_PARAMETER);
+    AssertPtrReturn(pszFileName, VERR_INVALID_PARAMETER);
+
+    RTListInit(&pFile->listPaths);
+#if 0
+    Assert(sizeof(RTISOFSDATESHORT) == 7);
+    Assert(sizeof(RTISOFSDATELONG) == 17);
+    int l = sizeof(RTISOFSDIRRECORD);
+    RTPrintf("RTISOFSDIRRECORD=%ld\n", l);
+    Assert(l == 33);
+    /* Each volume descriptor exactly occupies one sector. */
+    l = sizeof(RTISOFSPRIVOLDESC);
+    RTPrintf("RTISOFSPRIVOLDESC=%ld\n", l);
+    Assert(l == RTISOFS_SECTOR_SIZE);
+#endif
+    int rc = RTFileOpen(&pFile->file, pszFileName, RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_WRITE);
+    if (RT_SUCCESS(rc))
+    {
+        uint64_t cbSize;
+        rc = RTFileGetSize(pFile->file, &cbSize);
+        if (   RT_SUCCESS(rc)
+            && cbSize > 16 * RTISOFS_SECTOR_SIZE)
+        {
+            uint64_t cbOffset = 16 * RTISOFS_SECTOR_SIZE; /* Start reading at 32k. */
+            size_t cbRead;
+            RTISOFSPRIVOLDESC pvd;
+            bool fFoundPrimary = false;
+            bool fIsValid = false;
+            while (cbOffset < _1M)
+            {
+                /* Get primary descriptor. */
+                rc = RTFileRead(pFile->file, (PRTISOFSPRIVOLDESC)&pvd, sizeof(RTISOFSPRIVOLDESC), &cbRead);
+                if (RT_FAILURE(rc) || cbRead < sizeof(RTISOFSPRIVOLDESC))
+                    break;
+                if (   RTStrStr((char*)pvd.name_id, RTISOFS_STANDARD_ID)
+                    && pvd.type == 0x1 /* Primary Volume Descriptor */)
+                {
+                    memcpy((PRTISOFSPRIVOLDESC)&pFile->pvd,
+                           (PRTISOFSPRIVOLDESC)&pvd, sizeof(RTISOFSPRIVOLDESC));
+                    fFoundPrimary = true;
+                }
+                else if(pvd.type == 0xff /* Termination Volume Descriptor */)
+                {
+                    if (fFoundPrimary)
+                        fIsValid = true;
+                    break;
+                }
+                cbOffset += sizeof(RTISOFSPRIVOLDESC);
+            }
+
+            if (fIsValid)
+                rc = rtIsoFsUpdatePathCache(pFile);
+            else
+                rc = VERR_INVALID_PARAMETER;
+        }
+        if (RT_FAILURE(rc))
+            RTIsoFsClose(pFile);
+    }
+    return rc;
+}
+
+
+/**
+ *
+ *
+ *
+ * @param   pFile
+ */
+RTR3DECL(void) RTIsoFsClose(PRTISOFSFILE pFile)
+{
+    if (pFile)
+    {
+        rtIsoFsDestroyPathCache(pFile);
+        RTFileClose(pFile->file);
+    }
+}
+
+
+/**
+ * Parses an extent given at the specified sector + size and
+ * returns a directory record.
+ *
+ * @return  int
+ *
+ * @param   pFile
+ * @param   pszFileName
+ * @param   uExtentSector
+ * @param   cbExtent
+ * @param   ppRec
+ */
+RTR3DECL(int) rtIsoFsFindEntry(PRTISOFSFILE pFile, const char *pszFileName,
+                               uint32_t uExtentSector, uint32_t cbExtent /* Bytes */,
+                               PRTISOFSDIRRECORD *ppRec)
+{
+    AssertPtrReturn(pFile, VERR_INVALID_PARAMETER);
+    Assert(uExtentSector > 16);
+
+    int rc = RTFileSeek(pFile->file, uExtentSector * RTISOFS_SECTOR_SIZE,
+                        RTFILE_SEEK_BEGIN, NULL);
+    if (RT_SUCCESS(rc))
+    {
+        rc = VERR_FILE_NOT_FOUND;
+
+        uint8_t uBuffer[RTISOFS_SECTOR_SIZE];
+        size_t cbLeft = cbExtent;
+        while (!RT_SUCCESS(rc) && cbLeft > 0)
+        {
+            size_t cbRead;
+            int rc2 = RTFileRead(pFile->file, (void*)&uBuffer, sizeof(uBuffer), &cbRead);
+            Assert(RT_SUCCESS(rc2) && cbRead == RTISOFS_SECTOR_SIZE);
+            cbLeft -= cbRead;
+
+            uint32_t idx = 0;
+            while (idx < cbRead)
+            {
+                PRTISOFSDIRRECORD pCurRecord = (PRTISOFSDIRRECORD)&uBuffer[idx];
+                if (pCurRecord->record_length == 0)
+                    break;
+
+                Assert(pCurRecord->name_len > 0);
+                char *pszName = RTStrAlloc(pCurRecord->name_len + 1);
+                AssertPtr(pszName);
+                Assert(idx + sizeof(RTISOFSDIRRECORD) < cbRead);
+                memcpy(pszName, &uBuffer[idx + sizeof(RTISOFSDIRRECORD)], pCurRecord->name_len);
+
+                if (   pCurRecord->name_len == 1
+                    && pszName[0] == 0x0)
+                {
+                    /* This is a "." directory (self). */
+                }
+                else if (   pCurRecord->name_len == 1
+                         && pszName[0] == 0x1)
+                {
+                    /* This is a ".." directory (parent). */
+                }
+                else /* Regular directory or file */
+                {
+                    if (pCurRecord->flags & RT_BIT(1)) /* Directory */
+                    {
+                        /* We don't recursively go into directories
+                         * because we already have the cached path table. */
+                        pszName[pCurRecord->name_len] = 0;
+                        /*rc = rtIsoFsParseDir(pFile, pszFileName,
+                                                 pDirHdr->extent_location, pDirHdr->extent_data_length);*/
+                    }
+                    else /* File */
+                    {
+                        /* Get last occurence of ";" and cut it off. */
+                        char *pTerm = strrchr(pszName, ';');
+                        if (pTerm)
+                            pszName[pTerm - pszName] = 0;
+
+                        /* Don't use case sensitive comparison here, in IS0 9660 all
+                         * file / directory names are UPPERCASE. */
+                        if (!RTStrICmp(pszName, pszFileName))
+                        {
+                            PRTISOFSDIRRECORD pRec = (PRTISOFSDIRRECORD)RTMemAlloc(sizeof(RTISOFSDIRRECORD));
+                            if (pRec)
+                            {
+                                memcpy(pRec, pCurRecord, sizeof(RTISOFSDIRRECORD));
+                                *ppRec = pRec;
+                                rc = VINF_SUCCESS;
+                                break;
+                            }
+                            else
+                                rc = VERR_NO_MEMORY;
+                        }
+                    }
+                }
+                idx += pCurRecord->record_length;
+            }
+        }
+    }
+    return rc;
+}
+
+
+/**
+ *
+ *
+ * @return  int
+ *
+ * @param   pFile
+ * @param   pszPath
+ * @param   puSector
+ */
+RTR3DECL(int) rtIsoFsResolvePath(PRTISOFSFILE pFile, const char *pszPath, uint32_t *puSector)
+{
+    AssertPtrReturn(pFile, VERR_INVALID_PARAMETER);
+    AssertPtrReturn(pszPath, VERR_INVALID_PARAMETER);
+    AssertPtrReturn(puSector, VERR_INVALID_PARAMETER);
+
+    int rc = VERR_FILE_NOT_FOUND;
+    char *pszTemp = RTStrDup(pszPath);
+    if (pszTemp)
+    {
+        RTPathStripFilename(pszTemp);
+
+        bool bFound = false;
+        PRTISOFSPATHTABLEENTRY pNode;
+        if (!RTStrCmp(pszTemp, ".")) /* Root directory? Use first node! */
+        {
+            pNode = RTListNodeGetFirst(&pFile->listPaths, RTISOFSPATHTABLEENTRY, Node);
+            bFound = true;
+        }
+        else
+        {
+            RTListForEach(&pFile->listPaths, pNode, RTISOFSPATHTABLEENTRY, Node)
+            {
+                if (   pNode->path_full != NULL /* Root does not have a path! */
+                    && !RTStrICmp(pNode->path_full, pszTemp))
+                {
+                    bFound = true;
+                    break;
+                }
+            }
+        }
+        if (bFound)
+        {
+            *puSector = pNode->header.sector_dir_table;
+            rc = VINF_SUCCESS;
+        }
+        RTStrFree(pszTemp);
+    }
+    else
+        rc = VERR_NO_MEMORY;
+    return rc;
+}
+
+
+/**
+ *
+ *
+ * @return  int
+ *
+ * @param   pFile
+ * @param   pszPath
+ * @param   ppRecord
+ */
+RTR3DECL(int) rtIsoFsGetDirectoryRecord(PRTISOFSFILE pFile, const char *pszPath,
+                                        PRTISOFSDIRRECORD *ppRecord)
+{
+    AssertPtrReturn(pFile, VERR_INVALID_PARAMETER);
+    AssertPtrReturn(pszPath, VERR_INVALID_PARAMETER);
+    AssertPtrReturn(ppRecord, VERR_INVALID_PARAMETER);
+
+    uint32_t uSector;
+    int rc = rtIsoFsResolvePath(pFile, pszPath, &uSector);
+    if (RT_SUCCESS(rc))
+    {
+        /* Seek and read the directory record of given file. */
+        rc = RTFileSeek(pFile->file, uSector * RTISOFS_SECTOR_SIZE,
+                        RTFILE_SEEK_BEGIN, NULL);
+        if (RT_SUCCESS(rc))
+        {
+            size_t cbRead;
+            PRTISOFSDIRRECORD pRecord = (PRTISOFSDIRRECORD)RTMemAlloc(sizeof(RTISOFSDIRRECORD));
+            if (pRecord)
+            {
+                rc = RTFileRead(pFile->file, (PRTISOFSDIRRECORD)pRecord, sizeof(RTISOFSDIRRECORD), &cbRead);
+                if (RT_SUCCESS(rc))
+                {
+                    Assert(cbRead == sizeof(RTISOFSDIRRECORD));
+                    *ppRecord = pRecord;
+                }
+                if (RT_FAILURE(rc))
+                    RTMemFree(pRecord);
+            }
+            else
+                rc = VERR_NO_MEMORY;
+        }
+    }
+    return rc;
+}
+
+
+RTR3DECL(int) RTIsoFsGetFileInfo(PRTISOFSFILE pFile, const char *pszPath,
+                                 uint32_t *pcbOffset, size_t *pcbLength)
+{
+    AssertPtrReturn(pFile, VERR_INVALID_PARAMETER);
+    AssertPtrReturn(pszPath, VERR_INVALID_PARAMETER);
+    AssertPtrReturn(pcbOffset, VERR_INVALID_PARAMETER);
+
+    PRTISOFSDIRRECORD pDirRecord;
+    int rc = rtIsoFsGetDirectoryRecord(pFile, pszPath, &pDirRecord);
+    if (RT_SUCCESS(rc))
+    {
+        /* Get actual file record. */
+        PRTISOFSDIRRECORD pFileRecord;
+        rc = rtIsoFsFindEntry(pFile,
+                                RTPathFilename(pszPath),
+                                pDirRecord->extent_location,
+                                pDirRecord->extent_data_length,
+                                &pFileRecord);
+        if (RT_SUCCESS(rc))
+        {
+            *pcbOffset = pFileRecord->extent_location * RTISOFS_SECTOR_SIZE;
+            *pcbLength = pFileRecord->extent_data_length;
+            RTMemFree(pFileRecord);
+        }
+        RTMemFree(pDirRecord);
+    }
+    return rc;
+}
+
+
+RTR3DECL(int) RTIsoFsExtractFile(PRTISOFSFILE pFile, const char *pszSource,
+                                 const char *pszDest)
+{
+    AssertPtrReturn(pFile, VERR_INVALID_PARAMETER);
+    AssertPtrReturn(pszSource, VERR_INVALID_PARAMETER);
+    AssertPtrReturn(pszDest, VERR_INVALID_PARAMETER);
+
+    uint32_t cbOffset;
+    size_t cbLength;
+    int rc = RTIsoFsGetFileInfo(pFile, pszSource, &cbOffset, &cbLength);
+    if (RT_SUCCESS(rc))
+    {
+        rc = RTFileSeek(pFile->file, cbOffset, RTFILE_SEEK_BEGIN, NULL);
+        if (RT_SUCCESS(rc))
+        {
+            RTFILE fileDest;
+            rc = RTFileOpen(&fileDest, pszDest, RTFILE_O_CREATE | RTFILE_O_WRITE | RTFILE_O_DENY_WRITE);
+            if (RT_SUCCESS(rc))
+            {
+                size_t cbToRead, cbRead, cbWritten;
+                uint8_t byBuffer[_4K];
+                while (   cbLength > 0
+                       && RT_SUCCESS(rc))
+                {
+                    cbToRead = RT_MIN(cbLength, _4K);
+                    rc = RTFileRead(pFile->file, (uint8_t*)byBuffer, cbToRead, &cbRead);
+                    if (RT_FAILURE(rc))
+                        break;
+                    rc = RTFileWrite(fileDest, (uint8_t*)byBuffer, cbRead, &cbWritten);
+                    if (RT_FAILURE(rc))
+                        break;
+                    cbLength -= cbRead;
+                }
+                RTFileClose(fileDest);
+            }
+        }
+    }
+    return rc;
+}
+
