Added xdvdfs for issue #205
This is a modified copy of https://github.com/multimediamike/xbfuse/blob/master/src/xdvdfs.c Also included are: * a few improvements originating from Dxbx, * renames of a few variables, * and raw-dump support xbfuse Raw-dump support also required a few updates to support file system base sector numbers other than zero (see "Cxbx addition" in this commit).
This commit is contained in:
parent
6fc9aaa58f
commit
0239a13a41
|
@ -187,6 +187,8 @@ $(SOLUTIONDIR)Export.bat</Command>
|
||||||
<ClInclude Include="..\..\src\Common\Logging.h" />
|
<ClInclude Include="..\..\src\Common\Logging.h" />
|
||||||
<ClInclude Include="..\..\src\Common\Win32\AlignPosfix1.h" />
|
<ClInclude Include="..\..\src\Common\Win32\AlignPosfix1.h" />
|
||||||
<ClInclude Include="..\..\src\Common\Win32\AlignPrefix1.h" />
|
<ClInclude Include="..\..\src\Common\Win32\AlignPrefix1.h" />
|
||||||
|
<ClInclude Include="..\..\src\Common\XDVDFS Tools\buffered_io.h" />
|
||||||
|
<ClInclude Include="..\..\src\Common\XDVDFS Tools\xdvdfs.h" />
|
||||||
<ClInclude Include="..\..\src\Cxbx.h" />
|
<ClInclude Include="..\..\src\Cxbx.h" />
|
||||||
<ClInclude Include="..\..\src\CxbxKrnl\CxbxKrnl.h" />
|
<ClInclude Include="..\..\src\CxbxKrnl\CxbxKrnl.h" />
|
||||||
<ClInclude Include="..\..\src\CxbxKrnl\DbgConsole.h" />
|
<ClInclude Include="..\..\src\CxbxKrnl\DbgConsole.h" />
|
||||||
|
@ -352,6 +354,8 @@ $(SOLUTIONDIR)Export.bat</Command>
|
||||||
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\src\Common\XDVDFS Tools\buffered_io.cpp" />
|
||||||
|
<ClCompile Include="..\..\src\Common\XDVDFS Tools\xdvdfs.cpp" />
|
||||||
<ClCompile Include="..\..\src\CxbxKrnl\CxbxKrnl.cpp">
|
<ClCompile Include="..\..\src\CxbxKrnl\CxbxKrnl.cpp">
|
||||||
<AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
<AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||||
<AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
<AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||||
|
|
|
@ -187,6 +187,12 @@
|
||||||
<ClCompile Include="..\..\src\CxbxKrnl\ResourceTracker.cpp">
|
<ClCompile Include="..\..\src\CxbxKrnl\ResourceTracker.cpp">
|
||||||
<Filter>Emulator</Filter>
|
<Filter>Emulator</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\src\Common\XDVDFS Tools\xdvdfs.cpp">
|
||||||
|
<Filter>Shared</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\src\Common\XDVDFS Tools\buffered_io.cpp">
|
||||||
|
<Filter>Shared</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="..\..\src\Cxbx\DlgControllerConfig.h">
|
<ClInclude Include="..\..\src\Cxbx\DlgControllerConfig.h">
|
||||||
|
@ -492,6 +498,12 @@
|
||||||
<ClInclude Include="..\..\src\Common\Win32\AlignPrefix1.h">
|
<ClInclude Include="..\..\src\Common\Win32\AlignPrefix1.h">
|
||||||
<Filter>Shared</Filter>
|
<Filter>Shared</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\src\Common\XDVDFS Tools\buffered_io.h">
|
||||||
|
<Filter>Shared</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\src\Common\XDVDFS Tools\xdvdfs.h">
|
||||||
|
<Filter>Shared</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="..\..\resource\About.jpg">
|
<None Include="..\..\resource\About.jpg">
|
||||||
|
|
|
@ -0,0 +1,85 @@
|
||||||
|
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
|
||||||
|
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
|
||||||
|
#define _CXBXKRNL_INTERNAL
|
||||||
|
#define _XBOXKRNL_DEFEXTRN_
|
||||||
|
|
||||||
|
// prevent name collisions
|
||||||
|
namespace xboxkrnl
|
||||||
|
{
|
||||||
|
#include <xboxkrnl/xboxkrnl.h> //#include <stdtypes.h>
|
||||||
|
|
||||||
|
#include "buffered_io.h"
|
||||||
|
|
||||||
|
PBYTE GetSectorBuffered(
|
||||||
|
PCDIO_READ This,
|
||||||
|
DWORD SectorNumber)
|
||||||
|
{
|
||||||
|
int i, index;
|
||||||
|
PBYTE Ptr;
|
||||||
|
|
||||||
|
// Have we got this baby in buffer ?
|
||||||
|
for(i = 0;i < DISK_BUFFER;i++)
|
||||||
|
{
|
||||||
|
if (This->SectorList[i] == SectorNumber)
|
||||||
|
{
|
||||||
|
This->LockList[i]++;
|
||||||
|
return(&This->DiskBuffer[i * SECTOR_SIZE]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Nope, load the sector and store it in buffer
|
||||||
|
for(i = 0;i < DISK_BUFFER;i++)
|
||||||
|
{
|
||||||
|
if (This->LockList[This->WriteIndex] == 0)
|
||||||
|
{
|
||||||
|
// Take an entry into the ring buffer but do not
|
||||||
|
// write the sector number yet (this is needed
|
||||||
|
// for re-entrancy purposes
|
||||||
|
Ptr = &This->DiskBuffer[This->WriteIndex * SECTOR_SIZE];
|
||||||
|
|
||||||
|
This->LockList[This->WriteIndex]++;
|
||||||
|
This->SectorList[This->WriteIndex] = 0;
|
||||||
|
|
||||||
|
index = This->WriteIndex;
|
||||||
|
This->WriteIndex++;
|
||||||
|
This->WriteIndex %= DISK_BUFFER;
|
||||||
|
|
||||||
|
if (This->Sectors(This->Data, Ptr, SectorNumber, 1))
|
||||||
|
{
|
||||||
|
// OK, write the sector number and exit
|
||||||
|
This->SectorList[index] = SectorNumber;
|
||||||
|
return(Ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If something went bad free the slot
|
||||||
|
This->SectorList[index] = 0;
|
||||||
|
This->LockList[index]--;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
This->WriteIndex++;
|
||||||
|
This->WriteIndex %= DISK_BUFFER;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We land here if all entries were locked, and that's BAD !
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
void ReleaseBufferedSector(
|
||||||
|
PCDIO_READ This,
|
||||||
|
DWORD SectorNumber)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
// Find the sector in the lock list and decrease its usage count
|
||||||
|
for(i = 0;i < DISK_BUFFER;i++)
|
||||||
|
{
|
||||||
|
if ((This->SectorList[i] == SectorNumber)&&(This->LockList[i]))
|
||||||
|
{
|
||||||
|
This->LockList[i]--;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
|
@ -0,0 +1,51 @@
|
||||||
|
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
|
||||||
|
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
|
||||||
|
#ifndef __BUFFERED_IO_H__
|
||||||
|
#define __BUFFERED_IO_H__
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define BOOL BOOLEAN
|
||||||
|
#define LPSTR LPCH
|
||||||
|
|
||||||
|
// Determines how large a sector is
|
||||||
|
#define SECTOR_SIZE 2048
|
||||||
|
|
||||||
|
// Determines how many sectors are buffered in each instance of CDIO_READ
|
||||||
|
#define DISK_BUFFER 64
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
DWORD SectorList[DISK_BUFFER]; // Ring buffer for buffered disk i/o
|
||||||
|
DWORD LockList[DISK_BUFFER]; // Lock for each buffered sector
|
||||||
|
BYTE DiskBuffer[SECTOR_SIZE * DISK_BUFFER]; // Storage room for buffered sectors
|
||||||
|
DWORD WriteIndex; // Write pointer
|
||||||
|
|
||||||
|
// Pointer to arbitrary data passed at init
|
||||||
|
// (usually a file or device handle)
|
||||||
|
PVOID Data;
|
||||||
|
|
||||||
|
BOOL (*Sectors)( // Routine to get sectors
|
||||||
|
PVOID Data, // Pointer to arbitrary data
|
||||||
|
PVOID Buffer, // Buffer to fill
|
||||||
|
DWORD StartSector, // Start sector
|
||||||
|
DWORD ReadSize); // Number of sectors to read
|
||||||
|
|
||||||
|
} CDIO_READ, *PCDIO_READ;
|
||||||
|
|
||||||
|
// Get a sector from buffer and lock it
|
||||||
|
extern PBYTE GetSectorBuffered(
|
||||||
|
PCDIO_READ This,
|
||||||
|
DWORD SectorNumber);
|
||||||
|
|
||||||
|
// Release a locked buffer
|
||||||
|
extern void ReleaseBufferedSector(
|
||||||
|
PCDIO_READ This,
|
||||||
|
DWORD SectorNumber);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // __BUFFERED_IO_H__
|
|
@ -0,0 +1,513 @@
|
||||||
|
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
|
||||||
|
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
|
||||||
|
#define _CXBXKRNL_INTERNAL
|
||||||
|
#define _XBOXKRNL_DEFEXTRN_
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
#include "xdvdfs.h"
|
||||||
|
|
||||||
|
#define UPPERCASE(a) (((a) > 0x60) ? ((a) & 0xDF) : (a))
|
||||||
|
|
||||||
|
#ifndef MIN
|
||||||
|
#define MIN(a,b) (((a)<(b))?(a):(b))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef DIRECTORY_SEPARATOR
|
||||||
|
#ifdef _WIN32
|
||||||
|
#define DIRECTORY_SEPARATOR '\\'
|
||||||
|
#else
|
||||||
|
#define DIRECTORY_SEPARATOR '/'
|
||||||
|
#endif // _WIN32
|
||||||
|
#endif // DIRECTORY_SEPARATOR
|
||||||
|
|
||||||
|
#define TRANSFER_SIZE 32 // Read granularity (in sectors) = 32 * 2048 = 64 Kb
|
||||||
|
|
||||||
|
#define VOLUME_DESCRIPTOR_SECTOR_OFFSET 32
|
||||||
|
|
||||||
|
#if BYTE_ORDER == BIG_ENDIAN
|
||||||
|
//#define ENDIAN_SAFE16(a) ((((a)&0xFF00)>>8)|(((a)&0xFF)<<8))
|
||||||
|
#define ENDIAN_SAFE32(a) ((((a)&0xFF000000)>>24)|(((a)&0x00FF0000)>>8)|(((a)&0x0000FF00)<<8)|(((a)&0xFF)<<24))
|
||||||
|
#elif BYTE_ORDER == LITTLE_ENDIAN
|
||||||
|
//#define ENDIAN_SAFE16(a) (a)
|
||||||
|
#define ENDIAN_SAFE32(a) (a)
|
||||||
|
#else
|
||||||
|
#error "xdvdfs.c: Looks like endianness is not defined."
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Directory Entry
|
||||||
|
typedef struct {
|
||||||
|
WORD LeftSubTree;
|
||||||
|
WORD RightSubTree;
|
||||||
|
DWORD FileStartSector;
|
||||||
|
DWORD FileSize;
|
||||||
|
BYTE FileAttributes;
|
||||||
|
BYTE FilenameLength;
|
||||||
|
BYTE Filename[FILENAME_SIZE];
|
||||||
|
} XDVDFS_DIRECTORY_ENTRY, *PXDVDFS_DIRECTORY_ENTRY;
|
||||||
|
|
||||||
|
// XDVDFS init a session object
|
||||||
|
BOOL XDVDFS_Mount(
|
||||||
|
PXDVDFS_SESSION Session,
|
||||||
|
BOOL (*ReadFunc)(PVOID, PVOID, DWORD, DWORD),
|
||||||
|
PVOID Data)
|
||||||
|
{
|
||||||
|
Session->Read.Data = Data;
|
||||||
|
Session->Read.Sectors = ReadFunc;
|
||||||
|
|
||||||
|
XDVDFS_UnMount(Session);
|
||||||
|
|
||||||
|
// scan sectors until the signature is found
|
||||||
|
Session->FileSystemBaseSector = 0;
|
||||||
|
while (1) {
|
||||||
|
// Read in the volume descriptor
|
||||||
|
if (!Session->Read.Sectors(
|
||||||
|
Session->Read.Data,
|
||||||
|
(PVOID)&Session->Root,
|
||||||
|
// the actual root of the filesystem is 32 sectors back
|
||||||
|
Session->FileSystemBaseSector + VOLUME_DESCRIPTOR_SECTOR_OFFSET,
|
||||||
|
1))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
// Check signatures
|
||||||
|
if ((memcmp(Session->Root.Signature1, XDVDFS_Signature, SIGNATURE_SIZE) == 0) &&
|
||||||
|
(memcmp(Session->Root.Signature2, XDVDFS_Signature, SIGNATURE_SIZE) == 0)) {
|
||||||
|
/* From https://github.com/multimediamike/xbfuse/blob/master/src/xdvdfs.c#L258 :
|
||||||
|
// process the volume descriptor
|
||||||
|
root_directory_sector = LE_32(§or_buffer[0x14]);
|
||||||
|
root_directory_size = LE_32(§or_buffer[0x18]);
|
||||||
|
memcpy(timestamp, §or_buffer[0x1C], 8);
|
||||||
|
|
||||||
|
fprintf(stderr, "root @ sector 0x%X, 0x%X bytes; time = %02X %02X %02X %02X %02X %02X %02X %02X\n",
|
||||||
|
root_directory_sector, root_directory_size,
|
||||||
|
timestamp[0], timestamp[1], timestamp[2], timestamp[3],
|
||||||
|
timestamp[4], timestamp[5], timestamp[6], timestamp[7]);
|
||||||
|
*/
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
Session->FileSystemBaseSector++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// XDVDFS deinit a session object
|
||||||
|
BOOL XDVDFS_UnMount(
|
||||||
|
PXDVDFS_SESSION Session)
|
||||||
|
{
|
||||||
|
// Reset ring buffer
|
||||||
|
memset(Session->Read.SectorList, 0, sizeof(DWORD) * DISK_BUFFER);
|
||||||
|
memset(Session->Read.LockList, 0, sizeof(DWORD) * DISK_BUFFER);
|
||||||
|
Session->Read.WriteIndex = 0;
|
||||||
|
// Invalidate all open files & search structures
|
||||||
|
Session->Magic++;
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize a search record with root dir
|
||||||
|
// Note: Can return XDVDFS_NO_MORE_FILES if the image is empty
|
||||||
|
DWORD XDVDFS_GetRootDir(
|
||||||
|
PXDVDFS_SESSION Session,
|
||||||
|
PSEARCH_RECORD SearchRecord)
|
||||||
|
{
|
||||||
|
if (!Session->Root.RootDirectorySize)
|
||||||
|
return XDVDFS_NO_MORE_FILES;
|
||||||
|
|
||||||
|
SearchRecord->Magic = Session->Magic;
|
||||||
|
// Cxbx addition : Correct all sector-numbers with file system base sector :
|
||||||
|
SearchRecord->SearchStartSector = ENDIAN_SAFE32(Session->Root.RootDirectory) + Session->FileSystemBaseSector;
|
||||||
|
SearchRecord->DirectorySize = ENDIAN_SAFE32(Session->Root.RootDirectorySize);
|
||||||
|
SearchRecord->Position = 0;
|
||||||
|
return XDVDFS_NO_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enumerate files
|
||||||
|
DWORD XDVDFS_EnumFiles(
|
||||||
|
PXDVDFS_SESSION Session,
|
||||||
|
PSEARCH_RECORD SearchRecord)
|
||||||
|
{
|
||||||
|
PXDVDFS_DIRECTORY_ENTRY Entry;
|
||||||
|
DWORD SectorNumber, Position, i;
|
||||||
|
PBYTE Ptr;
|
||||||
|
|
||||||
|
enum_retry:
|
||||||
|
// Check structure validity
|
||||||
|
if (SearchRecord->Magic != Session->Magic)
|
||||||
|
return XDVDFS_EXPIRED_SESSION;
|
||||||
|
|
||||||
|
// Check if we reached the end of the directory
|
||||||
|
if (SearchRecord->Position >= SearchRecord->DirectorySize)
|
||||||
|
return XDVDFS_NO_MORE_FILES;
|
||||||
|
|
||||||
|
// Get current position in sector, remainder
|
||||||
|
SectorNumber = SearchRecord->Position / SECTOR_SIZE;
|
||||||
|
Position = SearchRecord->Position % SECTOR_SIZE;
|
||||||
|
// Get the current sector in buffer and lock it
|
||||||
|
Ptr = GetSectorBuffered(&Session->Read,
|
||||||
|
SectorNumber + SearchRecord->SearchStartSector);
|
||||||
|
if (!Ptr)
|
||||||
|
return XDVDFS_DISK_ERROR;
|
||||||
|
|
||||||
|
// If we're at the begining...
|
||||||
|
if (!SearchRecord->Position)
|
||||||
|
{
|
||||||
|
// ...bufferize the whole dir.
|
||||||
|
for(i = 1;i < MIN(DISK_BUFFER - 1, SearchRecord->DirectorySize / SECTOR_SIZE);i++)
|
||||||
|
{
|
||||||
|
GetSectorBuffered(&Session->Read, i + SearchRecord->SearchStartSector);
|
||||||
|
ReleaseBufferedSector(&Session->Read, i + SearchRecord->SearchStartSector);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Entry = (PXDVDFS_DIRECTORY_ENTRY)&Ptr[Position];
|
||||||
|
// If Entry->FileStartSector = 0xFFFFFFFF or Position > 2040, we reached the last
|
||||||
|
// entry of the sector
|
||||||
|
if ((Position > (SECTOR_SIZE - offsetof(XDVDFS_DIRECTORY_ENTRY, FileStartSector)))||(Entry->FileStartSector == 0xFFFFFFFF))
|
||||||
|
{
|
||||||
|
// Let's get the next one
|
||||||
|
ReleaseBufferedSector(&Session->Read,
|
||||||
|
SectorNumber + SearchRecord->SearchStartSector);
|
||||||
|
SearchRecord->Position = (SearchRecord->Position & ~(SECTOR_SIZE - 1)) + SECTOR_SIZE;
|
||||||
|
goto enum_retry;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy the filename (filenames up to 255 chars)
|
||||||
|
memcpy(SearchRecord->CurrentFilename, Entry->Filename, Entry->FilenameLength);
|
||||||
|
SearchRecord->CurrentFilename[Entry->FilenameLength] = 0;
|
||||||
|
// Copy file parameters in the search_rec
|
||||||
|
SearchRecord->CurrentFileAttributes = Entry->FileAttributes;
|
||||||
|
SearchRecord->CurrentFileSize = ENDIAN_SAFE32(Entry->FileSize);
|
||||||
|
// Cxbx addition : Correct all sector-numbers with file system base sector :
|
||||||
|
SearchRecord->CurrentFileStartSector = ENDIAN_SAFE32(Entry->FileStartSector) + Session->FileSystemBaseSector;
|
||||||
|
SearchRecord->CurrentFileEndSector = SearchRecord->CurrentFileStartSector
|
||||||
|
+ (SearchRecord->CurrentFileSize / SECTOR_SIZE);
|
||||||
|
if (SearchRecord->CurrentFileSize % SECTOR_SIZE)
|
||||||
|
SearchRecord->CurrentFileEndSector++;
|
||||||
|
|
||||||
|
// Advance to next entry
|
||||||
|
SearchRecord->Position += Entry->FilenameLength + offsetof(XDVDFS_DIRECTORY_ENTRY, Filename);
|
||||||
|
if (SearchRecord->Position & 3)
|
||||||
|
{
|
||||||
|
SearchRecord->Position &= ~3;
|
||||||
|
SearchRecord->Position += 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Free the buffer
|
||||||
|
ReleaseBufferedSector(&Session->Read,
|
||||||
|
SectorNumber + SearchRecord->SearchStartSector);
|
||||||
|
return XDVDFS_NO_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
DWORD XDVDFS_GetFileInfo(
|
||||||
|
PXDVDFS_SESSION Session,
|
||||||
|
LPSTR Filename,
|
||||||
|
PSEARCH_RECORD SearchRecord)
|
||||||
|
{
|
||||||
|
DWORD Length, i, ReturnCode;
|
||||||
|
|
||||||
|
// To begin, we will enter the root directory
|
||||||
|
XDVDFS_GetRootDir(Session, SearchRecord);
|
||||||
|
SearchRecord->CurrentFileStartSector = SearchRecord->SearchStartSector;
|
||||||
|
SearchRecord->CurrentFileSize = SearchRecord->DirectorySize;
|
||||||
|
SearchRecord->CurrentFileAttributes = XDVDFS_ATTRIBUTE_DIRECTORY;
|
||||||
|
SearchRecord->CurrentFilename[0] = 0;
|
||||||
|
// Skip leading backslash if present
|
||||||
|
if (*Filename == DIRECTORY_SEPARATOR)
|
||||||
|
Filename++;
|
||||||
|
|
||||||
|
while(*Filename)
|
||||||
|
{
|
||||||
|
// Skip backslashes
|
||||||
|
while(*Filename == DIRECTORY_SEPARATOR)
|
||||||
|
Filename++;
|
||||||
|
|
||||||
|
// If previously matched name is not a dir, fail
|
||||||
|
if (!(SearchRecord->CurrentFileAttributes & XDVDFS_ATTRIBUTE_DIRECTORY))
|
||||||
|
return XDVDFS_FILE_NOT_FOUND;
|
||||||
|
|
||||||
|
// Enter that directory
|
||||||
|
Length = 0;
|
||||||
|
SearchRecord->SearchStartSector = SearchRecord->CurrentFileStartSector;
|
||||||
|
SearchRecord->DirectorySize = SearchRecord->CurrentFileSize;
|
||||||
|
SearchRecord->Position = 0;
|
||||||
|
// Browse the contents of the dir
|
||||||
|
while( (ReturnCode = XDVDFS_EnumFiles(Session, SearchRecord)) ==
|
||||||
|
XDVDFS_NO_ERROR)
|
||||||
|
{
|
||||||
|
// Dxbx addition : Stop at first file if no further path is given
|
||||||
|
if (*Filename == 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Calculate length of the filename
|
||||||
|
Length = 0;
|
||||||
|
while( (SearchRecord->CurrentFilename[Length])&&
|
||||||
|
(SearchRecord->CurrentFilename[Length] != DIRECTORY_SEPARATOR) )
|
||||||
|
Length++;
|
||||||
|
|
||||||
|
// Match the filename against the one given
|
||||||
|
for(i = 0;i < Length;i++)
|
||||||
|
{
|
||||||
|
if ((Filename[i] == DIRECTORY_SEPARATOR)||
|
||||||
|
(!Filename[i])||
|
||||||
|
(UPPERCASE(Filename[i]) !=
|
||||||
|
UPPERCASE(SearchRecord->CurrentFilename[i])))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If it matched, exit
|
||||||
|
if ((i == Length)&&((Filename[i] == 0)
|
||||||
|
||(Filename[i] == DIRECTORY_SEPARATOR)))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we reached the end of the dir without matching, fail
|
||||||
|
if (ReturnCode == XDVDFS_NO_MORE_FILES)
|
||||||
|
return XDVDFS_FILE_NOT_FOUND;
|
||||||
|
|
||||||
|
// If any other error occured, fail
|
||||||
|
if (ReturnCode != XDVDFS_NO_ERROR)
|
||||||
|
return ReturnCode;
|
||||||
|
|
||||||
|
// Match next part of the given filename
|
||||||
|
Filename += Length;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we land here, everything matched and the SEARCH_RECORD structure is
|
||||||
|
// filled.
|
||||||
|
return XDVDFS_NO_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize a search record given a path
|
||||||
|
DWORD XDVDFS_OpenFolder(
|
||||||
|
PXDVDFS_SESSION Session,
|
||||||
|
LPSTR Path,
|
||||||
|
PSEARCH_RECORD SearchRecord)
|
||||||
|
{
|
||||||
|
DWORD ReturnCode;
|
||||||
|
|
||||||
|
// Find a file matching the given path
|
||||||
|
ReturnCode = XDVDFS_GetFileInfo(Session, Path, SearchRecord);
|
||||||
|
// If an error occured, fail
|
||||||
|
if (ReturnCode != XDVDFS_NO_ERROR)
|
||||||
|
return ReturnCode;
|
||||||
|
|
||||||
|
// If the returned file is not a dir, fail
|
||||||
|
if (!(SearchRecord->CurrentFileAttributes & XDVDFS_ATTRIBUTE_DIRECTORY))
|
||||||
|
return XDVDFS_FILE_NOT_FOUND;
|
||||||
|
|
||||||
|
// Copy folder info into the SEARCH_RECORD structure
|
||||||
|
SearchRecord->SearchStartSector = SearchRecord->CurrentFileStartSector;
|
||||||
|
SearchRecord->DirectorySize = SearchRecord->CurrentFileSize;
|
||||||
|
SearchRecord->Position = 0;
|
||||||
|
return XDVDFS_NO_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Open a file
|
||||||
|
DWORD XDVDFS_OpenFile(
|
||||||
|
PXDVDFS_SESSION Session,
|
||||||
|
LPSTR Filename,
|
||||||
|
PFILE_RECORD FileRecord)
|
||||||
|
{
|
||||||
|
SEARCH_RECORD SearchRecord;
|
||||||
|
DWORD ReturnCode;
|
||||||
|
|
||||||
|
// Find a file matching the given path
|
||||||
|
ReturnCode = XDVDFS_GetFileInfo(Session, Filename, &SearchRecord);
|
||||||
|
// If an error occured, fail
|
||||||
|
if (ReturnCode != XDVDFS_NO_ERROR)
|
||||||
|
return ReturnCode;
|
||||||
|
|
||||||
|
// If the returned file is a dir, fail
|
||||||
|
if (SearchRecord.CurrentFileAttributes & XDVDFS_ATTRIBUTE_DIRECTORY)
|
||||||
|
return XDVDFS_FILE_NOT_FOUND;
|
||||||
|
|
||||||
|
// Copy file info into the FILE_RECORD structure
|
||||||
|
FileRecord->Magic = SearchRecord.Magic;
|
||||||
|
FileRecord->PartialSector = 0;
|
||||||
|
FileRecord->FileStartSector = SearchRecord.CurrentFileStartSector;
|
||||||
|
FileRecord->FileSize = SearchRecord.CurrentFileSize;
|
||||||
|
FileRecord->CurrentPosition = 0;
|
||||||
|
return XDVDFS_NO_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Open a file pointed by a search rec
|
||||||
|
DWORD XDVDFS_OpenFileEx(
|
||||||
|
PXDVDFS_SESSION Session,
|
||||||
|
PSEARCH_RECORD SearchRecord,
|
||||||
|
PFILE_RECORD FileRecord)
|
||||||
|
{
|
||||||
|
// Check structure validity
|
||||||
|
if (SearchRecord->Magic != Session->Magic)
|
||||||
|
return XDVDFS_EXPIRED_SESSION;
|
||||||
|
|
||||||
|
// Do not accept a directory
|
||||||
|
if (SearchRecord->CurrentFileAttributes & XDVDFS_ATTRIBUTE_DIRECTORY)
|
||||||
|
return XDVDFS_FILE_NOT_FOUND;
|
||||||
|
|
||||||
|
// Copy file info into the FILE_RECORD structure
|
||||||
|
FileRecord->Magic = SearchRecord->Magic;
|
||||||
|
FileRecord->PartialSector = 0;
|
||||||
|
FileRecord->FileStartSector = SearchRecord->CurrentFileStartSector;
|
||||||
|
FileRecord->FileSize = SearchRecord->CurrentFileSize;
|
||||||
|
FileRecord->CurrentPosition = 0;
|
||||||
|
return XDVDFS_NO_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read a file
|
||||||
|
DWORD XDVDFS_FileRead(
|
||||||
|
PXDVDFS_SESSION Session,
|
||||||
|
PFILE_RECORD FileRecord,
|
||||||
|
PVOID OutBuffer,
|
||||||
|
DWORD Size)
|
||||||
|
{
|
||||||
|
DWORD CurrentSector, Position, PartialRead, Readed, i;
|
||||||
|
PBYTE Buffer = (PBYTE)OutBuffer;
|
||||||
|
|
||||||
|
Readed = 0;
|
||||||
|
// Check structure validity
|
||||||
|
if (FileRecord->Magic != Session->Magic)
|
||||||
|
return Readed;
|
||||||
|
|
||||||
|
// Limit read size
|
||||||
|
if ((FileRecord->CurrentPosition + Size) > FileRecord->FileSize)
|
||||||
|
Size = FileRecord->FileSize - FileRecord->CurrentPosition;
|
||||||
|
|
||||||
|
// Dxbx addition : Stop if there's nothing to read
|
||||||
|
if (!Size)
|
||||||
|
return Readed;
|
||||||
|
|
||||||
|
// Process partial sector read before
|
||||||
|
Position = FileRecord->CurrentPosition % SECTOR_SIZE;
|
||||||
|
if (Position)
|
||||||
|
{
|
||||||
|
CurrentSector = (FileRecord->CurrentPosition / SECTOR_SIZE) +
|
||||||
|
FileRecord->FileStartSector;
|
||||||
|
PartialRead = MIN(Size, SECTOR_SIZE - Position);
|
||||||
|
if (FileRecord->PartialSector != CurrentSector)
|
||||||
|
{
|
||||||
|
if (!Session->Read.Sectors(
|
||||||
|
Session->Read.Data,
|
||||||
|
FileRecord->PartialData,
|
||||||
|
CurrentSector,
|
||||||
|
1))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
FileRecord->PartialSector = CurrentSector;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(i = 0;i < PartialRead;i++)
|
||||||
|
*Buffer++ = FileRecord->PartialData[Position++];
|
||||||
|
|
||||||
|
Size -= PartialRead;
|
||||||
|
Readed += PartialRead;
|
||||||
|
FileRecord->CurrentPosition += PartialRead;
|
||||||
|
if (!Size)
|
||||||
|
return Readed;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process entire sector read
|
||||||
|
PartialRead = Size / SECTOR_SIZE;
|
||||||
|
if (PartialRead)
|
||||||
|
{
|
||||||
|
CurrentSector = (FileRecord->CurrentPosition / SECTOR_SIZE) + FileRecord->FileStartSector;
|
||||||
|
i = PartialRead;
|
||||||
|
while(i > 0)
|
||||||
|
{
|
||||||
|
Position = MIN(i, TRANSFER_SIZE);
|
||||||
|
if (!Session->Read.Sectors(
|
||||||
|
Session->Read.Data,
|
||||||
|
Buffer,
|
||||||
|
CurrentSector,
|
||||||
|
Position))
|
||||||
|
return Readed;
|
||||||
|
|
||||||
|
Buffer += Position * SECTOR_SIZE;
|
||||||
|
CurrentSector += Position;
|
||||||
|
i -= Position;
|
||||||
|
}
|
||||||
|
|
||||||
|
PartialRead *= SECTOR_SIZE;
|
||||||
|
Size -= PartialRead;
|
||||||
|
Readed += PartialRead;
|
||||||
|
FileRecord->CurrentPosition += PartialRead;
|
||||||
|
if (!Size)
|
||||||
|
return Readed;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process partial sector read after
|
||||||
|
PartialRead = Size;
|
||||||
|
CurrentSector = (FileRecord->CurrentPosition / SECTOR_SIZE)
|
||||||
|
+ FileRecord->FileStartSector;
|
||||||
|
if (FileRecord->PartialSector != CurrentSector)
|
||||||
|
{
|
||||||
|
if (!Session->Read.Sectors(
|
||||||
|
Session->Read.Data,
|
||||||
|
FileRecord->PartialData,
|
||||||
|
CurrentSector,
|
||||||
|
1))
|
||||||
|
return Readed;
|
||||||
|
|
||||||
|
FileRecord->PartialSector = CurrentSector;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(i = 0;i < PartialRead;i++)
|
||||||
|
*Buffer++ = FileRecord->PartialData[i];
|
||||||
|
|
||||||
|
Readed += PartialRead;
|
||||||
|
FileRecord->CurrentPosition += PartialRead;
|
||||||
|
return Readed;
|
||||||
|
}
|
||||||
|
|
||||||
|
DWORD XDVDFS_FileClose(
|
||||||
|
PXDVDFS_SESSION Session,
|
||||||
|
PFILE_RECORD FileRecord)
|
||||||
|
{
|
||||||
|
// Check structure validity
|
||||||
|
if (FileRecord->Magic != Session->Magic)
|
||||||
|
return XDVDFS_EXPIRED_SESSION;
|
||||||
|
|
||||||
|
// Invalidate the structure
|
||||||
|
FileRecord->Magic--;
|
||||||
|
return XDVDFS_NO_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
DWORD XDVDFS_FileSeek(
|
||||||
|
PXDVDFS_SESSION Session,
|
||||||
|
PFILE_RECORD FileRecord,
|
||||||
|
int Delta,
|
||||||
|
DWORD SeekMode)
|
||||||
|
{
|
||||||
|
// Check structure validity
|
||||||
|
if (FileRecord->Magic != Session->Magic)
|
||||||
|
return XDVDFS_EXPIRED_SESSION;
|
||||||
|
|
||||||
|
// Change file pointer
|
||||||
|
switch(SeekMode)
|
||||||
|
{
|
||||||
|
case SM_BEGIN:
|
||||||
|
FileRecord->CurrentPosition = Delta;
|
||||||
|
break;
|
||||||
|
case SM_CURRENT:
|
||||||
|
FileRecord->CurrentPosition += Delta;
|
||||||
|
break;
|
||||||
|
case SM_END:
|
||||||
|
FileRecord->CurrentPosition = FileRecord->FileSize - Delta;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return XDVDFS_INVALID_PARAMETER;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check the file pointer for limits
|
||||||
|
if (FileRecord->CurrentPosition > FileRecord->FileSize)
|
||||||
|
{
|
||||||
|
if (Delta < 0)
|
||||||
|
FileRecord->CurrentPosition = 0;
|
||||||
|
else
|
||||||
|
FileRecord->CurrentPosition = FileRecord->FileSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
return XDVDFS_NO_ERROR;
|
||||||
|
}
|
|
@ -0,0 +1,166 @@
|
||||||
|
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
|
||||||
|
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
|
||||||
|
#ifndef __XDVDFS_H__
|
||||||
|
#define __XDVDFS_H__
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <xboxkrnl/xboxkrnl.h> //#include <stdtypes.h>
|
||||||
|
|
||||||
|
#include "buffered_io.h"
|
||||||
|
|
||||||
|
CONST CHAR *XDVDFS_Signature = "MICROSOFT*XBOX*MEDIA";
|
||||||
|
|
||||||
|
//-- Defines ------------------------------------------------------------------
|
||||||
|
|
||||||
|
#define SIGNATURE_SIZE sizeof(XDVDFS_Signature)
|
||||||
|
|
||||||
|
#define FILENAME_SIZE 256
|
||||||
|
|
||||||
|
// Attributes
|
||||||
|
#define XDVDFS_ATTRIBUTE_READONLY 0x01
|
||||||
|
#define XDVDFS_ATTRIBUTE_HIDDEN 0x02
|
||||||
|
#define XDVDFS_ATTRIBUTE_SYSTEM 0x04
|
||||||
|
#define XDVDFS_ATTRIBUTE_DIRECTORY 0x10
|
||||||
|
#define XDVDFS_ATTRIBUTE_ARCHIVE 0x20
|
||||||
|
#define XDVDFS_ATTRIBUTE_NORMAL 0x80
|
||||||
|
|
||||||
|
// Error Codes
|
||||||
|
#define XDVDFS_NO_ERROR 0
|
||||||
|
#define XDVDFS_EXPIRED_SESSION 1
|
||||||
|
#define XDVDFS_NO_MORE_FILES 2
|
||||||
|
#define XDVDFS_DISK_ERROR 3
|
||||||
|
#define XDVDFS_FILE_NOT_FOUND 4
|
||||||
|
#define XDVDFS_INVALID_PARAMETER 5
|
||||||
|
|
||||||
|
// Seek Modes
|
||||||
|
#define SM_BEGIN 0
|
||||||
|
#define SM_CURRENT 1
|
||||||
|
#define SM_END 2
|
||||||
|
|
||||||
|
//-- Type Definitions ---------------------------------------------------------
|
||||||
|
|
||||||
|
// XDVDFS Volume descriptor
|
||||||
|
typedef struct {
|
||||||
|
BYTE Signature1[SIGNATURE_SIZE];
|
||||||
|
DWORD RootDirectory;
|
||||||
|
DWORD RootDirectorySize;
|
||||||
|
FILETIME ImageCreationTime;
|
||||||
|
BYTE Unused[1992];
|
||||||
|
BYTE Signature2[SIGNATURE_SIZE];
|
||||||
|
} XDVDFS_VOLUME_DESCRIPTOR, *PXDVDFS_VOLUME_DESCRIPTOR;
|
||||||
|
|
||||||
|
// XDVDFS session
|
||||||
|
typedef struct {
|
||||||
|
// Start sector of current session
|
||||||
|
DWORD FileSystemBaseSector;
|
||||||
|
|
||||||
|
// Volume Descriptor of the current session
|
||||||
|
XDVDFS_VOLUME_DESCRIPTOR Root;
|
||||||
|
|
||||||
|
// Our little interface for reading sectors
|
||||||
|
CDIO_READ Read;
|
||||||
|
|
||||||
|
// The dword below is incremented when the filesystem is unmounted
|
||||||
|
// automatically invalidating all open files and search records
|
||||||
|
DWORD Magic;
|
||||||
|
} XDVDFS_SESSION, *PXDVDFS_SESSION;
|
||||||
|
|
||||||
|
// File Record
|
||||||
|
typedef struct {
|
||||||
|
DWORD Magic;
|
||||||
|
BYTE PartialData[SECTOR_SIZE];
|
||||||
|
DWORD PartialSector;
|
||||||
|
DWORD FileStartSector;
|
||||||
|
DWORD FileSize;
|
||||||
|
DWORD CurrentPosition;
|
||||||
|
} FILE_RECORD, *PFILE_RECORD;
|
||||||
|
|
||||||
|
// Search Record
|
||||||
|
typedef struct {
|
||||||
|
DWORD Magic;
|
||||||
|
DWORD SearchStartSector;
|
||||||
|
DWORD DirectorySize;
|
||||||
|
DWORD Position;
|
||||||
|
BYTE CurrentFilename[FILENAME_SIZE];
|
||||||
|
DWORD CurrentFileAttributes;
|
||||||
|
DWORD CurrentFileSize;
|
||||||
|
DWORD CurrentFileStartSector;
|
||||||
|
DWORD CurrentFileEndSector;
|
||||||
|
} SEARCH_RECORD, *PSEARCH_RECORD;
|
||||||
|
|
||||||
|
//-- Exported Functions -------------------------------------------------------
|
||||||
|
|
||||||
|
// XDVDFS init a session object
|
||||||
|
extern BOOL XDVDFS_Mount(
|
||||||
|
PXDVDFS_SESSION Session,
|
||||||
|
BOOL (*ReadFunc)(PVOID, PVOID, DWORD, DWORD),
|
||||||
|
PVOID Data);
|
||||||
|
|
||||||
|
// XDVDFS deinit a session object
|
||||||
|
extern BOOL XDVDFS_UnMount(
|
||||||
|
PXDVDFS_SESSION Session);
|
||||||
|
|
||||||
|
// Initialize a search record with root dir
|
||||||
|
// Note: Can return XDVDFS_NO_MORE_FILES if the image is empty
|
||||||
|
extern DWORD XDVDFS_GetRootDir(
|
||||||
|
PXDVDFS_SESSION Session,
|
||||||
|
PSEARCH_RECORD SearchRecord);
|
||||||
|
|
||||||
|
// Enumerate files
|
||||||
|
extern DWORD XDVDFS_EnumFiles(
|
||||||
|
PXDVDFS_SESSION Session,
|
||||||
|
PSEARCH_RECORD SearchRecord);
|
||||||
|
|
||||||
|
// Find a file given its path
|
||||||
|
extern DWORD XDVDFS_GetFileInfo(
|
||||||
|
PXDVDFS_SESSION Session,
|
||||||
|
LPSTR Filename,
|
||||||
|
PSEARCH_RECORD SearchRecord);
|
||||||
|
|
||||||
|
// Initialize a search record given a path
|
||||||
|
extern DWORD XDVDFS_OpenFolder(
|
||||||
|
PXDVDFS_SESSION Session,
|
||||||
|
LPSTR Path,
|
||||||
|
PSEARCH_RECORD SearchRecord);
|
||||||
|
|
||||||
|
// Open a file
|
||||||
|
extern DWORD XDVDFS_OpenFile(
|
||||||
|
PXDVDFS_SESSION Session,
|
||||||
|
LPSTR Filename,
|
||||||
|
PFILE_RECORD FileRecord);
|
||||||
|
|
||||||
|
// Open a file pointed by a search rec
|
||||||
|
extern DWORD XDVDFS_OpenFileEx(
|
||||||
|
PXDVDFS_SESSION Session,
|
||||||
|
PSEARCH_RECORD SearchRecord,
|
||||||
|
PFILE_RECORD FileRecord);
|
||||||
|
|
||||||
|
// Read a file
|
||||||
|
extern DWORD XDVDFS_FileRead(
|
||||||
|
PXDVDFS_SESSION Session,
|
||||||
|
PFILE_RECORD FileRecord,
|
||||||
|
PVOID Buffer,
|
||||||
|
DWORD Size);
|
||||||
|
|
||||||
|
// Close file
|
||||||
|
extern DWORD XDVDFS_FileClose(
|
||||||
|
PXDVDFS_SESSION Session,
|
||||||
|
PFILE_RECORD FileRecord);
|
||||||
|
|
||||||
|
// File seek
|
||||||
|
extern DWORD XDVDFS_FileSeek(
|
||||||
|
PXDVDFS_SESSION Session,
|
||||||
|
PFILE_RECORD FileRecord,
|
||||||
|
int Delta,
|
||||||
|
DWORD SeekMode);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // __XDVDFS_H__
|
Loading…
Reference in New Issue