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