isofs.cpp revision 5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2a
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync * IPRT - ISO 9660 file system handling.
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync * Copyright (C) 2010 Oracle Corporation
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync * available from http://www.virtualbox.org. This file is free software;
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync * you can redistribute it and/or modify it under the terms of the GNU
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync * General Public License (GPL) as published by the Free Software
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync * The contents of this file may alternatively be used under the terms
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync * of the Common Development and Distribution License Version 1.0
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync * VirtualBox OSE distribution, in which case the provisions of the
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync * CDDL are applicable instead of those of the GPL.
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync * You may elect to license modified versions of this file under the
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync * terms and conditions of either the GPL or the CDDL or both.
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync/*******************************************************************************
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync* Header Files *
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync*******************************************************************************/
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync * Destroys the patch cache.
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync * @param pFile
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsyncRTR3DECL(void) rtIsoFsDestroyPathCache(PRTISOFSFILE pFile)
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync PRTISOFSPATHTABLEENTRY pNode = RTListNodeGetFirst(&pFile->listPaths, RTISOFSPATHTABLEENTRY, Node);
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync PRTISOFSPATHTABLEENTRY pNext = RTListNodeGetNext(&pNode->Node, RTISOFSPATHTABLEENTRY, Node);
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync bool fLast = RTListNodeIsLast(&pFile->listPaths, &pNode->Node);
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync * @return int
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync * @param pList
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync * @param pszPath
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync * @param pHeader
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsyncRTR3DECL(int) rtIsoFsAddToPathCache(PRTLISTNODE pList, const char *pszPath,
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync PRTISOFSPATHTABLEENTRY pNode = (PRTISOFSPATHTABLEENTRY)RTMemAlloc(sizeof(RTISOFSPATHTABLEENTRY));
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync if (RT_SUCCESS(RTStrAAppend(&pNode->path, pszPath)))
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync (RTISOFSPATHTABLEHEADER*)pHeader, sizeof(pNode->header));
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync * @return int
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync * @param pList
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync * @param pNode
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync * @param pszPathNode
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync * @param ppszPath
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsyncRTR3DECL(int) rtIsoFsGetParentPathSub(PRTLISTNODE pList, PRTISOFSPATHTABLEENTRY pNode,
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync PRTISOFSPATHTABLEENTRY pNodeParent = RTListNodeGetFirst(pList, RTISOFSPATHTABLEENTRY, Node);
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync pNodeParent = RTListNodeGetNext(&pNodeParent->Node, RTISOFSPATHTABLEENTRY, Node);
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync if (RTStrAPrintf(&pszPath, "%s/%s", pNodeParent->path, pszPathNode))
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync rc = rtIsoFsGetParentPathSub(pList, pNodeParent, pszPath, ppszPath);
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync * @return int
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync * @param pFile
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsyncRTR3DECL(int) rtIsoFsUpdatePathCache(PRTISOFSFILE pFile)
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync /* Seek to path tables. */
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync uint64_t uTableStart = (pFile->pvd.path_table_start_first * RTISOFS_SECTOR_SIZE);
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync Assert(uTableStart % RTISOFS_SECTOR_SIZE == 0); /* Make sure it's aligned. */
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync rc = RTFileSeek(pFile->file, uTableStart, RTFILE_SEEK_BEGIN, &uTableStart);
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync * Since this is a sequential format, for performance it's best to read the
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync * complete path table (every entry can have its own level (directory depth) first
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync * and the actual directories of the path table afterwards.
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync /* Read in the path table ... */
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync rc = RTFileRead(pFile->file, (RTISOFSPATHTABLEHEADER*)&header, sizeof(RTISOFSPATHTABLEHEADER), &cbRead);
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync /* Allocate and read in the actual path name. */
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync rc = RTFileRead(pFile->file, (char*)pszName, header.length, &cbRead);
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync /* Add entry to cache ... */
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync rc = rtIsoFsAddToPathCache(&pFile->listPaths, pszName, &header);
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync /* Read padding if required ... */
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync if ((header.length % 2) != 0) /* If we have an odd length, read/skip the padding byte. */
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync rc = RTFileSeek(pFile->file, 1, RTFILE_SEEK_CURRENT, NULL);
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync /* Transform path names into full paths. This is a bit ugly right now. */
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync PRTISOFSPATHTABLEENTRY pNode = RTListNodeGetLast(&pFile->listPaths, RTISOFSPATHTABLEENTRY, Node);
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync && !RTListNodeIsFirst(&pFile->listPaths, &pNode->Node)
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync rc = rtIsoFsGetParentPathSub(&pFile->listPaths, pNode,
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync pNode = RTListNodeGetPrev(&pNode->Node, RTISOFSPATHTABLEENTRY, Node);
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync * @return int
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync * @param pszFileName
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync * @param pFile
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsyncRTR3DECL(int) RTIsoFsOpen(PRTISOFSFILE pFile, const char *pszFileName)
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync AssertPtrReturn(pszFileName, VERR_INVALID_PARAMETER);
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync int l = sizeof(RTISOFSDIRRECORD);
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync /* Each volume descriptor exactly occupies one sector. */
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync int rc = RTFileOpen(&pFile->file, pszFileName, RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_WRITE);
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync uint64_t cbOffset = 16 * RTISOFS_SECTOR_SIZE; /* Start reading at 32k. */
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync bool fIsValid = false;
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync /* Get primary descriptor. */
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync rc = RTFileRead(pFile->file, (PRTISOFSPRIVOLDESC)&pvd, sizeof(RTISOFSPRIVOLDESC), &cbRead);
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync if (RT_FAILURE(rc) || cbRead < sizeof(RTISOFSPRIVOLDESC))
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync if ( RTStrStr((char*)pvd.name_id, RTISOFS_STANDARD_ID)
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync && pvd.type == 0x1 /* Primary Volume Descriptor */)
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync (PRTISOFSPRIVOLDESC)&pvd, sizeof(RTISOFSPRIVOLDESC));
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync else if(pvd.type == 0xff /* Termination Volume Descriptor */)
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync * @param pFile
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync * Parses an extent given at the specified sector + size and
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync * returns a directory record.
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync * @return int
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync * @param pFile
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync * @param pszFileName
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync * @param uExtentSector
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync * @param cbExtent
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync * @param ppRec
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsyncRTR3DECL(int) rtIsoFsFindEntry(PRTISOFSFILE pFile, const char *pszFileName,
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync uint32_t uExtentSector, uint32_t cbExtent /* Bytes */,
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync int rc = RTFileSeek(pFile->file, uExtentSector * RTISOFS_SECTOR_SIZE,
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync int rc2 = RTFileRead(pFile->file, (void*)&uBuffer, sizeof(uBuffer), &cbRead);
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync Assert(RT_SUCCESS(rc2) && cbRead == RTISOFS_SECTOR_SIZE);
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync PRTISOFSDIRRECORD pCurRecord = (PRTISOFSDIRRECORD)&uBuffer[idx];
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync char *pszName = RTStrAlloc(pCurRecord->name_len + 1);
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync memcpy(pszName, &uBuffer[idx + sizeof(RTISOFSDIRRECORD)], pCurRecord->name_len);
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync /* This is a "." directory (self). */
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync /* This is a ".." directory (parent). */
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync else /* Regular directory or file */
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync /* We don't recursively go into directories
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync * because we already have the cached path table. */
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync /*rc = rtIsoFsParseDir(pFile, pszFileName,
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync pDirHdr->extent_location, pDirHdr->extent_data_length);*/
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync else /* File */
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync /* Get last occurence of ";" and cut it off. */
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync /* Don't use case sensitive comparison here, in IS0 9660 all
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync * file / directory names are UPPERCASE. */
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync PRTISOFSDIRRECORD pRec = (PRTISOFSDIRRECORD)RTMemAlloc(sizeof(RTISOFSDIRRECORD));
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync memcpy(pRec, pCurRecord, sizeof(RTISOFSDIRRECORD));
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync * @return int
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync * @param pFile
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync * @param pszPath
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync * @param puSector
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsyncRTR3DECL(int) rtIsoFsResolvePath(PRTISOFSFILE pFile, const char *pszPath, uint32_t *puSector)
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync bool bFound = false;
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync if (!RTStrCmp(pszTemp, ".")) /* Root directory? Use first node! */
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync pNode = RTListNodeGetFirst(&pFile->listPaths, RTISOFSPATHTABLEENTRY, Node);
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync RTListForEach(&pFile->listPaths, pNode, RTISOFSPATHTABLEENTRY, Node)
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync if ( pNode->path_full != NULL /* Root does not have a path! */
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync * @return int
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync * @param pFile
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync * @param pszPath
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync * @param ppRecord
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsyncRTR3DECL(int) rtIsoFsGetDirectoryRecord(PRTISOFSFILE pFile, const char *pszPath,
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync int rc = rtIsoFsResolvePath(pFile, pszPath, &uSector);
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync /* Seek and read the directory record of given file. */
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync rc = RTFileSeek(pFile->file, uSector * RTISOFS_SECTOR_SIZE,
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync PRTISOFSDIRRECORD pRecord = (PRTISOFSDIRRECORD)RTMemAlloc(sizeof(RTISOFSDIRRECORD));
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync rc = RTFileRead(pFile->file, (PRTISOFSDIRRECORD)pRecord, sizeof(RTISOFSDIRRECORD), &cbRead);
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsyncRTR3DECL(int) RTIsoFsGetFileInfo(PRTISOFSFILE pFile, const char *pszPath,
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync AssertPtrReturn(pcbOffset, VERR_INVALID_PARAMETER);
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync int rc = rtIsoFsGetDirectoryRecord(pFile, pszPath, &pDirRecord);
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync /* Get actual file record. */
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync *pcbOffset = pFileRecord->extent_location * RTISOFS_SECTOR_SIZE;
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsyncRTR3DECL(int) RTIsoFsExtractFile(PRTISOFSFILE pFile, const char *pszSource,
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync const char *pszDest)
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync AssertPtrReturn(pszSource, VERR_INVALID_PARAMETER);
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync int rc = RTIsoFsGetFileInfo(pFile, pszSource, &cbOffset, &cbLength);
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync rc = RTFileSeek(pFile->file, cbOffset, RTFILE_SEEK_BEGIN, NULL);
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync rc = RTFileOpen(&fileDest, pszDest, RTFILE_O_CREATE | RTFILE_O_WRITE | RTFILE_O_DENY_WRITE);
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync rc = RTFileRead(pFile->file, (uint8_t*)byBuffer, cbToRead, &cbRead);