| /************************************************************** |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| *************************************************************/ |
| |
| |
| |
| // MARKER(update_precomp.py): autogen include statement, do not remove |
| #include "precompiled_sal.hxx" |
| |
| #include "osl/file.hxx" |
| |
| #include "osl/diagnose.h" |
| #include "rtl/alloc.h" |
| |
| #include "system.h" |
| #include "file_error_transl.h" |
| #include "file_url.h" |
| |
| #include <algorithm> |
| #include <limits> |
| |
| #include <string.h> |
| #include <pthread.h> |
| #include <sys/mman.h> |
| |
| #if defined(MACOSX) |
| |
| #include <sys/param.h> |
| #include <sys/mount.h> |
| #define HAVE_O_EXLOCK |
| |
| // add MACOSX Time Value |
| #define TimeValue CFTimeValue |
| #include <CoreFoundation/CoreFoundation.h> |
| #undef TimeValue |
| |
| #endif /* MACOSX */ |
| |
| #ifdef DEBUG_OSL_FILE |
| # define OSL_FILE_TRACE 0 ? (void)(0) : osl_trace |
| # define PERROR( a, b ) perror( a ); fprintf( stderr, b ) |
| #else |
| # define OSL_FILE_TRACE 1 ? (void)(0) : osl_trace |
| # define PERROR( a, b ) |
| #endif |
| |
| /******************************************************************* |
| * |
| * FileHandle_Impl interface |
| * |
| ******************************************************************/ |
| struct FileHandle_Impl |
| { |
| pthread_mutex_t m_mutex; |
| rtl_String * m_strFilePath; /* holds native file path */ |
| int m_fd; |
| |
| /** State |
| */ |
| enum StateBits |
| { |
| STATE_SEEKABLE = 1, /* default */ |
| STATE_READABLE = 2, /* default */ |
| STATE_WRITEABLE = 4, /* open() sets, write() requires, else osl_File_E_BADF */ |
| STATE_MODIFIED = 8 /* write() sets, flush() resets */ |
| }; |
| int m_state; |
| |
| sal_uInt64 m_size; /* file size */ |
| off_t m_offset; /* physical offset from begin of file */ |
| off_t m_fileptr; /* logical offset from begin of file */ |
| |
| off_t 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 (int fd, char const * path = "<anon>"); |
| ~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 uSize); |
| |
| oslFileError readAt ( |
| off_t nOffset, |
| void * pBuffer, |
| size_t nBytesRequested, |
| sal_uInt64 * pBytesRead); |
| |
| oslFileError writeAt ( |
| off_t nOffset, |
| void const * pBuffer, |
| size_t nBytesToWrite, |
| sal_uInt64 * pBytesWritten); |
| |
| oslFileError readFileAt ( |
| off_t nOffset, |
| void * pBuffer, |
| size_t nBytesRequested, |
| sal_uInt64 * pBytesRead); |
| |
| oslFileError writeFileAt ( |
| off_t nOffset, |
| void const * pBuffer, |
| size_t nBytesToWrite, |
| sal_uInt64 * pBytesWritten); |
| |
| oslFileError readLineAt ( |
| off_t 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 |
| { |
| pthread_mutex_t * m_mutex; |
| |
| public: |
| explicit Guard(pthread_mutex_t * pMutex); |
| ~Guard(); |
| }; |
| }; |
| |
| /******************************************************************* |
| * |
| * FileHandle_Impl implementation |
| * |
| ******************************************************************/ |
| |
| 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(); |
| if (size_t(-1) != pagesize) |
| { |
| 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"); |
| if ((0 != ppBuffer) && (0 != pnSize)) |
| *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(pthread_mutex_t * pMutex) |
| : m_mutex (pMutex) |
| { |
| OSL_PRECOND (m_mutex != 0, "FileHandle_Impl::Guard::Guard(): null pointer."); |
| (void) pthread_mutex_lock (m_mutex); // ignoring EINVAL ... |
| } |
| FileHandle_Impl::Guard::~Guard() |
| { |
| OSL_PRECOND (m_mutex != 0, "FileHandle_Impl::Guard::~Guard(): null pointer."); |
| (void) pthread_mutex_unlock (m_mutex); |
| } |
| |
| FileHandle_Impl::FileHandle_Impl (int fd, char const * path) |
| : m_strFilePath (0), |
| m_fd (fd), |
| m_state (STATE_SEEKABLE | STATE_READABLE), |
| m_size (0), |
| m_offset (0), |
| m_fileptr (0), |
| m_bufptr (-1), |
| m_buflen (0), |
| m_bufsiz (0), |
| m_buffer (0) |
| { |
| (void) pthread_mutex_init(&m_mutex, 0); |
| rtl_string_newFromStr (&m_strFilePath, path); |
| Allocator::get().allocate (&m_buffer, &m_bufsiz); |
| if (0 != m_buffer) |
| memset (m_buffer, 0, m_bufsiz); |
| } |
| FileHandle_Impl::~FileHandle_Impl() |
| { |
| Allocator::get().deallocate (m_buffer), m_buffer = 0; |
| rtl_string_release (m_strFilePath), m_strFilePath = 0; |
| (void) pthread_mutex_destroy(&m_mutex); // ignoring EBUSY ... |
| } |
| |
| 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() |
| { |
| #if defined(FREEBSD) || defined(NETBSD) || defined(MACOSX) |
| return sal::static_int_cast< size_t >(::getpagesize()); |
| #else /* POSIX */ |
| return sal::static_int_cast< size_t >(::sysconf(_SC_PAGESIZE)); |
| #endif /* xBSD || POSIX */ |
| } |
| |
| sal_uInt64 FileHandle_Impl::getPos() const |
| { |
| return sal::static_int_cast< sal_uInt64 >(m_fileptr); |
| } |
| |
| oslFileError FileHandle_Impl::setPos (sal_uInt64 uPos) |
| { |
| OSL_FILE_TRACE("FileHandle_Impl::setPos(%d, %lld) => %lld", m_fd, getPos(), uPos); |
| m_fileptr = sal::static_int_cast< off_t >(uPos); |
| return osl_File_E_None; |
| } |
| |
| sal_uInt64 FileHandle_Impl::getSize() const |
| { |
| off_t const bufend = std::max((off_t)(0), m_bufptr) + m_buflen; |
| return std::max(m_size, sal::static_int_cast< sal_uInt64 >(bufend)); |
| } |
| |
| oslFileError FileHandle_Impl::setSize (sal_uInt64 uSize) |
| { |
| off_t const nSize = sal::static_int_cast< off_t >(uSize); |
| if (-1 == ftruncate (m_fd, nSize)) |
| { |
| /* Failure. Save original result. Try fallback algorithm */ |
| oslFileError result = oslTranslateFileError (OSL_FET_ERROR, errno); |
| |
| /* Check against current size. Fail upon 'shrink' */ |
| if (uSize <= getSize()) |
| { |
| /* Failure upon 'shrink'. Return original result */ |
| return (result); |
| } |
| |
| /* Save current position */ |
| off_t const nCurPos = (off_t)lseek (m_fd, (off_t)0, SEEK_CUR); |
| if (nCurPos == (off_t)(-1)) |
| return (result); |
| |
| /* Try 'expand' via 'lseek()' and 'write()' */ |
| if (-1 == lseek (m_fd, (off_t)(nSize - 1), SEEK_SET)) |
| return (result); |
| |
| if (-1 == write (m_fd, (char*)"", (size_t)1)) |
| { |
| /* Failure. Restore saved position */ |
| (void) lseek (m_fd, (off_t)(nCurPos), SEEK_SET); |
| return (result); |
| } |
| |
| /* Success. Restore saved position */ |
| if (-1 == lseek (m_fd, (off_t)nCurPos, SEEK_SET)) |
| return (result); |
| } |
| |
| OSL_FILE_TRACE("osl_setFileSize(%d, %lld) => %ld", m_fd, getSize(), nSize); |
| m_size = sal::static_int_cast< sal_uInt64 >(nSize); |
| return osl_File_E_None; |
| } |
| |
| oslFileError FileHandle_Impl::readAt ( |
| off_t nOffset, |
| void * pBuffer, |
| size_t 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 defined(LINUX) || defined(SOLARIS) || defined(FREEBSD) || defined(MACOSX) |
| |
| ssize_t nBytes = ::pread (m_fd, pBuffer, nBytesRequested, nOffset); |
| if ((-1 == nBytes) && (EOVERFLOW == errno)) |
| { |
| /* Some 'pread()'s fail with EOVERFLOW when reading at (or past) |
| * end-of-file, different from 'lseek() + read()' behaviour. |
| * Returning '0 bytes read' and 'osl_File_E_None' instead. |
| */ |
| nBytes = 0; |
| } |
| if (-1 == nBytes) |
| return oslTranslateFileError (OSL_FET_ERROR, errno); |
| |
| #else /* no pread(2) ! */ |
| |
| if (nOffset != m_offset) |
| { |
| if (-1 == ::lseek (m_fd, nOffset, SEEK_SET)) |
| return oslTranslateFileError (OSL_FET_ERROR, errno); |
| m_offset = nOffset; |
| } |
| |
| ssize_t nBytes = ::read (m_fd, pBuffer, nBytesRequested); |
| if (-1 == nBytes) |
| return oslTranslateFileError (OSL_FET_ERROR, errno); |
| m_offset += nBytes; |
| |
| #endif /* no pread(2) ! */ |
| |
| OSL_FILE_TRACE("FileHandle_Impl::readAt(%d, %lld, %ld)", m_fd, nOffset, nBytes); |
| *pBytesRead = nBytes; |
| return osl_File_E_None; |
| } |
| |
| oslFileError FileHandle_Impl::writeAt ( |
| off_t nOffset, |
| void const * pBuffer, |
| size_t 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 defined(LINUX) || defined(SOLARIS) || defined(FREEBSD) || defined(MACOSX) |
| |
| ssize_t nBytes = ::pwrite (m_fd, pBuffer, nBytesToWrite, nOffset); |
| if (-1 == nBytes) |
| return oslTranslateFileError (OSL_FET_ERROR, errno); |
| |
| #else /* no pwrite(2) ! */ |
| |
| if (nOffset != m_offset) |
| { |
| if (-1 == ::lseek (m_fd, nOffset, SEEK_SET)) |
| return oslTranslateFileError (OSL_FET_ERROR, errno); |
| m_offset = nOffset; |
| } |
| |
| ssize_t nBytes = ::write (m_fd, pBuffer, nBytesToWrite); |
| if (-1 == nBytes) |
| return oslTranslateFileError (OSL_FET_ERROR, errno); |
| m_offset += nBytes; |
| |
| #endif /* no pwrite(2) ! */ |
| |
| OSL_FILE_TRACE("FileHandle_Impl::writeAt(%d, %lld, %ld)", m_fd, nOffset, nBytes); |
| m_size = std::max (m_size, sal::static_int_cast< sal_uInt64 >(nOffset + nBytes)); |
| |
| *pBytesWritten = nBytes; |
| return osl_File_E_None; |
| } |
| |
| oslFileError FileHandle_Impl::readFileAt ( |
| off_t nOffset, |
| void * pBuffer, |
| size_t nBytesRequested, |
| sal_uInt64 * pBytesRead) |
| { |
| if (0 == (m_state & STATE_SEEKABLE)) |
| { |
| // not seekable (pipe) |
| ssize_t nBytes = ::read (m_fd, pBuffer, nBytesRequested); |
| if (-1 == nBytes) |
| return oslTranslateFileError (OSL_FET_ERROR, errno); |
| *pBytesRead = nBytes; |
| 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; ) |
| { |
| off_t 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 -= 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 = uDone; |
| } |
| if (bufpos >= m_buflen) |
| { |
| // end of file |
| return osl_File_E_None; |
| } |
| |
| size_t const bytes = std::min (m_buflen - bufpos, nBytesRequested); |
| OSL_FILE_TRACE("FileHandle_Impl::readFileAt(%d, %lld, %ld)", m_fd, nOffset, bytes); |
| |
| memcpy (&(buffer[*pBytesRead]), &(m_buffer[bufpos]), bytes); |
| nBytesRequested -= bytes, *pBytesRead += bytes, nOffset += bytes; |
| } |
| return osl_File_E_None; |
| } |
| } |
| |
| oslFileError FileHandle_Impl::writeFileAt ( |
| off_t nOffset, |
| void const * pBuffer, |
| size_t nBytesToWrite, |
| sal_uInt64 * pBytesWritten) |
| { |
| if (0 == (m_state & STATE_SEEKABLE)) |
| { |
| // not seekable (pipe) |
| ssize_t nBytes = ::write (m_fd, pBuffer, nBytesToWrite); |
| if (-1 == nBytes) |
| return oslTranslateFileError (OSL_FET_ERROR, errno); |
| *pBytesWritten = nBytes; |
| 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; ) |
| { |
| off_t 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 to 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 -= 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 = uDone; |
| } |
| |
| size_t const bytes = std::min (m_bufsiz - bufpos, nBytesToWrite); |
| OSL_FILE_TRACE("FileHandle_Impl::writeFileAt(%d, %lld, %ld)", m_fd, nOffset, bytes); |
| |
| 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 ( |
| off_t nOffset, |
| sal_Sequence ** ppSequence, |
| sal_uInt64 * pBytesRead) |
| { |
| oslFileError result = osl_File_E_None; |
| |
| off_t 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 = 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 = 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 = uDone; |
| } |
| |
| bufpos = 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); |
| } |
| |
| /**************************************************************************** |
| * osl_createFileHandleFromFD |
| ***************************************************************************/ |
| extern "C" oslFileHandle osl_createFileHandleFromFD( int fd ) |
| { |
| if (-1 == fd) |
| return 0; // EINVAL |
| |
| struct stat aFileStat; |
| if (-1 == fstat (fd, &aFileStat)) |
| return 0; // EBADF |
| |
| FileHandle_Impl * pImpl = new FileHandle_Impl (fd); |
| if (0 == pImpl) |
| return 0; // ENOMEM |
| |
| // assume writeable |
| pImpl->m_state |= FileHandle_Impl::STATE_WRITEABLE; |
| if (!S_ISREG(aFileStat.st_mode)) |
| { |
| /* not a regular file, mark not seekable */ |
| pImpl->m_state &= ~FileHandle_Impl::STATE_SEEKABLE; |
| } |
| else |
| { |
| /* regular file, init current size */ |
| pImpl->m_size = sal::static_int_cast< sal_uInt64 >(aFileStat.st_size); |
| } |
| |
| OSL_FILE_TRACE("osl_createFileHandleFromFD(%d, writeable) => %s", |
| pImpl->m_fd, rtl_string_getStr(pImpl->m_strFilePath)); |
| return (oslFileHandle)(pImpl); |
| } |
| |
| /******************************************************************* |
| * osl_file_adjustLockFlags |
| ******************************************************************/ |
| static int osl_file_adjustLockFlags (const char * path, int flags) |
| { |
| #ifdef MACOSX |
| /* |
| * The AFP implementation of MacOS X 10.4 treats O_EXLOCK in a way |
| * that makes it impossible for OOo to create a backup copy of the |
| * file it keeps opened. OTOH O_SHLOCK for AFP behaves as desired by |
| * the OOo file handling, so we need to check the path of the file |
| * for the filesystem name. |
| */ |
| struct statfs s; |
| if( 0 <= statfs( path, &s ) ) |
| { |
| if( 0 == strncmp("afpfs", s.f_fstypename, 5) ) |
| { |
| flags &= ~O_EXLOCK; |
| flags |= O_SHLOCK; |
| } |
| else |
| { |
| /* Needed flags to allow opening a webdav file */ |
| flags &= ~(O_EXLOCK | O_SHLOCK | O_NONBLOCK); |
| } |
| } |
| #endif /* MACOSX */ |
| |
| (void) path; |
| return flags; |
| } |
| |
| /**************************************************************************** |
| * osl_file_queryLocking |
| ***************************************************************************/ |
| struct Locking_Impl |
| { |
| int m_enabled; |
| Locking_Impl() : m_enabled(0) |
| { |
| #ifndef HAVE_O_EXLOCK |
| m_enabled = ((getenv("SAL_ENABLE_FILE_LOCKING") != 0) || (getenv("STAR_ENABLE_FILE_LOCKING") != 0)); |
| #endif /* HAVE_O_EXLOCK */ |
| } |
| }; |
| static int osl_file_queryLocking (sal_uInt32 uFlags) |
| { |
| if (!(uFlags & osl_File_OpenFlag_NoLock)) |
| { |
| if ((uFlags & osl_File_OpenFlag_Write) || (uFlags & osl_File_OpenFlag_Create)) |
| { |
| static Locking_Impl g_locking; |
| return (g_locking.m_enabled != 0); |
| } |
| } |
| return 0; |
| } |
| |
| /**************************************************************************** |
| * osl_openFile |
| ***************************************************************************/ |
| #ifdef HAVE_O_EXLOCK |
| #define OPEN_WRITE_FLAGS ( O_RDWR | O_EXLOCK | O_NONBLOCK ) |
| #define OPEN_CREATE_FLAGS ( O_CREAT | O_EXCL | O_RDWR | O_EXLOCK | O_NONBLOCK ) |
| #else |
| #define OPEN_WRITE_FLAGS ( O_RDWR ) |
| #define OPEN_CREATE_FLAGS ( O_CREAT | O_EXCL | O_RDWR ) |
| #endif |
| |
| oslFileError |
| SAL_CALL osl_openFile( rtl_uString* ustrFileURL, oslFileHandle* pHandle, sal_uInt32 uFlags ) |
| { |
| oslFileError eRet; |
| |
| if ((ustrFileURL == 0) || (ustrFileURL->length == 0) || (pHandle == 0)) |
| return osl_File_E_INVAL; |
| |
| /* convert file URL to system path */ |
| char buffer[PATH_MAX]; |
| eRet = FileURLToPath (buffer, sizeof(buffer), ustrFileURL); |
| if (eRet != osl_File_E_None) |
| return eRet; |
| #ifdef MACOSX |
| if (macxp_resolveAlias (buffer, sizeof(buffer)) != 0) |
| return oslTranslateFileError (OSL_FET_ERROR, errno); |
| #endif /* MACOSX */ |
| |
| /* set mode and flags */ |
| int mode = S_IRUSR | S_IRGRP | S_IROTH; |
| int flags = O_RDONLY; |
| if (uFlags & osl_File_OpenFlag_Write) |
| { |
| mode |= S_IWUSR | S_IWGRP | S_IWOTH; |
| flags = OPEN_WRITE_FLAGS; |
| } |
| if (uFlags & osl_File_OpenFlag_Create) |
| { |
| mode |= S_IWUSR | S_IWGRP | S_IWOTH; |
| flags = OPEN_CREATE_FLAGS; |
| } |
| if (uFlags & osl_File_OpenFlag_NoLock) |
| { |
| #ifdef HAVE_O_EXLOCK |
| flags &= ~(O_EXLOCK | O_SHLOCK | O_NONBLOCK); |
| #endif /* HAVE_O_EXLOCK */ |
| } |
| else |
| { |
| flags = osl_file_adjustLockFlags (buffer, flags); |
| } |
| |
| /* open the file */ |
| int fd = open( buffer, flags, mode ); |
| if (-1 == fd) |
| return oslTranslateFileError (OSL_FET_ERROR, errno); |
| |
| /* reset O_NONBLOCK flag */ |
| if (flags & O_NONBLOCK) |
| { |
| int f = fcntl (fd, F_GETFL, 0); |
| if (-1 == f) |
| { |
| eRet = oslTranslateFileError (OSL_FET_ERROR, errno); |
| (void) close(fd); |
| return eRet; |
| } |
| if (-1 == fcntl (fd, F_SETFL, (f & ~O_NONBLOCK))) |
| { |
| eRet = oslTranslateFileError (OSL_FET_ERROR, errno); |
| (void) close(fd); |
| return eRet; |
| } |
| } |
| |
| /* get file status (mode, size) */ |
| struct stat aFileStat; |
| if (-1 == fstat (fd, &aFileStat)) |
| { |
| eRet = oslTranslateFileError (OSL_FET_ERROR, errno); |
| (void) close(fd); |
| return eRet; |
| } |
| if (!S_ISREG(aFileStat.st_mode)) |
| { |
| /* we only open regular files here */ |
| (void) close(fd); |
| return osl_File_E_INVAL; |
| } |
| |
| if (osl_file_queryLocking (uFlags)) |
| { |
| #ifdef MACOSX |
| if (-1 == flock (fd, LOCK_EX | LOCK_NB)) |
| { |
| /* Mac OSX returns ENOTSUP for webdav drives. We should try read lock */ |
| if ((errno != ENOTSUP) || ((-1 == flock (fd, LOCK_SH | LOCK_NB)) && (errno != ENOTSUP))) |
| { |
| eRet = oslTranslateFileError (OSL_FET_ERROR, errno); |
| (void) close(fd); |
| return eRet; |
| } |
| } |
| #else /* F_SETLK */ |
| { |
| struct flock aflock; |
| |
| aflock.l_type = F_WRLCK; |
| aflock.l_whence = SEEK_SET; |
| aflock.l_start = 0; |
| aflock.l_len = 0; |
| |
| if (-1 == fcntl (fd, F_SETLK, &aflock)) |
| { |
| eRet = oslTranslateFileError (OSL_FET_ERROR, errno); |
| (void) close(fd); |
| return eRet; |
| } |
| } |
| #endif /* F_SETLK */ |
| } |
| |
| /* allocate memory for impl structure */ |
| FileHandle_Impl * pImpl = new FileHandle_Impl (fd, buffer); |
| if (!pImpl) |
| { |
| eRet = oslTranslateFileError (OSL_FET_ERROR, ENOMEM); |
| (void) close(fd); |
| return eRet; |
| } |
| if (flags & O_RDWR) |
| pImpl->m_state |= FileHandle_Impl::STATE_WRITEABLE; |
| pImpl->m_size = sal::static_int_cast< sal_uInt64 >(aFileStat.st_size); |
| |
| OSL_TRACE("osl_openFile(%d, %s) => %s", pImpl->m_fd, |
| flags & O_RDWR ? "writeable":"readonly", |
| rtl_string_getStr(pImpl->m_strFilePath)); |
| |
| *pHandle = (oslFileHandle)(pImpl); |
| return osl_File_E_None; |
| } |
| |
| /****************************************************************************/ |
| /* osl_closeFile */ |
| /****************************************************************************/ |
| oslFileError |
| SAL_CALL osl_closeFile( oslFileHandle Handle ) |
| { |
| FileHandle_Impl* pImpl = static_cast<FileHandle_Impl*>(Handle); |
| |
| if ((pImpl == 0) || (pImpl->m_fd < 0)) |
| return osl_File_E_INVAL; |
| |
| (void) pthread_mutex_lock (&(pImpl->m_mutex)); |
| |
| /* close(2) implicitly (and unconditionally) unlocks */ |
| OSL_TRACE("osl_closeFile(%d) => %s", pImpl->m_fd, rtl_string_getStr(pImpl->m_strFilePath)); |
| oslFileError result = pImpl->syncFile(); |
| if (result != osl_File_E_None) |
| { |
| /* close, ignoring double failure */ |
| (void) close (pImpl->m_fd); |
| } |
| else if (-1 == close (pImpl->m_fd)) |
| { |
| /* translate error code */ |
| result = oslTranslateFileError (OSL_FET_ERROR, errno); |
| } |
| |
| (void) pthread_mutex_unlock (&(pImpl->m_mutex)); |
| delete pImpl; |
| return (result); |
| } |
| |
| /************************************************ |
| * osl_syncFile |
| ***********************************************/ |
| oslFileError |
| SAL_CALL osl_syncFile(oslFileHandle Handle) |
| { |
| FileHandle_Impl* pImpl = static_cast<FileHandle_Impl*>(Handle); |
| |
| if ((0 == pImpl) || (-1 == pImpl->m_fd)) |
| return osl_File_E_INVAL; |
| |
| FileHandle_Impl::Guard lock (&(pImpl->m_mutex)); |
| |
| OSL_TRACE("osl_syncFile(%d)", pImpl->m_fd); |
| oslFileError result = pImpl->syncFile(); |
| if (result != osl_File_E_None) |
| return (result); |
| if (-1 == fsync (pImpl->m_fd)) |
| return oslTranslateFileError (OSL_FET_ERROR, errno); |
| |
| return osl_File_E_None; |
| } |
| |
| /******************************************* |
| osl_mapFile |
| ********************************************/ |
| oslFileError |
| SAL_CALL osl_mapFile ( |
| oslFileHandle Handle, |
| void** ppAddr, |
| sal_uInt64 uLength, |
| sal_uInt64 uOffset, |
| sal_uInt32 uFlags |
| ) |
| { |
| FileHandle_Impl* pImpl = static_cast<FileHandle_Impl*>(Handle); |
| |
| if ((0 == pImpl) || (-1 == pImpl->m_fd) || (0 == ppAddr)) |
| return osl_File_E_INVAL; |
| *ppAddr = 0; |
| |
| static sal_uInt64 const g_limit_size_t = std::numeric_limits< size_t >::max(); |
| if (g_limit_size_t < uLength) |
| return osl_File_E_OVERFLOW; |
| size_t const nLength = sal::static_int_cast< size_t >(uLength); |
| |
| static sal_uInt64 const g_limit_off_t = std::numeric_limits< off_t >::max(); |
| if (g_limit_off_t < uOffset) |
| return osl_File_E_OVERFLOW; |
| off_t const nOffset = sal::static_int_cast< off_t >(uOffset); |
| |
| void* p = mmap(NULL, nLength, PROT_READ, MAP_SHARED, pImpl->m_fd, nOffset); |
| if (MAP_FAILED == p) |
| return oslTranslateFileError(OSL_FET_ERROR, errno); |
| *ppAddr = p; |
| |
| if (uFlags & osl_File_MapFlag_RandomAccess) |
| { |
| // Determine memory pagesize. |
| size_t const nPageSize = FileHandle_Impl::getpagesize(); |
| if (size_t(-1) != nPageSize) |
| { |
| /* |
| * Pagein, touching first byte of every memory page. |
| * Note: volatile disables optimizing the loop away. |
| */ |
| sal_uInt8 * pData (reinterpret_cast<sal_uInt8*>(*ppAddr)); |
| size_t nSize (nLength); |
| |
| volatile sal_uInt8 c = 0; |
| while (nSize > nPageSize) |
| { |
| c ^= pData[0]; |
| pData += nPageSize; |
| nSize -= nPageSize; |
| } |
| if (nSize > 0) |
| { |
| c^= pData[0]; |
| pData += nSize; |
| nSize -= nSize; |
| } |
| } |
| } |
| if (uFlags & osl_File_MapFlag_WillNeed) |
| { |
| // On Linux, madvise(..., MADV_WILLNEED) appears to have the undesirable |
| // effect of not returning until the data has actually been paged in, so |
| // that its net effect would typically be to slow down the process |
| // (which could start processing at the beginning of the data while the |
| // OS simultaneously pages in the rest); on other platforms, it remains |
| // to be evaluated whether madvise or equivalent is available and |
| // actually useful: |
| #if defined MACOSX |
| int e = posix_madvise(p, nLength, POSIX_MADV_WILLNEED); |
| if (e != 0) |
| { |
| OSL_TRACE( |
| "posix_madvise(..., POSIX_MADV_WILLNEED) failed with %d", e); |
| } |
| #elif defined SOLARIS |
| if (madvise(static_cast< caddr_t >(p), nLength, MADV_WILLNEED) != 0) |
| { |
| OSL_TRACE("madvise(..., MADV_WILLNEED) failed with %d", errno); |
| } |
| #endif |
| } |
| return osl_File_E_None; |
| } |
| |
| /******************************************* |
| osl_unmapFile |
| ********************************************/ |
| oslFileError |
| SAL_CALL osl_unmapFile (void* pAddr, sal_uInt64 uLength) |
| { |
| if (0 == pAddr) |
| return osl_File_E_INVAL; |
| |
| static sal_uInt64 const g_limit_size_t = std::numeric_limits< size_t >::max(); |
| if (g_limit_size_t < uLength) |
| return osl_File_E_OVERFLOW; |
| size_t const nLength = sal::static_int_cast< size_t >(uLength); |
| |
| if (-1 == munmap(static_cast<char*>(pAddr), nLength)) |
| return oslTranslateFileError(OSL_FET_ERROR, errno); |
| |
| return osl_File_E_None; |
| } |
| |
| /******************************************* |
| osl_readLine |
| ********************************************/ |
| oslFileError |
| SAL_CALL osl_readLine ( |
| oslFileHandle Handle, |
| sal_Sequence ** ppSequence) |
| { |
| FileHandle_Impl * pImpl = static_cast<FileHandle_Impl*>(Handle); |
| |
| if ((0 == pImpl) || (-1 == pImpl->m_fd) || (0 == ppSequence)) |
| return osl_File_E_INVAL; |
| sal_uInt64 uBytesRead = 0; |
| |
| // read at current fileptr; fileptr += uBytesRead; |
| FileHandle_Impl::Guard lock (&(pImpl->m_mutex)); |
| oslFileError result = pImpl->readLineAt ( |
| pImpl->m_fileptr, ppSequence, &uBytesRead); |
| if (result == osl_File_E_None) |
| pImpl->m_fileptr += uBytesRead; |
| return (result); |
| } |
| |
| /******************************************* |
| osl_readFile |
| ********************************************/ |
| 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) || (-1 == pImpl->m_fd) || (0 == pBuffer) || (0 == pBytesRead)) |
| return osl_File_E_INVAL; |
| |
| static sal_uInt64 const g_limit_ssize_t = std::numeric_limits< ssize_t >::max(); |
| if (g_limit_ssize_t < uBytesRequested) |
| return osl_File_E_OVERFLOW; |
| size_t const nBytesRequested = sal::static_int_cast< size_t >(uBytesRequested); |
| |
| // read at current fileptr; fileptr += *pBytesRead; |
| FileHandle_Impl::Guard lock (&(pImpl->m_mutex)); |
| oslFileError result = pImpl->readFileAt ( |
| pImpl->m_fileptr, pBuffer, nBytesRequested, pBytesRead); |
| if (result == osl_File_E_None) |
| pImpl->m_fileptr += *pBytesRead; |
| return (result); |
| } |
| |
| /******************************************* |
| osl_writeFile |
| ********************************************/ |
| 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) || (-1 == pImpl->m_fd) || (0 == pBuffer) || (0 == pBytesWritten)) |
| 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_ssize_t = std::numeric_limits< ssize_t >::max(); |
| if (g_limit_ssize_t < uBytesToWrite) |
| return osl_File_E_OVERFLOW; |
| size_t const nBytesToWrite = sal::static_int_cast< size_t >(uBytesToWrite); |
| |
| // write at current fileptr; fileptr += *pBytesWritten; |
| FileHandle_Impl::Guard lock (&(pImpl->m_mutex)); |
| oslFileError result = pImpl->writeFileAt ( |
| pImpl->m_fileptr, pBuffer, nBytesToWrite, pBytesWritten); |
| if (result == osl_File_E_None) |
| pImpl->m_fileptr += *pBytesWritten; |
| return (result); |
| } |
| |
| /******************************************* |
| osl_readFileAt |
| ********************************************/ |
| 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) || (-1 == pImpl->m_fd) || (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_off_t = std::numeric_limits< off_t >::max(); |
| if (g_limit_off_t < uOffset) |
| return osl_File_E_OVERFLOW; |
| off_t const nOffset = sal::static_int_cast< off_t >(uOffset); |
| |
| static sal_uInt64 const g_limit_ssize_t = std::numeric_limits< ssize_t >::max(); |
| if (g_limit_ssize_t < uBytesRequested) |
| return osl_File_E_OVERFLOW; |
| size_t const nBytesRequested = sal::static_int_cast< size_t >(uBytesRequested); |
| |
| // read at specified fileptr |
| FileHandle_Impl::Guard lock (&(pImpl->m_mutex)); |
| return pImpl->readFileAt (nOffset, pBuffer, nBytesRequested, pBytesRead); |
| } |
| |
| /******************************************* |
| osl_writeFileAt |
| ********************************************/ |
| 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) || (-1 == pImpl->m_fd) || (0 == pBuffer) || (0 == pBytesWritten)) |
| return osl_File_E_INVAL; |
| if (0 == (pImpl->m_state & FileHandle_Impl::STATE_SEEKABLE)) |
| return osl_File_E_SPIPE; |
| if (0 == (pImpl->m_state & FileHandle_Impl::STATE_WRITEABLE)) |
| return osl_File_E_BADF; |
| |
| static sal_uInt64 const g_limit_off_t = std::numeric_limits< off_t >::max(); |
| if (g_limit_off_t < uOffset) |
| return osl_File_E_OVERFLOW; |
| off_t const nOffset = sal::static_int_cast< off_t >(uOffset); |
| |
| static sal_uInt64 const g_limit_ssize_t = std::numeric_limits< ssize_t >::max(); |
| if (g_limit_ssize_t < uBytesToWrite) |
| return osl_File_E_OVERFLOW; |
| size_t const nBytesToWrite = sal::static_int_cast< size_t >(uBytesToWrite); |
| |
| // write at specified fileptr |
| FileHandle_Impl::Guard lock (&(pImpl->m_mutex)); |
| return pImpl->writeFileAt (nOffset, pBuffer, nBytesToWrite, pBytesWritten); |
| } |
| |
| /****************************************************************************/ |
| /* osl_isEndOfFile */ |
| /****************************************************************************/ |
| oslFileError |
| SAL_CALL osl_isEndOfFile( oslFileHandle Handle, sal_Bool *pIsEOF ) |
| { |
| FileHandle_Impl* pImpl = static_cast<FileHandle_Impl*>(Handle); |
| |
| if ((0 == pImpl) || (-1 == pImpl->m_fd) || (0 == pIsEOF)) |
| return osl_File_E_INVAL; |
| |
| FileHandle_Impl::Guard lock (&(pImpl->m_mutex)); |
| *pIsEOF = (pImpl->getPos() == pImpl->getSize()); |
| return osl_File_E_None; |
| } |
| |
| /************************************************ |
| * osl_getFilePos |
| ***********************************************/ |
| oslFileError |
| SAL_CALL osl_getFilePos( oslFileHandle Handle, sal_uInt64* pPos ) |
| { |
| FileHandle_Impl* pImpl = static_cast<FileHandle_Impl*>(Handle); |
| |
| if ((0 == pImpl) || (-1 == pImpl->m_fd) || (0 == pPos)) |
| return osl_File_E_INVAL; |
| |
| FileHandle_Impl::Guard lock (&(pImpl->m_mutex)); |
| *pPos = pImpl->getPos(); |
| return osl_File_E_None; |
| } |
| |
| /******************************************* |
| osl_setFilePos |
| ********************************************/ |
| oslFileError |
| SAL_CALL osl_setFilePos (oslFileHandle Handle, sal_uInt32 uHow, sal_Int64 uOffset) |
| { |
| FileHandle_Impl* pImpl = static_cast<FileHandle_Impl*>(Handle); |
| |
| if ((0 == pImpl) || (-1 == pImpl->m_fd)) |
| return osl_File_E_INVAL; |
| |
| static sal_Int64 const g_limit_off_t = std::numeric_limits< off_t >::max(); |
| if (g_limit_off_t < uOffset) |
| return osl_File_E_OVERFLOW; |
| off_t nPos = 0, nOffset = sal::static_int_cast< off_t >(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< off_t >(pImpl->getPos()); |
| if ((0 > nOffset) && (-1*nOffset > nPos)) |
| return osl_File_E_INVAL; |
| if (g_limit_off_t < nPos + nOffset) |
| return osl_File_E_OVERFLOW; |
| break; |
| |
| case osl_Pos_End: |
| nPos = sal::static_int_cast< off_t >(pImpl->getSize()); |
| if ((0 > nOffset) && (-1*nOffset > nPos)) |
| return osl_File_E_INVAL; |
| if (g_limit_off_t < nPos + nOffset) |
| return osl_File_E_OVERFLOW; |
| break; |
| |
| default: |
| return osl_File_E_INVAL; |
| } |
| |
| return pImpl->setPos (nPos + nOffset); |
| } |
| |
| /**************************************************************************** |
| * osl_getFileSize |
| ****************************************************************************/ |
| oslFileError |
| SAL_CALL osl_getFileSize( oslFileHandle Handle, sal_uInt64* pSize ) |
| { |
| FileHandle_Impl* pImpl = static_cast<FileHandle_Impl*>(Handle); |
| |
| if ((0 == pImpl) || (-1 == pImpl->m_fd) || (0 == pSize)) |
| return osl_File_E_INVAL; |
| |
| FileHandle_Impl::Guard lock (&(pImpl->m_mutex)); |
| *pSize = pImpl->getSize(); |
| return osl_File_E_None; |
| } |
| |
| /************************************************ |
| * osl_setFileSize |
| ***********************************************/ |
| oslFileError |
| SAL_CALL osl_setFileSize( oslFileHandle Handle, sal_uInt64 uSize ) |
| { |
| FileHandle_Impl* pImpl = static_cast<FileHandle_Impl*>(Handle); |
| |
| if ((0 == pImpl) || (-1 == pImpl->m_fd)) |
| 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_off_t = std::numeric_limits< off_t >::max(); |
| if (g_limit_off_t < uSize) |
| return osl_File_E_OVERFLOW; |
| |
| oslFileError result = pImpl->syncFile(); |
| if (result != osl_File_E_None) |
| return (result); |
| pImpl->m_bufptr = -1, pImpl->m_buflen = 0; |
| |
| return pImpl->setSize (uSize); |
| } |