예제 #1
0
        public override unsafe Native.NtStatus NtReadFileImpl(IntPtr handle, IntPtr hEvent, IntPtr *apcRoutine, IntPtr *apcContext,
                                                              ref Native.IO_STATUS_BLOCK ioStatus, byte *buffer, uint length, LARGE_INTEGER *byteOffset, IntPtr key)
        {
            var cpk       = mCpkByHandle[handle];
            var effOffset = Utils.ResolveReadFileOffset(cpk.FilePointer, byteOffset);

            Unsafe.CopyBlock(buffer, (byte *)cpk.Instance.Native.Ptr + effOffset, length);
            SetBytesRead(handle, (int)cpk.FilePointer, (int)length, ref ioStatus);
            return(NtStatus.Success);
        }
예제 #2
0
        public override unsafe Native.NtStatus NtReadFileImpl(IntPtr handle, IntPtr hEvent, IntPtr *apcRoutine, IntPtr *apcContext,
                                                              ref Native.IO_STATUS_BLOCK ioStatus, byte *buffer, uint length, LARGE_INTEGER *byteOffset, IntPtr key)
        {
            NtStatus result;
            var      packHandle = mPacksByHandle[handle];
            var      pack       = packHandle.Instance;
            var      offset     = packHandle.FilePointer;
            var      reqOffset  = (byteOffset != null || (byteOffset != null && byteOffset->HighPart == -1 && byteOffset->LowPart == FILE_USE_FILE_POINTER_POSITION)) ?
                                  byteOffset->QuadPart : -1;
            var effOffset  = reqOffset == -1 ? offset : reqOffset;
            var dataOffset = pack.Native.Data - pack.Native.Ptr;

            if ((effOffset + length) <= dataOffset)
            {
                // Header read
                if (effOffset >= sizeof(DwPackHeader))
                {
                    // Ensure entry is redirected before entry is read
                    // This improves startup times greatly, as otherwise thousands of redirections could potentially have to be done at
                    // startup
                    var entryIndex = ( int )((effOffset - sizeof(DwPackHeader)) / sizeof(DwPackEntry));
                    if (!pack.Entries[entryIndex].RedirectAttempted)
                    {
                        pack.Entries[entryIndex].Redirect(mModDb);
                    }
                }

                Unsafe.CopyBlock(buffer, pack.Native.Ptr + effOffset, length);
                SetBytesRead(handle, ( int )offset, ( int )length, ref ioStatus);
                result = NtStatus.Success;
            }
            else if (effOffset >= dataOffset && effOffset < pack.VirtualFileSize)
            {
                result = ReadFile(handle, hEvent, apcRoutine, apcContext, ref ioStatus, buffer, length, byteOffset, key, pack, offset, effOffset);
            }
            else
            {
                mLogger.Error($"{pack.FileName} Hnd: {handle} Unexpected read request!! Offset: {effOffset:X8} Length: {length:X8}");
                result = mHooks.NtReadFileHook.OriginalFunction(handle, hEvent, apcRoutine, apcContext, ref ioStatus, buffer, length, byteOffset, key);
            }

            if (result != NtStatus.Success)
            {
                mLogger.Error($"{pack.FileName} Hnd: {handle} NtReadFile failed with {result}!!!");
            }

            return(result);
        }
예제 #3
0
        public override unsafe NtStatus NtQueryInformationFileImpl(IntPtr hfile, out Native.IO_STATUS_BLOCK ioStatusBlock, void *fileInformation, uint length, Native.FileInformationClass fileInformationClass)
        {
            var result = mHooks.NtQueryInformationFileHook.OriginalFunction(hfile, out ioStatusBlock, fileInformation, length, fileInformationClass);

            if (!mPacksByHandle.TryGetValue(hfile, out var pack))
            {
                return(result);
            }

            if (fileInformationClass == FileInformationClass.FileStandardInformation)
            {
                var info = (FILE_STANDARD_INFORMATION *)fileInformation;
                info->EndOfFile = uint.MaxValue;
            }
            else
            {
                mLogger.Debug($"NtQueryInformationFileImpl( IntPtr hfile = {hfile}, out Native.IO_STATUS_BLOCK ioStatusBlock, void* fileInformation, length = {length}, fileInformationClass = {fileInformationClass} )");
            }

            return(result);
        }
예제 #4
0
        public override Native.NtStatus NtCreateFileImpl(string newFilePath, out IntPtr handle, FileAccess access, ref Native.OBJECT_ATTRIBUTES objectAttributes,
                                                         ref Native.IO_STATUS_BLOCK ioStatus, ref long allocSize, uint fileAttributes, FileShare share, uint createDisposition, uint createOptions, IntPtr eaBuffer, uint eaLength)
        {
            var result = mHooks.NtCreateFileHook.OriginalFunction(out handle, access, ref objectAttributes, ref ioStatus, ref allocSize, fileAttributes,
                                                                  share, createDisposition, createOptions, eaBuffer, eaLength);

            var              fileName   = Path.GetFileNameWithoutExtension(newFilePath);
            var              ext        = Path.GetExtension(newFilePath);
            var              isWaveBank = ext.Equals(".xwb", StringComparison.OrdinalIgnoreCase);
            VirtualWaveBank  waveBank   = null;
            VirtualSoundBank soundBank  = null;

            if (isWaveBank && !mWaveBankByName.TryGetValue(fileName, out waveBank))
            {
                // Try get sound bank for cue names
                mSoundBankByName.TryGetValue(fileName, out soundBank);

                // Wave bank
                mWaveBankByName[fileName] = waveBank = new VirtualWaveBank(mLogger);

                // Load wave bank
                using (var fileStream = new FileStream(new SafeFileHandle(handle, true), FileAccess.Read, 1024 * 1024))
                    waveBank.LoadFromFile(newFilePath, fileStream);

                // Reopen file to reset it
                result = mHooks.NtCreateFileHook.OriginalFunction(out handle, access, ref objectAttributes, ref ioStatus, ref allocSize, fileAttributes,
                                                                  share, createDisposition, createOptions, eaBuffer, eaLength);

                ProcessWaveBankEntries(newFilePath, soundBank, waveBank);
                mLogger.Debug($"{newFilePath} registered");
            }
            else if (!mSoundBankByName.TryGetValue(fileName, out soundBank))
            {
                // Sound bank
                mSoundBankByName[fileName] = soundBank = new VirtualSoundBank(mLogger);

                // Load wave bank
                using (var fileStream = new FileStream(new SafeFileHandle(handle, true), FileAccess.Read, 1024 * 1024))
                    soundBank.LoadFromFile(newFilePath, fileStream);

                // Reopen file to reset it
                result = mHooks.NtCreateFileHook.OriginalFunction(out handle, access, ref objectAttributes, ref ioStatus, ref allocSize, fileAttributes,
                                                                  share, createDisposition, createOptions, eaBuffer, eaLength);

                // Find associated wave bank
                if (!mWaveBankByName.TryGetValue(soundBank.Native.WaveBankNames[0].Name, out waveBank))
                {
                    mLogger.Error($"{newFilePath} Can't find wavebank!");
                }
                else
                {
                    ProcessWaveBankEntries(newFilePath, soundBank, waveBank);
                }
            }

            if (isWaveBank)
            {
                mWaveBankByHandle.Add(handle, waveBank);
                mLogger.Debug($"{waveBank.FileName} Hnd {handle} registered");
            }
            else
            {
                mSoundBankByHandle.Add(handle, soundBank);
            }


            return(result);
        }
예제 #5
0
        public override unsafe Native.NtStatus NtReadFileImpl(IntPtr handle, IntPtr hEvent, IntPtr *apcRoutine, IntPtr *apcContext, ref Native.IO_STATUS_BLOCK ioStatus,
                                                              byte *buffer, uint length, Native.LARGE_INTEGER *byteOffset, IntPtr key)
        {
            if (!mWaveBankByHandle.TryGetValue(handle, out var waveBank))
            {
                return(mHooks.NtReadFileHook.OriginalFunction(handle, hEvent, apcRoutine, apcContext, ref ioStatus, buffer, length, byteOffset, key));
            }

            var offset    = waveBank.FilePointer;
            var reqOffset = (byteOffset != null || (byteOffset != null && byteOffset->HighPart == -1 && byteOffset->LowPart == FILE_USE_FILE_POINTER_POSITION)) ?
                            byteOffset->QuadPart : -1;
            var effOffset = reqOffset == -1 ? offset : reqOffset;

            var result         = NtStatus.Success;
            var waveDataOffset = waveBank.Native.Header->Segments[(int)WaveBankSegmentIndex.EntryWaveData].Offset;

            if ((effOffset + length) <= waveDataOffset)
            {
                // Header read
                Unsafe.CopyBlock(buffer, waveBank.Native.Ptr + effOffset, length);
                SetBytesRead(handle, (int)offset, (int)length, ref ioStatus);
                result = NtStatus.Success;
            }
            else if (effOffset >= waveDataOffset && effOffset < waveBank.VirtualFileSize)
            {
                if ((waveBank.Native.Data->Flags & WaveBankFlags.Compact) != 0)
                {
                    // TODO: compact format
                    result = mHooks.NtReadFileHook.OriginalFunction(handle, hEvent, apcRoutine, apcContext, ref ioStatus, buffer, length, byteOffset, key);
                }
                else
                {
                    ReadEntryWaveData(waveBank, effOffset, handle, hEvent, apcRoutine, apcContext, ref ioStatus, buffer, length, byteOffset, key);
                }
            }
            else
            {
                mLogger.Error($"{waveBank.FileName} Hnd: {handle} Unexpected read request!! Offset: {effOffset:X8} Length: {length:X8}");
                result = mHooks.NtReadFileHook.OriginalFunction(handle, hEvent, apcRoutine, apcContext, ref ioStatus, buffer, length, byteOffset, key);
            }


            if (result != NtStatus.Success)
            {
                mLogger.Error($"{waveBank.FileName} Hnd: {handle} NtReadFile failed with {result}!!!");
            }

            return(result);
        }
예제 #6
0
        private NtStatus ReadEntryWaveData(VirtualWaveBank waveBank, long absOffset,
                                           IntPtr handle, IntPtr hEvent, IntPtr *apcRoutine, IntPtr *apcContext, ref Native.IO_STATUS_BLOCK ioStatus, byte *buffer, uint length, Native.LARGE_INTEGER *byteOffset, IntPtr key)
        {
            var status  = NtStatus.Success;
            var handled = false;

            var segBaseOffset = waveBank.Native.Header->Segments[(int)WaveBankSegmentIndex.EntryWaveData].Offset;
            var segOffset     = absOffset - segBaseOffset;

            for (int i = 0; i < waveBank.Entries.Count; i++)
            {
                var entry = waveBank.Entries[i];
                if (segOffset < entry.Native->PlayRegion.Offset || segOffset >= (entry.Native->PlayRegion.Offset + entry.Native->PlayRegion.Length))
                {
                    continue;
                }

                var fileDataOffset = segOffset - entry.Native->PlayRegion.Offset;
                var readEndOffset  = fileDataOffset + length;
                var nextDataOffset = i < waveBank.Entries.Count - 1 ? waveBank.Entries[i + 1].Native->PlayRegion.Offset : (waveBank.VirtualFileSize - segBaseOffset);
                if (readEndOffset > nextDataOffset)
                {
                    continue;
                }

                handled = true;
                if (!entry.IsRedirected)
                {
                    // Trigger cache miss
                    for (int j = 0; j < mCache.Length; j++)
                    {
                        var cacheEntry = mCache[j].Entry;
                        if (mCache[j].Miss())
                        {
                            mLogger.Debug($"{waveBank.FileName} Hnd: {handle} Index: {j} {cacheEntry.CueName} removed from cache");
                        }
                    }

                    mLogger.Info($"{waveBank.FileName} Hnd: {handle} Index: {i} {entry.CueName} Data access Offset: 0x{absOffset:X8} Length: 0x{length:X8}");
                    status = mHooks.NtReadFileHook.OriginalFunction(handle, hEvent, apcRoutine, apcContext, ref ioStatus, buffer, length, byteOffset, key);
                }
                else
                {
                    mLogger.Info($"{waveBank.FileName} Hnd: {handle} Index: {i} {entry.CueName} Data access Offset: 0x{absOffset:X8} Length: 0x{length:X8} redirected to {entry.FilePath}");
                    status = NtStatus.Success;

                    if (fileDataOffset < 0)
                    {
                        mLogger.Error($"{waveBank.FileName} Hnd: {handle} Index: {i} {entry.CueName} Offset is before start of data!!!");
                        continue;
                    }
                    else if (fileDataOffset > entry.FileSize)
                    {
                        mLogger.Error($"{waveBank.FileName} Hnd: {handle} Index: {i} {entry.CueName} Offset is after end of data!!!");
                        //continue;
                    }

                    mLogger.Debug($"{waveBank.FileName} Hnd: {handle} Index: {i} {entry.CueName} Reading 0x{length:X8} bytes from redirected file at offset 0x{fileDataOffset:X8}");

                    // Get cached file stream if the file was previously opened or open a new file
                    Stream redirectedStream = null;
                    for (int j = 0; j < mCache.Length; j++)
                    {
                        if (mCache[j].Entry == entry)
                        {
                            // Found entry in cache, increase score
                            mCache[j].Hit();
                            mLogger.Debug($"{waveBank.FileName} Hnd: {handle} Index: {i} {entry.CueName} loaded from cache");
                            redirectedStream = mCache[j].Stream;
                            break;
                        }
                        else
                        {
                            // Entry is not the one we're looking for, so we lower its score
                            var cacheEntry = mCache[j].Entry;
                            if (mCache[j].Miss())
                            {
                                mLogger.Debug($"{waveBank.FileName} Hnd: {handle} Index: {j} {cacheEntry.CueName} removed from cache");
                            }
                        }
                    }

                    if (redirectedStream == null)
                    {
                        // Wasn't found in cache
                        mLogger.Debug($"{waveBank.FileName} Hnd: {handle} Index: {i} {entry.CueName} added to cache");
                        redirectedStream = entry.OpenRead();
                        for (int j = 0; j < mCache.Length; j++)
                        {
                            if (mCache[j].Entry == null)
                            {
                                mCache[j] = new CacheEntry()
                                {
                                    Entry = entry, Score = 1, Stream = redirectedStream
                                };
                                break;;
                            }
                        }
                    }

                    // Read from redirected file into the buffer
                    try
                    {
                        redirectedStream.Seek(fileDataOffset, SeekOrigin.Begin);
                        var readBytes = redirectedStream.Read(new Span <byte>(( void * )buffer, ( int )length));
                        SetBytesRead(handle, ( int )waveBank.FilePointer, ( int )length, ref ioStatus);

                        if (readBytes != length)
                        {
                            mLogger.Error($"{waveBank.FileName} Hnd: {handle} Index: {i} {entry.CueName} File read length doesnt match requested read length!! Expected 0x{length:X8}, Actual 0x{readBytes:X8}");
                        }

                        mLogger.Debug($"{waveBank.FileName} Hnd: {handle} Index: {i} {entry.CueName} Wrote redirected file to buffer");
                    }
                    catch (Exception e)
                    {
                        mLogger.Debug($"{waveBank.FileName} Hnd: {handle} Index: {i} {entry.CueName} Unhandled exception thrown during reading {entry.FileName}: {e}");
                    }
                }
            }

            if (!handled)
            {
                mLogger.Error($"{waveBank.FileName} Hnd: {handle} Unhandled file data read request!! Offset: 0x{absOffset:X8} Length: 0x{length:X8}");
                status = mHooks.NtReadFileHook.OriginalFunction(handle, hEvent, apcRoutine, apcContext, ref ioStatus, buffer, length, byteOffset, key);
            }

            return(status);
        }
예제 #7
0
        public override Native.NtStatus NtCreateFileImpl(string filePath, out IntPtr handle, FileAccess access,
                                                         ref Native.OBJECT_ATTRIBUTES objectAttributes, ref Native.IO_STATUS_BLOCK ioStatus, ref long allocSize,
                                                         uint fileAttributes, FileShare share, uint createDisposition, uint createOptions, IntPtr eaBuffer, uint eaLength)
        {
            var result = mHooks.NtCreateFileHook.OriginalFunction(out handle, access, ref objectAttributes, ref ioStatus, ref allocSize,
                                                                  fileAttributes, share, createDisposition, createOptions, eaBuffer, eaLength);


            if (!mPacksByName.TryGetValue(filePath, out var pack))
            {
                mPacksByName[filePath] = pack = new VirtualDwPack(mLogger, filePath);

                var pacIndex = int.Parse(pack.FileName.Substring(pack.FileName.Length - 5, 5));
                var cpkName  = pack.FileName.Substring(0, pack.FileName.Length - 5);
                var cpk      = mLoadedCpks.Find(x => x.FileName.Contains(cpkName) && x.Entries.Any(y => y.PacIndex == pacIndex));
                pack.Cpk = cpk;

                if (result != NtStatus.ObjectNameNotFound)
                {
                    // Load file
                    using (var fileStream = new FileStream(new SafeFileHandle(handle, true), FileAccess.Read, 1024 * 1024))
                        pack.LoadFromFile(filePath, fileStream);

                    //pack.AddNewFiles( cpk );

                    // Reopen file to reset it
                    result = mHooks.NtCreateFileHook.OriginalFunction(out handle, access, ref objectAttributes, ref ioStatus, ref allocSize,
                                                                      fileAttributes, share, createDisposition, createOptions, eaBuffer, eaLength);
                }
                else
                {
                    pack.LoadFromCpk(pacIndex, cpk);
                    handle = GenerateHandle();
                    ioStatus.Information = (IntPtr)1;
                    ioStatus.Status      = 0;
                    result = NtStatus.Success;
                }

                mLogger.Debug($"Registered {filePath}");

                // Entries are redirected as needed to improve startup performance
            }
            else if (result == NtStatus.ObjectNameNotFound)
            {
                // Find handle from name
                if (!mHandleByPack.TryGetValue(pack, out handle))
                {
                    handle = GenerateHandle();
                }

                ioStatus.Information = (IntPtr)1;
                ioStatus.Status      = 0;
                result = NtStatus.Success;
            }

            mPacksByHandle[handle] = new VirtualDwPackHandle()
            {
                Instance = pack
            };
            mHandleByPack[pack] = handle;
            mLogger.Debug($"Hnd {handle} {filePath} handle registered");
            return(result);
        }
예제 #8
0
        private NtStatus ReadFile(IntPtr handle, IntPtr hEvent, IntPtr *apcRoutine, IntPtr *apcContext,
                                  ref Native.IO_STATUS_BLOCK ioStatus, byte *buffer, uint length, LARGE_INTEGER *byteOffset, IntPtr key,
                                  VirtualDwPack pack, long offset, long effOffset)
        {
            // File data read
            NtStatus result = NtStatus.Success;

            for (int i = 0; i < pack.Entries.Count; i++)
            {
                var entry      = pack.Entries[i];
                var dataOffset = (pack.Native.Data + entry.Native->DataOffset) - pack.Native.Ptr;
                if (effOffset < dataOffset || effOffset >= (dataOffset + entry.Native->CompressedSize))
                {
                    continue;
                }

                var fileDataOffset = effOffset - dataOffset;
                var readEndOffset  = fileDataOffset + length;
                if (readEndOffset > entry.Native->CompressedSize)
                {
                    continue;
                }

                // Make sure the file has been redirected
                // This is done as late as possible to improve startup times
                if (!entry.IsRedirected)
                {
                    mLogger.Info($"{pack.FileName} Hnd: {handle} {entry.Native->Path} Idx: ({i}) Data access Offset: 0x{effOffset:X8} Length: 0x{length:X8}");
                    result = mHooks.NtReadFileHook.OriginalFunction(handle, hEvent, apcRoutine, apcContext, ref ioStatus, buffer, length, byteOffset, key);
                }
                else
                {
                    mLogger.Info($"{pack.FileName} Hnd: {handle} {entry.Native->Path} Idx: ({i}) Data access Offset: 0x{effOffset:X8} Length: 0x{length:X8} redirected to {entry.RedirectedFilePath}");
                    result = NtStatus.Success;

                    if (fileDataOffset < 0)
                    {
                        mLogger.Error($"{pack.FileName} Hnd: {handle} {entry.Native->Path} Idx: ({i}) Offset is before start of data!!!");
                    }
                    else if (fileDataOffset > entry.RedirectedFileSize)
                    {
                        mLogger.Error($"{pack.FileName} Hnd: {handle} {entry.Native->Path} Idx: ({i}) Offset is after end of data!!!");
                    }

                    mLogger.Debug($"{pack.FileName} Hnd: {handle} {entry.Native->Path} Idx: ({i}) Reading 0x{length:X8} bytes from redirected file at offset 0x{fileDataOffset:X8}");

                    // Get cached file stream if the file was previously opened or open a new file
                    Stream redirectedStream;
                    if (mCachedFile == entry)
                    {
                        redirectedStream = mCachedFileStream;
                    }
                    else
                    {
                        mCachedFileStream?.Close();
                        mCachedFile       = entry;
                        mCachedFileStream = redirectedStream = entry.OpenRead();
                    }

                    // Read from redirected file into the buffer
                    try
                    {
                        redirectedStream.Seek(fileDataOffset, SeekOrigin.Begin);
                        var readBytes = redirectedStream.Read(new Span <byte>(( void * )buffer, ( int )length));
                        SetBytesRead(handle, ( int )offset, ( int )length, ref ioStatus);

                        if (readBytes != length)
                        {
                            mLogger.Error($"{pack.FileName} Hnd: {handle} {entry.Native->Path} Idx: ({i}) File read length doesnt match requested read length!! Expected 0x{length:X8}, Actual 0x{readBytes:X8}");
                        }

                        mLogger.Debug($"{pack.FileName} Hnd: {handle} {entry.Native->Path} Idx: ({i}) Wrote redirected file to buffer");
                    }
                    catch (Exception e)
                    {
                        mLogger.Debug($"{pack.FileName} Hnd: {handle} Idx: {i} {entry.Native->Path} Unhandled exception thrown during reading {entry.RedirectedFilePath}: {e}");
                    }
                }

                // Return early, we're done here
                return(result);
            }

            mLogger.Error($"{pack.FileName} Hnd: {handle} Unhandled file data read request!! Offset: 0x{effOffset:X8} Length: 0x{length:X8}");
            return(mHooks.NtReadFileHook.OriginalFunction(handle, hEvent, apcRoutine, apcContext, ref ioStatus, buffer, length, byteOffset, key));
        }
예제 #9
0
        public override Native.NtStatus NtCreateFileImpl(string filePath, out IntPtr handle, FileAccess access,
                                                         ref Native.OBJECT_ATTRIBUTES objectAttributes, ref Native.IO_STATUS_BLOCK ioStatus, ref long allocSize,
                                                         uint fileAttributes, FileShare share, uint createDisposition, uint createOptions, IntPtr eaBuffer, uint eaLength)
        {
            var result = mHooks.NtCreateFileHook.OriginalFunction(out handle, access, ref objectAttributes, ref ioStatus, ref allocSize,
                                                                  fileAttributes, share, createDisposition, createOptions, eaBuffer, eaLength);

            if (!mCpkByName.TryGetValue(filePath, out var cpk))
            {
                mCpkByName[filePath] = cpk = new VirtualCpk(mLogger);

                // Load file
                using (var fileStream = new FileStream(new SafeFileHandle(handle, true), FileAccess.Read, 1024 * 1024))
                    cpk.LoadFromFile(filePath, fileStream);

                // Reopen file to reset it
                result = mHooks.NtCreateFileHook.OriginalFunction(out handle, access, ref objectAttributes, ref ioStatus, ref allocSize,
                                                                  fileAttributes, share, createDisposition, createOptions, eaBuffer, eaLength);

                mLogger.Debug($"Registered {filePath}");

                // Redirect entries to a non-existent pac that will be handled by the DwPack redirector
                cpk.Redirect(mModDb);
            }

            mCpkByHandle[handle] = new VirtualCpkHandle()
            {
                Instance = cpk
            };
            mLogger.Debug($"Hnd {handle} {filePath} handle registered");
            CpkLoaded?.Invoke(this, cpk);
            return(result);
        }
예제 #10
0
        public override Native.NtStatus NtCreateFileImpl(string filePath, out IntPtr handle, FileAccess access,
                                                         ref Native.OBJECT_ATTRIBUTES objectAttributes, ref Native.IO_STATUS_BLOCK ioStatus, ref long allocSize,
                                                         uint fileAttributes, FileShare share, uint createDisposition, uint createOptions, IntPtr eaBuffer, uint eaLength)
        {
            var result = mHooks.NtCreateFileHook.OriginalFunction(out handle, access, ref objectAttributes, ref ioStatus, ref allocSize,
                                                                  fileAttributes, share, createDisposition, createOptions, eaBuffer, eaLength);

            if (!mPacksByName.TryGetValue(filePath, out var pack))
            {
                mPacksByName[filePath] = pack = new VirtualDwPack(mLogger);

                // Load file
                using (var fileStream = new FileStream(new SafeFileHandle(handle, true), FileAccess.Read, 1024 * 1024))
                    pack.LoadFromFile(filePath, fileStream);

                // Reopen file to reset it
                result = mHooks.NtCreateFileHook.OriginalFunction(out handle, access, ref objectAttributes, ref ioStatus, ref allocSize,
                                                                  fileAttributes, share, createDisposition, createOptions, eaBuffer, eaLength);

                mLogger.Debug($"Registered {filePath}");

                // Entries are redirected as needed to improve startup performance
            }

            mPacksByHandle[handle] = pack;
            mLogger.Debug($"Hnd {handle} {filePath} handle registered");
            return(result);
        }