diff options
Diffstat (limited to 'sal/osl/w32/file.cxx')
-rw-r--r-- | sal/osl/w32/file.cxx | 1194 |
1 files changed, 1194 insertions, 0 deletions
diff --git a/sal/osl/w32/file.cxx b/sal/osl/w32/file.cxx new file mode 100644 index 000000000000..7728189387cd --- /dev/null +++ b/sal/osl/w32/file.cxx @@ -0,0 +1,1194 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sal.hxx" + +#define UNICODE +#define _UNICODE +#define _WIN32_WINNT 0x0500 +#include "systools/win32/uwinapi.h" + +#include "osl/file.hxx" + +#include "file_url.h" +#include "file_error.h" + +#include "osl/diagnose.h" +#include "rtl/alloc.h" +#include "rtl/byteseq.h" +#include "rtl/ustring.hxx" + +#include <stdio.h> +#include <tchar.h> + +#ifdef __MINGW32__ +#include <wchar.h> +#include <ctype.h> +#endif + +#include <algorithm> +#include <limits> + +#ifdef max /* conflict w/ std::numeric_limits<T>::max() */ +#undef max +#endif +#ifdef min +#undef min +#endif + +//################################################################## +// File handle implementation +//################################################################## +struct FileHandle_Impl +{ + CRITICAL_SECTION m_mutex; + HANDLE m_hFile; + + /** State + */ + enum StateBits + { + STATE_SEEKABLE = 1, /* open() sets, iff regular file */ + STATE_READABLE = 2, /* open() sets, read() requires */ + STATE_WRITEABLE = 4, /* open() sets, write() requires */ + STATE_MODIFIED = 8 /* write() sets, flush() resets */ + }; + int m_state; + + sal_uInt64 m_size; /* file size */ + LONGLONG m_offset; /* physical offset from begin of file */ + LONGLONG m_filepos; /* logical offset from begin of file */ + + LONGLONG m_bufptr; /* buffer offset from begin of file */ + SIZE_T m_buflen; /* buffer filled [0, m_bufsiz - 1] */ + + SIZE_T m_bufsiz; + sal_uInt8 * m_buffer; + + explicit FileHandle_Impl (HANDLE hFile); + ~FileHandle_Impl(); + + static void* operator new(size_t n); + static void operator delete(void * p, size_t); + static SIZE_T getpagesize(); + + sal_uInt64 getPos() const; + oslFileError setPos (sal_uInt64 uPos); + + sal_uInt64 getSize() const; + oslFileError setSize (sal_uInt64 uPos); + + oslFileError readAt ( + LONGLONG nOffset, + void * pBuffer, + DWORD nBytesRequested, + sal_uInt64 * pBytesRead); + + oslFileError writeAt ( + LONGLONG nOffset, + void const * pBuffer, + DWORD nBytesToWrite, + sal_uInt64 * pBytesWritten); + + oslFileError readFileAt ( + LONGLONG nOffset, + void * pBuffer, + sal_uInt64 uBytesRequested, + sal_uInt64 * pBytesRead); + + oslFileError writeFileAt ( + LONGLONG nOffset, + void const * pBuffer, + sal_uInt64 uBytesToWrite, + sal_uInt64 * pBytesWritten); + + oslFileError readLineAt ( + LONGLONG nOffset, + sal_Sequence ** ppSequence, + sal_uInt64 * pBytesRead); + + oslFileError writeSequence_Impl ( + sal_Sequence ** ppSequence, + SIZE_T * pnOffset, + const void * pBuffer, + SIZE_T nBytes); + + oslFileError syncFile(); + + /** Buffer cache / allocator. + */ + class Allocator + { + rtl_cache_type * m_cache; + SIZE_T m_bufsiz; + + Allocator (Allocator const &); + Allocator & operator= (Allocator const &); + + public: + static Allocator & get(); + + void allocate (sal_uInt8 ** ppBuffer, SIZE_T * pnSize); + void deallocate (sal_uInt8 * pBuffer); + + protected: + Allocator(); + ~Allocator(); + }; + + /** Guard. + */ + class Guard + { + LPCRITICAL_SECTION m_mutex; + + public: + explicit Guard(LPCRITICAL_SECTION pMutex); + ~Guard(); + }; +}; + +FileHandle_Impl::Allocator & +FileHandle_Impl::Allocator::get() +{ + static Allocator g_aBufferAllocator; + return g_aBufferAllocator; +} + +FileHandle_Impl::Allocator::Allocator() + : m_cache (0), + m_bufsiz (0) +{ + SIZE_T const pagesize = FileHandle_Impl::getpagesize(); + m_cache = rtl_cache_create ( + "osl_file_buffer_cache", pagesize, 0, 0, 0, 0, 0, 0, 0); + if (0 != m_cache) + m_bufsiz = pagesize; +} + +FileHandle_Impl::Allocator::~Allocator() +{ + rtl_cache_destroy(m_cache), m_cache = 0; +} + +void FileHandle_Impl::Allocator::allocate (sal_uInt8 ** ppBuffer, SIZE_T * pnSize) +{ + OSL_PRECOND((0 != ppBuffer) && (0 != pnSize), "FileHandle_Impl::Allocator::allocate(): contract violation"); + *ppBuffer = static_cast< sal_uInt8* >(rtl_cache_alloc(m_cache)), *pnSize = m_bufsiz; +} + +void FileHandle_Impl::Allocator::deallocate (sal_uInt8 * pBuffer) +{ + if (0 != pBuffer) + rtl_cache_free (m_cache, pBuffer); +} + +FileHandle_Impl::Guard::Guard(LPCRITICAL_SECTION pMutex) + : m_mutex (pMutex) +{ + OSL_PRECOND (m_mutex != 0, "FileHandle_Impl::Guard::Guard(): null pointer."); + ::EnterCriticalSection (m_mutex); +} +FileHandle_Impl::Guard::~Guard() +{ + OSL_PRECOND (m_mutex != 0, "FileHandle_Impl::Guard::~Guard(): null pointer."); + ::LeaveCriticalSection (m_mutex); +} + +FileHandle_Impl::FileHandle_Impl(HANDLE hFile) + : m_hFile (hFile), + m_state (STATE_READABLE | STATE_WRITEABLE), + m_size (0), + m_offset (0), + m_filepos (0), + m_bufptr (-1), + m_buflen (0), + m_bufsiz (0), + m_buffer (0) +{ + ::InitializeCriticalSection (&m_mutex); + Allocator::get().allocate (&m_buffer, &m_bufsiz); + if (m_buffer != 0) + memset (m_buffer, 0, m_bufsiz); +} + +FileHandle_Impl::~FileHandle_Impl() +{ + Allocator::get().deallocate (m_buffer), m_buffer = 0; + ::DeleteCriticalSection (&m_mutex); +} + +void * FileHandle_Impl::operator new(size_t n) +{ + return rtl_allocateMemory(n); +} + +void FileHandle_Impl::operator delete(void * p, size_t) +{ + rtl_freeMemory(p); +} + +SIZE_T FileHandle_Impl::getpagesize() +{ + SYSTEM_INFO info; + ::GetSystemInfo (&info); + return sal::static_int_cast< SIZE_T >(info.dwPageSize); +} + +sal_uInt64 FileHandle_Impl::getPos() const +{ + return sal::static_int_cast< sal_uInt64 >(m_filepos); +} + +oslFileError FileHandle_Impl::setPos (sal_uInt64 uPos) +{ + m_filepos = sal::static_int_cast< LONGLONG >(uPos); + return osl_File_E_None; +} + +sal_uInt64 FileHandle_Impl::getSize() const +{ + LONGLONG bufend = std::max((LONGLONG)(0), m_bufptr) + m_buflen; + return std::max(m_size, sal::static_int_cast< sal_uInt64 >(bufend)); +} + +oslFileError FileHandle_Impl::setSize (sal_uInt64 uSize) +{ + LARGE_INTEGER nDstPos; nDstPos.QuadPart = sal::static_int_cast< LONGLONG >(uSize); + if (!::SetFilePointerEx(m_hFile, nDstPos, 0, FILE_BEGIN)) + return oslTranslateFileError( GetLastError() ); + + if (!::SetEndOfFile(m_hFile)) + return oslTranslateFileError( GetLastError() ); + m_size = uSize; + + nDstPos.QuadPart = m_offset; + if (!::SetFilePointerEx(m_hFile, nDstPos, 0, FILE_BEGIN)) + return oslTranslateFileError( GetLastError() ); + + return osl_File_E_None; +} + +oslFileError FileHandle_Impl::readAt ( + LONGLONG nOffset, + void * pBuffer, + DWORD nBytesRequested, + sal_uInt64 * pBytesRead) +{ + OSL_PRECOND(m_state & STATE_SEEKABLE, "FileHandle_Impl::readAt(): not seekable"); + if (!(m_state & STATE_SEEKABLE)) + return osl_File_E_SPIPE; + + OSL_PRECOND(m_state & STATE_READABLE, "FileHandle_Impl::readAt(): not readable"); + if (!(m_state & STATE_READABLE)) + return osl_File_E_BADF; + + if (nOffset != m_offset) + { + LARGE_INTEGER liOffset; liOffset.QuadPart = nOffset; + if (!::SetFilePointerEx(m_hFile, liOffset, 0, FILE_BEGIN)) + return oslTranslateFileError( GetLastError() ); + m_offset = nOffset; + } + + DWORD dwDone = 0; + if (!::ReadFile(m_hFile, pBuffer, nBytesRequested, &dwDone, 0)) + return oslTranslateFileError( GetLastError() ); + m_offset += dwDone; + + *pBytesRead = dwDone; + return osl_File_E_None; +} + +oslFileError FileHandle_Impl::writeAt ( + LONGLONG nOffset, + void const * pBuffer, + DWORD nBytesToWrite, + sal_uInt64 * pBytesWritten) +{ + OSL_PRECOND(m_state & STATE_SEEKABLE, "FileHandle_Impl::writeAt(): not seekable"); + if (!(m_state & STATE_SEEKABLE)) + return osl_File_E_SPIPE; + + OSL_PRECOND(m_state & STATE_WRITEABLE, "FileHandle_Impl::writeAt(): not writeable"); + if (!(m_state & STATE_WRITEABLE)) + return osl_File_E_BADF; + + if (nOffset != m_offset) + { + LARGE_INTEGER liOffset; liOffset.QuadPart = nOffset; + if (!::SetFilePointerEx (m_hFile, liOffset, 0, FILE_BEGIN)) + return oslTranslateFileError( GetLastError() ); + m_offset = nOffset; + } + + DWORD dwDone = 0; + if (!::WriteFile(m_hFile, pBuffer, nBytesToWrite, &dwDone, 0)) + return oslTranslateFileError( GetLastError() ); + m_offset += dwDone; + + m_size = std::max(m_size, sal::static_int_cast< sal_uInt64 >(m_offset)); + + *pBytesWritten = dwDone; + return osl_File_E_None; +} + +oslFileError FileHandle_Impl::readFileAt ( + LONGLONG nOffset, + void * pBuffer, + sal_uInt64 uBytesRequested, + sal_uInt64 * pBytesRead) +{ + static sal_uInt64 const g_limit_dword = std::numeric_limits< DWORD >::max(); + if (g_limit_dword < uBytesRequested) + return osl_File_E_OVERFLOW; + DWORD nBytesRequested = sal::static_int_cast< DWORD >(uBytesRequested); + + if (0 == (m_state & STATE_SEEKABLE)) + { + // not seekable (pipe) + DWORD dwDone = 0; + if (!::ReadFile(m_hFile, pBuffer, nBytesRequested, &dwDone, 0)) + return oslTranslateFileError( GetLastError() ); + *pBytesRead = dwDone; + return osl_File_E_None; + } + else if (0 == m_buffer) + { + // not buffered + return readAt (nOffset, pBuffer, nBytesRequested, pBytesRead); + } + else + { + sal_uInt8 * buffer = static_cast< sal_uInt8* >(pBuffer); + for (*pBytesRead = 0; nBytesRequested > 0; ) + { + LONGLONG const bufptr = (nOffset / m_bufsiz) * m_bufsiz; + SIZE_T const bufpos = (nOffset % m_bufsiz); + + if (bufptr != m_bufptr) + { + // flush current buffer + oslFileError result = syncFile(); + if (result != osl_File_E_None) + return (result); + m_bufptr = -1, m_buflen = 0; + + if (nBytesRequested >= m_bufsiz) + { + // buffer too small, read through from file + sal_uInt64 uDone = 0; + result = readAt (nOffset, &(buffer[*pBytesRead]), nBytesRequested, &uDone); + if (result != osl_File_E_None) + return (result); + + nBytesRequested -= sal::static_int_cast< DWORD >(uDone), *pBytesRead += uDone; + return osl_File_E_None; + } + + // update buffer (pointer) + sal_uInt64 uDone = 0; + result = readAt (bufptr, m_buffer, m_bufsiz, &uDone); + if (result != osl_File_E_None) + return (result); + m_bufptr = bufptr, m_buflen = sal::static_int_cast< SIZE_T >(uDone); + } + if (bufpos >= m_buflen) + { + // end of file + return osl_File_E_None; + } + + SIZE_T const bytes = std::min(m_buflen - bufpos, nBytesRequested); + memcpy (&(buffer[*pBytesRead]), &(m_buffer[bufpos]), bytes); + nBytesRequested -= bytes, *pBytesRead += bytes, nOffset += bytes; + } + return osl_File_E_None; + } +} + +oslFileError FileHandle_Impl::writeFileAt ( + LONGLONG nOffset, + void const * pBuffer, + sal_uInt64 uBytesToWrite, + sal_uInt64 * pBytesWritten) +{ + static sal_uInt64 const g_limit_dword = std::numeric_limits< DWORD >::max(); + if (g_limit_dword < uBytesToWrite) + return osl_File_E_OVERFLOW; + DWORD nBytesToWrite = sal::static_int_cast< DWORD >(uBytesToWrite); + + if (0 == (m_state & STATE_SEEKABLE)) + { + // not seekable (pipe) + DWORD dwDone = 0; + if (!::WriteFile(m_hFile, pBuffer, nBytesToWrite, &dwDone, 0)) + return oslTranslateFileError( GetLastError() ); + *pBytesWritten = dwDone; + return osl_File_E_None; + } + else if (0 == m_buffer) + { + // not buffered + return writeAt(nOffset, pBuffer, nBytesToWrite, pBytesWritten); + } + else + { + sal_uInt8 const * buffer = static_cast< sal_uInt8 const* >(pBuffer); + for (*pBytesWritten = 0; nBytesToWrite > 0; ) + { + LONGLONG const bufptr = (nOffset / m_bufsiz) * m_bufsiz; + SIZE_T const bufpos = (nOffset % m_bufsiz); + if (bufptr != m_bufptr) + { + // flush current buffer + oslFileError result = syncFile(); + if (result != osl_File_E_None) + return (result); + m_bufptr = -1, m_buflen = 0; + + if (nBytesToWrite >= m_bufsiz) + { + // buffer too small, write through to file + sal_uInt64 uDone = 0; + result = writeAt (nOffset, &(buffer[*pBytesWritten]), nBytesToWrite, &uDone); + if (result != osl_File_E_None) + return (result); + if (uDone != nBytesToWrite) + return osl_File_E_IO; + + nBytesToWrite -= sal::static_int_cast< DWORD >(uDone), *pBytesWritten += uDone; + return osl_File_E_None; + } + + // update buffer (pointer) + sal_uInt64 uDone = 0; + result = readAt (bufptr, m_buffer, m_bufsiz, &uDone); + if (result != osl_File_E_None) + return (result); + m_bufptr = bufptr, m_buflen = sal::static_int_cast< SIZE_T >(uDone); + } + + SIZE_T const bytes = std::min(m_bufsiz - bufpos, nBytesToWrite); + memcpy (&(m_buffer[bufpos]), &(buffer[*pBytesWritten]), bytes); + nBytesToWrite -= bytes, *pBytesWritten += bytes, nOffset += bytes; + + m_buflen = std::max(m_buflen, bufpos + bytes); + m_state |= STATE_MODIFIED; + } + return osl_File_E_None; + } +} + +oslFileError FileHandle_Impl::readLineAt ( + LONGLONG nOffset, + sal_Sequence ** ppSequence, + sal_uInt64 * pBytesRead) +{ + oslFileError result = osl_File_E_None; + + LONGLONG bufptr = (nOffset / m_bufsiz) * m_bufsiz; + if (bufptr != m_bufptr) + { + /* flush current buffer */ + result = syncFile(); + if (result != osl_File_E_None) + return (result); + + /* update buffer (pointer) */ + sal_uInt64 uDone = 0; + result = readAt (bufptr, m_buffer, m_bufsiz, &uDone); + if (result != osl_File_E_None) + return (result); + + m_bufptr = bufptr, m_buflen = sal::static_int_cast< SIZE_T >(uDone); + } + + static int const LINE_STATE_BEGIN = 0; + static int const LINE_STATE_CR = 1; + static int const LINE_STATE_LF = 2; + + SIZE_T bufpos = sal::static_int_cast< SIZE_T >(nOffset - m_bufptr), curpos = bufpos, dstpos = 0; + int state = (bufpos >= m_buflen) ? LINE_STATE_LF : LINE_STATE_BEGIN; + + for ( ; state != LINE_STATE_LF; ) + { + if (curpos >= m_buflen) + { + /* buffer examined */ + if (0 < (curpos - bufpos)) + { + /* flush buffer to sequence */ + result = writeSequence_Impl ( + ppSequence, &dstpos, &(m_buffer[bufpos]), curpos - bufpos); + if (result != osl_File_E_None) + return (result); + *pBytesRead += curpos - bufpos, nOffset += curpos - bufpos; + } + + bufptr = nOffset / m_bufsiz * m_bufsiz; + if (bufptr != m_bufptr) + { + /* update buffer (pointer) */ + sal_uInt64 uDone = 0; + result = readAt (bufptr, m_buffer, m_bufsiz, &uDone); + if (result != osl_File_E_None) + return (result); + m_bufptr = bufptr, m_buflen = sal::static_int_cast< SIZE_T >(uDone); + } + + bufpos = sal::static_int_cast< SIZE_T >(nOffset - m_bufptr), curpos = bufpos; + if (bufpos >= m_buflen) + break; + } + switch (state) + { + case LINE_STATE_CR: + state = LINE_STATE_LF; + switch (m_buffer[curpos]) + { + case 0x0A: /* CRLF */ + /* eat current char */ + curpos++; + break; + default: /* single CR */ + /* keep current char */ + break; + } + break; + default: + /* determine next state */ + switch (m_buffer[curpos]) + { + case 0x0A: /* single LF */ + state = LINE_STATE_LF; + break; + case 0x0D: /* CR */ + state = LINE_STATE_CR; + break; + default: /* advance to next char */ + curpos++; + break; + } + if (state != LINE_STATE_BEGIN) + { + /* store (and eat) the newline char */ + m_buffer[curpos] = 0x0A, curpos++; + + /* flush buffer to sequence */ + result = writeSequence_Impl ( + ppSequence, &dstpos, &(m_buffer[bufpos]), curpos - bufpos - 1); + if (result != osl_File_E_None) + return (result); + *pBytesRead += curpos - bufpos, nOffset += curpos - bufpos; + } + break; + } + } + + result = writeSequence_Impl (ppSequence, &dstpos, 0, 0); + if (result != osl_File_E_None) + return (result); + if (0 < dstpos) + return osl_File_E_None; + if (bufpos >= m_buflen) + return osl_File_E_AGAIN; + return osl_File_E_None; +} + +oslFileError FileHandle_Impl::writeSequence_Impl ( + sal_Sequence ** ppSequence, + SIZE_T * pnOffset, + const void * pBuffer, + SIZE_T nBytes) +{ + sal_Int32 nElements = *pnOffset + nBytes; + if (!*ppSequence) + { + /* construct sequence */ + rtl_byte_sequence_constructNoDefault(ppSequence, nElements); + } + else if (nElements != (*ppSequence)->nElements) + { + /* resize sequence */ + rtl_byte_sequence_realloc(ppSequence, nElements); + } + if (*ppSequence != 0) + { + /* fill sequence */ + memcpy(&((*ppSequence)->elements[*pnOffset]), pBuffer, nBytes), *pnOffset += nBytes; + } + return (*ppSequence != 0) ? osl_File_E_None : osl_File_E_NOMEM; +} + +oslFileError FileHandle_Impl::syncFile() +{ + oslFileError result = osl_File_E_None; + if (m_state & STATE_MODIFIED) + { + sal_uInt64 uDone = 0; + result = writeAt (m_bufptr, m_buffer, m_buflen, &uDone); + if (result != osl_File_E_None) + return (result); + if (uDone != m_buflen) + return osl_File_E_IO; + m_state &= ~STATE_MODIFIED; + } + return (result); +} + +//################################################################## +// File I/O functions +//################################################################## + +extern "C" oslFileHandle +SAL_CALL osl_createFileHandleFromOSHandle ( + HANDLE hFile, + sal_uInt32 uFlags) +{ + if ( !IsValidHandle(hFile) ) + return 0; // EINVAL + + FileHandle_Impl * pImpl = new FileHandle_Impl(hFile); + if (pImpl == 0) + { + // cleanup and fail + (void) ::CloseHandle(hFile); + return 0; // ENOMEM + } + + /* check for regular file */ + if (FILE_TYPE_DISK == GetFileType(hFile)) + { + /* mark seekable */ + pImpl->m_state |= FileHandle_Impl::STATE_SEEKABLE; + + /* init current size */ + LARGE_INTEGER uSize = { 0, 0 }; + (void) ::GetFileSizeEx(hFile, &uSize); + pImpl->m_size = (sal::static_int_cast<sal_uInt64>(uSize.HighPart) << 32) + uSize.LowPart; + } + + if (!(uFlags & osl_File_OpenFlag_Read)) + pImpl->m_state &= ~FileHandle_Impl::STATE_READABLE; + if (!(uFlags & osl_File_OpenFlag_Write)) + pImpl->m_state &= ~FileHandle_Impl::STATE_WRITEABLE; + + OSL_POSTCOND( + (uFlags & osl_File_OpenFlag_Read) || (uFlags & osl_File_OpenFlag_Write), + "osl_createFileHandleFromOSHandle(): missing read/write access flags"); + return (oslFileHandle)(pImpl); +} + +//############################################# +oslFileError +SAL_CALL osl_openFile( + rtl_uString * strPath, + oslFileHandle * pHandle, + sal_uInt32 uFlags ) +{ + rtl_uString * strSysPath = 0; + oslFileError result = _osl_getSystemPathFromFileURL( strPath, &strSysPath, sal_False ); + if (result != osl_File_E_None) + return (result); + + DWORD dwAccess = GENERIC_READ, dwShare = FILE_SHARE_READ, dwCreation = 0, dwAttributes = 0; + + if ( uFlags & osl_File_OpenFlag_Write ) + dwAccess |= GENERIC_WRITE; + else + dwShare |= FILE_SHARE_WRITE; + + if ( uFlags & osl_File_OpenFlag_NoLock ) + dwShare |= FILE_SHARE_WRITE; + + if ( uFlags & osl_File_OpenFlag_Create ) + dwCreation |= CREATE_NEW; + else + dwCreation |= OPEN_EXISTING; + + HANDLE hFile = CreateFileW( + reinterpret_cast<LPCWSTR>(rtl_uString_getStr( strSysPath )), + dwAccess, dwShare, NULL, dwCreation, dwAttributes, NULL ); + + // @@@ ERROR HANDLING @@@ + if ( !IsValidHandle( hFile ) ) + result = oslTranslateFileError( GetLastError() ); + + *pHandle = osl_createFileHandleFromOSHandle (hFile, uFlags | osl_File_OpenFlag_Read); + + rtl_uString_release( strSysPath ); + return (result); +} + +//############################################# +oslFileError +SAL_CALL osl_syncFile(oslFileHandle Handle) +{ + FileHandle_Impl * pImpl = static_cast<FileHandle_Impl*>(Handle); + if ((0 == pImpl) || !IsValidHandle(pImpl->m_hFile)) + return osl_File_E_INVAL; + + FileHandle_Impl::Guard lock (&(pImpl->m_mutex)); + + oslFileError result = pImpl->syncFile(); + if (result != osl_File_E_None) + return result; + + if (!FlushFileBuffers(pImpl->m_hFile)) + return oslTranslateFileError(GetLastError()); + + return osl_File_E_None; +} + +//############################################# +oslFileError +SAL_CALL osl_closeFile(oslFileHandle Handle) +{ + FileHandle_Impl * pImpl = static_cast<FileHandle_Impl*>(Handle); + if ((0 == pImpl) || !IsValidHandle(pImpl->m_hFile)) + return osl_File_E_INVAL; + + ::EnterCriticalSection (&(pImpl->m_mutex)); + + oslFileError result = pImpl->syncFile(); + if (result != osl_File_E_None) + { + /* ignore double failure */ + (void)::CloseHandle(pImpl->m_hFile); + } + else if (!::CloseHandle(pImpl->m_hFile)) + { + /* translate error code */ + result = oslTranslateFileError( GetLastError() ); + } + + ::LeaveCriticalSection (&(pImpl->m_mutex)); + delete pImpl; + return (result); +} + +//############################################# +oslFileError +SAL_CALL osl_mapFile( + oslFileHandle Handle, + void** ppAddr, + sal_uInt64 uLength, + sal_uInt64 uOffset, + sal_uInt32 uFlags) +{ + struct FileMapping + { + HANDLE m_handle; + + explicit FileMapping (HANDLE hMap) + : m_handle (hMap) + {} + + ~FileMapping() + { + (void)::CloseHandle(m_handle); + } + }; + + FileHandle_Impl * pImpl = static_cast<FileHandle_Impl*>(Handle); + if ((0 == pImpl) || !IsValidHandle(pImpl->m_hFile) || (0 == ppAddr)) + return osl_File_E_INVAL; + *ppAddr = 0; + + static SIZE_T const nLimit = std::numeric_limits< SIZE_T >::max(); + if (uLength > nLimit) + return osl_File_E_OVERFLOW; + SIZE_T const nLength = sal::static_int_cast< SIZE_T >(uLength); + + OSVERSIONINFO osinfo; + osinfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); + (void)::GetVersionEx(&osinfo); + + if (VER_PLATFORM_WIN32_NT != osinfo.dwPlatformId) + return osl_File_E_NOSYS; // Unsupported + + FileMapping aMap( ::CreateFileMapping (pImpl->m_hFile, NULL, SEC_COMMIT | PAGE_READONLY, 0, 0, NULL) ); + if (!IsValidHandle(aMap.m_handle)) + return oslTranslateFileError( GetLastError() ); + + DWORD const dwOffsetHi = sal::static_int_cast<DWORD>(uOffset >> 32); + DWORD const dwOffsetLo = sal::static_int_cast<DWORD>(uOffset & 0xFFFFFFFF); + + *ppAddr = ::MapViewOfFile( aMap.m_handle, FILE_MAP_READ, dwOffsetHi, dwOffsetLo, nLength ); + if (0 == *ppAddr) + return oslTranslateFileError( GetLastError() ); + + if (uFlags & osl_File_MapFlag_RandomAccess) + { + // Determine memory pagesize. + SYSTEM_INFO info; + ::GetSystemInfo( &info ); + DWORD const dwPageSize = info.dwPageSize; + + /* + * Pagein, touching first byte of each memory page. + * Note: volatile disables optimizing the loop away. + */ + BYTE * pData (reinterpret_cast<BYTE*>(*ppAddr)); + SIZE_T nSize (nLength); + + volatile BYTE c = 0; + while (nSize > dwPageSize) + { + c ^= pData[0]; + pData += dwPageSize; + nSize -= dwPageSize; + } + if (nSize > 0) + { + c ^= pData[0]; + pData += nSize; + nSize -= nSize; + } + } + return osl_File_E_None; +} + +//############################################# +oslFileError +SAL_CALL osl_unmapFile(void* pAddr, sal_uInt64 /* uLength */) +{ + if (0 == pAddr) + return osl_File_E_INVAL; + + if (!::UnmapViewOfFile (pAddr)) + return oslTranslateFileError( GetLastError() ); + + return osl_File_E_None; +} + +//############################################# +oslFileError +SAL_CALL osl_readLine( + oslFileHandle Handle, + sal_Sequence ** ppSequence) +{ + FileHandle_Impl * pImpl = static_cast<FileHandle_Impl*>(Handle); + if ((0 == pImpl) || !IsValidHandle(pImpl->m_hFile) || (0 == ppSequence)) + return osl_File_E_INVAL; + sal_uInt64 uBytesRead = 0; + + // read at current filepos; filepos += uBytesRead; + FileHandle_Impl::Guard lock (&(pImpl->m_mutex)); + oslFileError result = pImpl->readLineAt ( + pImpl->m_filepos, ppSequence, &uBytesRead); + if (result == osl_File_E_None) + pImpl->m_filepos += uBytesRead; + return (result); +} + +//############################################# +oslFileError +SAL_CALL osl_readFile( + oslFileHandle Handle, + void * pBuffer, + sal_uInt64 uBytesRequested, + sal_uInt64 * pBytesRead) +{ + FileHandle_Impl * pImpl = static_cast<FileHandle_Impl*>(Handle); + if ((0 == pImpl) || !IsValidHandle(pImpl->m_hFile) || (0 == pBuffer) || (0 == pBytesRead)) + return osl_File_E_INVAL; + + // read at current filepos; filepos += *pBytesRead; + FileHandle_Impl::Guard lock (&(pImpl->m_mutex)); + oslFileError result = pImpl->readFileAt ( + pImpl->m_filepos, pBuffer, uBytesRequested, pBytesRead); + if (result == osl_File_E_None) + pImpl->m_filepos += *pBytesRead; + return (result); +} + +//############################################# +oslFileError +SAL_CALL osl_writeFile( + oslFileHandle Handle, + const void * pBuffer, + sal_uInt64 uBytesToWrite, + sal_uInt64 * pBytesWritten ) +{ + FileHandle_Impl * pImpl = static_cast<FileHandle_Impl*>(Handle); + + if ((0 == pImpl) || !IsValidHandle(pImpl->m_hFile) || (0 == pBuffer) || (0 == pBytesWritten)) + return osl_File_E_INVAL; + + // write at current filepos; filepos += *pBytesWritten; + FileHandle_Impl::Guard lock (&(pImpl->m_mutex)); + oslFileError result = pImpl->writeFileAt ( + pImpl->m_filepos, pBuffer, uBytesToWrite, pBytesWritten); + if (result == osl_File_E_None) + pImpl->m_filepos += *pBytesWritten; + return (result); +} + +//############################################# +oslFileError +SAL_CALL osl_readFileAt( + oslFileHandle Handle, + sal_uInt64 uOffset, + void* pBuffer, + sal_uInt64 uBytesRequested, + sal_uInt64* pBytesRead) +{ + FileHandle_Impl * pImpl = static_cast<FileHandle_Impl*>(Handle); + + if ((0 == pImpl) || !IsValidHandle(pImpl->m_hFile) || (0 == pBuffer) || (0 == pBytesRead)) + return osl_File_E_INVAL; + if (0 == (pImpl->m_state & FileHandle_Impl::STATE_SEEKABLE)) + return osl_File_E_SPIPE; + + static sal_uInt64 const g_limit_longlong = std::numeric_limits< LONGLONG >::max(); + if (g_limit_longlong < uOffset) + return osl_File_E_OVERFLOW; + LONGLONG const nOffset = sal::static_int_cast< LONGLONG >(uOffset); + + // read at specified fileptr + FileHandle_Impl::Guard lock (&(pImpl->m_mutex)); + return pImpl->readFileAt (nOffset, pBuffer, uBytesRequested, pBytesRead); +} + +//############################################# +oslFileError +SAL_CALL osl_writeFileAt( + oslFileHandle Handle, + sal_uInt64 uOffset, + const void* pBuffer, + sal_uInt64 uBytesToWrite, + sal_uInt64* pBytesWritten) +{ + FileHandle_Impl * pImpl = static_cast<FileHandle_Impl*>(Handle); + + if ((0 == pImpl) || !IsValidHandle(pImpl->m_hFile) || (0 == pBuffer) || (0 == pBytesWritten)) + return osl_File_E_INVAL; + if (0 == (pImpl->m_state & FileHandle_Impl::STATE_SEEKABLE)) + return osl_File_E_SPIPE; + + static sal_uInt64 const g_limit_longlong = std::numeric_limits< LONGLONG >::max(); + if (g_limit_longlong < uOffset) + return osl_File_E_OVERFLOW; + LONGLONG const nOffset = sal::static_int_cast< LONGLONG >(uOffset); + + // write at specified fileptr + FileHandle_Impl::Guard lock (&(pImpl->m_mutex)); + return pImpl->writeFileAt (nOffset, pBuffer, uBytesToWrite, pBytesWritten); +} + +//############################################# +oslFileError +SAL_CALL osl_isEndOfFile (oslFileHandle Handle, sal_Bool *pIsEOF) +{ + FileHandle_Impl * pImpl = static_cast<FileHandle_Impl*>(Handle); + + if ((0 == pImpl) || !IsValidHandle(pImpl->m_hFile) || (0 == pIsEOF)) + return osl_File_E_INVAL; + + FileHandle_Impl::Guard lock (&(pImpl->m_mutex)); + *pIsEOF = (pImpl->getPos() == pImpl->getSize()); + return osl_File_E_None; +} + +//############################################# +oslFileError +SAL_CALL osl_getFilePos(oslFileHandle Handle, sal_uInt64 *pPos) +{ + FileHandle_Impl * pImpl = static_cast<FileHandle_Impl*>(Handle); + if ((0 == pImpl) || !IsValidHandle(pImpl->m_hFile) || (0 == pPos)) + return osl_File_E_INVAL; + + FileHandle_Impl::Guard lock (&(pImpl->m_mutex)); + *pPos = pImpl->getPos(); + return osl_File_E_None; +} + +//############################################# +oslFileError +SAL_CALL osl_setFilePos(oslFileHandle Handle, sal_uInt32 uHow, sal_Int64 uOffset) +{ + FileHandle_Impl * pImpl = static_cast<FileHandle_Impl*>(Handle); + if ((0 == pImpl) || !IsValidHandle(pImpl->m_hFile)) + return osl_File_E_INVAL; + + static sal_Int64 const g_limit_longlong = std::numeric_limits< LONGLONG >::max(); + if (g_limit_longlong < uOffset) + return osl_File_E_OVERFLOW; + LONGLONG nPos = 0, nOffset = sal::static_int_cast< LONGLONG >(uOffset); + + FileHandle_Impl::Guard lock (&(pImpl->m_mutex)); + switch (uHow) + { + case osl_Pos_Absolut: + if (0 > nOffset) + return osl_File_E_INVAL; + break; + + case osl_Pos_Current: + nPos = sal::static_int_cast< LONGLONG >(pImpl->getPos()); + if ((0 > nOffset) && (-1*nOffset > nPos)) + return osl_File_E_INVAL; + if (g_limit_longlong < nPos + nOffset) + return osl_File_E_OVERFLOW; + break; + + case osl_Pos_End: + nPos = sal::static_int_cast< LONGLONG >(pImpl->getSize()); + if ((0 > nOffset) && (-1*nOffset > nPos)) + return osl_File_E_INVAL; + if (g_limit_longlong < nPos + nOffset) + return osl_File_E_OVERFLOW; + break; + + default: + return osl_File_E_INVAL; + } + + return pImpl->setPos (nPos + nOffset); +} + +//############################################# +oslFileError +SAL_CALL osl_getFileSize (oslFileHandle Handle, sal_uInt64 *pSize) +{ + FileHandle_Impl * pImpl = static_cast<FileHandle_Impl*>(Handle); + + if ((0 == pImpl) || !IsValidHandle(pImpl->m_hFile) || (0 == pSize)) + return osl_File_E_INVAL; + + FileHandle_Impl::Guard lock (&(pImpl->m_mutex)); + *pSize = pImpl->getSize(); + return osl_File_E_None; +} + +//############################################# +oslFileError +SAL_CALL osl_setFileSize (oslFileHandle Handle, sal_uInt64 uSize) +{ + FileHandle_Impl * pImpl = static_cast<FileHandle_Impl*>(Handle); + + if ((0 == pImpl) || !IsValidHandle(pImpl->m_hFile)) + return osl_File_E_INVAL; + if (0 == (pImpl->m_state & FileHandle_Impl::STATE_WRITEABLE)) + return osl_File_E_BADF; + + static sal_uInt64 const g_limit_longlong = std::numeric_limits< LONGLONG >::max(); + if (g_limit_longlong < uSize) + return osl_File_E_OVERFLOW; + + FileHandle_Impl::Guard lock (&(pImpl->m_mutex)); + oslFileError result = pImpl->syncFile(); + if (result != osl_File_E_None) + return (result); + pImpl->m_bufptr = -1, pImpl->m_buflen = 0; + + return pImpl->setSize (uSize); +} + +//################################################################## +// File handling functions +//################################################################## + +//############################################# +oslFileError SAL_CALL osl_removeFile( rtl_uString* strPath ) +{ + rtl_uString *strSysPath = NULL; + oslFileError error = _osl_getSystemPathFromFileURL( strPath, &strSysPath, sal_False ); + + if ( osl_File_E_None == error ) + { + if ( DeleteFile( reinterpret_cast<LPCTSTR>(rtl_uString_getStr( strSysPath )) ) ) + error = osl_File_E_None; + else + error = oslTranslateFileError( GetLastError() ); + + rtl_uString_release( strSysPath ); + } + return error; +} + +//############################################# +#define osl_File_CopyRecursive 0x0001 +#define osl_File_CopyOverwrite 0x0002 + +oslFileError SAL_CALL osl_copyFile( rtl_uString* strPath, rtl_uString *strDestPath ) +{ + rtl_uString *strSysPath = NULL, *strSysDestPath = NULL; + oslFileError error = _osl_getSystemPathFromFileURL( strPath, &strSysPath, sal_False ); + + if ( osl_File_E_None == error ) + error = _osl_getSystemPathFromFileURL( strDestPath, &strSysDestPath, sal_False ); + + if ( osl_File_E_None == error ) + { + LPCTSTR src = reinterpret_cast<LPCTSTR>(rtl_uString_getStr( strSysPath )); + LPCTSTR dst = reinterpret_cast<LPCTSTR>(rtl_uString_getStr( strSysDestPath )); + + if ( CopyFile( src, dst, FALSE ) ) + error = osl_File_E_None; + else + error = oslTranslateFileError( GetLastError() ); + } + + if ( strSysPath ) + rtl_uString_release( strSysPath ); + if ( strSysDestPath ) + rtl_uString_release( strSysDestPath ); + + return error; +} + +//############################################# +oslFileError SAL_CALL osl_moveFile( rtl_uString* strPath, rtl_uString *strDestPath ) +{ + rtl_uString *strSysPath = NULL, *strSysDestPath = NULL; + oslFileError error = _osl_getSystemPathFromFileURL( strPath, &strSysPath, sal_False ); + + if ( osl_File_E_None == error ) + error = _osl_getSystemPathFromFileURL( strDestPath, &strSysDestPath, sal_False ); + + if ( osl_File_E_None == error ) + { + LPCTSTR src = reinterpret_cast<LPCTSTR>(rtl_uString_getStr( strSysPath )); + LPCTSTR dst = reinterpret_cast<LPCTSTR>(rtl_uString_getStr( strSysDestPath )); + + if ( MoveFileEx( src, dst, MOVEFILE_COPY_ALLOWED | MOVEFILE_WRITE_THROUGH | MOVEFILE_REPLACE_EXISTING ) ) + error = osl_File_E_None; + else + error = oslTranslateFileError( GetLastError() ); + } + + if ( strSysPath ) + rtl_uString_release( strSysPath ); + if ( strSysDestPath ) + rtl_uString_release( strSysDestPath ); + + return error; +} |