Exemplo n.º 1
0
//*****************************************************************************
// This version only reads from disk.
//*****************************************************************************
HRESULT StgIO::ReadFromDisk(            // Return code.
    void        *pbBuff,                // Write buffer here.
    ULONG       cbBuff,                 // How much to read.
    ULONG       *pcbRead)               // How much read.
{
    ULONG       cbRead;

    _ASSERTE(m_iType == STGIO_HFILE || m_iType == STGIO_STREAM);

    // Need to have a buffer.
    if (!pcbRead)
        pcbRead = &cbRead;

    // Read only from file to avoid recursive logic.
    if (m_iType == STGIO_HFILE || m_iType == STGIO_HFILEMEM)
    {
        if (::ReadFile(m_hFile, pbBuff, cbBuff, pcbRead, 0))
            return (S_OK);
        return (MapFileError(GetLastError()));
    }
    // Read directly from stream.
    else
    {
        return (m_pIStream->Read(pbBuff, cbBuff, pcbRead));
    }
}
Exemplo n.º 2
0
//*****************************************************************************
// This version will force the data in cache out to disk for real.  The code
// can handle the different types of storage we might be sitting on based on
// the open type.
//*****************************************************************************
HRESULT StgIO::WriteToDisk(             // Return code.
    const void  *pbBuff,                // Buffer to write.
    ULONG       cbWrite,                // How much.
    ULONG       *pcbWritten)            // Return how much written.
{
    ULONG       cbWritten;              // Buffer for write funcs.
    HRESULT     hr = S_OK;

    // Pretty obvious.
    _ASSERTE(!IsReadOnly());

    // Always need a buffer to write this data to.
    if (!pcbWritten)
        pcbWritten = &cbWritten;

    // Action taken depends on type of storage.
    switch (m_iType)
    {
        case STGIO_HFILE:
        case STGIO_HFILEMEM:
        {
            // Use the file system's move.
            _ASSERTE(m_hFile != INVALID_HANDLE_VALUE);

            // Do the write to disk.
            if (!::WriteFile(m_hFile, pbBuff, cbWrite, pcbWritten, 0))
                hr = MapFileError(GetLastError());
        }
        break;

        // Free the stream pointer.
        case STGIO_STREAM:
        {
            // Delegate write to stream code.
            hr = m_pIStream->Write(pbBuff, cbWrite, pcbWritten);
        }
        break;

        // We cannot write to fixed read/only memory or LoadLibrary module.
        case STGIO_HMODULE:
        case STGIO_MEM:
#ifndef FEATURE_METADATA_STANDALONE_WINRT_RO
        case STGIO_SHAREDMEM:
#endif
        _ASSERTE(0);
        hr = BadError(E_UNEXPECTED);
        break;

        // Weird to seek with no data.
        case STGIO_NODATA:
        default:
        _ASSERTE(0);
        break;
    }
    return (hr);
}
Exemplo n.º 3
0
//*****************************************************************************
// Tells the file system to flush any cached data it may have.  This is
// expensive, but if successful guarantees you won't lose writes short of
// a disk failure.
//*****************************************************************************
HRESULT StgIO::FlushFileBuffers()
{
    _ASSERTE(!IsReadOnly());

    if (m_hFile != INVALID_HANDLE_VALUE)
    {
        if (::FlushFileBuffers(m_hFile))
            return (S_OK);
        else
            return (MapFileError(GetLastError()));
    }
    return (S_OK);
}
Exemplo n.º 4
0
//*****************************************************************************
// Copy the contents of the file for this storage to the target path.
//*****************************************************************************
HRESULT StgIO::CopyFileInternal(        // Return code.
    LPCWSTR     szTo,                   // Target save path for file.
    int         bFailIfThere,           // true to fail if target exists.
    int         bWriteThrough)          // Should copy be written through OS cache.
{
    DWORD       iCurrent;               // Save original location.
    DWORD       cbRead;                 // Byte count for buffer.
    DWORD       cbWrite;                // Check write of bytes.
    const DWORD cbBuff = 4096;          // Size of buffer for copy (in bytes).
    BYTE       *pBuff = (BYTE*)alloca(cbBuff); // Buffer for copy.
    HANDLE      hFile;                  // Target file.
    HRESULT     hr = S_OK;

    // Create target file.
    if ((hFile = ::WszCreateFile(szTo, GENERIC_WRITE, 0, 0, 
            (bFailIfThere) ? CREATE_NEW : CREATE_ALWAYS, 
            (bWriteThrough) ? FILE_FLAG_WRITE_THROUGH : 0, 
            0)) == INVALID_HANDLE_VALUE)
    {
        return (MapFileError(GetLastError()));
    }

    // Save current location and reset it later.
    iCurrent = ::SetFilePointer(m_hFile, 0, 0, FILE_CURRENT);
    ::SetFilePointer(m_hFile, 0, 0, FILE_BEGIN);

    // Copy while there are bytes.
    while (::ReadFile(m_hFile, pBuff, cbBuff, &cbRead, 0) && cbRead)
    {
        if (!::WriteFile(hFile, pBuff, cbRead, &cbWrite, 0) || cbWrite != cbRead)
        {
            hr = STG_E_WRITEFAULT;
            break;
        }
    }

    // Reset file offset.
    ::SetFilePointer(m_hFile, iCurrent, 0, FILE_BEGIN);

    // Close target.
    if (!bWriteThrough)
        VERIFY(::FlushFileBuffers(hFile));
    ::CloseHandle(hFile);
    return (hr);
}
Exemplo n.º 5
0
//*****************************************************************************
// Map the file contents to a memory mapped file and return a pointer to the 
// data.  For read/write with a backing store, map the file using an internal
// paging system.
//*****************************************************************************
HRESULT StgIO::MapFileToMem(            // Return code.
    void        *&ptr,                  // Return pointer to file data.
    ULONG       *pcbSize,               // Return size of data.
    LPSECURITY_ATTRIBUTES pAttributes)  // Security token.
{
    char        rcShared[MAXSHMEM];     // ANSI version of shared name.
    HRESULT     hr = S_OK;

    // Don't penalize for multiple calls.  Also, allow calls for mem type so
    // callers don't need to do so much checking.
    if (IsBackingStore() || 
        IsMemoryMapped() || 
        (m_iType == STGIO_MEM) || 
        (m_iType == STGIO_SHAREDMEM) ||
        (m_iType == STGIO_HFILEMEM))
    {
        ptr = m_pData;
        if (pcbSize)
            *pcbSize = m_cbData;
        return (S_OK);
    }

    //#CopySmallFiles
    // Check the size of the data we want to map.  If it is small enough, then
    // simply allocate a chunk of memory from a finer grained heap.  This saves
    // virtual memory space, page table entries, and should reduce overall working set.
    // Also, open for read/write needs a full backing store.
    if ((m_cbData <= SMALL_ALLOC_MAP_SIZE) && (SMALL_ALLOC_MAP_SIZE > 0))
    {
        DWORD cbRead = m_cbData;
        _ASSERTE(m_pData == 0);

        // Just malloc a chunk of data to use.
        m_pBaseData = m_pData = AllocateMemory(m_cbData);
        if (!m_pData)
        {
            hr = OutOfMemory();
            goto ErrExit;
        }

        // Read all of the file contents into this piece of memory.
        IfFailGo( Seek(0, FILE_BEGIN) );
        if (FAILED(hr = Read(m_pData, cbRead, &cbRead)))
        {
            FreeMemory(m_pData);
            m_pData = 0;
            goto ErrExit;
        }
        _ASSERTE(cbRead == m_cbData);

        // If the file isn't being opened for exclusive mode, then free it.
        // If it is for exclusive, then we need to keep the handle open so the
        // file is locked, preventing other readers.  Also leave it open if
        // in read/write mode so we can truncate and rewrite.
        if (m_hFile == INVALID_HANDLE_VALUE ||
            ((m_fFlags & DBPROP_TMODEF_EXCLUSIVE) == 0 && (m_fFlags & DBPROP_TMODEF_WRITE) == 0))
        {
            // If there was a handle open, then free it.
            if (m_hFile != INVALID_HANDLE_VALUE)
            {
                VERIFY(CloseHandle(m_hFile));
                m_hFile = INVALID_HANDLE_VALUE;
            }
            // Free the stream pointer.
            else
            if (m_pIStream != 0)
            {
                m_pIStream->Release();
                m_pIStream = 0;
            }

            // Switch the type to memory only access.
            m_iType = STGIO_MEM;
        }
        else
            m_iType = STGIO_HFILEMEM;

        // Free the memory when we shut down.
        m_bFreeMem = true;
    }
    // Finally, a real mapping file must be created.
    else
    {
        // Now we will map, so better have it right.
        _ASSERTE(m_hFile != INVALID_HANDLE_VALUE || m_iType == STGIO_STREAM);
        _ASSERTE(m_rgPageMap == 0);

        // For read mode, use a memory mapped file since the size will never
        // change for the life of the handle.
        if ((m_fFlags & DBPROP_TMODEF_WRITE) == 0 && m_iType != STGIO_STREAM)
        {
            // Create a mapping object for the file.
            _ASSERTE(m_hMapping == 0);

            DWORD dwProtectionFlags = PAGE_READONLY;
            
            if ((m_hMapping = WszCreateFileMapping(m_hFile, pAttributes, dwProtectionFlags,
                0, 0, nullptr)) == 0)
            {
                return (MapFileError(GetLastError()));
            }
            m_mtMappedType = MTYPE_FLAT;
            // Check to see if the memory already exists, in which case we have
            // no guarantees it is the right piece of data.
            if (GetLastError() == ERROR_ALREADY_EXISTS)
            {
                hr = PostError(CLDB_E_SMDUPLICATE, rcShared);
                goto ErrExit;
            }

            // Now map the file into memory so we can read from pointer access.
            // <REVISIT_TODO>Note: Added a check for IsBadReadPtr per the Services team which
            // indicates that under some conditions this API can give you back
            // a totally bogus pointer.</REVISIT_TODO>
            if ((m_pBaseData = m_pData = MapViewOfFile(m_hMapping, FILE_MAP_READ,
                        0, 0, 0)) == 0)
            {
                hr = MapFileError(GetLastError());
                if (SUCCEEDED(hr))
                {
                    _ASSERTE_MSG(FALSE, "Error code doesn't indicate error.");
                    hr = PostError(CLDB_E_FILE_CORRUPT);
                }
                
                // In case we got back a bogus pointer.
                m_pBaseData = m_pData = NULL;
                goto ErrExit;
            }
        }
        // In write mode, we need the hybrid combination of being able to back up
        // the data in memory via cache, but then later rewrite the contents and
        // throw away our cached copy.  Memory mapped files are not good for this
        // case due to poor write characteristics.
        else
        {
            ULONG iMaxSize;         // How much memory required for file.

            // Figure out how many pages we'll require, round up actual data
            // size to page size.
            iMaxSize = (((m_cbData - 1) & ~(m_iPageSize - 1)) + m_iPageSize);
            // Check integer overflow in previous statement
            if (iMaxSize < m_cbData)
            {
                IfFailGo(PostError(COR_E_OVERFLOW));
            }
            
            // Allocate a bit vector to track loaded pages.
            if ((m_rgPageMap = new (nothrow) BYTE[iMaxSize / m_iPageSize]) == 0)
                return (PostError(OutOfMemory()));
            memset(m_rgPageMap, 0, sizeof(BYTE) * (iMaxSize / m_iPageSize));

            // Allocate space for the file contents.
            if ((m_pBaseData = m_pData = ::ClrVirtualAlloc(0, iMaxSize, MEM_RESERVE, PAGE_NOACCESS)) == 0)
            {
                hr = PostError(OutOfMemory());
                goto ErrExit;
            }
        }
    }

    // Reset any changes made by mapping.
    IfFailGo( Seek(0, FILE_BEGIN) );

ErrExit:

    // Check for errors and clean up.
    if (FAILED(hr))
    {
        if (m_hMapping)
            CloseHandle(m_hMapping);
        m_hMapping = 0;
        m_pBaseData = m_pData = 0;
        m_cbData = 0;
    }
    ptr = m_pData;
    if (pcbSize)
        *pcbSize = m_cbData;
    return (hr);
}
Exemplo n.º 6
0
//*****************************************************************************
// Open the base file on top of: (a) file, (b) memory buffer, or (c) stream.
// If create flag is specified, then this will create a new file with the
// name supplied.  No data is read from an opened file.  You must call
// MapFileToMem before doing direct pointer access to the contents.
//*****************************************************************************
HRESULT StgIO::Open(                    // Return code.
    LPCWSTR     szName,                 // Name of the storage.
    int        fFlags,                 // How to open the file.
    const void  *pbBuff,                // Optional buffer for memory.
    ULONG       cbBuff,                 // Size of buffer.
    IStream     *pIStream,              // Stream for input.
    LPSECURITY_ATTRIBUTES pAttributes)  // Security token.
{
    HRESULT hr;
    
    // If we were given the storage memory to begin with, then use it.
    if (pbBuff && cbBuff)
    {
        _ASSERTE((fFlags & DBPROP_TMODEF_WRITE) == 0);

        // Save the memory address and size only.  No handles.
        m_pData = (void *) pbBuff;
        m_cbData = cbBuff;

        // All access to data will be by memory provided.
        if ((fFlags & DBPROP_TMODEF_SHAREDMEM) == DBPROP_TMODEF_SHAREDMEM)
        {
            // We're taking ownership of this memory
            m_pBaseData = m_pData;
            m_iType = STGIO_SHAREDMEM;
        }
        else
        {
            m_iType = STGIO_MEM;
        }
        goto ErrExit;
    }
    // Check for data backed by a stream pointer.
    else if (pIStream)
    {
        // If this is for the non-create case, get the size of existing data.
        if ((fFlags & DBPROP_TMODEF_CREATE) == 0)
        {
            LARGE_INTEGER   iMove = { { 0, 0 } };
            ULARGE_INTEGER  iSize;

            // Need the size of the data so we can map it into memory.
            if (FAILED(hr = pIStream->Seek(iMove, STREAM_SEEK_END, &iSize)))
                return (hr);
            m_cbData = iSize.u.LowPart;
        }
        // Else there is nothing.
        else
            m_cbData = 0;

        // Save an addref'd copy of the stream.
        m_pIStream = pIStream;
        m_pIStream->AddRef();

        // All access to data will be by memory provided.
        m_iType = STGIO_STREAM;
        goto ErrExit;
    }

    // If not on memory, we need a file to do a create/open.
    if (!szName || !*szName)
    {
        return (PostError(E_INVALIDARG));
    }
    // Check for create of a new file.
    else if (fFlags & DBPROP_TMODEF_CREATE)
    {
        //<REVISIT_TODO>@future: This could chose to open the file in write through
        // mode, which would provide better Duribility (from ACID props),
        // but would be much slower.</REVISIT_TODO>

        // Create the new file, overwriting only if caller allows it.
        if ((m_hFile = WszCreateFile(szName, GENERIC_READ | GENERIC_WRITE, 0, 0, 
                (fFlags & DBPROP_TMODEF_FAILIFTHERE) ? CREATE_NEW : CREATE_ALWAYS, 
                0, 0)) == INVALID_HANDLE_VALUE)
        {
            return (MapFileError(GetLastError()));
        }

        // Data will come from the file.
        m_iType = STGIO_HFILE;
    }
    // For open in read mode, need to open the file on disk.  If opening a shared
    // memory view, it has to be opened already, so no file open.
    else if ((fFlags & DBPROP_TMODEF_WRITE) == 0)
    {
        // We have not opened the file nor loaded it as module
        _ASSERTE(m_hFile == INVALID_HANDLE_VALUE);
        _ASSERTE(m_hModule == NULL);

        // Open the file for read.  Sharing is determined by caller, it can
        // allow other readers or be exclusive.
        DWORD dwFileSharingFlags = FILE_SHARE_DELETE;
        if (!(fFlags & DBPROP_TMODEF_EXCLUSIVE))
        {
            dwFileSharingFlags |= FILE_SHARE_READ;
            
#if !defined(DACCESS_COMPILE) && !defined(FEATURE_PAL) 
            // PEDecoder is not defined in DAC
            
            // We prefer to use LoadLibrary if we can because it will share already loaded images (used for execution) 
            // which saves virtual memory. We only do this if our caller has indicated that this PE file is trusted 
            // and thus it is OK to do LoadLibrary (note that we still only load it as a resource, which mitigates 
            // most of the security risk anyway).
            if ((fFlags & DBPROP_TMODEF_TRYLOADLIBRARY) != 0)
            {
                m_hModule = WszLoadLibraryEx(szName, NULL, LOAD_LIBRARY_AS_IMAGE_RESOURCE);
                if (m_hModule != NULL)
                {
                    m_iType = STGIO_HMODULE;
                    
                    m_mtMappedType = MTYPE_IMAGE;
                    
                    // LoadLibraryEx returns 2 lowest bits indicating how the module was loaded
                    m_pBaseData = m_pData = (void *)(((INT_PTR)m_hModule) & ~(INT_PTR)0x3);
                    
                    PEDecoder peDecoder;
                    if (SUCCEEDED(peDecoder.Init(
                                m_pBaseData, 
                                false)) &&  // relocated
                        peDecoder.CheckNTHeaders())
                    {
                        m_cbData = peDecoder.GetNTHeaders32()->OptionalHeader.SizeOfImage;
                    }
                    else
                    {
                        // PEDecoder failed on loaded library, let's backout all our changes to this object 
                        // and fall back to file mapping
                        m_iType = STGIO_NODATA;
                        m_mtMappedType = MTYPE_NOMAPPING;
                        m_pBaseData = m_pData = NULL;
                        
                        FreeLibrary(m_hModule);
                        m_hModule = NULL;
                    }
                }
            }
#endif //!DACCESS_COMPILE && !FEATURE_PAL
        }

        if (m_hModule == NULL)
        {   // We didn't get the loaded module (we either didn't want to or it failed)
            HandleHolder hFile(WszCreateFile(szName, 
                                             GENERIC_READ, 
                                             dwFileSharingFlags,
                                             0, 
                                             OPEN_EXISTING, 
                                             0, 
                                             0));

            if (hFile == INVALID_HANDLE_VALUE)
                return (MapFileError(GetLastError()));

            // Get size of file.
            m_cbData = ::SetFilePointer(hFile, 0, 0, FILE_END);

            // Can't read anything from an empty file.
            if (m_cbData == 0)
                return (PostError(CLDB_E_NO_DATA));

            // Data will come from the file.
            m_hFile = hFile.Extract();
            
            m_iType = STGIO_HFILE;
        }
    }

ErrExit:

    // If we will ever write, then we need the buffer cache.
    if (fFlags & DBPROP_TMODEF_WRITE)
    {
        // Allocate a cache buffer for writing.
        if ((m_rgBuff = (BYTE *) AllocateMemory(m_iCacheSize)) == NULL)
        {
            Close();
            return PostError(OutOfMemory());
        }
        m_cbBuff = 0;
    }
    
    // Save flags for later.
    m_fFlags = fFlags;
    if ((szName != NULL) && (*szName != 0))
    {
        WCHAR rcExt[_MAX_PATH];
        SplitPath(szName, NULL, 0, NULL, 0, NULL, 0, rcExt, _MAX_PATH);
        if (SString::_wcsicmp(rcExt, W(".obj")) == 0)
        {
            m_FileType = FILETYPE_NTOBJ;
        }
        else if (SString::_wcsicmp(rcExt, W(".tlb")) == 0)
        {
            m_FileType = FILETYPE_TLB;
        }
    }

    // For auto map case, map the view of the file as part of open.
    if (m_bAutoMap && 
        (m_iType == STGIO_HFILE || m_iType == STGIO_STREAM) &&
        !(fFlags & DBPROP_TMODEF_CREATE))
    {
        void * ptr;
        ULONG  cb;
        
        if (FAILED(hr = MapFileToMem(ptr, &cb, pAttributes)))
        {
            Close();
            return hr;
        }
    }
    return S_OK;
} // StgIO::Open