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

Generated by: LCOV version 1.11