LCOV - code coverage report
Current view: top level - sal/osl/unx - file.cxx (source / functions) Hit Total Coverage
Test: commit 10e77ab3ff6f4314137acd6e2702a6e5c1ce1fae Lines: 435 568 76.6 %
Date: 2014-11-03 Functions: 45 46 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.h"
      34             : #include "createfilehandlefromfd.hxx"
      35             : #include "file_error_transl.h"
      36             : #include "file_impl.hxx"
      37             : #include "file_url.h"
      38             : #include "uunxapi.h"
      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             :     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      328898 : FileHandle_Impl::Allocator::get()
     182             : {
     183      328898 :     static Allocator g_aBufferAllocator;
     184      328898 :     return g_aBufferAllocator;
     185             : }
     186             : 
     187        2242 : FileHandle_Impl::Allocator::Allocator()
     188             :     : m_cache  (0),
     189        2242 :       m_bufsiz (0)
     190             : {
     191        2242 :     size_t const pagesize = FileHandle_Impl::getpagesize();
     192        2242 :     if (size_t(-1) != pagesize)
     193             :     {
     194             :         m_cache  = rtl_cache_create (
     195        2242 :             "osl_file_buffer_cache", pagesize, 0, 0, 0, 0, 0, 0, 0);
     196        2242 :         if (0 != m_cache)
     197        2242 :             m_bufsiz = pagesize;
     198             :     }
     199        2242 : }
     200        2242 : FileHandle_Impl::Allocator::~Allocator()
     201             : {
     202        2242 :     rtl_cache_destroy (m_cache), m_cache = 0;
     203        2242 : }
     204             : 
     205      164550 : 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      164550 :     if ((0 != ppBuffer) && (0 != pnSize))
     209      164550 :         *ppBuffer = static_cast< sal_uInt8* >(rtl_cache_alloc(m_cache)), *pnSize = m_bufsiz;
     210      164550 : }
     211      164348 : void FileHandle_Impl::Allocator::deallocate (sal_uInt8 * pBuffer)
     212             : {
     213      164348 :     if (0 != pBuffer)
     214      164348 :         rtl_cache_free (m_cache, pBuffer);
     215      164348 : }
     216             : 
     217    78283172 : FileHandle_Impl::Guard::Guard(pthread_mutex_t * pMutex)
     218    78283172 :     : m_mutex (pMutex)
     219             : {
     220             :     OSL_PRECOND (m_mutex != 0, "FileHandle_Impl::Guard::Guard(): null pointer.");
     221    78283172 :     (void) pthread_mutex_lock (m_mutex); // ignoring EINVAL ...
     222    78283182 : }
     223    78283178 : FileHandle_Impl::Guard::~Guard()
     224             : {
     225             :     OSL_PRECOND (m_mutex != 0, "FileHandle_Impl::Guard::~Guard(): null pointer.");
     226    78283178 :     (void) pthread_mutex_unlock (m_mutex);
     227    78283181 : }
     228             : 
     229      164550 : 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      164550 :       m_buffer  (0)
     241             : {
     242      164550 :     (void) pthread_mutex_init(&m_mutex, 0);
     243      164550 :     rtl_string_newFromStr (&m_strFilePath, path);
     244      164550 :     if (m_kind == KIND_FD) {
     245      164550 :         Allocator::get().allocate (&m_buffer, &m_bufsiz);
     246      164550 :         if (0 != m_buffer)
     247      164550 :             memset (m_buffer, 0, m_bufsiz);
     248             :     }
     249      164550 : }
     250      164348 : FileHandle_Impl::~FileHandle_Impl()
     251             : {
     252      164348 :     if (m_kind == KIND_FD)
     253      164348 :         Allocator::get().deallocate (m_buffer), m_buffer = 0;
     254      164348 :     rtl_string_release (m_strFilePath), m_strFilePath = 0;
     255      164348 :     (void) pthread_mutex_destroy(&m_mutex); // ignoring EBUSY ...
     256      164348 : }
     257             : 
     258      164550 : void* FileHandle_Impl::operator new (size_t n)
     259             : {
     260      164550 :     return rtl_allocateMemory(n);
     261             : }
     262      164348 : void FileHandle_Impl::operator delete (void * p)
     263             : {
     264      164348 :     rtl_freeMemory(p);
     265      164348 : }
     266             : 
     267        9803 : 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        9803 :     return sal::static_int_cast< size_t >(::sysconf(_SC_PAGESIZE));
     274             : #endif /* xBSD || POSIX */
     275             : }
     276             : 
     277    27580805 : sal_uInt64 FileHandle_Impl::getPos() const
     278             : {
     279    27580805 :     return sal::static_int_cast< sal_uInt64 >(m_fileptr);
     280             : }
     281             : 
     282    20973090 : oslFileError FileHandle_Impl::setPos (sal_uInt64 uPos)
     283             : {
     284             :     SAL_INFO("sal.file", "FileHandle_Impl::setPos(" << m_fd << ", " << getPos() << ") => " << uPos);
     285    20973090 :     m_fileptr = sal::static_int_cast< off_t >(uPos);
     286    20973090 :     return osl_File_E_None;
     287             : }
     288             : 
     289      329230 : sal_uInt64 FileHandle_Impl::getSize() const
     290             : {
     291      329230 :     off_t const bufend = std::max((off_t)(0), m_bufptr) + m_buflen;
     292      329230 :     return std::max(m_size, sal::static_int_cast< sal_uInt64 >(bufend));
     293             : }
     294             : 
     295        2872 : oslFileError FileHandle_Impl::setSize (sal_uInt64 uSize)
     296             : {
     297        2872 :     off_t const nSize = sal::static_int_cast< off_t >(uSize);
     298        2872 :     if (-1 == ftruncate_with_name (m_fd, nSize, m_strFilePath))
     299             :     {
     300             :         /* Failure. Save original result. Try fallback algorithm */
     301           0 :         oslFileError result = oslTranslateFileError (OSL_FET_ERROR, errno);
     302             : 
     303             :         /* Check against current size. Fail upon 'shrink' */
     304           0 :         if (uSize <= getSize())
     305             :         {
     306             :             /* Failure upon 'shrink'. Return original result */
     307           0 :             return (result);
     308             :         }
     309             : 
     310             :         /* Save current position */
     311           0 :         off_t const nCurPos = (off_t)lseek (m_fd, (off_t)0, SEEK_CUR);
     312           0 :         if (nCurPos == (off_t)(-1))
     313           0 :             return (result);
     314             : 
     315             :         /* Try 'expand' via 'lseek()' and 'write()' */
     316           0 :         if (-1 == lseek (m_fd, (off_t)(nSize - 1), SEEK_SET))
     317           0 :             return (result);
     318             : 
     319           0 :         if (-1 == write (m_fd, (char*)"", (size_t)1))
     320             :         {
     321             :             /* Failure. Restore saved position */
     322           0 :             (void) lseek (m_fd, (off_t)(nCurPos), SEEK_SET);
     323           0 :             return (result);
     324             :         }
     325             : 
     326             :         /* Success. Restore saved position */
     327           0 :         if (-1 == lseek (m_fd, (off_t)nCurPos, SEEK_SET))
     328           0 :             return (result);
     329             :     }
     330             : 
     331             :     SAL_INFO("sal.file", "osl_setFileSize(" << m_fd << ", " << getSize() << ") => " << nSize);
     332        2872 :     m_size = sal::static_int_cast< sal_uInt64 >(nSize);
     333        2872 :     return osl_File_E_None;
     334             : }
     335             : 
     336      453613 : oslFileError FileHandle_Impl::readAt (
     337             :     off_t        nOffset,
     338             :     void *       pBuffer,
     339             :     size_t       nBytesRequested,
     340             :     sal_uInt64 * pBytesRead)
     341             : {
     342             :     OSL_PRECOND((m_state & STATE_SEEKABLE), "FileHandle_Impl::readAt(): not seekable");
     343      453613 :     if (!(m_state & STATE_SEEKABLE))
     344           0 :         return osl_File_E_SPIPE;
     345             : 
     346             :     OSL_PRECOND((m_state & STATE_READABLE), "FileHandle_Impl::readAt(): not readable");
     347      453613 :     if (!(m_state & STATE_READABLE))
     348           0 :         return osl_File_E_BADF;
     349             : 
     350      453613 :     if (m_kind == KIND_MEM)
     351             :     {
     352             :         ssize_t nBytes;
     353             : 
     354           0 :         m_offset = nOffset;
     355             : 
     356           0 :         if ((sal_uInt64) m_offset >= m_size)
     357           0 :             nBytes = 0;
     358             :         else
     359             :         {
     360           0 :             nBytes = std::min(nBytesRequested, (size_t) (m_size - m_offset));
     361           0 :             memmove(pBuffer, m_buffer + m_offset, nBytes);
     362           0 :             m_offset += nBytes;
     363             :         }
     364           0 :         *pBytesRead = nBytes;
     365           0 :         return osl_File_E_None;
     366             :     }
     367             : 
     368      453613 :     ssize_t nBytes = ::pread (m_fd, pBuffer, nBytesRequested, nOffset);
     369      453613 :     if ((-1 == nBytes) && (EOVERFLOW == errno))
     370             :     {
     371             :         /* Some 'pread()'s fail with EOVERFLOW when reading at (or past)
     372             :          * end-of-file, different from 'lseek() + read()' behaviour.
     373             :          * Returning '0 bytes read' and 'osl_File_E_None' instead.
     374             :          */
     375           0 :         nBytes = 0;
     376             :     }
     377      453613 :     if (-1 == nBytes)
     378           0 :         return oslTranslateFileError (OSL_FET_ERROR, errno);
     379             : 
     380             :     SAL_INFO("sal.file", "FileHandle_Impl::readAt(" << m_fd << ", " << nOffset << ", " << nBytes << ")");
     381      453613 :     *pBytesRead = nBytes;
     382      453613 :     return osl_File_E_None;
     383             : }
     384             : 
     385      111579 : oslFileError FileHandle_Impl::writeAt (
     386             :     off_t        nOffset,
     387             :     void const * pBuffer,
     388             :     size_t       nBytesToWrite,
     389             :     sal_uInt64 * pBytesWritten)
     390             : {
     391             :     OSL_PRECOND((m_state & STATE_SEEKABLE), "FileHandle_Impl::writeAt(): not seekable");
     392      111579 :     if (!(m_state & STATE_SEEKABLE))
     393           0 :         return osl_File_E_SPIPE;
     394             : 
     395             :     OSL_PRECOND((m_state & STATE_WRITEABLE), "FileHandle_Impl::writeAt(): not writeable");
     396      111579 :     if (!(m_state & STATE_WRITEABLE))
     397           0 :         return osl_File_E_BADF;
     398             : 
     399      111579 :     ssize_t nBytes = ::pwrite (m_fd, pBuffer, nBytesToWrite, nOffset);
     400      111579 :     if (-1 == nBytes)
     401           0 :         return oslTranslateFileError (OSL_FET_ERROR, errno);
     402             : 
     403             :     SAL_INFO("sal.file", "FileHandle_Impl::writeAt(" << m_fd << ", " << nOffset << ", " << nBytes << ")");
     404      111579 :     m_size = std::max (m_size, sal::static_int_cast< sal_uInt64 >(nOffset + nBytes));
     405             : 
     406      111579 :     *pBytesWritten = nBytes;
     407      111579 :     return osl_File_E_None;
     408             : }
     409             : 
     410    22164072 : oslFileError FileHandle_Impl::readFileAt (
     411             :     off_t        nOffset,
     412             :     void *       pBuffer,
     413             :     size_t       nBytesRequested,
     414             :     sal_uInt64 * pBytesRead)
     415             : {
     416    22164072 :     if (0 == (m_state & STATE_SEEKABLE))
     417             :     {
     418             :         // not seekable (pipe)
     419      543526 :         ssize_t nBytes = ::read (m_fd, pBuffer, nBytesRequested);
     420      543526 :         if (-1 == nBytes)
     421           0 :             return oslTranslateFileError (OSL_FET_ERROR, errno);
     422      543526 :         *pBytesRead = nBytes;
     423      543526 :         return osl_File_E_None;
     424             :     }
     425    21620546 :     else if (m_kind == KIND_MEM || 0 == m_buffer)
     426             :     {
     427             :         // not buffered
     428           0 :         return readAt (nOffset, pBuffer, nBytesRequested, pBytesRead);
     429             :     }
     430             :     else
     431             :     {
     432    21620546 :         sal_uInt8 * buffer = static_cast<sal_uInt8*>(pBuffer);
     433    44672604 :         for (*pBytesRead = 0; nBytesRequested > 0; )
     434             :         {
     435    21718291 :             off_t  const bufptr = (nOffset / m_bufsiz) * m_bufsiz;
     436    21718291 :             size_t const bufpos = (nOffset % m_bufsiz);
     437             : 
     438    21718291 :             if (bufptr != m_bufptr)
     439             :             {
     440             :                 // flush current buffer
     441      384996 :                 oslFileError result = syncFile();
     442      384996 :                 if (result != osl_File_E_None)
     443      162200 :                     return (result);
     444      384996 :                 m_bufptr = -1, m_buflen = 0;
     445             : 
     446      384996 :                 if (nBytesRequested >= m_bufsiz)
     447             :                 {
     448             :                     // buffer too small, read through from file
     449      162200 :                     sal_uInt64 uDone = 0;
     450      162200 :                     result = readAt (nOffset, &(buffer[*pBytesRead]), nBytesRequested, &uDone);
     451      162200 :                     if (result != osl_File_E_None)
     452           0 :                         return (result);
     453             : 
     454      162200 :                     *pBytesRead += uDone;
     455      162200 :                     return osl_File_E_None;
     456             :                 }
     457             : 
     458             :                 // update buffer (pointer)
     459      222796 :                 sal_uInt64 uDone = 0;
     460      222796 :                 result = readAt (bufptr, m_buffer, m_bufsiz, &uDone);
     461      222796 :                 if (result != osl_File_E_None)
     462           0 :                     return (result);
     463      222796 :                 m_bufptr = bufptr, m_buflen = uDone;
     464             :             }
     465    21556091 :             if (bufpos >= m_buflen)
     466             :             {
     467             :                 // end of file
     468    20124579 :                 return osl_File_E_None;
     469             :             }
     470             : 
     471     1431512 :             size_t const bytes = std::min (m_buflen - bufpos, nBytesRequested);
     472             :             SAL_INFO("sal.file", "FileHandle_Impl::readFileAt(" << m_fd << ", " << nOffset << ", " << bytes << ")");
     473             : 
     474     1431512 :             memcpy (&(buffer[*pBytesRead]), &(m_buffer[bufpos]), bytes);
     475     1431512 :             nBytesRequested -= bytes, *pBytesRead += bytes, nOffset += bytes;
     476             :         }
     477     1333767 :         return osl_File_E_None;
     478             :     }
     479             : }
     480             : 
     481     7215358 : oslFileError FileHandle_Impl::writeFileAt (
     482             :     off_t        nOffset,
     483             :     void const * pBuffer,
     484             :     size_t       nBytesToWrite,
     485             :     sal_uInt64 * pBytesWritten)
     486             : {
     487     7215358 :     if (0 == (m_state & STATE_SEEKABLE))
     488             :     {
     489             :         // not seekable (pipe)
     490          10 :         ssize_t nBytes = ::write (m_fd, pBuffer, nBytesToWrite);
     491          10 :         if (-1 == nBytes)
     492           0 :             return oslTranslateFileError (OSL_FET_ERROR, errno);
     493          10 :         *pBytesWritten = nBytes;
     494          10 :         return osl_File_E_None;
     495             :     }
     496     7215348 :     else if (0 == m_buffer)
     497             :     {
     498             :         // not buffered
     499           0 :         return writeAt (nOffset, pBuffer, nBytesToWrite, pBytesWritten);
     500             :     }
     501             :     else
     502             :     {
     503     7215348 :         sal_uInt8 const * buffer = static_cast<sal_uInt8 const *>(pBuffer);
     504    21574570 :         for (*pBytesWritten = 0; nBytesToWrite > 0; )
     505             :         {
     506     7189288 :             off_t  const bufptr = (nOffset / m_bufsiz) * m_bufsiz;
     507     7189288 :             size_t const bufpos = (nOffset % m_bufsiz);
     508     7189288 :             if (bufptr != m_bufptr)
     509             :             {
     510             :                 // flush current buffer
     511      111561 :                 oslFileError result = syncFile();
     512      111561 :                 if (result != osl_File_E_None)
     513       45414 :                     return (result);
     514      111561 :                 m_bufptr = -1, m_buflen = 0;
     515             : 
     516      111561 :                 if (nBytesToWrite >= m_bufsiz)
     517             :                 {
     518             :                     // buffer to small, write through to file
     519       45414 :                     sal_uInt64 uDone = 0;
     520       45414 :                     result = writeAt (nOffset, &(buffer[*pBytesWritten]), nBytesToWrite, &uDone);
     521       45414 :                     if (result != osl_File_E_None)
     522           0 :                         return (result);
     523       45414 :                     if (uDone != nBytesToWrite)
     524           0 :                         return osl_File_E_IO;
     525             : 
     526       45414 :                     *pBytesWritten += uDone;
     527       45414 :                     return osl_File_E_None;
     528             :                 }
     529             : 
     530             :                 // update buffer (pointer)
     531       66147 :                 sal_uInt64 uDone = 0;
     532       66147 :                 result = readAt (bufptr, m_buffer, m_bufsiz, &uDone);
     533       66147 :                 if (result != osl_File_E_None)
     534           0 :                     return (result);
     535       66147 :                 m_bufptr = bufptr, m_buflen = uDone;
     536             :             }
     537             : 
     538     7143874 :             size_t const bytes = std::min (m_bufsiz - bufpos, nBytesToWrite);
     539             :             SAL_INFO("sal.file", "FileHandle_Impl::writeFileAt(" << m_fd << ", " << nOffset << ", " << bytes << ")");
     540             : 
     541     7143874 :             memcpy (&(m_buffer[bufpos]), &(buffer[*pBytesWritten]), bytes);
     542     7143874 :             nBytesToWrite -= bytes, *pBytesWritten += bytes, nOffset += bytes;
     543             : 
     544     7143874 :             m_buflen = std::max(m_buflen, bufpos + bytes);
     545     7143874 :             m_state |= STATE_MODIFIED;
     546             :         }
     547     7169934 :         return osl_File_E_None;
     548             :     }
     549             : }
     550             : 
     551       27180 : oslFileError FileHandle_Impl::readLineAt (
     552             :     off_t           nOffset,
     553             :     sal_Sequence ** ppSequence,
     554             :     sal_uInt64 *    pBytesRead)
     555             : {
     556       27180 :     oslFileError result = osl_File_E_None;
     557             : 
     558       27180 :     off_t bufptr = nOffset / m_bufsiz * m_bufsiz;
     559       27180 :     if (bufptr != m_bufptr)
     560             :     {
     561             :         /* flush current buffer */
     562        2425 :         result = syncFile();
     563        2425 :         if (result != osl_File_E_None)
     564           0 :             return (result);
     565             : 
     566             :         /* update buffer (pointer) */
     567        2425 :         sal_uInt64 uDone = 0;
     568        2425 :         result = readAt (bufptr, m_buffer, m_bufsiz, &uDone);
     569        2425 :         if (result != osl_File_E_None)
     570           0 :             return (result);
     571             : 
     572        2425 :         m_bufptr = bufptr, m_buflen = uDone;
     573             :     }
     574             : 
     575             :     static int const LINE_STATE_BEGIN = 0;
     576             :     static int const LINE_STATE_CR    = 1;
     577             :     static int const LINE_STATE_LF    = 2;
     578             : 
     579       27180 :     size_t bufpos = nOffset - m_bufptr, curpos = bufpos, dstpos = 0;
     580       27180 :     int    state  = (bufpos >= m_buflen) ? LINE_STATE_LF : LINE_STATE_BEGIN;
     581             : 
     582     1749719 :     for ( ; state != LINE_STATE_LF; )
     583             :     {
     584     1695455 :         if (curpos >= m_buflen)
     585             :         {
     586             :             /* buffer examined */
     587         141 :             if (0 < (curpos - bufpos))
     588             :             {
     589             :                 /* flush buffer to sequence */
     590             :                 result = writeSequence_Impl (
     591         141 :                     ppSequence, &dstpos, &(m_buffer[bufpos]), curpos - bufpos);
     592         141 :                 if (result != osl_File_E_None)
     593           0 :                     return (result);
     594         141 :                 *pBytesRead += curpos - bufpos, nOffset += curpos - bufpos;
     595             :             }
     596             : 
     597         141 :             bufptr = nOffset / m_bufsiz * m_bufsiz;
     598         141 :             if (bufptr != m_bufptr)
     599             :             {
     600             :                 /* update buffer (pointer) */
     601          45 :                 sal_uInt64 uDone = 0;
     602          45 :                 result = readAt (bufptr, m_buffer, m_bufsiz, &uDone);
     603          45 :                 if (result != osl_File_E_None)
     604           0 :                     return (result);
     605          45 :                 m_bufptr = bufptr, m_buflen = uDone;
     606             :             }
     607             : 
     608         141 :             bufpos = nOffset - m_bufptr, curpos = bufpos;
     609         141 :             if (bufpos >= m_buflen)
     610          96 :                 break;
     611             :         }
     612     1695359 :         switch (state)
     613             :         {
     614             :         case LINE_STATE_CR:
     615           0 :             state = LINE_STATE_LF;
     616           0 :             switch (m_buffer[curpos])
     617             :             {
     618             :             case 0x0A: /* CRLF */
     619             :                 /* eat current char */
     620           0 :                 curpos++;
     621           0 :                 break;
     622             :             default: /* single CR */
     623             :                 /* keep current char */
     624           0 :                 break;
     625             :             }
     626           0 :             break;
     627             :         default:
     628             :             /* determine next state */
     629     1695359 :             switch (m_buffer[curpos])
     630             :             {
     631             :             case 0x0A: /* single LF */
     632       24760 :                 state = LINE_STATE_LF;
     633       24760 :                 break;
     634             :             case 0x0D: /* CR */
     635           0 :                 state = LINE_STATE_CR;
     636           0 :                 break;
     637             :             default: /* advance to next char */
     638     1670599 :                 curpos++;
     639     1670599 :                 break;
     640             :             }
     641     1695359 :             if (state != LINE_STATE_BEGIN)
     642             :             {
     643             :                 /* skip the newline char */
     644       24760 :                 curpos++;
     645             : 
     646             :                 /* flush buffer to sequence */
     647             :                 result = writeSequence_Impl (
     648       24760 :                     ppSequence, &dstpos, &(m_buffer[bufpos]), curpos - bufpos - 1);
     649       24760 :                 if (result != osl_File_E_None)
     650           0 :                     return (result);
     651       24760 :                 *pBytesRead += curpos - bufpos, nOffset += curpos - bufpos;
     652             :             }
     653     1695359 :             break;
     654             :         }
     655             :     }
     656             : 
     657       27180 :     result = writeSequence_Impl (ppSequence, &dstpos, 0, 0);
     658       27180 :     if (result != osl_File_E_None)
     659           0 :         return (result);
     660       27180 :     if (0 < dstpos)
     661       24856 :         return osl_File_E_None;
     662        2324 :     if (bufpos >= m_buflen)
     663        2324 :         return osl_File_E_AGAIN;
     664           0 :     return osl_File_E_None;
     665             : }
     666             : 
     667       52081 : oslFileError FileHandle_Impl::writeSequence_Impl (
     668             :     sal_Sequence ** ppSequence,
     669             :     size_t *        pnOffset,
     670             :     const void *    pBuffer,
     671             :     size_t          nBytes)
     672             : {
     673       52081 :     sal_Int32 nElements = *pnOffset + nBytes;
     674       52081 :     if (!*ppSequence)
     675             :     {
     676             :         /* construct sequence */
     677           0 :         rtl_byte_sequence_constructNoDefault(ppSequence, nElements);
     678             :     }
     679       52081 :     else if (nElements != (*ppSequence)->nElements)
     680             :     {
     681             :         /* resize sequence */
     682       26877 :         rtl_byte_sequence_realloc(ppSequence, nElements);
     683             :     }
     684       52081 :     if (*ppSequence != 0)
     685             :     {
     686             :         /* fill sequence */
     687       52081 :         memcpy(&((*ppSequence)->elements[*pnOffset]), pBuffer, nBytes), *pnOffset += nBytes;
     688             :     }
     689       52081 :     return (*ppSequence != 0) ? osl_File_E_None : osl_File_E_NOMEM;
     690             : }
     691             : 
     692      667829 : oslFileError FileHandle_Impl::syncFile()
     693             : {
     694      667829 :     oslFileError result = osl_File_E_None;
     695      667829 :     if (m_state & STATE_MODIFIED)
     696             :     {
     697       66165 :         sal_uInt64 uDone = 0;
     698       66165 :         result = writeAt (m_bufptr, m_buffer, m_buflen, &uDone);
     699       66165 :         if (result != osl_File_E_None)
     700           0 :             return (result);
     701       66165 :         if (uDone != m_buflen)
     702           0 :             return osl_File_E_IO;
     703       66165 :         m_state &= ~STATE_MODIFIED;
     704             :     }
     705      667829 :     return (result);
     706             : }
     707             : 
     708         386 : oslFileHandle osl::detail::createFileHandleFromFD( int fd )
     709             : {
     710         386 :     if (-1 == fd)
     711           0 :         return 0; // EINVAL
     712             : 
     713             :     struct stat aFileStat;
     714         386 :     if (-1 == fstat (fd, &aFileStat))
     715           0 :         return 0; // EBADF
     716             : 
     717         386 :     FileHandle_Impl * pImpl = new FileHandle_Impl (fd);
     718         386 :     if (0 == pImpl)
     719           0 :         return 0; // ENOMEM
     720             : 
     721             :     // assume writeable
     722         386 :     pImpl->m_state |= FileHandle_Impl::STATE_WRITEABLE;
     723         386 :     if (!S_ISREG(aFileStat.st_mode))
     724             :     {
     725             :         /* not a regular file, mark not seekable */
     726         386 :         pImpl->m_state &= ~FileHandle_Impl::STATE_SEEKABLE;
     727             :     }
     728             :     else
     729             :     {
     730             :         /* regular file, init current size */
     731           0 :         pImpl->m_size = sal::static_int_cast< sal_uInt64 >(aFileStat.st_size);
     732             :     }
     733             : 
     734             :     SAL_INFO("sal.file", "osl::detail::createFileHandleFromFD(" << pImpl->m_fd << ", writeable) => " << pImpl->m_strFilePath);
     735         386 :     return (oslFileHandle)(pImpl);
     736             : }
     737             : 
     738      114524 : static int osl_file_adjustLockFlags (const char * path, int flags)
     739             : {
     740             : #ifdef MACOSX
     741             :     /*
     742             :      * The AFP implementation of MacOS X 10.4 treats O_EXLOCK in a way
     743             :      * that makes it impossible for OOo to create a backup copy of the
     744             :      * file it keeps opened. OTOH O_SHLOCK for AFP behaves as desired by
     745             :      * the OOo file handling, so we need to check the path of the file
     746             :      * for the filesystem name.
     747             :      */
     748             :     struct statfs s;
     749             :     if( 0 <= statfs( path, &s ) )
     750             :     {
     751             :         if( 0 == strncmp("afpfs", s.f_fstypename, 5) )
     752             :         {
     753             :             flags &= ~O_EXLOCK;
     754             :             flags |=  O_SHLOCK;
     755             :         }
     756             :         else
     757             :         {
     758             :             /* Needed flags to allow opening a webdav file */
     759             :             flags &= ~(O_EXLOCK | O_SHLOCK | O_NONBLOCK);
     760             :         }
     761             :     }
     762             : #endif /* MACOSX */
     763             : 
     764             :     (void) path;
     765      114524 :     return flags;
     766             : }
     767             : 
     768      164164 : static bool osl_file_queryLocking (sal_uInt32 uFlags)
     769             : {
     770             : #if !defined HAVE_O_EXLOCK
     771      164164 :     if (!(uFlags & osl_File_OpenFlag_NoLock)
     772      104440 :         && ((uFlags & osl_File_OpenFlag_Write)
     773       39541 :             || (uFlags & osl_File_OpenFlag_Create)))
     774             :     {
     775       66302 :         static bool enabled = getenv("SAL_ENABLE_FILE_LOCKING") != 0;
     776             :             // getenv is not thread safe, so minimize use of result
     777       66302 :         return enabled;
     778             :     }
     779             : #endif
     780             :     (void) uFlags;
     781       97862 :     return false;
     782             : }
     783             : 
     784             : #if defined ANDROID
     785             : 
     786             : namespace {
     787             : 
     788             : static oslFileError
     789             : openMemoryAsFile( void *address, size_t size, oslFileHandle *pHandle, const char *path )
     790             : {
     791             :     oslFileError eRet;
     792             :     FileHandle_Impl * pImpl = new FileHandle_Impl (-1, FileHandle_Impl::KIND_MEM, path);
     793             :     if (!pImpl)
     794             :     {
     795             :         eRet = oslTranslateFileError (OSL_FET_ERROR, ENOMEM);
     796             :         return eRet;
     797             :     }
     798             :     pImpl->m_size = sal::static_int_cast< sal_uInt64 >(size);
     799             : 
     800             :     *pHandle = (oslFileHandle)(pImpl);
     801             : 
     802             :     pImpl->m_bufptr = 0;
     803             :     pImpl->m_buflen = size;
     804             : 
     805             :     pImpl->m_bufsiz = size;
     806             :     pImpl->m_buffer = (sal_uInt8*) address;
     807             : 
     808             :     return osl_File_E_None;
     809             : }
     810             : 
     811             : }
     812             : 
     813             : #endif
     814             : 
     815             : #ifdef HAVE_O_EXLOCK
     816             : #define OPEN_WRITE_FLAGS ( O_RDWR | O_EXLOCK | O_NONBLOCK )
     817             : #define OPEN_CREATE_FLAGS ( O_CREAT | O_RDWR | O_EXLOCK | O_NONBLOCK )
     818             : #else
     819             : #define OPEN_WRITE_FLAGS ( O_RDWR )
     820             : #define OPEN_CREATE_FLAGS ( O_CREAT | O_RDWR )
     821             : #endif
     822             : 
     823             : oslFileError
     824      178113 : openFilePath( const char *cpFilePath, oslFileHandle* pHandle, sal_uInt32 uFlags,
     825             :               mode_t mode)
     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 openMemoryAsFile(address, size, pHandle, cpFilePath);
     852             :     }
     853             : #endif
     854             : 
     855             :     /* set mode and flags */
     856      178113 :     int defmode = uFlags & osl_File_OpenFlag_Private
     857      178113 :         ? S_IRUSR : S_IRUSR | S_IRGRP | S_IROTH;
     858      178113 :     int flags = O_RDONLY;
     859      178113 :     if (uFlags & osl_File_OpenFlag_Write)
     860             :     {
     861       70883 :         defmode |= uFlags & osl_File_OpenFlag_Private
     862       70883 :             ? S_IWUSR : S_IWUSR | S_IWGRP | S_IWOTH;
     863       70883 :         flags = OPEN_WRITE_FLAGS;
     864             :     }
     865      178113 :     if (uFlags & osl_File_OpenFlag_Create)
     866             :     {
     867       65153 :         defmode |= uFlags & osl_File_OpenFlag_Private
     868       65153 :             ? S_IWUSR : S_IWUSR | S_IWGRP | S_IWOTH;
     869       65153 :         flags = OPEN_CREATE_FLAGS;
     870             :     }
     871      178113 :     if (mode == mode_t(-1))
     872             :     {
     873      156308 :         mode = defmode;
     874             :     }
     875             : 
     876             :     /* Check for flags passed in from SvFileStream::Open() */
     877      178113 :     if (uFlags & osl_File_OpenFlag_Trunc)
     878         152 :         flags |= O_TRUNC;
     879      178113 :     if (!(uFlags & osl_File_OpenFlag_NoExcl))
     880      159043 :         flags |= O_EXCL;
     881             : 
     882      178113 :     if (uFlags & osl_File_OpenFlag_NoLock)
     883             :     {
     884             : #ifdef HAVE_O_EXLOCK
     885             :         flags &= ~(O_EXLOCK | O_SHLOCK | O_NONBLOCK);
     886             : #endif /* HAVE_O_EXLOCK */
     887             :     }
     888             :     else
     889             :     {
     890      114524 :         flags = osl_file_adjustLockFlags (cpFilePath, flags);
     891             :     }
     892             : 
     893             :     /* open the file */
     894      178113 :     int fd = open_c( cpFilePath, flags, mode );
     895             : 
     896             : #ifdef IOS
     897             :     /* Horrible hack: If opening for RDWR and getting EPERM, just try
     898             :      * again for RDONLY. Quicker this way than to figure out why
     899             :      * we get that oh so useful General Error when trying to open a
     900             :      * read-only document.
     901             :      */
     902             :     if (-1 == fd && (flags & O_RDWR) && EPERM == errno)
     903             :     {
     904             :         int rdonly_flags = (flags & ~O_ACCMODE) | O_RDONLY;
     905             :         fd = open_c( cpFilePath, rdonly_flags, mode );
     906             :     }
     907             : #endif
     908      178113 :     if (-1 == fd)
     909             :     {
     910       13949 :         int saved_errno = errno;
     911             :         SAL_INFO("sal.file", "osl_openFile(" << cpFilePath << ", " << (flags & O_RDWR ? "writeable":"readonly") << ") failed: " << strerror(saved_errno));
     912       13949 :         return oslTranslateFileError (OSL_FET_ERROR, saved_errno);
     913             :     }
     914             : 
     915             : #if !HAVE_FEATURE_MACOSX_SANDBOX
     916             :     /* reset O_NONBLOCK flag */
     917      164164 :     if (flags & O_NONBLOCK)
     918             :     {
     919           0 :         int f = fcntl (fd, F_GETFL, 0);
     920           0 :         if (-1 == f)
     921             :         {
     922           0 :             int saved_errno = errno;
     923             :             SAL_INFO("sal.file", "osl_openFile(" << cpFilePath << ", " << (flags & O_RDWR ? "writeable":"readonly") << "): fcntl(" << fd << ", F_GETFL) failed: " << strerror(saved_errno));
     924           0 :             eRet = oslTranslateFileError (OSL_FET_ERROR, saved_errno);
     925           0 :             (void) close(fd);
     926           0 :             return eRet;
     927             :         }
     928           0 :         if (-1 == fcntl (fd, F_SETFL, (f & ~O_NONBLOCK)))
     929             :         {
     930           0 :             int saved_errno = errno;
     931             :              SAL_INFO("sal.file", "osl_openFile(" << cpFilePath << ", " << (flags & O_RDWR ? "writeable":"readonly") << "): fcntl(" << fd << ", F_SETFL) failed: " << strerror(saved_errno));
     932           0 :             eRet = oslTranslateFileError (OSL_FET_ERROR, saved_errno);
     933           0 :             (void) close(fd);
     934           0 :             return eRet;
     935             :         }
     936             :     }
     937             : #endif
     938             :     /* get file status (mode, size) */
     939             :     struct stat aFileStat;
     940      164164 :     if (-1 == fstat (fd, &aFileStat))
     941             :     {
     942           0 :         int saved_errno = errno;
     943             :         SAL_INFO("sal.file", "osl_openFile(" << cpFilePath << ", " << (flags & O_RDWR ? "writeable":"readonly") << "): fstat(" << fd << ") failed: " << strerror(saved_errno));
     944           0 :         eRet = oslTranslateFileError (OSL_FET_ERROR, saved_errno);
     945           0 :         (void) close(fd);
     946           0 :         return eRet;
     947             :     }
     948      164164 :     if (!S_ISREG(aFileStat.st_mode))
     949             :     {
     950             :         /* we only open regular files here */
     951             :         SAL_INFO("sal.file", "osl_openFile(" << cpFilePath << "): not a regular file");
     952           0 :         (void) close(fd);
     953           0 :         return osl_File_E_INVAL;
     954             :     }
     955             : 
     956      164164 :     if (osl_file_queryLocking (uFlags))
     957             :     {
     958             : #ifdef MACOSX
     959             :         if (-1 == flock (fd, LOCK_EX | LOCK_NB))
     960             :         {
     961             :             /* Mac OSX returns ENOTSUP for webdav drives. We should try read lock */
     962             :             if ((errno != ENOTSUP) || ((-1 == flock (fd, LOCK_SH | LOCK_NB)) && (errno != ENOTSUP)))
     963             :             {
     964             :                 eRet = oslTranslateFileError (OSL_FET_ERROR, errno);
     965             :                 (void) close(fd);
     966             :                 return eRet;
     967             :             }
     968             :         }
     969             : #else   /* F_SETLK */
     970             :         {
     971             :             struct flock aflock;
     972             : 
     973       66302 :             aflock.l_type = F_WRLCK;
     974       66302 :             aflock.l_whence = SEEK_SET;
     975       66302 :             aflock.l_start = 0;
     976       66302 :             aflock.l_len = 0;
     977             : 
     978       66302 :             if (-1 == fcntl (fd, F_SETLK, &aflock))
     979             :             {
     980           0 :                 int saved_errno = errno;
     981             :                 SAL_INFO("sal.file", "osl_openFile(" << cpFilePath << ", " << (flags & O_RDWR ? "writeable":"readonly") << "): fcntl(" << fd << ", F_SETLK) failed: " << strerror(saved_errno));
     982           0 :                 eRet = oslTranslateFileError (OSL_FET_ERROR, saved_errno);
     983           0 :                 (void) close(fd);
     984           0 :                 return eRet;
     985             :             }
     986             :         }
     987             : #endif  /* F_SETLK */
     988             :     }
     989             : 
     990             :     /* allocate memory for impl structure */
     991      164164 :     FileHandle_Impl * pImpl = new FileHandle_Impl (fd, FileHandle_Impl::KIND_FD, cpFilePath);
     992      164164 :     if (!pImpl)
     993             :     {
     994           0 :         eRet = oslTranslateFileError (OSL_FET_ERROR, ENOMEM);
     995           0 :         (void) close(fd);
     996           0 :         return eRet;
     997             :     }
     998      164164 :     if (flags & O_RDWR)
     999      105184 :         pImpl->m_state |= FileHandle_Impl::STATE_WRITEABLE;
    1000      164164 :     pImpl->m_size = sal::static_int_cast< sal_uInt64 >(aFileStat.st_size);
    1001             : 
    1002             :     SAL_INFO("sal.file", "osl_openFile(" << cpFilePath << ", " << (flags & O_RDWR ? "writeable":"readonly") << ") => " << pImpl->m_fd);
    1003             : 
    1004      164164 :     *pHandle = (oslFileHandle)(pImpl);
    1005      164164 :     return osl_File_E_None;
    1006             : }
    1007             : 
    1008             : oslFileError
    1009      148314 : SAL_CALL osl_openFile( rtl_uString* ustrFileURL, oslFileHandle* pHandle, sal_uInt32 uFlags )
    1010             : {
    1011      148314 :     return openFile(ustrFileURL, pHandle, uFlags, mode_t(-1));
    1012             : }
    1013             : 
    1014             : oslFileError
    1015      170119 : SAL_CALL openFile( rtl_uString* ustrFileURL, oslFileHandle* pHandle, sal_uInt32 uFlags, mode_t mode )
    1016             : {
    1017             :     oslFileError eRet;
    1018             : 
    1019      170119 :     if ((ustrFileURL == 0) || (ustrFileURL->length == 0) || (pHandle == 0))
    1020           0 :         return osl_File_E_INVAL;
    1021             : 
    1022             :     /* convert file URL to system path */
    1023             :     char buffer[PATH_MAX];
    1024      170119 :     eRet = FileURLToPath (buffer, sizeof(buffer), ustrFileURL);
    1025      170119 :     if (eRet != osl_File_E_None)
    1026           0 :         return eRet;
    1027             : 
    1028             : #ifdef MACOSX
    1029             :     if (macxp_resolveAlias (buffer, sizeof(buffer)) != 0)
    1030             :         return oslTranslateFileError (OSL_FET_ERROR, errno);
    1031             : #endif /* MACOSX */
    1032             : 
    1033      170119 :     return openFilePath (buffer, pHandle, uFlags, mode);
    1034             : }
    1035             : 
    1036             : oslFileError
    1037      164348 : SAL_CALL osl_closeFile( oslFileHandle Handle )
    1038             : {
    1039      164348 :     FileHandle_Impl* pImpl = static_cast<FileHandle_Impl*>(Handle);
    1040             : 
    1041      164348 :     if (pImpl == 0)
    1042           0 :         return osl_File_E_INVAL;
    1043             : 
    1044             :     SAL_INFO("sal.file", "osl_closeFile(" << rtl::OString(pImpl->m_strFilePath) << ":" << pImpl->m_fd << ")");
    1045             : 
    1046      164348 :     if (pImpl->m_kind == FileHandle_Impl::KIND_MEM)
    1047             :     {
    1048           0 :         delete pImpl;
    1049           0 :         return osl_File_E_None;
    1050             :     }
    1051             : 
    1052      164348 :     if (pImpl->m_fd < 0)
    1053           0 :         return osl_File_E_INVAL;
    1054             : 
    1055      164348 :     (void) pthread_mutex_lock (&(pImpl->m_mutex));
    1056             : 
    1057             :     /* close(2) implicitly (and unconditionally) unlocks */
    1058      164348 :     oslFileError result = pImpl->syncFile();
    1059      164348 :     if (result != osl_File_E_None)
    1060             :     {
    1061             :         /* close, ignoring double failure */
    1062           0 :         (void) close (pImpl->m_fd);
    1063             :     }
    1064      164348 :     else if (-1 == close (pImpl->m_fd))
    1065             :     {
    1066             :         /* translate error code */
    1067           0 :         result = oslTranslateFileError (OSL_FET_ERROR, errno);
    1068             :     }
    1069             : 
    1070      164348 :     (void) pthread_mutex_unlock (&(pImpl->m_mutex));
    1071      164348 :     delete pImpl;
    1072      164348 :     return (result);
    1073             : }
    1074             : 
    1075             : oslFileError
    1076        1629 : SAL_CALL osl_syncFile(oslFileHandle Handle)
    1077             : {
    1078        1629 :     FileHandle_Impl* pImpl = static_cast<FileHandle_Impl*>(Handle);
    1079             : 
    1080        1629 :     if ((0 == pImpl) || ((pImpl->m_kind == FileHandle_Impl::KIND_FD) && (-1 == pImpl->m_fd)))
    1081           2 :         return osl_File_E_INVAL;
    1082             : 
    1083        1627 :     if (pImpl->m_kind == FileHandle_Impl::KIND_MEM)
    1084           0 :         return osl_File_E_None;
    1085             : 
    1086        1627 :     FileHandle_Impl::Guard lock (&(pImpl->m_mutex));
    1087             : 
    1088             :     SAL_INFO("sal.file", "osl_syncFile(" << pImpl->m_fd << ")");
    1089        1627 :     oslFileError result = pImpl->syncFile();
    1090        1627 :     if (result != osl_File_E_None)
    1091           0 :         return (result);
    1092        1627 :     if (-1 == fsync (pImpl->m_fd))
    1093           0 :         return oslTranslateFileError (OSL_FET_ERROR, errno);
    1094             : 
    1095        1627 :     return osl_File_E_None;
    1096             : }
    1097             : 
    1098    21006510 : inline off_t max_off_t()
    1099             : {
    1100    21006510 :     return std::numeric_limits< off_t >::max();
    1101             : }
    1102             : 
    1103             : oslFileError
    1104       24492 : SAL_CALL osl_mapFile (
    1105             :     oslFileHandle Handle,
    1106             :     void**        ppAddr,
    1107             :     sal_uInt64    uLength,
    1108             :     sal_uInt64    uOffset,
    1109             :     sal_uInt32    uFlags
    1110             : )
    1111             : {
    1112       24492 :     FileHandle_Impl* pImpl = static_cast<FileHandle_Impl*>(Handle);
    1113             : 
    1114       24492 :     if ((0 == pImpl) || ((pImpl->m_kind == FileHandle_Impl::KIND_FD) && (-1 == pImpl->m_fd)) || (0 == ppAddr))
    1115           0 :         return osl_File_E_INVAL;
    1116       24492 :     *ppAddr = 0;
    1117             : 
    1118             :     if (uLength > SAL_MAX_SIZE)
    1119             :         return osl_File_E_OVERFLOW;
    1120       24492 :     size_t const nLength = sal::static_int_cast< size_t >(uLength);
    1121             : 
    1122       24492 :     sal_uInt64 const limit_off_t = max_off_t();
    1123       24492 :     if (uOffset > limit_off_t)
    1124           0 :         return osl_File_E_OVERFLOW;
    1125             : 
    1126       24492 :     if (pImpl->m_kind == FileHandle_Impl::KIND_MEM)
    1127             :     {
    1128           0 :         *ppAddr = pImpl->m_buffer + uOffset;
    1129           0 :         return osl_File_E_None;
    1130             :     }
    1131             : 
    1132       24492 :     off_t const nOffset = sal::static_int_cast< off_t >(uOffset);
    1133             : 
    1134       24492 :     void* p = mmap(NULL, nLength, PROT_READ, MAP_SHARED, pImpl->m_fd, nOffset);
    1135       24492 :     if (MAP_FAILED == p)
    1136           8 :         return oslTranslateFileError(OSL_FET_ERROR, errno);
    1137       24484 :     *ppAddr = p;
    1138             : 
    1139       24484 :     if (uFlags & osl_File_MapFlag_RandomAccess)
    1140             :     {
    1141             :         // Determine memory pagesize.
    1142        7561 :         size_t const nPageSize = FileHandle_Impl::getpagesize();
    1143        7561 :         if (size_t(-1) != nPageSize)
    1144             :         {
    1145             :             /*
    1146             :              * Pagein, touching first byte of every memory page.
    1147             :              * Note: volatile disables optimizing the loop away.
    1148             :              */
    1149        7561 :             sal_uInt8 * pData (reinterpret_cast<sal_uInt8*>(*ppAddr));
    1150        7561 :             size_t      nSize (nLength);
    1151             : 
    1152        7561 :             volatile sal_uInt8 c = 0;
    1153      111488 :             while (nSize > nPageSize)
    1154             :             {
    1155       96366 :                 c ^= pData[0];
    1156       96366 :                 pData += nPageSize;
    1157       96366 :                 nSize -= nPageSize;
    1158             :             }
    1159        7561 :             if (nSize > 0)
    1160             :             {
    1161        7561 :                 c^= pData[0];
    1162             :             }
    1163             :         }
    1164             :     }
    1165       24484 :     if (uFlags & osl_File_MapFlag_WillNeed)
    1166             :     {
    1167             :         // On Linux, madvise(..., MADV_WILLNEED) appears to have the undesirable
    1168             :         // effect of not returning until the data has actually been paged in, so
    1169             :         // that its net effect would typically be to slow down the process
    1170             :         // (which could start processing at the beginning of the data while the
    1171             :         // OS simultaneously pages in the rest); on other platforms, it remains
    1172             :         // to be evaluated whether madvise or equivalent is available and
    1173             :         // actually useful:
    1174             : #if defined MACOSX
    1175             :         int e = posix_madvise(p, nLength, POSIX_MADV_WILLNEED);
    1176             :         if (e != 0)
    1177             :         {
    1178             :             SAL_INFO("sal.file", "posix_madvise(..., POSIX_MADV_WILLNEED) failed with " << e);
    1179             :         }
    1180             : #elif defined SOLARIS
    1181             :         if (madvise(static_cast< caddr_t >(p), nLength, MADV_WILLNEED) != 0)
    1182             :         {
    1183             :             SAL_INFO("sal.file", "madvise(..., MADV_WILLNEED) failed with " << strerror(errno));
    1184             :         }
    1185             : #endif
    1186             :     }
    1187       24484 :     return osl_File_E_None;
    1188             : }
    1189             : 
    1190             : static
    1191             : oslFileError
    1192       24351 : unmapFile (void* pAddr, sal_uInt64 uLength)
    1193             : {
    1194       24351 :     if (0 == pAddr)
    1195           0 :         return osl_File_E_INVAL;
    1196             : 
    1197             :     if (uLength > SAL_MAX_SIZE)
    1198             :         return osl_File_E_OVERFLOW;
    1199       24351 :     size_t const nLength = sal::static_int_cast< size_t >(uLength);
    1200             : 
    1201       24351 :     if (-1 == munmap(static_cast<char*>(pAddr), nLength))
    1202           0 :         return oslTranslateFileError(OSL_FET_ERROR, errno);
    1203             : 
    1204       24351 :     return osl_File_E_None;
    1205             : }
    1206             : 
    1207             : #ifndef ANDROID
    1208             : 
    1209             : // Note that osl_unmapFile() just won't work on Android in general
    1210             : // where for (uncompressed) files inside the .apk, in the /assets
    1211             : // folder osl_mapFile just returns a pointer to the file inside the
    1212             : // already mmapped .apk archive.
    1213             : 
    1214             : oslFileError
    1215           0 : SAL_CALL osl_unmapFile (void* pAddr, sal_uInt64 uLength)
    1216             : {
    1217           0 :     return unmapFile (pAddr, uLength);
    1218             : }
    1219             : 
    1220             : #endif
    1221             : 
    1222             : oslFileError
    1223       24351 : SAL_CALL osl_unmapMappedFile (oslFileHandle Handle, void* pAddr, sal_uInt64 uLength)
    1224             : {
    1225       24351 :     FileHandle_Impl * pImpl = static_cast<FileHandle_Impl*>(Handle);
    1226             : 
    1227       24351 :     if (pImpl == 0)
    1228           0 :         return osl_File_E_INVAL;
    1229             : 
    1230       24351 :     if (pImpl->m_kind == FileHandle_Impl::KIND_FD)
    1231       24351 :         return unmapFile (pAddr, uLength);
    1232             : 
    1233             :     // For parts of already mmapped "parent" files, whose mapping we
    1234             :     // can't change, not much we can or should do...
    1235           0 :     return osl_File_E_None;
    1236             : }
    1237             : 
    1238             : oslFileError
    1239       27180 : SAL_CALL osl_readLine (
    1240             :     oslFileHandle   Handle,
    1241             :     sal_Sequence ** ppSequence)
    1242             : {
    1243       27180 :     FileHandle_Impl * pImpl = static_cast<FileHandle_Impl*>(Handle);
    1244             : 
    1245       27180 :     if ((0 == pImpl) || ((pImpl->m_kind == FileHandle_Impl::KIND_FD) && (-1 == pImpl->m_fd)) || (0 == ppSequence))
    1246           0 :         return osl_File_E_INVAL;
    1247       27180 :     sal_uInt64 uBytesRead = 0;
    1248             : 
    1249             :     // read at current fileptr; fileptr += uBytesRead;
    1250       27180 :     FileHandle_Impl::Guard lock (&(pImpl->m_mutex));
    1251             :     oslFileError result = pImpl->readLineAt (
    1252       27180 :         pImpl->m_fileptr, ppSequence, &uBytesRead);
    1253       27180 :     if (result == osl_File_E_None)
    1254       24856 :         pImpl->m_fileptr += uBytesRead;
    1255       27180 :     return (result);
    1256             : }
    1257             : 
    1258             : oslFileError
    1259    22163756 : SAL_CALL osl_readFile (
    1260             :     oslFileHandle Handle,
    1261             :     void *        pBuffer,
    1262             :     sal_uInt64    uBytesRequested,
    1263             :     sal_uInt64 *  pBytesRead)
    1264             : {
    1265    22163756 :     FileHandle_Impl* pImpl = static_cast<FileHandle_Impl*>(Handle);
    1266             : 
    1267    22163756 :     if ((0 == pImpl) || ((pImpl->m_kind == FileHandle_Impl::KIND_FD) && (-1 == pImpl->m_fd)) || (0 == pBuffer) || (0 == pBytesRead))
    1268           0 :         return osl_File_E_INVAL;
    1269             : 
    1270             :     static sal_uInt64 const g_limit_ssize_t = std::numeric_limits< ssize_t >::max();
    1271    22163756 :     if (g_limit_ssize_t < uBytesRequested)
    1272           0 :         return osl_File_E_OVERFLOW;
    1273    22163756 :     size_t const nBytesRequested = sal::static_int_cast< size_t >(uBytesRequested);
    1274             : 
    1275             :     // read at current fileptr; fileptr += *pBytesRead;
    1276    22163756 :     FileHandle_Impl::Guard lock (&(pImpl->m_mutex));
    1277             :     oslFileError result = pImpl->readFileAt (
    1278    22163756 :         pImpl->m_fileptr, pBuffer, nBytesRequested, pBytesRead);
    1279    22163755 :     if (result == osl_File_E_None)
    1280    22163755 :         pImpl->m_fileptr += *pBytesRead;
    1281    22163755 :     return (result);
    1282             : }
    1283             : 
    1284             : oslFileError
    1285     7209620 : SAL_CALL osl_writeFile (
    1286             :     oslFileHandle Handle,
    1287             :     const void *  pBuffer,
    1288             :     sal_uInt64    uBytesToWrite,
    1289             :     sal_uInt64 *  pBytesWritten)
    1290             : {
    1291     7209620 :     FileHandle_Impl* pImpl = static_cast<FileHandle_Impl*>(Handle);
    1292             : 
    1293     7209620 :     if ((0 == pImpl) || (-1 == pImpl->m_fd) || (0 == pBuffer) || (0 == pBytesWritten))
    1294           2 :         return osl_File_E_INVAL;
    1295     7209618 :     if (0 == (pImpl->m_state & FileHandle_Impl::STATE_WRITEABLE))
    1296           0 :         return osl_File_E_BADF;
    1297             : 
    1298             :     static sal_uInt64 const g_limit_ssize_t = std::numeric_limits< ssize_t >::max();
    1299     7209618 :     if (g_limit_ssize_t < uBytesToWrite)
    1300           0 :         return osl_File_E_OVERFLOW;
    1301     7209618 :     size_t const nBytesToWrite = sal::static_int_cast< size_t >(uBytesToWrite);
    1302             : 
    1303             :     // write at current fileptr; fileptr += *pBytesWritten;
    1304     7209618 :     FileHandle_Impl::Guard lock (&(pImpl->m_mutex));
    1305             :     oslFileError result = pImpl->writeFileAt (
    1306     7209618 :         pImpl->m_fileptr, pBuffer, nBytesToWrite, pBytesWritten);
    1307     7209618 :     if (result == osl_File_E_None)
    1308     7209618 :         pImpl->m_fileptr += *pBytesWritten;
    1309     7209618 :     return (result);
    1310             : }
    1311             : 
    1312             : oslFileError
    1313         316 : SAL_CALL osl_readFileAt (
    1314             :     oslFileHandle Handle,
    1315             :     sal_uInt64    uOffset,
    1316             :     void*         pBuffer,
    1317             :     sal_uInt64    uBytesRequested,
    1318             :     sal_uInt64*   pBytesRead)
    1319             : {
    1320         316 :     FileHandle_Impl* pImpl = static_cast<FileHandle_Impl*>(Handle);
    1321             : 
    1322         316 :     if ((0 == pImpl) || ((pImpl->m_kind == FileHandle_Impl::KIND_FD) && (-1 == pImpl->m_fd)) || (0 == pBuffer) || (0 == pBytesRead))
    1323           0 :         return osl_File_E_INVAL;
    1324         316 :     if (0 == (pImpl->m_state & FileHandle_Impl::STATE_SEEKABLE))
    1325           0 :         return osl_File_E_SPIPE;
    1326             : 
    1327         316 :     sal_uInt64 const limit_off_t = max_off_t();
    1328         316 :     if (uOffset > limit_off_t)
    1329           0 :         return osl_File_E_OVERFLOW;
    1330         316 :     off_t const nOffset = sal::static_int_cast< off_t >(uOffset);
    1331             : 
    1332             :     static sal_uInt64 const g_limit_ssize_t = std::numeric_limits< ssize_t >::max();
    1333         316 :     if (g_limit_ssize_t < uBytesRequested)
    1334           0 :         return osl_File_E_OVERFLOW;
    1335         316 :     size_t const nBytesRequested = sal::static_int_cast< size_t >(uBytesRequested);
    1336             : 
    1337             :     // read at specified fileptr
    1338         316 :     FileHandle_Impl::Guard lock (&(pImpl->m_mutex));
    1339         316 :     return pImpl->readFileAt (nOffset, pBuffer, nBytesRequested, pBytesRead);
    1340             : }
    1341             : 
    1342             : oslFileError
    1343        5740 : SAL_CALL osl_writeFileAt (
    1344             :     oslFileHandle Handle,
    1345             :     sal_uInt64    uOffset,
    1346             :     const void*   pBuffer,
    1347             :     sal_uInt64    uBytesToWrite,
    1348             :     sal_uInt64*   pBytesWritten)
    1349             : {
    1350        5740 :     FileHandle_Impl* pImpl = static_cast<FileHandle_Impl*>(Handle);
    1351             : 
    1352        5740 :     if ((0 == pImpl) || (-1 == pImpl->m_fd) || (0 == pBuffer) || (0 == pBytesWritten))
    1353           0 :         return osl_File_E_INVAL;
    1354        5740 :     if (0 == (pImpl->m_state & FileHandle_Impl::STATE_SEEKABLE))
    1355           0 :         return osl_File_E_SPIPE;
    1356        5740 :     if (0 == (pImpl->m_state & FileHandle_Impl::STATE_WRITEABLE))
    1357           0 :         return osl_File_E_BADF;
    1358             : 
    1359        5740 :     sal_uInt64 const limit_off_t = max_off_t();
    1360        5740 :     if (limit_off_t < uOffset)
    1361           0 :         return osl_File_E_OVERFLOW;
    1362        5740 :     off_t const nOffset = sal::static_int_cast< off_t >(uOffset);
    1363             : 
    1364             :     static sal_uInt64 const g_limit_ssize_t = std::numeric_limits< ssize_t >::max();
    1365        5740 :     if (g_limit_ssize_t < uBytesToWrite)
    1366           0 :         return osl_File_E_OVERFLOW;
    1367        5740 :     size_t const nBytesToWrite = sal::static_int_cast< size_t >(uBytesToWrite);
    1368             : 
    1369             :     // write at specified fileptr
    1370        5740 :     FileHandle_Impl::Guard lock (&(pImpl->m_mutex));
    1371        5740 :     return pImpl->writeFileAt (nOffset, pBuffer, nBytesToWrite, pBytesWritten);
    1372             : }
    1373             : 
    1374             : oslFileError
    1375          10 : SAL_CALL osl_isEndOfFile( oslFileHandle Handle, sal_Bool *pIsEOF )
    1376             : {
    1377          10 :     FileHandle_Impl* pImpl = static_cast<FileHandle_Impl*>(Handle);
    1378             : 
    1379          10 :     if ((0 == pImpl) || ((pImpl->m_kind == FileHandle_Impl::KIND_FD) && (-1 == pImpl->m_fd)) || (0 == pIsEOF))
    1380           0 :         return osl_File_E_INVAL;
    1381             : 
    1382          10 :     FileHandle_Impl::Guard lock (&(pImpl->m_mutex));
    1383          10 :     *pIsEOF = (pImpl->getPos() == pImpl->getSize());
    1384          10 :     return osl_File_E_None;
    1385             : }
    1386             : 
    1387             : oslFileError
    1388    27579069 : SAL_CALL osl_getFilePos( oslFileHandle Handle, sal_uInt64* pPos )
    1389             : {
    1390    27579069 :     FileHandle_Impl* pImpl = static_cast<FileHandle_Impl*>(Handle);
    1391             : 
    1392    27579069 :     if ((0 == pImpl) || ((pImpl->m_kind == FileHandle_Impl::KIND_FD) && (-1 == pImpl->m_fd)) || (0 == pPos))
    1393           0 :         return osl_File_E_INVAL;
    1394             : 
    1395    27579069 :     FileHandle_Impl::Guard lock (&(pImpl->m_mutex));
    1396    27579069 :     *pPos = pImpl->getPos();
    1397    27579069 :     return osl_File_E_None;
    1398             : }
    1399             : 
    1400             : oslFileError
    1401    20973090 : SAL_CALL osl_setFilePos (oslFileHandle Handle, sal_uInt32 uHow, sal_Int64 uOffset)
    1402             : {
    1403    20973090 :     FileHandle_Impl* pImpl = static_cast<FileHandle_Impl*>(Handle);
    1404             : 
    1405    20973090 :     if ((0 == pImpl) || ((pImpl->m_kind == FileHandle_Impl::KIND_FD) && (-1 == pImpl->m_fd)))
    1406           0 :         return osl_File_E_INVAL;
    1407             : 
    1408    20973090 :     sal_Int64 const limit_off_t = max_off_t();
    1409    20973090 :     if (uOffset > limit_off_t)
    1410           0 :         return osl_File_E_OVERFLOW;
    1411    20973090 :     off_t nPos = 0, nOffset = sal::static_int_cast< off_t >(uOffset);
    1412             : 
    1413    20973090 :     FileHandle_Impl::Guard lock (&(pImpl->m_mutex));
    1414    20973090 :     switch(uHow)
    1415             :     {
    1416             :         case osl_Pos_Absolut:
    1417    20964921 :             if (0 > nOffset)
    1418           0 :                 return osl_File_E_INVAL;
    1419    20964921 :             break;
    1420             : 
    1421             :         case osl_Pos_Current:
    1422        1726 :             nPos = sal::static_int_cast< off_t >(pImpl->getPos());
    1423        1726 :             if ((0 > nOffset) && (-1*nOffset > nPos))
    1424           0 :                 return osl_File_E_INVAL;
    1425        1726 :             if (limit_off_t < (sal_Int64) nPos + nOffset)
    1426           0 :                 return osl_File_E_OVERFLOW;
    1427        1726 :             break;
    1428             : 
    1429             :         case osl_Pos_End:
    1430        6443 :             nPos = sal::static_int_cast< off_t >(pImpl->getSize());
    1431        6443 :             if ((0 > nOffset) && (-1*nOffset > nPos))
    1432           0 :                 return osl_File_E_INVAL;
    1433        6443 :             if (limit_off_t < (sal_Int64) nPos + nOffset)
    1434           0 :                 return osl_File_E_OVERFLOW;
    1435        6443 :             break;
    1436             : 
    1437             :         default:
    1438           0 :             return osl_File_E_INVAL;
    1439             :     }
    1440             : 
    1441    20973090 :     return pImpl->setPos (nPos + nOffset);
    1442             : }
    1443             : 
    1444             : oslFileError
    1445      322777 : SAL_CALL osl_getFileSize( oslFileHandle Handle, sal_uInt64* pSize )
    1446             : {
    1447      322777 :     FileHandle_Impl* pImpl = static_cast<FileHandle_Impl*>(Handle);
    1448             : 
    1449      322777 :     if ((0 == pImpl) || ((pImpl->m_kind == FileHandle_Impl::KIND_FD) && (-1 == pImpl->m_fd)) || (0 == pSize))
    1450           0 :         return osl_File_E_INVAL;
    1451             : 
    1452      322777 :     FileHandle_Impl::Guard lock (&(pImpl->m_mutex));
    1453      322777 :     *pSize = pImpl->getSize();
    1454      322777 :     return osl_File_E_None;
    1455             : }
    1456             : 
    1457             : oslFileError
    1458        2872 : SAL_CALL osl_setFileSize( oslFileHandle Handle, sal_uInt64 uSize )
    1459             : {
    1460        2872 :     FileHandle_Impl* pImpl = static_cast<FileHandle_Impl*>(Handle);
    1461             : 
    1462        2872 :     if ((0 == pImpl) || (-1 == pImpl->m_fd))
    1463           0 :         return osl_File_E_INVAL;
    1464        2872 :     if (0 == (pImpl->m_state & FileHandle_Impl::STATE_WRITEABLE))
    1465           0 :         return osl_File_E_BADF;
    1466             : 
    1467        2872 :     sal_uInt64 const limit_off_t = max_off_t();
    1468        2872 :     if (uSize > limit_off_t)
    1469           0 :         return osl_File_E_OVERFLOW;
    1470             : 
    1471        2872 :     oslFileError result = pImpl->syncFile();
    1472        2872 :     if (result != osl_File_E_None)
    1473           0 :         return (result);
    1474        2872 :     pImpl->m_bufptr = -1, pImpl->m_buflen = 0;
    1475             : 
    1476        2872 :     return pImpl->setSize (uSize);
    1477             : }
    1478             : 
    1479             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10