LCOV - code coverage report
Current view: top level - sal/osl/unx - file.cxx (source / functions) Hit Total Coverage
Test: commit e02a6cb2c3e2b23b203b422e4e0680877f232636 Lines: 297 572 51.9 %
Date: 2014-04-14 Functions: 33 47 70.2 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /*
       3             :  * This file is part of the LibreOffice project.
       4             :  *
       5             :  * This Source Code Form is subject to the terms of the Mozilla Public
       6             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       7             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       8             :  *
       9             :  * This file incorporates work covered by the following license notice:
      10             :  *
      11             :  *   Licensed to the Apache Software Foundation (ASF) under one or more
      12             :  *   contributor license agreements. See the NOTICE file distributed
      13             :  *   with this work for additional information regarding copyright
      14             :  *   ownership. The ASF licenses this file to you under the Apache
      15             :  *   License, Version 2.0 (the "License"); you may not use this file
      16             :  *   except in compliance with the License. You may obtain a copy of
      17             :  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
      18             :  */
      19             : 
      20             : #include <config_features.h>
      21             : 
      22             : #include "boost/noncopyable.hpp"
      23             : #include "osl/file.hxx"
      24             : #include "osl/detail/file.h"
      25             : 
      26             : #include "osl/diagnose.h"
      27             : #include "rtl/alloc.h"
      28             : 
      29             : #include <rtl/string.hxx>
      30             : 
      31             : #include <sal/log.hxx>
      32             : 
      33             : #include "system.h"
      34             : #include "createfilehandlefromfd.hxx"
      35             : #include "file_error_transl.h"
      36             : #include "file_url.h"
      37             : #include "uunxapi.h"
      38             : 
      39             : #include <algorithm>
      40             : #include <limits>
      41             : 
      42             : #include <string.h>
      43             : #include <pthread.h>
      44             : #include <sys/mman.h>
      45             : 
      46             : #if defined(MACOSX)
      47             : 
      48             : #include <sys/param.h>
      49             : #include <sys/mount.h>
      50             : #define HAVE_O_EXLOCK
      51             : 
      52             : #include <CoreFoundation/CoreFoundation.h>
      53             : 
      54             : #endif /* MACOSX */
      55             : 
      56             : #ifdef ANDROID
      57             : #include <osl/detail/android-bootstrap.h>
      58             : #endif
      59             : 
      60             : /*******************************************************************
      61             :  *
      62             :  * FileHandle_Impl interface
      63             :  *
      64             :  ******************************************************************/
      65             : struct FileHandle_Impl
      66             : {
      67             :     pthread_mutex_t m_mutex;
      68             :     rtl_String *    m_strFilePath; /* holds native file path */
      69             :     int             m_fd;
      70             : 
      71             :     enum Kind
      72             :     {
      73             :         KIND_FD = 1,
      74             :         KIND_MEM = 2
      75             :     };
      76             :     int          m_kind;
      77             :     /** State
      78             :      */
      79             :     enum StateBits
      80             :     {
      81             :         STATE_SEEKABLE  = 1, /* default */
      82             :         STATE_READABLE  = 2, /* default */
      83             :         STATE_WRITEABLE = 4, /* open() sets, write() requires, else osl_File_E_BADF */
      84             :         STATE_MODIFIED  = 8  /* write() sets, flush() resets  */
      85             :     };
      86             :     int          m_state;
      87             : 
      88             :     sal_uInt64   m_size;    /* file size */
      89             :     off_t        m_offset;  /* physical offset from begin of file */
      90             :     off_t        m_fileptr; /* logical offset from begin of file */
      91             : 
      92             :     off_t        m_bufptr;  /* buffer offset from begin of file */
      93             :     size_t       m_buflen;  /* buffer filled [0, m_bufsiz - 1] */
      94             : 
      95             :     size_t       m_bufsiz;
      96             :     sal_uInt8 *  m_buffer;
      97             : 
      98             :     explicit FileHandle_Impl (int fd, Kind kind = KIND_FD, char const * path = "<anon>");
      99             :     ~FileHandle_Impl();
     100             : 
     101             :     static void* operator new (size_t n);
     102             :     static void  operator delete (void * p);
     103             : 
     104             :     static size_t getpagesize();
     105             : 
     106             :     sal_uInt64   getPos() const;
     107             :     oslFileError setPos (sal_uInt64 uPos);
     108             : 
     109             :     sal_uInt64   getSize() const;
     110             :     oslFileError setSize (sal_uInt64 uSize);
     111             : 
     112             :     oslFileError readAt (
     113             :         off_t        nOffset,
     114             :         void *       pBuffer,
     115             :         size_t       nBytesRequested,
     116             :         sal_uInt64 * pBytesRead);
     117             : 
     118             :     oslFileError writeAt (
     119             :         off_t        nOffset,
     120             :         void const * pBuffer,
     121             :         size_t       nBytesToWrite,
     122             :         sal_uInt64 * pBytesWritten);
     123             : 
     124             :     oslFileError readFileAt (
     125             :         off_t        nOffset,
     126             :         void *       pBuffer,
     127             :         size_t       nBytesRequested,
     128             :         sal_uInt64 * pBytesRead);
     129             : 
     130             :     oslFileError writeFileAt (
     131             :         off_t        nOffset,
     132             :         void const * pBuffer,
     133             :         size_t       nBytesToWrite,
     134             :         sal_uInt64 * pBytesWritten);
     135             : 
     136             :     oslFileError readLineAt (
     137             :         off_t           nOffset,
     138             :         sal_Sequence ** ppSequence,
     139             :         sal_uInt64 *    pBytesRead);
     140             : 
     141             :     oslFileError writeSequence_Impl (
     142             :         sal_Sequence ** ppSequence,
     143             :         size_t *        pnOffset,
     144             :         const void *    pBuffer,
     145             :         size_t          nBytes);
     146             : 
     147             :     oslFileError syncFile();
     148             : 
     149             :     /** Buffer cache / allocator.
     150             :      */
     151             :     class Allocator: private boost::noncopyable
     152             :     {
     153             :         rtl_cache_type * m_cache;
     154             :         size_t           m_bufsiz;
     155             : 
     156             :     public:
     157             :         static Allocator & get();
     158             : 
     159             :         void allocate (sal_uInt8 ** ppBuffer, size_t * pnSize);
     160             :         void deallocate (sal_uInt8 * pBuffer);
     161             : 
     162             :     protected:
     163             :         Allocator();
     164             :         ~Allocator();
     165             :     };
     166             : 
     167             :     /** Guard.
     168             :      */
     169             :     class Guard
     170             :     {
     171             :         pthread_mutex_t * m_mutex;
     172             : 
     173             :     public:
     174             :         explicit Guard(pthread_mutex_t * pMutex);
     175             :         ~Guard();
     176             :     };
     177             : };
     178             : 
     179             : FileHandle_Impl::Allocator &
     180      595136 : FileHandle_Impl::Allocator::get()
     181             : {
     182      595136 :     static Allocator g_aBufferAllocator;
     183      595136 :     return g_aBufferAllocator;
     184             : }
     185             : 
     186       85011 : FileHandle_Impl::Allocator::Allocator()
     187             :     : m_cache  (0),
     188       85011 :       m_bufsiz (0)
     189             : {
     190       85011 :     size_t const pagesize = FileHandle_Impl::getpagesize();
     191       85011 :     if (size_t(-1) != pagesize)
     192             :     {
     193             :         m_cache  = rtl_cache_create (
     194       85011 :             "osl_file_buffer_cache", pagesize, 0, 0, 0, 0, 0, 0, 0);
     195       85011 :         if (0 != m_cache)
     196       85011 :             m_bufsiz = pagesize;
     197             :     }
     198       85011 : }
     199       85011 : FileHandle_Impl::Allocator::~Allocator()
     200             : {
     201       85011 :     rtl_cache_destroy (m_cache), m_cache = 0;
     202       85011 : }
     203             : 
     204      297568 : void FileHandle_Impl::Allocator::allocate (sal_uInt8 ** ppBuffer, size_t * pnSize)
     205             : {
     206             :     OSL_PRECOND((0 != ppBuffer) && (0 != pnSize), "FileHandle_Impl::Allocator::allocate(): contract violation");
     207      297568 :     if ((0 != ppBuffer) && (0 != pnSize))
     208      297568 :         *ppBuffer = static_cast< sal_uInt8* >(rtl_cache_alloc(m_cache)), *pnSize = m_bufsiz;
     209      297568 : }
     210      297568 : void FileHandle_Impl::Allocator::deallocate (sal_uInt8 * pBuffer)
     211             : {
     212      297568 :     if (0 != pBuffer)
     213      297568 :         rtl_cache_free (m_cache, pBuffer);
     214      297568 : }
     215             : 
     216     3832806 : FileHandle_Impl::Guard::Guard(pthread_mutex_t * pMutex)
     217     3832806 :     : m_mutex (pMutex)
     218             : {
     219             :     OSL_PRECOND (m_mutex != 0, "FileHandle_Impl::Guard::Guard(): null pointer.");
     220     3832806 :     (void) pthread_mutex_lock (m_mutex); // ignoring EINVAL ...
     221     3832806 : }
     222     3832806 : FileHandle_Impl::Guard::~Guard()
     223             : {
     224             :     OSL_PRECOND (m_mutex != 0, "FileHandle_Impl::Guard::~Guard(): null pointer.");
     225     3832806 :     (void) pthread_mutex_unlock (m_mutex);
     226     3832806 : }
     227             : 
     228      297568 : FileHandle_Impl::FileHandle_Impl (int fd, enum Kind kind, char const * path)
     229             :     : m_strFilePath (0),
     230             :       m_fd      (fd),
     231             :       m_kind    (kind),
     232             :       m_state   (STATE_SEEKABLE | STATE_READABLE),
     233             :       m_size    (0),
     234             :       m_offset  (0),
     235             :       m_fileptr (0),
     236             :       m_bufptr  (-1),
     237             :       m_buflen  (0),
     238             :       m_bufsiz  (0),
     239      297568 :       m_buffer  (0)
     240             : {
     241      297568 :     (void) pthread_mutex_init(&m_mutex, 0);
     242      297568 :     rtl_string_newFromStr (&m_strFilePath, path);
     243      297568 :     if (m_kind == KIND_FD) {
     244      297568 :         Allocator::get().allocate (&m_buffer, &m_bufsiz);
     245      297568 :         if (0 != m_buffer)
     246      297568 :             memset (m_buffer, 0, m_bufsiz);
     247             :     }
     248      297568 : }
     249      297568 : FileHandle_Impl::~FileHandle_Impl()
     250             : {
     251      297568 :     if (m_kind == KIND_FD)
     252      297568 :         Allocator::get().deallocate (m_buffer), m_buffer = 0;
     253      297568 :     rtl_string_release (m_strFilePath), m_strFilePath = 0;
     254      297568 :     (void) pthread_mutex_destroy(&m_mutex); // ignoring EBUSY ...
     255      297568 : }
     256             : 
     257      297568 : void* FileHandle_Impl::operator new (size_t n)
     258             : {
     259      297568 :     return rtl_allocateMemory(n);
     260             : }
     261      297568 : void FileHandle_Impl::operator delete (void * p)
     262             : {
     263      297568 :     rtl_freeMemory(p);
     264      297568 : }
     265             : 
     266       85014 : size_t FileHandle_Impl::getpagesize()
     267             : {
     268             : #if defined(FREEBSD) || defined(NETBSD) || defined(MACOSX) || \
     269             :     defined(OPENBSD) || defined(DRAGONFLY)
     270             :     return sal::static_int_cast< size_t >(::getpagesize());
     271             : #else /* POSIX */
     272       85014 :     return sal::static_int_cast< size_t >(::sysconf(_SC_PAGESIZE));
     273             : #endif /* xBSD || POSIX */
     274             : }
     275             : 
     276           0 : sal_uInt64 FileHandle_Impl::getPos() const
     277             : {
     278           0 :     return sal::static_int_cast< sal_uInt64 >(m_fileptr);
     279             : }
     280             : 
     281           0 : oslFileError FileHandle_Impl::setPos (sal_uInt64 uPos)
     282             : {
     283             :     SAL_INFO("sal.file", "FileHandle_Impl::setPos(" << m_fd << ", " << getPos() << ") => " << uPos);
     284           0 :     m_fileptr = sal::static_int_cast< off_t >(uPos);
     285           0 :     return osl_File_E_None;
     286             : }
     287             : 
     288          20 : sal_uInt64 FileHandle_Impl::getSize() const
     289             : {
     290          20 :     off_t const bufend = std::max((off_t)(0), m_bufptr) + m_buflen;
     291          20 :     return std::max(m_size, sal::static_int_cast< sal_uInt64 >(bufend));
     292             : }
     293             : 
     294           0 : oslFileError FileHandle_Impl::setSize (sal_uInt64 uSize)
     295             : {
     296           0 :     off_t const nSize = sal::static_int_cast< off_t >(uSize);
     297           0 :     if (-1 == ftruncate_with_name (m_fd, nSize, m_strFilePath))
     298             :     {
     299             :         /* Failure. Save original result. Try fallback algorithm */
     300           0 :         oslFileError result = oslTranslateFileError (OSL_FET_ERROR, errno);
     301             : 
     302             :         /* Check against current size. Fail upon 'shrink' */
     303           0 :         if (uSize <= getSize())
     304             :         {
     305             :             /* Failure upon 'shrink'. Return original result */
     306           0 :             return (result);
     307             :         }
     308             : 
     309             :         /* Save current position */
     310           0 :         off_t const nCurPos = (off_t)lseek (m_fd, (off_t)0, SEEK_CUR);
     311           0 :         if (nCurPos == (off_t)(-1))
     312           0 :             return (result);
     313             : 
     314             :         /* Try 'expand' via 'lseek()' and 'write()' */
     315           0 :         if (-1 == lseek (m_fd, (off_t)(nSize - 1), SEEK_SET))
     316           0 :             return (result);
     317             : 
     318           0 :         if (-1 == write (m_fd, (char*)"", (size_t)1))
     319             :         {
     320             :             /* Failure. Restore saved position */
     321           0 :             (void) lseek (m_fd, (off_t)(nCurPos), SEEK_SET);
     322           0 :             return (result);
     323             :         }
     324             : 
     325             :         /* Success. Restore saved position */
     326           0 :         if (-1 == lseek (m_fd, (off_t)nCurPos, SEEK_SET))
     327           0 :             return (result);
     328             :     }
     329             : 
     330             :     SAL_INFO("sal.file", "osl_setFileSize(" << m_fd << ", " << getSize() << ") => " << nSize);
     331           0 :     m_size = sal::static_int_cast< sal_uInt64 >(nSize);
     332           0 :     return osl_File_E_None;
     333             : }
     334             : 
     335      255039 : oslFileError FileHandle_Impl::readAt (
     336             :     off_t        nOffset,
     337             :     void *       pBuffer,
     338             :     size_t       nBytesRequested,
     339             :     sal_uInt64 * pBytesRead)
     340             : {
     341             :     OSL_PRECOND((m_state & STATE_SEEKABLE), "FileHandle_Impl::readAt(): not seekable");
     342      255039 :     if (!(m_state & STATE_SEEKABLE))
     343           0 :         return osl_File_E_SPIPE;
     344             : 
     345             :     OSL_PRECOND((m_state & STATE_READABLE), "FileHandle_Impl::readAt(): not readable");
     346      255039 :     if (!(m_state & STATE_READABLE))
     347           0 :         return osl_File_E_BADF;
     348             : 
     349      255039 :     if (m_kind == KIND_MEM)
     350             :     {
     351             :         ssize_t nBytes;
     352             : 
     353           0 :         m_offset = nOffset;
     354             : 
     355           0 :         if ((sal_uInt64) m_offset >= m_size)
     356           0 :             nBytes = 0;
     357             :         else
     358             :         {
     359           0 :             nBytes = std::min(nBytesRequested, (size_t) (m_size - m_offset));
     360           0 :             memmove(pBuffer, m_buffer + m_offset, nBytes);
     361           0 :             m_offset += nBytes;
     362             :         }
     363           0 :         *pBytesRead = nBytes;
     364           0 :         return osl_File_E_None;
     365             :     }
     366             : 
     367      255039 :     ssize_t nBytes = ::pread (m_fd, pBuffer, nBytesRequested, nOffset);
     368      255039 :     if ((-1 == nBytes) && (EOVERFLOW == errno))
     369             :     {
     370             :         /* Some 'pread()'s fail with EOVERFLOW when reading at (or past)
     371             :          * end-of-file, different from 'lseek() + read()' behaviour.
     372             :          * Returning '0 bytes read' and 'osl_File_E_None' instead.
     373             :          */
     374           0 :         nBytes = 0;
     375             :     }
     376      255039 :     if (-1 == nBytes)
     377           0 :         return oslTranslateFileError (OSL_FET_ERROR, errno);
     378             : 
     379             :     SAL_INFO("sal.file", "FileHandle_Impl::readAt(" << m_fd << ", " << nOffset << ", " << nBytes << ")");
     380      255039 :     *pBytesRead = nBytes;
     381      255039 :     return osl_File_E_None;
     382             : }
     383             : 
     384           1 : oslFileError FileHandle_Impl::writeAt (
     385             :     off_t        nOffset,
     386             :     void const * pBuffer,
     387             :     size_t       nBytesToWrite,
     388             :     sal_uInt64 * pBytesWritten)
     389             : {
     390             :     OSL_PRECOND((m_state & STATE_SEEKABLE), "FileHandle_Impl::writeAt(): not seekable");
     391           1 :     if (!(m_state & STATE_SEEKABLE))
     392           0 :         return osl_File_E_SPIPE;
     393             : 
     394             :     OSL_PRECOND((m_state & STATE_WRITEABLE), "FileHandle_Impl::writeAt(): not writeable");
     395           1 :     if (!(m_state & STATE_WRITEABLE))
     396           0 :         return osl_File_E_BADF;
     397             : 
     398           1 :     ssize_t nBytes = ::pwrite (m_fd, pBuffer, nBytesToWrite, nOffset);
     399           1 :     if (-1 == nBytes)
     400           0 :         return oslTranslateFileError (OSL_FET_ERROR, errno);
     401             : 
     402             :     SAL_INFO("sal.file", "FileHandle_Impl::writeAt(" << m_fd << ", " << nOffset << ", " << nBytes << ")");
     403           1 :     m_size = std::max (m_size, sal::static_int_cast< sal_uInt64 >(nOffset + nBytes));
     404             : 
     405           1 :     *pBytesWritten = nBytes;
     406           1 :     return osl_File_E_None;
     407             : }
     408             : 
     409       49718 : oslFileError FileHandle_Impl::readFileAt (
     410             :     off_t        nOffset,
     411             :     void *       pBuffer,
     412             :     size_t       nBytesRequested,
     413             :     sal_uInt64 * pBytesRead)
     414             : {
     415       49718 :     if (0 == (m_state & STATE_SEEKABLE))
     416             :     {
     417             :         // not seekable (pipe)
     418       49718 :         ssize_t nBytes = ::read (m_fd, pBuffer, nBytesRequested);
     419       49718 :         if (-1 == nBytes)
     420           0 :             return oslTranslateFileError (OSL_FET_ERROR, errno);
     421       49718 :         *pBytesRead = nBytes;
     422       49718 :         return osl_File_E_None;
     423             :     }
     424           0 :     else if (m_kind == KIND_MEM || 0 == m_buffer)
     425             :     {
     426             :         // not buffered
     427           0 :         return readAt (nOffset, pBuffer, nBytesRequested, pBytesRead);
     428             :     }
     429             :     else
     430             :     {
     431           0 :         sal_uInt8 * buffer = static_cast<sal_uInt8*>(pBuffer);
     432           0 :         for (*pBytesRead = 0; nBytesRequested > 0; )
     433             :         {
     434           0 :             off_t  const bufptr = (nOffset / m_bufsiz) * m_bufsiz;
     435           0 :             size_t const bufpos = (nOffset % m_bufsiz);
     436             : 
     437           0 :             if (bufptr != m_bufptr)
     438             :             {
     439             :                 // flush current buffer
     440           0 :                 oslFileError result = syncFile();
     441           0 :                 if (result != osl_File_E_None)
     442           0 :                     return (result);
     443           0 :                 m_bufptr = -1, m_buflen = 0;
     444             : 
     445           0 :                 if (nBytesRequested >= m_bufsiz)
     446             :                 {
     447             :                     // buffer too small, read through from file
     448           0 :                     sal_uInt64 uDone = 0;
     449           0 :                     result = readAt (nOffset, &(buffer[*pBytesRead]), nBytesRequested, &uDone);
     450           0 :                     if (result != osl_File_E_None)
     451           0 :                         return (result);
     452             : 
     453           0 :                     *pBytesRead += uDone;
     454           0 :                     return osl_File_E_None;
     455             :                 }
     456             : 
     457             :                 // update buffer (pointer)
     458           0 :                 sal_uInt64 uDone = 0;
     459           0 :                 result = readAt (bufptr, m_buffer, m_bufsiz, &uDone);
     460           0 :                 if (result != osl_File_E_None)
     461           0 :                     return (result);
     462           0 :                 m_bufptr = bufptr, m_buflen = uDone;
     463             :             }
     464           0 :             if (bufpos >= m_buflen)
     465             :             {
     466             :                 // end of file
     467           0 :                 return osl_File_E_None;
     468             :             }
     469             : 
     470           0 :             size_t const bytes = std::min (m_buflen - bufpos, nBytesRequested);
     471             :             SAL_INFO("sal.file", "FileHandle_Impl::readFileAt(" << m_fd << ", " << nOffset << ", " << bytes << ")");
     472             : 
     473           0 :             memcpy (&(buffer[*pBytesRead]), &(m_buffer[bufpos]), bytes);
     474           0 :             nBytesRequested -= bytes, *pBytesRead += bytes, nOffset += bytes;
     475             :         }
     476           0 :         return osl_File_E_None;
     477             :     }
     478             : }
     479             : 
     480          14 : oslFileError FileHandle_Impl::writeFileAt (
     481             :     off_t        nOffset,
     482             :     void const * pBuffer,
     483             :     size_t       nBytesToWrite,
     484             :     sal_uInt64 * pBytesWritten)
     485             : {
     486          14 :     if (0 == (m_state & STATE_SEEKABLE))
     487             :     {
     488             :         // not seekable (pipe)
     489           0 :         ssize_t nBytes = ::write (m_fd, pBuffer, nBytesToWrite);
     490           0 :         if (-1 == nBytes)
     491           0 :             return oslTranslateFileError (OSL_FET_ERROR, errno);
     492           0 :         *pBytesWritten = nBytes;
     493           0 :         return osl_File_E_None;
     494             :     }
     495          14 :     else if (0 == m_buffer)
     496             :     {
     497             :         // not buffered
     498           0 :         return writeAt (nOffset, pBuffer, nBytesToWrite, pBytesWritten);
     499             :     }
     500             :     else
     501             :     {
     502          14 :         sal_uInt8 const * buffer = static_cast<sal_uInt8 const *>(pBuffer);
     503          42 :         for (*pBytesWritten = 0; nBytesToWrite > 0; )
     504             :         {
     505          14 :             off_t  const bufptr = (nOffset / m_bufsiz) * m_bufsiz;
     506          14 :             size_t const bufpos = (nOffset % m_bufsiz);
     507          14 :             if (bufptr != m_bufptr)
     508             :             {
     509             :                 // flush current buffer
     510           1 :                 oslFileError result = syncFile();
     511           1 :                 if (result != osl_File_E_None)
     512           0 :                     return (result);
     513           1 :                 m_bufptr = -1, m_buflen = 0;
     514             : 
     515           1 :                 if (nBytesToWrite >= m_bufsiz)
     516             :                 {
     517             :                     // buffer to small, write through to file
     518           0 :                     sal_uInt64 uDone = 0;
     519           0 :                     result = writeAt (nOffset, &(buffer[*pBytesWritten]), nBytesToWrite, &uDone);
     520           0 :                     if (result != osl_File_E_None)
     521           0 :                         return (result);
     522           0 :                     if (uDone != nBytesToWrite)
     523           0 :                         return osl_File_E_IO;
     524             : 
     525           0 :                     *pBytesWritten += uDone;
     526           0 :                     return osl_File_E_None;
     527             :                 }
     528             : 
     529             :                 // update buffer (pointer)
     530           1 :                 sal_uInt64 uDone = 0;
     531           1 :                 result = readAt (bufptr, m_buffer, m_bufsiz, &uDone);
     532           1 :                 if (result != osl_File_E_None)
     533           0 :                     return (result);
     534           1 :                 m_bufptr = bufptr, m_buflen = uDone;
     535             :             }
     536             : 
     537          14 :             size_t const bytes = std::min (m_bufsiz - bufpos, nBytesToWrite);
     538             :             SAL_INFO("sal.file", "FileHandle_Impl::writeFileAt(" << m_fd << ", " << nOffset << ", " << bytes << ")");
     539             : 
     540          14 :             memcpy (&(m_buffer[bufpos]), &(buffer[*pBytesWritten]), bytes);
     541          14 :             nBytesToWrite -= bytes, *pBytesWritten += bytes, nOffset += bytes;
     542             : 
     543          14 :             m_buflen = std::max(m_buflen, bufpos + bytes);
     544          14 :             m_state |= STATE_MODIFIED;
     545             :         }
     546          14 :         return osl_File_E_None;
     547             :     }
     548             : }
     549             : 
     550     3783054 : oslFileError FileHandle_Impl::readLineAt (
     551             :     off_t           nOffset,
     552             :     sal_Sequence ** ppSequence,
     553             :     sal_uInt64 *    pBytesRead)
     554             : {
     555     3783054 :     oslFileError result = osl_File_E_None;
     556             : 
     557     3783054 :     off_t bufptr = nOffset / m_bufsiz * m_bufsiz;
     558     3783054 :     if (bufptr != m_bufptr)
     559             :     {
     560             :         /* flush current buffer */
     561      255038 :         result = syncFile();
     562      255038 :         if (result != osl_File_E_None)
     563           0 :             return (result);
     564             : 
     565             :         /* update buffer (pointer) */
     566      255038 :         sal_uInt64 uDone = 0;
     567      255038 :         result = readAt (bufptr, m_buffer, m_bufsiz, &uDone);
     568      255038 :         if (result != osl_File_E_None)
     569           0 :             return (result);
     570             : 
     571      255038 :         m_bufptr = bufptr, m_buflen = uDone;
     572             :     }
     573             : 
     574             :     static int const LINE_STATE_BEGIN = 0;
     575             :     static int const LINE_STATE_CR    = 1;
     576             :     static int const LINE_STATE_LF    = 2;
     577             : 
     578     3783054 :     size_t bufpos = nOffset - m_bufptr, curpos = bufpos, dstpos = 0;
     579     3783054 :     int    state  = (bufpos >= m_buflen) ? LINE_STATE_LF : LINE_STATE_BEGIN;
     580             : 
     581   211256395 :     for ( ; state != LINE_STATE_LF; )
     582             :     {
     583   203690288 :         if (curpos >= m_buflen)
     584             :         {
     585             :             /* buffer examined */
     586           1 :             if (0 < (curpos - bufpos))
     587             :             {
     588             :                 /* flush buffer to sequence */
     589             :                 result = writeSequence_Impl (
     590           1 :                     ppSequence, &dstpos, &(m_buffer[bufpos]), curpos - bufpos);
     591           1 :                 if (result != osl_File_E_None)
     592           0 :                     return (result);
     593           1 :                 *pBytesRead += curpos - bufpos, nOffset += curpos - bufpos;
     594             :             }
     595             : 
     596           1 :             bufptr = nOffset / m_bufsiz * m_bufsiz;
     597           1 :             if (bufptr != m_bufptr)
     598             :             {
     599             :                 /* update buffer (pointer) */
     600           0 :                 sal_uInt64 uDone = 0;
     601           0 :                 result = readAt (bufptr, m_buffer, m_bufsiz, &uDone);
     602           0 :                 if (result != osl_File_E_None)
     603           0 :                     return (result);
     604           0 :                 m_bufptr = bufptr, m_buflen = uDone;
     605             :             }
     606             : 
     607           1 :             bufpos = nOffset - m_bufptr, curpos = bufpos;
     608           1 :             if (bufpos >= m_buflen)
     609           1 :                 break;
     610             :         }
     611   203690287 :         switch (state)
     612             :         {
     613             :         case LINE_STATE_CR:
     614           0 :             state = LINE_STATE_LF;
     615           0 :             switch (m_buffer[curpos])
     616             :             {
     617             :             case 0x0A: /* CRLF */
     618             :                 /* eat current char */
     619           0 :                 curpos++;
     620           0 :                 break;
     621             :             default: /* single CR */
     622             :                 /* keep current char */
     623           0 :                 break;
     624             :             }
     625           0 :             break;
     626             :         default:
     627             :             /* determine next state */
     628   203690287 :             switch (m_buffer[curpos])
     629             :             {
     630             :             case 0x0A: /* single LF */
     631     3528016 :                 state = LINE_STATE_LF;
     632     3528016 :                 break;
     633             :             case 0x0D: /* CR */
     634           0 :                 state = LINE_STATE_CR;
     635           0 :                 break;
     636             :             default: /* advance to next char */
     637   200162271 :                 curpos++;
     638   200162271 :                 break;
     639             :             }
     640   203690287 :             if (state != LINE_STATE_BEGIN)
     641             :             {
     642             :                 /* skip the newline char */
     643     3528016 :                 curpos++;
     644             : 
     645             :                 /* flush buffer to sequence */
     646             :                 result = writeSequence_Impl (
     647     3528016 :                     ppSequence, &dstpos, &(m_buffer[bufpos]), curpos - bufpos - 1);
     648     3528016 :                 if (result != osl_File_E_None)
     649           0 :                     return (result);
     650     3528016 :                 *pBytesRead += curpos - bufpos, nOffset += curpos - bufpos;
     651             :             }
     652   203690287 :             break;
     653             :         }
     654             :     }
     655             : 
     656     3783054 :     result = writeSequence_Impl (ppSequence, &dstpos, 0, 0);
     657     3783054 :     if (result != osl_File_E_None)
     658           0 :         return (result);
     659     3783054 :     if (0 < dstpos)
     660     3528017 :         return osl_File_E_None;
     661      255037 :     if (bufpos >= m_buflen)
     662      255037 :         return osl_File_E_AGAIN;
     663           0 :     return osl_File_E_None;
     664             : }
     665             : 
     666     7311071 : oslFileError FileHandle_Impl::writeSequence_Impl (
     667             :     sal_Sequence ** ppSequence,
     668             :     size_t *        pnOffset,
     669             :     const void *    pBuffer,
     670             :     size_t          nBytes)
     671             : {
     672     7311071 :     sal_Int32 nElements = *pnOffset + nBytes;
     673     7311071 :     if (!*ppSequence)
     674             :     {
     675             :         /* construct sequence */
     676           0 :         rtl_byte_sequence_constructNoDefault(ppSequence, nElements);
     677             :     }
     678     7311071 :     else if (nElements != (*ppSequence)->nElements)
     679             :     {
     680             :         /* resize sequence */
     681     3485515 :         rtl_byte_sequence_realloc(ppSequence, nElements);
     682             :     }
     683     7311071 :     if (*ppSequence != 0)
     684             :     {
     685             :         /* fill sequence */
     686     7311071 :         memcpy(&((*ppSequence)->elements[*pnOffset]), pBuffer, nBytes), *pnOffset += nBytes;
     687             :     }
     688     7311071 :     return (*ppSequence != 0) ? osl_File_E_None : osl_File_E_NOMEM;
     689             : }
     690             : 
     691      552607 : oslFileError FileHandle_Impl::syncFile()
     692             : {
     693      552607 :     oslFileError result = osl_File_E_None;
     694      552607 :     if (m_state & STATE_MODIFIED)
     695             :     {
     696           1 :         sal_uInt64 uDone = 0;
     697           1 :         result = writeAt (m_bufptr, m_buffer, m_buflen, &uDone);
     698           1 :         if (result != osl_File_E_None)
     699           0 :             return (result);
     700           1 :         if (uDone != m_buflen)
     701           0 :             return osl_File_E_IO;
     702           1 :         m_state &= ~STATE_MODIFIED;
     703             :     }
     704      552607 :     return (result);
     705             : }
     706             : 
     707       42509 : oslFileHandle osl::detail::createFileHandleFromFD( int fd )
     708             : {
     709       42509 :     if (-1 == fd)
     710           0 :         return 0; // EINVAL
     711             : 
     712             :     struct stat aFileStat;
     713       42509 :     if (-1 == fstat (fd, &aFileStat))
     714           0 :         return 0; // EBADF
     715             : 
     716       42509 :     FileHandle_Impl * pImpl = new FileHandle_Impl (fd);
     717       42509 :     if (0 == pImpl)
     718           0 :         return 0; // ENOMEM
     719             : 
     720             :     // assume writeable
     721       42509 :     pImpl->m_state |= FileHandle_Impl::STATE_WRITEABLE;
     722       42509 :     if (!S_ISREG(aFileStat.st_mode))
     723             :     {
     724             :         /* not a regular file, mark not seekable */
     725       42509 :         pImpl->m_state &= ~FileHandle_Impl::STATE_SEEKABLE;
     726             :     }
     727             :     else
     728             :     {
     729             :         /* regular file, init current size */
     730           0 :         pImpl->m_size = sal::static_int_cast< sal_uInt64 >(aFileStat.st_size);
     731             :     }
     732             : 
     733             :     SAL_INFO("sal.file", "osl::detail::createFileHandleFromFD(" << pImpl->m_fd << ", writeable) => " << pImpl->m_strFilePath);
     734       42509 :     return (oslFileHandle)(pImpl);
     735             : }
     736             : 
     737      255059 : static int osl_file_adjustLockFlags (const char * path, int flags)
     738             : {
     739             : #ifdef MACOSX
     740             :     /*
     741             :      * The AFP implementation of MacOS X 10.4 treats O_EXLOCK in a way
     742             :      * that makes it impossible for OOo to create a backup copy of the
     743             :      * file it keeps opened. OTOH O_SHLOCK for AFP behaves as desired by
     744             :      * the OOo file handling, so we need to check the path of the file
     745             :      * for the filesystem name.
     746             :      */
     747             :     struct statfs s;
     748             :     if( 0 <= statfs( path, &s ) )
     749             :     {
     750             :         if( 0 == strncmp("afpfs", s.f_fstypename, 5) )
     751             :         {
     752             :             flags &= ~O_EXLOCK;
     753             :             flags |=  O_SHLOCK;
     754             :         }
     755             :         else
     756             :         {
     757             :             /* Needed flags to allow opening a webdav file */
     758             :             flags &= ~(O_EXLOCK | O_SHLOCK | O_NONBLOCK);
     759             :         }
     760             :     }
     761             : #endif /* MACOSX */
     762             : 
     763             :     (void) path;
     764      255059 :     return flags;
     765             : }
     766             : 
     767      255059 : static bool osl_file_queryLocking (sal_uInt32 uFlags)
     768             : {
     769             : #if !defined HAVE_O_EXLOCK
     770      255059 :     if (!(uFlags & osl_File_OpenFlag_NoLock)
     771      255059 :         && ((uFlags & osl_File_OpenFlag_Write)
     772      255058 :             || (uFlags & osl_File_OpenFlag_Create)))
     773             :     {
     774           1 :         static bool enabled = getenv("SAL_ENABLE_FILE_LOCKING") != 0;
     775             :             // getenv is not thread safe, so minimize use of result
     776           1 :         return enabled;
     777             :     }
     778             : #endif
     779             :     (void) uFlags;
     780      255058 :     return false;
     781             : }
     782             : 
     783             : #ifdef UNX
     784             : 
     785             : static oslFileError
     786           0 : osl_openMemoryAsFile( void *address, size_t size, oslFileHandle *pHandle, const char *path )
     787             : {
     788             :     oslFileError eRet;
     789           0 :     FileHandle_Impl * pImpl = new FileHandle_Impl (-1, FileHandle_Impl::KIND_MEM, path);
     790           0 :     if (!pImpl)
     791             :     {
     792           0 :         eRet = oslTranslateFileError (OSL_FET_ERROR, ENOMEM);
     793           0 :         return eRet;
     794             :     }
     795           0 :     pImpl->m_size = sal::static_int_cast< sal_uInt64 >(size);
     796             : 
     797           0 :     *pHandle = (oslFileHandle)(pImpl);
     798             : 
     799           0 :     pImpl->m_bufptr = 0;
     800           0 :     pImpl->m_buflen = size;
     801             : 
     802           0 :     pImpl->m_bufsiz = size;
     803           0 :     pImpl->m_buffer = (sal_uInt8*) address;
     804             : 
     805           0 :     return osl_File_E_None;
     806             : }
     807             : 
     808             : oslFileError
     809           0 : SAL_CALL osl_openMemoryAsFile( void *address, size_t size, oslFileHandle *pHandle )
     810             : {
     811           0 :     return osl_openMemoryAsFile( address, size, pHandle, "<anon>" );
     812             : }
     813             : 
     814             : #endif
     815             : 
     816             : #ifdef HAVE_O_EXLOCK
     817             : #define OPEN_WRITE_FLAGS ( O_RDWR | O_EXLOCK | O_NONBLOCK )
     818             : #define OPEN_CREATE_FLAGS ( O_CREAT | O_RDWR | O_EXLOCK | O_NONBLOCK )
     819             : #else
     820             : #define OPEN_WRITE_FLAGS ( O_RDWR )
     821             : #define OPEN_CREATE_FLAGS ( O_CREAT | O_RDWR )
     822             : #endif
     823             : 
     824             : oslFileError
     825      255059 : SAL_CALL osl_openFilePath( const char *cpFilePath, oslFileHandle* pHandle, sal_uInt32 uFlags )
     826             : {
     827             :     oslFileError eRet;
     828             : 
     829             : #ifdef ANDROID
     830             :     /* Opening a file from /assets read-only means
     831             :      * we should mmap it from the .apk file
     832             :      */
     833             :     if (strncmp (cpFilePath, "/assets/", sizeof ("/assets/") - 1) == 0)
     834             :     {
     835             :         if (uFlags & osl_File_OpenFlag_Write)
     836             :         {
     837             :             // It seems to work better to silently "open" it read-only
     838             :             // and let write attempts, if any, fail later. Otherwise
     839             :             // loading a document from /assets fails with that idiotic
     840             :             // "General Error" dialog...
     841             :         }
     842             :         void *address;
     843             :         size_t size;
     844             :         address = lo_apkentry(cpFilePath, &size);
     845             :         SAL_INFO("sal.file", "osl_openFile(" << cpFilePath << ") => " << address);
     846             :         if (address == NULL)
     847             :         {
     848             :             errno = ENOENT;
     849             :             return osl_File_E_NOENT;
     850             :         }
     851             :         return osl_openMemoryAsFile(address, size, pHandle, cpFilePath);
     852             :     }
     853             : #endif
     854             : 
     855             :     /* set mode and flags */
     856      255059 :     int mode  = S_IRUSR | S_IRGRP | S_IROTH;
     857      255059 :     int flags = O_RDONLY;
     858      255059 :     if (uFlags & osl_File_OpenFlag_Write)
     859             :     {
     860           1 :         mode |= S_IWUSR | S_IWGRP | S_IWOTH;
     861           1 :         flags = OPEN_WRITE_FLAGS;
     862             :     }
     863      255059 :     if (uFlags & osl_File_OpenFlag_Create)
     864             :     {
     865           1 :         mode |= S_IWUSR | S_IWGRP | S_IWOTH;
     866           1 :         flags = OPEN_CREATE_FLAGS;
     867             :     }
     868             : 
     869             :     /* Check for flags passed in from SvFileStream::Open() */
     870      255059 :     if (uFlags & osl_File_OpenFlag_Trunc)
     871           0 :         flags |= O_TRUNC;
     872      255059 :     if (!(uFlags & osl_File_OpenFlag_NoExcl))
     873      255059 :         flags |= O_EXCL;
     874             : 
     875      255059 :     if (uFlags & osl_File_OpenFlag_NoLock)
     876             :     {
     877             : #ifdef HAVE_O_EXLOCK
     878             :         flags &= ~(O_EXLOCK | O_SHLOCK | O_NONBLOCK);
     879             : #endif /* HAVE_O_EXLOCK */
     880             :     }
     881             :     else
     882             :     {
     883      255059 :         flags = osl_file_adjustLockFlags (cpFilePath, flags);
     884             :     }
     885             : 
     886             :     /* open the file */
     887      255059 :     int fd = open_c( cpFilePath, flags, mode );
     888             : 
     889             : #ifdef IOS
     890             :     /* Horrible hack: If opening for RDWR and getting EPERM, just try
     891             :      * again for RDONLY. Quicker this way than to figure out why
     892             :      * we get that oh so useful General Error when trying to open a
     893             :      * read-only document.
     894             :      */
     895             :     if (-1 == fd && (flags & O_RDWR) && EPERM == errno)
     896             :     {
     897             :         int rdonly_flags = (flags & ~O_ACCMODE) | O_RDONLY;
     898             :         fd = open_c( cpFilePath, rdonly_flags, mode );
     899             :     }
     900             : #endif
     901      255059 :     if (-1 == fd)
     902             :     {
     903           0 :         int saved_errno = errno;
     904             :         SAL_INFO("sal.file", "osl_openFile(" << cpFilePath << ", " << (flags & O_RDWR ? "writeable":"readonly") << ") failed: " << strerror(saved_errno));
     905           0 :         return oslTranslateFileError (OSL_FET_ERROR, saved_errno);
     906             :     }
     907             : 
     908             : #if !HAVE_FEATURE_MACOSX_SANDBOX
     909             :     /* reset O_NONBLOCK flag */
     910      255059 :     if (flags & O_NONBLOCK)
     911             :     {
     912           0 :         int f = fcntl (fd, F_GETFL, 0);
     913           0 :         if (-1 == f)
     914             :         {
     915           0 :             int saved_errno = errno;
     916             :             SAL_INFO("sal.file", "osl_openFile(" << cpFilePath << ", " << (flags & O_RDWR ? "writeable":"readonly") << "): fcntl(" << fd << ", F_GETFL) failed: " << strerror(saved_errno));
     917           0 :             eRet = oslTranslateFileError (OSL_FET_ERROR, saved_errno);
     918           0 :             (void) close(fd);
     919           0 :             return eRet;
     920             :         }
     921           0 :         if (-1 == fcntl (fd, F_SETFL, (f & ~O_NONBLOCK)))
     922             :         {
     923           0 :             int saved_errno = errno;
     924             :              SAL_INFO("sal.file", "osl_openFile(" << cpFilePath << ", " << (flags & O_RDWR ? "writeable":"readonly") << "): fcntl(" << fd << ", F_SETFL) failed: " << strerror(saved_errno));
     925           0 :             eRet = oslTranslateFileError (OSL_FET_ERROR, saved_errno);
     926           0 :             (void) close(fd);
     927           0 :             return eRet;
     928             :         }
     929             :     }
     930             : #endif
     931             :     /* get file status (mode, size) */
     932             :     struct stat aFileStat;
     933      255059 :     if (-1 == fstat (fd, &aFileStat))
     934             :     {
     935           0 :         int saved_errno = errno;
     936             :         SAL_INFO("sal.file", "osl_openFile(" << cpFilePath << ", " << (flags & O_RDWR ? "writeable":"readonly") << "): fstat(" << fd << ") failed: " << strerror(saved_errno));
     937           0 :         eRet = oslTranslateFileError (OSL_FET_ERROR, saved_errno);
     938           0 :         (void) close(fd);
     939           0 :         return eRet;
     940             :     }
     941      255059 :     if (!S_ISREG(aFileStat.st_mode))
     942             :     {
     943             :         /* we only open regular files here */
     944             :         SAL_INFO("sal.file", "osl_openFile(" << cpFilePath << "): not a regular file");
     945           0 :         (void) close(fd);
     946           0 :         return osl_File_E_INVAL;
     947             :     }
     948             : 
     949      255059 :     if (osl_file_queryLocking (uFlags))
     950             :     {
     951             : #ifdef MACOSX
     952             :         if (-1 == flock (fd, LOCK_EX | LOCK_NB))
     953             :         {
     954             :             /* Mac OSX returns ENOTSUP for webdav drives. We should try read lock */
     955             :             if ((errno != ENOTSUP) || ((-1 == flock (fd, LOCK_SH | LOCK_NB)) && (errno != ENOTSUP)))
     956             :             {
     957             :                 eRet = oslTranslateFileError (OSL_FET_ERROR, errno);
     958             :                 (void) close(fd);
     959             :                 return eRet;
     960             :             }
     961             :         }
     962             : #else   /* F_SETLK */
     963             :         {
     964             :             struct flock aflock;
     965             : 
     966           1 :             aflock.l_type = F_WRLCK;
     967           1 :             aflock.l_whence = SEEK_SET;
     968           1 :             aflock.l_start = 0;
     969           1 :             aflock.l_len = 0;
     970             : 
     971           1 :             if (-1 == fcntl (fd, F_SETLK, &aflock))
     972             :             {
     973           0 :                 int saved_errno = errno;
     974             :                 SAL_INFO("sal.file", "osl_openFile(" << cpFilePath << ", " << (flags & O_RDWR ? "writeable":"readonly") << "): fcntl(" << fd << ", F_SETLK) failed: " << strerror(saved_errno));
     975           0 :                 eRet = oslTranslateFileError (OSL_FET_ERROR, saved_errno);
     976           0 :                 (void) close(fd);
     977           0 :                 return eRet;
     978             :             }
     979             :         }
     980             : #endif  /* F_SETLK */
     981             :     }
     982             : 
     983             :     /* allocate memory for impl structure */
     984      255059 :     FileHandle_Impl * pImpl = new FileHandle_Impl (fd, FileHandle_Impl::KIND_FD, cpFilePath);
     985      255059 :     if (!pImpl)
     986             :     {
     987           0 :         eRet = oslTranslateFileError (OSL_FET_ERROR, ENOMEM);
     988           0 :         (void) close(fd);
     989           0 :         return eRet;
     990             :     }
     991      255059 :     if (flags & O_RDWR)
     992           1 :         pImpl->m_state |= FileHandle_Impl::STATE_WRITEABLE;
     993      255059 :     pImpl->m_size = sal::static_int_cast< sal_uInt64 >(aFileStat.st_size);
     994             : 
     995             :     SAL_INFO("sal.file", "osl_openFile(" << cpFilePath << ", " << (flags & O_RDWR ? "writeable":"readonly") << ") => " << pImpl->m_fd);
     996             : 
     997      255059 :     *pHandle = (oslFileHandle)(pImpl);
     998      255059 :     return osl_File_E_None;
     999             : }
    1000             : 
    1001             : oslFileError
    1002      255059 : SAL_CALL osl_openFile( rtl_uString* ustrFileURL, oslFileHandle* pHandle, sal_uInt32 uFlags )
    1003             : {
    1004             :     oslFileError eRet;
    1005             : 
    1006      255059 :     if ((ustrFileURL == 0) || (ustrFileURL->length == 0) || (pHandle == 0))
    1007           0 :         return osl_File_E_INVAL;
    1008             : 
    1009             :     /* convert file URL to system path */
    1010             :     char buffer[PATH_MAX];
    1011      255059 :     eRet = FileURLToPath (buffer, sizeof(buffer), ustrFileURL);
    1012      255059 :     if (eRet != osl_File_E_None)
    1013           0 :         return eRet;
    1014             : 
    1015             : #ifdef MACOSX
    1016             :     if (macxp_resolveAlias (buffer, sizeof(buffer)) != 0)
    1017             :         return oslTranslateFileError (OSL_FET_ERROR, errno);
    1018             : #endif /* MACOSX */
    1019             : 
    1020      255059 :     return osl_openFilePath (buffer, pHandle, uFlags);
    1021             : }
    1022             : 
    1023             : oslFileError
    1024      297568 : SAL_CALL osl_closeFile( oslFileHandle Handle )
    1025             : {
    1026      297568 :     FileHandle_Impl* pImpl = static_cast<FileHandle_Impl*>(Handle);
    1027             : 
    1028      297568 :     if (pImpl == 0)
    1029           0 :         return osl_File_E_INVAL;
    1030             : 
    1031             :     SAL_INFO("sal.file", "osl_closeFile(" << rtl::OString(pImpl->m_strFilePath) << ":" << pImpl->m_fd << ")");
    1032             : 
    1033      297568 :     if (pImpl->m_kind == FileHandle_Impl::KIND_MEM)
    1034             :     {
    1035           0 :         delete pImpl;
    1036           0 :         return osl_File_E_None;
    1037             :     }
    1038             : 
    1039      297568 :     if (pImpl->m_fd < 0)
    1040           0 :         return osl_File_E_INVAL;
    1041             : 
    1042      297568 :     (void) pthread_mutex_lock (&(pImpl->m_mutex));
    1043             : 
    1044             :     /* close(2) implicitly (and unconditionally) unlocks */
    1045      297568 :     oslFileError result = pImpl->syncFile();
    1046      297568 :     if (result != osl_File_E_None)
    1047             :     {
    1048             :         /* close, ignoring double failure */
    1049           0 :         (void) close (pImpl->m_fd);
    1050             :     }
    1051      297568 :     else if (-1 == close (pImpl->m_fd))
    1052             :     {
    1053             :         /* translate error code */
    1054           0 :         result = oslTranslateFileError (OSL_FET_ERROR, errno);
    1055             :     }
    1056             : 
    1057      297568 :     (void) pthread_mutex_unlock (&(pImpl->m_mutex));
    1058      297568 :     delete pImpl;
    1059      297568 :     return (result);
    1060             : }
    1061             : 
    1062             : oslFileError
    1063           0 : SAL_CALL osl_syncFile(oslFileHandle Handle)
    1064             : {
    1065           0 :     FileHandle_Impl* pImpl = static_cast<FileHandle_Impl*>(Handle);
    1066             : 
    1067           0 :     if ((0 == pImpl) || ((pImpl->m_kind == FileHandle_Impl::KIND_FD) && (-1 == pImpl->m_fd)))
    1068           0 :         return osl_File_E_INVAL;
    1069             : 
    1070           0 :     if (pImpl->m_kind == FileHandle_Impl::KIND_MEM)
    1071           0 :         return osl_File_E_None;
    1072             : 
    1073           0 :     FileHandle_Impl::Guard lock (&(pImpl->m_mutex));
    1074             : 
    1075             :     SAL_INFO("sal.file", "osl_syncFile(" << pImpl->m_fd << ")");
    1076           0 :     oslFileError result = pImpl->syncFile();
    1077           0 :     if (result != osl_File_E_None)
    1078           0 :         return (result);
    1079           0 :     if (-1 == fsync (pImpl->m_fd))
    1080           0 :         return oslTranslateFileError (OSL_FET_ERROR, errno);
    1081             : 
    1082           0 :     return osl_File_E_None;
    1083             : }
    1084             : 
    1085             : oslFileError
    1086           0 : SAL_CALL osl_getFileOSHandle(
    1087             :     oslFileHandle Handle,
    1088             :     sal_IntPtr *piFileHandle )
    1089             : {
    1090           0 :     FileHandle_Impl* pImpl = static_cast<FileHandle_Impl*>(Handle);
    1091             : 
    1092           0 :     if (0 == pImpl || pImpl->m_kind != FileHandle_Impl::KIND_FD || -1 == pImpl->m_fd)
    1093           0 :         return osl_File_E_INVAL;
    1094             : 
    1095           0 :     *piFileHandle = pImpl->m_fd;
    1096             : 
    1097           0 :     return osl_File_E_None;
    1098             : }
    1099             : 
    1100             : oslFileError
    1101          20 : SAL_CALL osl_mapFile (
    1102             :     oslFileHandle Handle,
    1103             :     void**        ppAddr,
    1104             :     sal_uInt64    uLength,
    1105             :     sal_uInt64    uOffset,
    1106             :     sal_uInt32    uFlags
    1107             : )
    1108             : {
    1109          20 :     FileHandle_Impl* pImpl = static_cast<FileHandle_Impl*>(Handle);
    1110             : 
    1111          20 :     if ((0 == pImpl) || ((pImpl->m_kind == FileHandle_Impl::KIND_FD) && (-1 == pImpl->m_fd)) || (0 == ppAddr))
    1112           0 :         return osl_File_E_INVAL;
    1113          20 :     *ppAddr = 0;
    1114             : 
    1115             :     static sal_uInt64 const g_limit_size_t = std::numeric_limits< size_t >::max();
    1116          20 :     if (g_limit_size_t < uLength)
    1117           0 :         return osl_File_E_OVERFLOW;
    1118          20 :     size_t const nLength = sal::static_int_cast< size_t >(uLength);
    1119             : 
    1120             :     static sal_uInt64 const g_limit_off_t = std::numeric_limits< off_t >::max();
    1121          20 :     if (g_limit_off_t < uOffset)
    1122           0 :         return osl_File_E_OVERFLOW;
    1123             : 
    1124          20 :     if (pImpl->m_kind == FileHandle_Impl::KIND_MEM)
    1125             :     {
    1126           0 :         *ppAddr = pImpl->m_buffer + uOffset;
    1127           0 :         return osl_File_E_None;
    1128             :     }
    1129             : 
    1130          20 :     off_t const nOffset = sal::static_int_cast< off_t >(uOffset);
    1131             : 
    1132          20 :     void* p = mmap(NULL, nLength, PROT_READ, MAP_SHARED, pImpl->m_fd, nOffset);
    1133          20 :     if (MAP_FAILED == p)
    1134           0 :         return oslTranslateFileError(OSL_FET_ERROR, errno);
    1135          20 :     *ppAddr = p;
    1136             : 
    1137          20 :     if (uFlags & osl_File_MapFlag_RandomAccess)
    1138             :     {
    1139             :         // Determine memory pagesize.
    1140           3 :         size_t const nPageSize = FileHandle_Impl::getpagesize();
    1141           3 :         if (size_t(-1) != nPageSize)
    1142             :         {
    1143             :             /*
    1144             :              * Pagein, touching first byte of every memory page.
    1145             :              * Note: volatile disables optimizing the loop away.
    1146             :              */
    1147           3 :             sal_uInt8 * pData (reinterpret_cast<sal_uInt8*>(*ppAddr));
    1148           3 :             size_t      nSize (nLength);
    1149             : 
    1150           3 :             volatile sal_uInt8 c = 0;
    1151         266 :             while (nSize > nPageSize)
    1152             :             {
    1153         260 :                 c ^= pData[0];
    1154         260 :                 pData += nPageSize;
    1155         260 :                 nSize -= nPageSize;
    1156             :             }
    1157           3 :             if (nSize > 0)
    1158             :             {
    1159           3 :                 c^= pData[0];
    1160             :             }
    1161             :         }
    1162             :     }
    1163          20 :     if (uFlags & osl_File_MapFlag_WillNeed)
    1164             :     {
    1165             :         // On Linux, madvise(..., MADV_WILLNEED) appears to have the undesirable
    1166             :         // effect of not returning until the data has actually been paged in, so
    1167             :         // that its net effect would typically be to slow down the process
    1168             :         // (which could start processing at the beginning of the data while the
    1169             :         // OS simultaneously pages in the rest); on other platforms, it remains
    1170             :         // to be evaluated whether madvise or equivalent is available and
    1171             :         // actually useful:
    1172             : #if defined MACOSX
    1173             :         int e = posix_madvise(p, nLength, POSIX_MADV_WILLNEED);
    1174             :         if (e != 0)
    1175             :         {
    1176             :             SAL_INFO("sal.file", "posix_madvise(..., POSIX_MADV_WILLNEED) failed with " << e);
    1177             :         }
    1178             : #elif defined SOLARIS
    1179             :         if (madvise(static_cast< caddr_t >(p), nLength, MADV_WILLNEED) != 0)
    1180             :         {
    1181             :             SAL_INFO("sal.file", "madvise(..., MADV_WILLNEED) failed with " << strerror(errno));
    1182             :         }
    1183             : #endif
    1184             :     }
    1185          20 :     return osl_File_E_None;
    1186             : }
    1187             : 
    1188             : static
    1189             : oslFileError
    1190          20 : unmapFile (void* pAddr, sal_uInt64 uLength)
    1191             : {
    1192          20 :     if (0 == pAddr)
    1193           0 :         return osl_File_E_INVAL;
    1194             : 
    1195             :     static sal_uInt64 const g_limit_size_t = std::numeric_limits< size_t >::max();
    1196          20 :     if (g_limit_size_t < uLength)
    1197           0 :         return osl_File_E_OVERFLOW;
    1198          20 :     size_t const nLength = sal::static_int_cast< size_t >(uLength);
    1199             : 
    1200          20 :     if (-1 == munmap(static_cast<char*>(pAddr), nLength))
    1201           0 :         return oslTranslateFileError(OSL_FET_ERROR, errno);
    1202             : 
    1203          20 :     return osl_File_E_None;
    1204             : }
    1205             : 
    1206             : #ifndef ANDROID
    1207             : 
    1208             : // Note that osl_unmapFile() just won't work on Android in general
    1209             : // where for (uncompressed) files inside the .apk, in the /assets
    1210             : // folder osl_mapFile just returns a pointer to the file inside the
    1211             : // already mmapped .apk archive.
    1212             : 
    1213             : oslFileError
    1214           0 : SAL_CALL osl_unmapFile (void* pAddr, sal_uInt64 uLength)
    1215             : {
    1216           0 :     return unmapFile (pAddr, uLength);
    1217             : }
    1218             : 
    1219             : #endif
    1220             : 
    1221             : oslFileError
    1222          20 : SAL_CALL osl_unmapMappedFile (oslFileHandle Handle, void* pAddr, sal_uInt64 uLength)
    1223             : {
    1224          20 :     FileHandle_Impl * pImpl = static_cast<FileHandle_Impl*>(Handle);
    1225             : 
    1226          20 :     if (pImpl == 0)
    1227           0 :         return osl_File_E_INVAL;
    1228             : 
    1229          20 :     if (pImpl->m_kind == FileHandle_Impl::KIND_FD)
    1230          20 :         return unmapFile (pAddr, uLength);
    1231             : 
    1232             :     // For parts of already mmapped "parent" files, whose mapping we
    1233             :     // can't change, not much we can or should do...
    1234           0 :     return osl_File_E_None;
    1235             : }
    1236             : 
    1237             : oslFileError
    1238     3783054 : SAL_CALL osl_readLine (
    1239             :     oslFileHandle   Handle,
    1240             :     sal_Sequence ** ppSequence)
    1241             : {
    1242     3783054 :     FileHandle_Impl * pImpl = static_cast<FileHandle_Impl*>(Handle);
    1243             : 
    1244     3783054 :     if ((0 == pImpl) || ((pImpl->m_kind == FileHandle_Impl::KIND_FD) && (-1 == pImpl->m_fd)) || (0 == ppSequence))
    1245           0 :         return osl_File_E_INVAL;
    1246     3783054 :     sal_uInt64 uBytesRead = 0;
    1247             : 
    1248             :     // read at current fileptr; fileptr += uBytesRead;
    1249     3783054 :     FileHandle_Impl::Guard lock (&(pImpl->m_mutex));
    1250             :     oslFileError result = pImpl->readLineAt (
    1251     3783054 :         pImpl->m_fileptr, ppSequence, &uBytesRead);
    1252     3783054 :     if (result == osl_File_E_None)
    1253     3528017 :         pImpl->m_fileptr += uBytesRead;
    1254     3783054 :     return (result);
    1255             : }
    1256             : 
    1257             : oslFileError
    1258       49718 : SAL_CALL osl_readFile (
    1259             :     oslFileHandle Handle,
    1260             :     void *        pBuffer,
    1261             :     sal_uInt64    uBytesRequested,
    1262             :     sal_uInt64 *  pBytesRead)
    1263             : {
    1264       49718 :     FileHandle_Impl* pImpl = static_cast<FileHandle_Impl*>(Handle);
    1265             : 
    1266       49718 :     if ((0 == pImpl) || ((pImpl->m_kind == FileHandle_Impl::KIND_FD) && (-1 == pImpl->m_fd)) || (0 == pBuffer) || (0 == pBytesRead))
    1267           0 :         return osl_File_E_INVAL;
    1268             : 
    1269             :     static sal_uInt64 const g_limit_ssize_t = std::numeric_limits< ssize_t >::max();
    1270       49718 :     if (g_limit_ssize_t < uBytesRequested)
    1271           0 :         return osl_File_E_OVERFLOW;
    1272       49718 :     size_t const nBytesRequested = sal::static_int_cast< size_t >(uBytesRequested);
    1273             : 
    1274             :     // read at current fileptr; fileptr += *pBytesRead;
    1275       49718 :     FileHandle_Impl::Guard lock (&(pImpl->m_mutex));
    1276             :     oslFileError result = pImpl->readFileAt (
    1277       49718 :         pImpl->m_fileptr, pBuffer, nBytesRequested, pBytesRead);
    1278       49718 :     if (result == osl_File_E_None)
    1279       49718 :         pImpl->m_fileptr += *pBytesRead;
    1280       49718 :     return (result);
    1281             : }
    1282             : 
    1283             : oslFileError
    1284          14 : SAL_CALL osl_writeFile (
    1285             :     oslFileHandle Handle,
    1286             :     const void *  pBuffer,
    1287             :     sal_uInt64    uBytesToWrite,
    1288             :     sal_uInt64 *  pBytesWritten)
    1289             : {
    1290          14 :     FileHandle_Impl* pImpl = static_cast<FileHandle_Impl*>(Handle);
    1291             : 
    1292          14 :     if ((0 == pImpl) || (-1 == pImpl->m_fd) || (0 == pBuffer) || (0 == pBytesWritten))
    1293           0 :         return osl_File_E_INVAL;
    1294          14 :     if (0 == (pImpl->m_state & FileHandle_Impl::STATE_WRITEABLE))
    1295           0 :         return osl_File_E_BADF;
    1296             : 
    1297             :     static sal_uInt64 const g_limit_ssize_t = std::numeric_limits< ssize_t >::max();
    1298          14 :     if (g_limit_ssize_t < uBytesToWrite)
    1299           0 :         return osl_File_E_OVERFLOW;
    1300          14 :     size_t const nBytesToWrite = sal::static_int_cast< size_t >(uBytesToWrite);
    1301             : 
    1302             :     // write at current fileptr; fileptr += *pBytesWritten;
    1303          14 :     FileHandle_Impl::Guard lock (&(pImpl->m_mutex));
    1304             :     oslFileError result = pImpl->writeFileAt (
    1305          14 :         pImpl->m_fileptr, pBuffer, nBytesToWrite, pBytesWritten);
    1306          14 :     if (result == osl_File_E_None)
    1307          14 :         pImpl->m_fileptr += *pBytesWritten;
    1308          14 :     return (result);
    1309             : }
    1310             : 
    1311             : oslFileError
    1312           0 : SAL_CALL osl_readFileAt (
    1313             :     oslFileHandle Handle,
    1314             :     sal_uInt64    uOffset,
    1315             :     void*         pBuffer,
    1316             :     sal_uInt64    uBytesRequested,
    1317             :     sal_uInt64*   pBytesRead)
    1318             : {
    1319           0 :     FileHandle_Impl* pImpl = static_cast<FileHandle_Impl*>(Handle);
    1320             : 
    1321           0 :     if ((0 == pImpl) || ((pImpl->m_kind == FileHandle_Impl::KIND_FD) && (-1 == pImpl->m_fd)) || (0 == pBuffer) || (0 == pBytesRead))
    1322           0 :         return osl_File_E_INVAL;
    1323           0 :     if (0 == (pImpl->m_state & FileHandle_Impl::STATE_SEEKABLE))
    1324           0 :         return osl_File_E_SPIPE;
    1325             : 
    1326             :     static sal_uInt64 const g_limit_off_t = std::numeric_limits< off_t >::max();
    1327           0 :     if (g_limit_off_t < uOffset)
    1328           0 :         return osl_File_E_OVERFLOW;
    1329           0 :     off_t const nOffset = sal::static_int_cast< off_t >(uOffset);
    1330             : 
    1331             :     static sal_uInt64 const g_limit_ssize_t = std::numeric_limits< ssize_t >::max();
    1332           0 :     if (g_limit_ssize_t < uBytesRequested)
    1333           0 :         return osl_File_E_OVERFLOW;
    1334           0 :     size_t const nBytesRequested = sal::static_int_cast< size_t >(uBytesRequested);
    1335             : 
    1336             :     // read at specified fileptr
    1337           0 :     FileHandle_Impl::Guard lock (&(pImpl->m_mutex));
    1338           0 :     return pImpl->readFileAt (nOffset, pBuffer, nBytesRequested, pBytesRead);
    1339             : }
    1340             : 
    1341             : oslFileError
    1342           0 : SAL_CALL osl_writeFileAt (
    1343             :     oslFileHandle Handle,
    1344             :     sal_uInt64    uOffset,
    1345             :     const void*   pBuffer,
    1346             :     sal_uInt64    uBytesToWrite,
    1347             :     sal_uInt64*   pBytesWritten)
    1348             : {
    1349           0 :     FileHandle_Impl* pImpl = static_cast<FileHandle_Impl*>(Handle);
    1350             : 
    1351           0 :     if ((0 == pImpl) || (-1 == pImpl->m_fd) || (0 == pBuffer) || (0 == pBytesWritten))
    1352           0 :         return osl_File_E_INVAL;
    1353           0 :     if (0 == (pImpl->m_state & FileHandle_Impl::STATE_SEEKABLE))
    1354           0 :         return osl_File_E_SPIPE;
    1355           0 :     if (0 == (pImpl->m_state & FileHandle_Impl::STATE_WRITEABLE))
    1356           0 :         return osl_File_E_BADF;
    1357             : 
    1358             :     static sal_uInt64 const g_limit_off_t = std::numeric_limits< off_t >::max();
    1359           0 :     if (g_limit_off_t < uOffset)
    1360           0 :         return osl_File_E_OVERFLOW;
    1361           0 :     off_t const nOffset = sal::static_int_cast< off_t >(uOffset);
    1362             : 
    1363             :     static sal_uInt64 const g_limit_ssize_t = std::numeric_limits< ssize_t >::max();
    1364           0 :     if (g_limit_ssize_t < uBytesToWrite)
    1365           0 :         return osl_File_E_OVERFLOW;
    1366           0 :     size_t const nBytesToWrite = sal::static_int_cast< size_t >(uBytesToWrite);
    1367             : 
    1368             :     // write at specified fileptr
    1369           0 :     FileHandle_Impl::Guard lock (&(pImpl->m_mutex));
    1370           0 :     return pImpl->writeFileAt (nOffset, pBuffer, nBytesToWrite, pBytesWritten);
    1371             : }
    1372             : 
    1373             : oslFileError
    1374           0 : SAL_CALL osl_isEndOfFile( oslFileHandle Handle, sal_Bool *pIsEOF )
    1375             : {
    1376           0 :     FileHandle_Impl* pImpl = static_cast<FileHandle_Impl*>(Handle);
    1377             : 
    1378           0 :     if ((0 == pImpl) || ((pImpl->m_kind == FileHandle_Impl::KIND_FD) && (-1 == pImpl->m_fd)) || (0 == pIsEOF))
    1379           0 :         return osl_File_E_INVAL;
    1380             : 
    1381           0 :     FileHandle_Impl::Guard lock (&(pImpl->m_mutex));
    1382           0 :     *pIsEOF = (pImpl->getPos() == pImpl->getSize());
    1383           0 :     return osl_File_E_None;
    1384             : }
    1385             : 
    1386             : oslFileError
    1387           0 : SAL_CALL osl_getFilePos( oslFileHandle Handle, sal_uInt64* pPos )
    1388             : {
    1389           0 :     FileHandle_Impl* pImpl = static_cast<FileHandle_Impl*>(Handle);
    1390             : 
    1391           0 :     if ((0 == pImpl) || ((pImpl->m_kind == FileHandle_Impl::KIND_FD) && (-1 == pImpl->m_fd)) || (0 == pPos))
    1392           0 :         return osl_File_E_INVAL;
    1393             : 
    1394           0 :     FileHandle_Impl::Guard lock (&(pImpl->m_mutex));
    1395           0 :     *pPos = pImpl->getPos();
    1396           0 :     return osl_File_E_None;
    1397             : }
    1398             : 
    1399             : oslFileError
    1400           0 : SAL_CALL osl_setFilePos (oslFileHandle Handle, sal_uInt32 uHow, sal_Int64 uOffset)
    1401             : {
    1402           0 :     FileHandle_Impl* pImpl = static_cast<FileHandle_Impl*>(Handle);
    1403             : 
    1404           0 :     if ((0 == pImpl) || ((pImpl->m_kind == FileHandle_Impl::KIND_FD) && (-1 == pImpl->m_fd)))
    1405           0 :         return osl_File_E_INVAL;
    1406             : 
    1407             :     static sal_Int64 const g_limit_off_t = std::numeric_limits< off_t >::max();
    1408             :     if (g_limit_off_t < uOffset)
    1409             :         return osl_File_E_OVERFLOW;
    1410           0 :     off_t nPos = 0, nOffset = sal::static_int_cast< off_t >(uOffset);
    1411             : 
    1412           0 :     FileHandle_Impl::Guard lock (&(pImpl->m_mutex));
    1413           0 :     switch(uHow)
    1414             :     {
    1415             :         case osl_Pos_Absolut:
    1416           0 :             if (0 > nOffset)
    1417           0 :                 return osl_File_E_INVAL;
    1418           0 :             break;
    1419             : 
    1420             :         case osl_Pos_Current:
    1421           0 :             nPos = sal::static_int_cast< off_t >(pImpl->getPos());
    1422           0 :             if ((0 > nOffset) && (-1*nOffset > nPos))
    1423           0 :                 return osl_File_E_INVAL;
    1424             :             if (g_limit_off_t < (sal_Int64) nPos + nOffset)
    1425             :                 return osl_File_E_OVERFLOW;
    1426           0 :             break;
    1427             : 
    1428             :         case osl_Pos_End:
    1429           0 :             nPos = sal::static_int_cast< off_t >(pImpl->getSize());
    1430           0 :             if ((0 > nOffset) && (-1*nOffset > nPos))
    1431           0 :                 return osl_File_E_INVAL;
    1432             :             if (g_limit_off_t < (sal_Int64) nPos + nOffset)
    1433             :                 return osl_File_E_OVERFLOW;
    1434           0 :             break;
    1435             : 
    1436             :         default:
    1437           0 :             return osl_File_E_INVAL;
    1438             :     }
    1439             : 
    1440           0 :     return pImpl->setPos (nPos + nOffset);
    1441             : }
    1442             : 
    1443             : oslFileError
    1444          20 : SAL_CALL osl_getFileSize( oslFileHandle Handle, sal_uInt64* pSize )
    1445             : {
    1446          20 :     FileHandle_Impl* pImpl = static_cast<FileHandle_Impl*>(Handle);
    1447             : 
    1448          20 :     if ((0 == pImpl) || ((pImpl->m_kind == FileHandle_Impl::KIND_FD) && (-1 == pImpl->m_fd)) || (0 == pSize))
    1449           0 :         return osl_File_E_INVAL;
    1450             : 
    1451          20 :     FileHandle_Impl::Guard lock (&(pImpl->m_mutex));
    1452          20 :     *pSize = pImpl->getSize();
    1453          20 :     return osl_File_E_None;
    1454             : }
    1455             : 
    1456             : oslFileError
    1457           0 : SAL_CALL osl_setFileSize( oslFileHandle Handle, sal_uInt64 uSize )
    1458             : {
    1459           0 :     FileHandle_Impl* pImpl = static_cast<FileHandle_Impl*>(Handle);
    1460             : 
    1461           0 :     if ((0 == pImpl) || (-1 == pImpl->m_fd))
    1462           0 :         return osl_File_E_INVAL;
    1463           0 :     if (0 == (pImpl->m_state & FileHandle_Impl::STATE_WRITEABLE))
    1464           0 :         return osl_File_E_BADF;
    1465             : 
    1466             :     static sal_uInt64 const g_limit_off_t = std::numeric_limits< off_t >::max();
    1467           0 :     if (g_limit_off_t < uSize)
    1468           0 :         return osl_File_E_OVERFLOW;
    1469             : 
    1470           0 :     oslFileError result = pImpl->syncFile();
    1471           0 :     if (result != osl_File_E_None)
    1472           0 :         return (result);
    1473           0 :     pImpl->m_bufptr = -1, pImpl->m_buflen = 0;
    1474             : 
    1475           0 :     return pImpl->setSize (uSize);
    1476             : }
    1477             : 
    1478             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10