Bump for 3.6-28
[LibreOffice.git] / sal / osl / unx / file.cxx
blob3a5dac5f97410f594785dc3767fbfaa33e26cc85
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*************************************************************************
4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 * Copyright 2000, 2010 Oracle and/or its affiliates.
8 * OpenOffice.org - a multi-platform office productivity suite
10 * This file is part of OpenOffice.org.
12 * OpenOffice.org is free software: you can redistribute it and/or modify
13 * it under the terms of the GNU Lesser General Public License version 3
14 * only, as published by the Free Software Foundation.
16 * OpenOffice.org is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Lesser General Public License version 3 for more details
20 * (a copy is included in the LICENSE file that accompanied this code).
22 * You should have received a copy of the GNU Lesser General Public License
23 * version 3 along with OpenOffice.org. If not, see
24 * <http://www.openoffice.org/license.html>
25 * for a copy of the LGPLv3 License.
27 ************************************************************************/
30 #include "osl/file.hxx"
31 #include "osl/detail/file.h"
33 #include "osl/diagnose.h"
34 #include "rtl/alloc.h"
36 #include "system.h"
37 #include "createfilehandlefromfd.hxx"
38 #include "file_error_transl.h"
39 #include "file_url.h"
41 #include <algorithm>
42 #include <limits>
44 #include <string.h>
45 #include <pthread.h>
46 #include <sys/mman.h>
48 #if defined(MACOSX)
50 #include <sys/param.h>
51 #include <sys/mount.h>
52 #define HAVE_O_EXLOCK
54 // add MACOSX Time Value
55 #define TimeValue CFTimeValue
56 #include <CoreFoundation/CoreFoundation.h>
57 #undef TimeValue
59 #endif /* MACOSX */
61 #ifdef ANDROID
62 #include <osl/detail/android-bootstrap.h>
63 #endif
65 #ifdef DEBUG_OSL_FILE
66 # define OSL_FILE_TRACE osl_trace
67 # define PERROR( a, b ) perror( a ); fprintf( stderr, b )
68 #else
69 # define OSL_FILE_TRACE(fmt, ...)
70 # define PERROR( a, b )
71 #endif
75 /*******************************************************************
77 * FileHandle_Impl interface
79 ******************************************************************/
80 struct FileHandle_Impl
82 pthread_mutex_t m_mutex;
83 rtl_String * m_strFilePath; /* holds native file path */
84 int m_fd;
86 enum Kind
88 KIND_FD = 1,
89 KIND_MEM = 2
91 int m_kind;
92 /** State
94 enum StateBits
96 STATE_SEEKABLE = 1, /* default */
97 STATE_READABLE = 2, /* default */
98 STATE_WRITEABLE = 4, /* open() sets, write() requires, else osl_File_E_BADF */
99 STATE_MODIFIED = 8 /* write() sets, flush() resets */
101 int m_state;
103 sal_uInt64 m_size; /* file size */
104 off_t m_offset; /* physical offset from begin of file */
105 off_t m_fileptr; /* logical offset from begin of file */
107 off_t m_bufptr; /* buffer offset from begin of file */
108 size_t m_buflen; /* buffer filled [0, m_bufsiz - 1] */
110 size_t m_bufsiz;
111 sal_uInt8 * m_buffer;
113 explicit FileHandle_Impl (int fd, Kind kind = KIND_FD, char const * path = "<anon>");
114 ~FileHandle_Impl();
116 static void* operator new (size_t n);
117 static void operator delete (void * p);
119 static size_t getpagesize();
121 sal_uInt64 getPos() const;
122 oslFileError setPos (sal_uInt64 uPos);
124 sal_uInt64 getSize() const;
125 oslFileError setSize (sal_uInt64 uSize);
127 oslFileError readAt (
128 off_t nOffset,
129 void * pBuffer,
130 size_t nBytesRequested,
131 sal_uInt64 * pBytesRead);
133 oslFileError writeAt (
134 off_t nOffset,
135 void const * pBuffer,
136 size_t nBytesToWrite,
137 sal_uInt64 * pBytesWritten);
139 oslFileError readFileAt (
140 off_t nOffset,
141 void * pBuffer,
142 size_t nBytesRequested,
143 sal_uInt64 * pBytesRead);
145 oslFileError writeFileAt (
146 off_t nOffset,
147 void const * pBuffer,
148 size_t nBytesToWrite,
149 sal_uInt64 * pBytesWritten);
151 oslFileError readLineAt (
152 off_t nOffset,
153 sal_Sequence ** ppSequence,
154 sal_uInt64 * pBytesRead);
156 oslFileError writeSequence_Impl (
157 sal_Sequence ** ppSequence,
158 size_t * pnOffset,
159 const void * pBuffer,
160 size_t nBytes);
162 oslFileError syncFile();
164 /** Buffer cache / allocator.
166 class Allocator
168 rtl_cache_type * m_cache;
169 size_t m_bufsiz;
171 Allocator (Allocator const &);
172 Allocator & operator= (Allocator const &);
174 public:
175 static Allocator & get();
177 void allocate (sal_uInt8 ** ppBuffer, size_t * pnSize);
178 void deallocate (sal_uInt8 * pBuffer);
180 protected:
181 Allocator();
182 ~Allocator();
185 /** Guard.
187 class Guard
189 pthread_mutex_t * m_mutex;
191 public:
192 explicit Guard(pthread_mutex_t * pMutex);
193 ~Guard();
197 /*******************************************************************
199 * FileHandle_Impl implementation
201 ******************************************************************/
203 FileHandle_Impl::Allocator &
204 FileHandle_Impl::Allocator::get()
206 static Allocator g_aBufferAllocator;
207 return g_aBufferAllocator;
210 FileHandle_Impl::Allocator::Allocator()
211 : m_cache (0),
212 m_bufsiz (0)
214 size_t const pagesize = FileHandle_Impl::getpagesize();
215 if (size_t(-1) != pagesize)
217 m_cache = rtl_cache_create (
218 "osl_file_buffer_cache", pagesize, 0, 0, 0, 0, 0, 0, 0);
219 if (0 != m_cache)
220 m_bufsiz = pagesize;
223 FileHandle_Impl::Allocator::~Allocator()
225 rtl_cache_destroy (m_cache), m_cache = 0;
228 void FileHandle_Impl::Allocator::allocate (sal_uInt8 ** ppBuffer, size_t * pnSize)
230 OSL_PRECOND((0 != ppBuffer) && (0 != pnSize), "FileHandle_Impl::Allocator::allocate(): contract violation");
231 if ((0 != ppBuffer) && (0 != pnSize))
232 *ppBuffer = static_cast< sal_uInt8* >(rtl_cache_alloc(m_cache)), *pnSize = m_bufsiz;
234 void FileHandle_Impl::Allocator::deallocate (sal_uInt8 * pBuffer)
236 if (0 != pBuffer)
237 rtl_cache_free (m_cache, pBuffer);
240 FileHandle_Impl::Guard::Guard(pthread_mutex_t * pMutex)
241 : m_mutex (pMutex)
243 OSL_PRECOND (m_mutex != 0, "FileHandle_Impl::Guard::Guard(): null pointer.");
244 (void) pthread_mutex_lock (m_mutex); // ignoring EINVAL ...
246 FileHandle_Impl::Guard::~Guard()
248 OSL_PRECOND (m_mutex != 0, "FileHandle_Impl::Guard::~Guard(): null pointer.");
249 (void) pthread_mutex_unlock (m_mutex);
252 FileHandle_Impl::FileHandle_Impl (int fd, enum Kind kind, char const * path)
253 : m_strFilePath (0),
254 m_fd (fd),
255 m_kind (kind),
256 m_state (STATE_SEEKABLE | STATE_READABLE),
257 m_size (0),
258 m_offset (0),
259 m_fileptr (0),
260 m_bufptr (-1),
261 m_buflen (0),
262 m_bufsiz (0),
263 m_buffer (0)
265 (void) pthread_mutex_init(&m_mutex, 0);
266 rtl_string_newFromStr (&m_strFilePath, path);
267 if (m_kind == KIND_FD) {
268 Allocator::get().allocate (&m_buffer, &m_bufsiz);
269 if (0 != m_buffer)
270 memset (m_buffer, 0, m_bufsiz);
273 FileHandle_Impl::~FileHandle_Impl()
275 if (m_kind == KIND_FD)
276 Allocator::get().deallocate (m_buffer), m_buffer = 0;
277 rtl_string_release (m_strFilePath), m_strFilePath = 0;
278 (void) pthread_mutex_destroy(&m_mutex); // ignoring EBUSY ...
281 void* FileHandle_Impl::operator new (size_t n)
283 return rtl_allocateMemory(n);
285 void FileHandle_Impl::operator delete (void * p)
287 rtl_freeMemory(p);
290 size_t FileHandle_Impl::getpagesize()
292 #if defined(FREEBSD) || defined(NETBSD) || defined(MACOSX) || \
293 defined(OPENBSD) || defined(DRAGONFLY)
294 return sal::static_int_cast< size_t >(::getpagesize());
295 #else /* POSIX */
296 return sal::static_int_cast< size_t >(::sysconf(_SC_PAGESIZE));
297 #endif /* xBSD || POSIX */
300 sal_uInt64 FileHandle_Impl::getPos() const
302 return sal::static_int_cast< sal_uInt64 >(m_fileptr);
305 oslFileError FileHandle_Impl::setPos (sal_uInt64 uPos)
307 OSL_FILE_TRACE("FileHandle_Impl::setPos(%d, %lld) => %lld", m_fd, getPos(), uPos);
308 m_fileptr = sal::static_int_cast< off_t >(uPos);
309 return osl_File_E_None;
312 sal_uInt64 FileHandle_Impl::getSize() const
314 off_t const bufend = std::max((off_t)(0), m_bufptr) + m_buflen;
315 return std::max(m_size, sal::static_int_cast< sal_uInt64 >(bufend));
318 oslFileError FileHandle_Impl::setSize (sal_uInt64 uSize)
320 off_t const nSize = sal::static_int_cast< off_t >(uSize);
321 if (-1 == ftruncate (m_fd, nSize))
323 /* Failure. Save original result. Try fallback algorithm */
324 oslFileError result = oslTranslateFileError (OSL_FET_ERROR, errno);
326 /* Check against current size. Fail upon 'shrink' */
327 if (uSize <= getSize())
329 /* Failure upon 'shrink'. Return original result */
330 return (result);
333 /* Save current position */
334 off_t const nCurPos = (off_t)lseek (m_fd, (off_t)0, SEEK_CUR);
335 if (nCurPos == (off_t)(-1))
336 return (result);
338 /* Try 'expand' via 'lseek()' and 'write()' */
339 if (-1 == lseek (m_fd, (off_t)(nSize - 1), SEEK_SET))
340 return (result);
342 if (-1 == write (m_fd, (char*)"", (size_t)1))
344 /* Failure. Restore saved position */
345 (void) lseek (m_fd, (off_t)(nCurPos), SEEK_SET);
346 return (result);
349 /* Success. Restore saved position */
350 if (-1 == lseek (m_fd, (off_t)nCurPos, SEEK_SET))
351 return (result);
354 OSL_FILE_TRACE("osl_setFileSize(%d, %lld) => %ld", m_fd, getSize(), nSize);
355 m_size = sal::static_int_cast< sal_uInt64 >(nSize);
356 return osl_File_E_None;
359 oslFileError FileHandle_Impl::readAt (
360 off_t nOffset,
361 void * pBuffer,
362 size_t nBytesRequested,
363 sal_uInt64 * pBytesRead)
365 OSL_PRECOND((m_state & STATE_SEEKABLE), "FileHandle_Impl::readAt(): not seekable");
366 if (!(m_state & STATE_SEEKABLE))
367 return osl_File_E_SPIPE;
369 OSL_PRECOND((m_state & STATE_READABLE), "FileHandle_Impl::readAt(): not readable");
370 if (!(m_state & STATE_READABLE))
371 return osl_File_E_BADF;
373 if (m_kind == KIND_MEM)
375 ssize_t nBytes;
377 m_offset = nOffset;
379 if ((sal_uInt64) m_offset >= m_size)
380 nBytes = 0;
381 else
383 nBytes = std::min(nBytesRequested, (size_t) (m_size - m_offset));
384 memmove(pBuffer, m_buffer + m_offset, nBytes);
385 m_offset += nBytes;
387 *pBytesRead = nBytes;
388 return osl_File_E_None;
391 #if defined(LINUX) || defined(SOLARIS)
393 ssize_t nBytes = ::pread (m_fd, pBuffer, nBytesRequested, nOffset);
394 if ((-1 == nBytes) && (EOVERFLOW == errno))
396 /* Some 'pread()'s fail with EOVERFLOW when reading at (or past)
397 * end-of-file, different from 'lseek() + read()' behaviour.
398 * Returning '0 bytes read' and 'osl_File_E_None' instead.
400 nBytes = 0;
402 if (-1 == nBytes)
403 return oslTranslateFileError (OSL_FET_ERROR, errno);
405 #else /* !(LINUX || SOLARIS) */
407 if (nOffset != m_offset)
409 if (-1 == ::lseek (m_fd, nOffset, SEEK_SET))
410 return oslTranslateFileError (OSL_FET_ERROR, errno);
411 m_offset = nOffset;
414 ssize_t nBytes = ::read (m_fd, pBuffer, nBytesRequested);
415 if (-1 == nBytes)
416 return oslTranslateFileError (OSL_FET_ERROR, errno);
417 m_offset += nBytes;
419 #endif /* !(LINUX || SOLARIS) */
421 OSL_FILE_TRACE("FileHandle_Impl::readAt(%d, %lld, %ld)", m_fd, nOffset, nBytes);
422 *pBytesRead = nBytes;
423 return osl_File_E_None;
426 oslFileError FileHandle_Impl::writeAt (
427 off_t nOffset,
428 void const * pBuffer,
429 size_t nBytesToWrite,
430 sal_uInt64 * pBytesWritten)
432 OSL_PRECOND((m_state & STATE_SEEKABLE), "FileHandle_Impl::writeAt(): not seekable");
433 if (!(m_state & STATE_SEEKABLE))
434 return osl_File_E_SPIPE;
436 OSL_PRECOND((m_state & STATE_WRITEABLE), "FileHandle_Impl::writeAt(): not writeable");
437 if (!(m_state & STATE_WRITEABLE))
438 return osl_File_E_BADF;
440 #if defined(LINUX) || defined(SOLARIS)
442 ssize_t nBytes = ::pwrite (m_fd, pBuffer, nBytesToWrite, nOffset);
443 if (-1 == nBytes)
444 return oslTranslateFileError (OSL_FET_ERROR, errno);
446 #else /* !(LINUX || SOLARIS) */
448 if (nOffset != m_offset)
450 if (-1 == ::lseek (m_fd, nOffset, SEEK_SET))
451 return oslTranslateFileError (OSL_FET_ERROR, errno);
452 m_offset = nOffset;
455 ssize_t nBytes = ::write (m_fd, pBuffer, nBytesToWrite);
456 if (-1 == nBytes)
457 return oslTranslateFileError (OSL_FET_ERROR, errno);
458 m_offset += nBytes;
460 #endif /* !(LINUX || SOLARIS) */
462 OSL_FILE_TRACE("FileHandle_Impl::writeAt(%d, %lld, %ld)", m_fd, nOffset, nBytes);
463 m_size = std::max (m_size, sal::static_int_cast< sal_uInt64 >(nOffset + nBytes));
465 *pBytesWritten = nBytes;
466 return osl_File_E_None;
469 oslFileError FileHandle_Impl::readFileAt (
470 off_t nOffset,
471 void * pBuffer,
472 size_t nBytesRequested,
473 sal_uInt64 * pBytesRead)
475 if (0 == (m_state & STATE_SEEKABLE))
477 // not seekable (pipe)
478 ssize_t nBytes = ::read (m_fd, pBuffer, nBytesRequested);
479 if (-1 == nBytes)
480 return oslTranslateFileError (OSL_FET_ERROR, errno);
481 *pBytesRead = nBytes;
482 return osl_File_E_None;
484 else if (m_kind == KIND_MEM || 0 == m_buffer)
486 // not buffered
487 return readAt (nOffset, pBuffer, nBytesRequested, pBytesRead);
489 else
491 sal_uInt8 * buffer = static_cast<sal_uInt8*>(pBuffer);
492 for (*pBytesRead = 0; nBytesRequested > 0; )
494 off_t const bufptr = (nOffset / m_bufsiz) * m_bufsiz;
495 size_t const bufpos = (nOffset % m_bufsiz);
497 if (bufptr != m_bufptr)
499 // flush current buffer
500 oslFileError result = syncFile();
501 if (result != osl_File_E_None)
502 return (result);
503 m_bufptr = -1, m_buflen = 0;
505 if (nBytesRequested >= m_bufsiz)
507 // buffer too small, read through from file
508 sal_uInt64 uDone = 0;
509 result = readAt (nOffset, &(buffer[*pBytesRead]), nBytesRequested, &uDone);
510 if (result != osl_File_E_None)
511 return (result);
513 nBytesRequested -= uDone, *pBytesRead += uDone;
514 return osl_File_E_None;
517 // update buffer (pointer)
518 sal_uInt64 uDone = 0;
519 result = readAt (bufptr, m_buffer, m_bufsiz, &uDone);
520 if (result != osl_File_E_None)
521 return (result);
522 m_bufptr = bufptr, m_buflen = uDone;
524 if (bufpos >= m_buflen)
526 // end of file
527 return osl_File_E_None;
530 size_t const bytes = std::min (m_buflen - bufpos, nBytesRequested);
531 OSL_FILE_TRACE("FileHandle_Impl::readFileAt(%d, %lld, %ld)", m_fd, nOffset, bytes);
533 memcpy (&(buffer[*pBytesRead]), &(m_buffer[bufpos]), bytes);
534 nBytesRequested -= bytes, *pBytesRead += bytes, nOffset += bytes;
536 return osl_File_E_None;
540 oslFileError FileHandle_Impl::writeFileAt (
541 off_t nOffset,
542 void const * pBuffer,
543 size_t nBytesToWrite,
544 sal_uInt64 * pBytesWritten)
546 if (0 == (m_state & STATE_SEEKABLE))
548 // not seekable (pipe)
549 ssize_t nBytes = ::write (m_fd, pBuffer, nBytesToWrite);
550 if (-1 == nBytes)
551 return oslTranslateFileError (OSL_FET_ERROR, errno);
552 *pBytesWritten = nBytes;
553 return osl_File_E_None;
555 else if (0 == m_buffer)
557 // not buffered
558 return writeAt (nOffset, pBuffer, nBytesToWrite, pBytesWritten);
560 else
562 sal_uInt8 const * buffer = static_cast<sal_uInt8 const *>(pBuffer);
563 for (*pBytesWritten = 0; nBytesToWrite > 0; )
565 off_t const bufptr = (nOffset / m_bufsiz) * m_bufsiz;
566 size_t const bufpos = (nOffset % m_bufsiz);
567 if (bufptr != m_bufptr)
569 // flush current buffer
570 oslFileError result = syncFile();
571 if (result != osl_File_E_None)
572 return (result);
573 m_bufptr = -1, m_buflen = 0;
575 if (nBytesToWrite >= m_bufsiz)
577 // buffer to small, write through to file
578 sal_uInt64 uDone = 0;
579 result = writeAt (nOffset, &(buffer[*pBytesWritten]), nBytesToWrite, &uDone);
580 if (result != osl_File_E_None)
581 return (result);
582 if (uDone != nBytesToWrite)
583 return osl_File_E_IO;
585 nBytesToWrite -= uDone, *pBytesWritten += uDone;
586 return osl_File_E_None;
589 // update buffer (pointer)
590 sal_uInt64 uDone = 0;
591 result = readAt (bufptr, m_buffer, m_bufsiz, &uDone);
592 if (result != osl_File_E_None)
593 return (result);
594 m_bufptr = bufptr, m_buflen = uDone;
597 size_t const bytes = std::min (m_bufsiz - bufpos, nBytesToWrite);
598 OSL_FILE_TRACE("FileHandle_Impl::writeFileAt(%d, %lld, %ld)", m_fd, nOffset, bytes);
600 memcpy (&(m_buffer[bufpos]), &(buffer[*pBytesWritten]), bytes);
601 nBytesToWrite -= bytes, *pBytesWritten += bytes, nOffset += bytes;
603 m_buflen = std::max(m_buflen, bufpos + bytes);
604 m_state |= STATE_MODIFIED;
606 return osl_File_E_None;
610 oslFileError FileHandle_Impl::readLineAt (
611 off_t nOffset,
612 sal_Sequence ** ppSequence,
613 sal_uInt64 * pBytesRead)
615 oslFileError result = osl_File_E_None;
617 off_t bufptr = nOffset / m_bufsiz * m_bufsiz;
618 if (bufptr != m_bufptr)
620 /* flush current buffer */
621 result = syncFile();
622 if (result != osl_File_E_None)
623 return (result);
625 /* update buffer (pointer) */
626 sal_uInt64 uDone = 0;
627 result = readAt (bufptr, m_buffer, m_bufsiz, &uDone);
628 if (result != osl_File_E_None)
629 return (result);
631 m_bufptr = bufptr, m_buflen = uDone;
634 static int const LINE_STATE_BEGIN = 0;
635 static int const LINE_STATE_CR = 1;
636 static int const LINE_STATE_LF = 2;
638 size_t bufpos = nOffset - m_bufptr, curpos = bufpos, dstpos = 0;
639 int state = (bufpos >= m_buflen) ? LINE_STATE_LF : LINE_STATE_BEGIN;
641 for ( ; state != LINE_STATE_LF; )
643 if (curpos >= m_buflen)
645 /* buffer examined */
646 if (0 < (curpos - bufpos))
648 /* flush buffer to sequence */
649 result = writeSequence_Impl (
650 ppSequence, &dstpos, &(m_buffer[bufpos]), curpos - bufpos);
651 if (result != osl_File_E_None)
652 return (result);
653 *pBytesRead += curpos - bufpos, nOffset += curpos - bufpos;
656 bufptr = nOffset / m_bufsiz * m_bufsiz;
657 if (bufptr != m_bufptr)
659 /* update buffer (pointer) */
660 sal_uInt64 uDone = 0;
661 result = readAt (bufptr, m_buffer, m_bufsiz, &uDone);
662 if (result != osl_File_E_None)
663 return (result);
664 m_bufptr = bufptr, m_buflen = uDone;
667 bufpos = nOffset - m_bufptr, curpos = bufpos;
668 if (bufpos >= m_buflen)
669 break;
671 switch (state)
673 case LINE_STATE_CR:
674 state = LINE_STATE_LF;
675 switch (m_buffer[curpos])
677 case 0x0A: /* CRLF */
678 /* eat current char */
679 curpos++;
680 break;
681 default: /* single CR */
682 /* keep current char */
683 break;
685 break;
686 default:
687 /* determine next state */
688 switch (m_buffer[curpos])
690 case 0x0A: /* single LF */
691 state = LINE_STATE_LF;
692 break;
693 case 0x0D: /* CR */
694 state = LINE_STATE_CR;
695 break;
696 default: /* advance to next char */
697 curpos++;
698 break;
700 if (state != LINE_STATE_BEGIN)
702 /* skip the newline char */
703 curpos++;
705 /* flush buffer to sequence */
706 result = writeSequence_Impl (
707 ppSequence, &dstpos, &(m_buffer[bufpos]), curpos - bufpos - 1);
708 if (result != osl_File_E_None)
709 return (result);
710 *pBytesRead += curpos - bufpos, nOffset += curpos - bufpos;
712 break;
716 result = writeSequence_Impl (ppSequence, &dstpos, 0, 0);
717 if (result != osl_File_E_None)
718 return (result);
719 if (0 < dstpos)
720 return osl_File_E_None;
721 if (bufpos >= m_buflen)
722 return osl_File_E_AGAIN;
723 return osl_File_E_None;
726 oslFileError FileHandle_Impl::writeSequence_Impl (
727 sal_Sequence ** ppSequence,
728 size_t * pnOffset,
729 const void * pBuffer,
730 size_t nBytes)
732 sal_Int32 nElements = *pnOffset + nBytes;
733 if (!*ppSequence)
735 /* construct sequence */
736 rtl_byte_sequence_constructNoDefault(ppSequence, nElements);
738 else if (nElements != (*ppSequence)->nElements)
740 /* resize sequence */
741 rtl_byte_sequence_realloc(ppSequence, nElements);
743 if (*ppSequence != 0)
745 /* fill sequence */
746 memcpy(&((*ppSequence)->elements[*pnOffset]), pBuffer, nBytes), *pnOffset += nBytes;
748 return (*ppSequence != 0) ? osl_File_E_None : osl_File_E_NOMEM;
751 oslFileError FileHandle_Impl::syncFile()
753 oslFileError result = osl_File_E_None;
754 if (m_state & STATE_MODIFIED)
756 sal_uInt64 uDone = 0;
757 result = writeAt (m_bufptr, m_buffer, m_buflen, &uDone);
758 if (result != osl_File_E_None)
759 return (result);
760 if (uDone != m_buflen)
761 return osl_File_E_IO;
762 m_state &= ~STATE_MODIFIED;
764 return (result);
767 oslFileHandle osl::detail::createFileHandleFromFD( int fd )
769 if (-1 == fd)
770 return 0; // EINVAL
772 struct stat aFileStat;
773 if (-1 == fstat (fd, &aFileStat))
774 return 0; // EBADF
776 FileHandle_Impl * pImpl = new FileHandle_Impl (fd);
777 if (0 == pImpl)
778 return 0; // ENOMEM
780 // assume writeable
781 pImpl->m_state |= FileHandle_Impl::STATE_WRITEABLE;
782 if (!S_ISREG(aFileStat.st_mode))
784 /* not a regular file, mark not seekable */
785 pImpl->m_state &= ~FileHandle_Impl::STATE_SEEKABLE;
787 else
789 /* regular file, init current size */
790 pImpl->m_size = sal::static_int_cast< sal_uInt64 >(aFileStat.st_size);
793 OSL_FILE_TRACE("osl::detail::createFileHandleFromFD(%d, writeable) => %s",
794 pImpl->m_fd, rtl_string_getStr(pImpl->m_strFilePath));
795 return (oslFileHandle)(pImpl);
798 /*******************************************************************
799 * osl_file_adjustLockFlags
800 ******************************************************************/
801 static int osl_file_adjustLockFlags (const char * path, int flags)
803 #ifdef MACOSX
805 * The AFP implementation of MacOS X 10.4 treats O_EXLOCK in a way
806 * that makes it impossible for OOo to create a backup copy of the
807 * file it keeps opened. OTOH O_SHLOCK for AFP behaves as desired by
808 * the OOo file handling, so we need to check the path of the file
809 * for the filesystem name.
811 struct statfs s;
812 if( 0 <= statfs( path, &s ) )
814 if( 0 == strncmp("afpfs", s.f_fstypename, 5) )
816 flags &= ~O_EXLOCK;
817 flags |= O_SHLOCK;
819 else
821 /* Needed flags to allow opening a webdav file */
822 flags &= ~(O_EXLOCK | O_SHLOCK | O_NONBLOCK);
825 #endif /* MACOSX */
827 (void) path;
828 return flags;
831 /****************************************************************************
832 * osl_file_queryLocking
833 ***************************************************************************/
834 struct Locking_Impl
836 int m_enabled;
837 Locking_Impl() : m_enabled(0)
839 #ifndef HAVE_O_EXLOCK
840 m_enabled = (getenv("SAL_ENABLE_FILE_LOCKING") != 0);
841 #endif /* HAVE_O_EXLOCK */
844 static int osl_file_queryLocking (sal_uInt32 uFlags)
846 if (!(uFlags & osl_File_OpenFlag_NoLock))
848 if ((uFlags & osl_File_OpenFlag_Write) || (uFlags & osl_File_OpenFlag_Create))
850 static Locking_Impl g_locking;
851 return (g_locking.m_enabled != 0);
854 return 0;
857 #ifdef UNX
859 static oslFileError
860 osl_openMemoryAsFile( void *address, size_t size, oslFileHandle *pHandle, const char *path )
862 oslFileError eRet;
863 FileHandle_Impl * pImpl = new FileHandle_Impl (-1, FileHandle_Impl::KIND_MEM, path);
864 if (!pImpl)
866 eRet = oslTranslateFileError (OSL_FET_ERROR, ENOMEM);
867 return eRet;
869 pImpl->m_size = sal::static_int_cast< sal_uInt64 >(size);
871 *pHandle = (oslFileHandle)(pImpl);
873 pImpl->m_bufptr = 0;
874 pImpl->m_buflen = size;
876 pImpl->m_bufsiz = size;
877 pImpl->m_buffer = (sal_uInt8*) address;
879 return osl_File_E_None;
882 oslFileError
883 SAL_CALL osl_openMemoryAsFile( void *address, size_t size, oslFileHandle *pHandle )
885 return osl_openMemoryAsFile( address, size, pHandle, "<anon>" );
888 #endif
890 /****************************************************************************
891 * osl_openFile
892 ***************************************************************************/
893 #ifdef HAVE_O_EXLOCK
894 #define OPEN_WRITE_FLAGS ( O_RDWR | O_EXLOCK | O_NONBLOCK )
895 #define OPEN_CREATE_FLAGS ( O_CREAT | O_RDWR | O_EXLOCK | O_NONBLOCK )
896 #else
897 #define OPEN_WRITE_FLAGS ( O_RDWR )
898 #define OPEN_CREATE_FLAGS ( O_CREAT | O_RDWR )
899 #endif
901 oslFileError
902 SAL_CALL osl_openFilePath( const char *cpFilePath, oslFileHandle* pHandle, sal_uInt32 uFlags )
904 oslFileError eRet;
906 #ifdef ANDROID
907 /* Opening a file from /assets read-only means
908 * we should mmap it from the .apk file
910 if (strncmp (cpFilePath, "/assets/", sizeof ("/assets/") - 1) == 0)
912 if (uFlags & osl_File_OpenFlag_Write)
914 // Or should we just silently "open" it read-only and let write
915 // attempts, if any, fail then later?
916 OSL_TRACE("osl_openFile(%s, writeable), not possible!", cpFilePath);
917 errno = EPERM;
918 return osl_File_E_PERM;
920 void *address;
921 size_t size;
922 address = lo_apkentry(cpFilePath, &size);
923 OSL_TRACE("osl_openFile(%s) => %p",
924 cpFilePath, address);
925 if (address == NULL)
927 errno = ENOENT;
928 return osl_File_E_NOENT;
930 return osl_openMemoryAsFile(address, size, pHandle, cpFilePath);
932 #endif
934 /* set mode and flags */
935 int mode = S_IRUSR | S_IRGRP | S_IROTH;
936 int flags = O_RDONLY;
937 if (uFlags & osl_File_OpenFlag_Write)
939 mode |= S_IWUSR | S_IWGRP | S_IWOTH;
940 flags = OPEN_WRITE_FLAGS;
942 if (uFlags & osl_File_OpenFlag_Create)
944 mode |= S_IWUSR | S_IWGRP | S_IWOTH;
945 flags = OPEN_CREATE_FLAGS;
948 /* Check for flags passed in from SvFileStream::Open() */
949 if (uFlags & osl_File_OpenFlag_Trunc)
950 flags |= O_TRUNC;
951 if (!(uFlags & osl_File_OpenFlag_NoExcl))
952 flags |= O_EXCL;
954 if (uFlags & osl_File_OpenFlag_NoLock)
956 #ifdef HAVE_O_EXLOCK
957 flags &= ~(O_EXLOCK | O_SHLOCK | O_NONBLOCK);
958 #endif /* HAVE_O_EXLOCK */
960 else
962 flags = osl_file_adjustLockFlags (cpFilePath, flags);
965 /* open the file */
966 int fd = open( cpFilePath, flags, mode );
967 if (-1 == fd)
969 int saved_errno = errno;
970 OSL_TRACE("osl_openFile(%s, %s) failed: %s",
971 cpFilePath,
972 flags & O_RDWR ? "writeable":"readonly",
973 strerror(saved_errno));
974 return oslTranslateFileError (OSL_FET_ERROR, saved_errno);
977 /* reset O_NONBLOCK flag */
978 if (flags & O_NONBLOCK)
980 int f = fcntl (fd, F_GETFL, 0);
981 if (-1 == f)
983 int saved_errno = errno;
984 OSL_TRACE("osl_openFile(%s, %s): fcntl(%d, F_GETFL) failed: %s",
985 cpFilePath,
986 flags & O_RDWR ? "writeable":"readonly",
988 strerror(saved_errno));
989 eRet = oslTranslateFileError (OSL_FET_ERROR, saved_errno);
990 (void) close(fd);
991 return eRet;
993 if (-1 == fcntl (fd, F_SETFL, (f & ~O_NONBLOCK)))
995 int saved_errno = errno;
996 OSL_TRACE("osl_openFile(%s, %s): fcntl(%d, F_SETFL) failed: %s",
997 cpFilePath,
998 flags & O_RDWR ? "writeable":"readonly",
1000 strerror(saved_errno));
1001 eRet = oslTranslateFileError (OSL_FET_ERROR, saved_errno);
1002 (void) close(fd);
1003 return eRet;
1007 /* get file status (mode, size) */
1008 struct stat aFileStat;
1009 if (-1 == fstat (fd, &aFileStat))
1011 int saved_errno = errno;
1012 OSL_TRACE("osl_openFile(%s, %s): fstat(%d) failed: %s",
1013 cpFilePath,
1014 flags & O_RDWR ? "writeable":"readonly",
1016 strerror(saved_errno));
1017 eRet = oslTranslateFileError (OSL_FET_ERROR, saved_errno);
1018 (void) close(fd);
1019 return eRet;
1021 if (!S_ISREG(aFileStat.st_mode))
1023 /* we only open regular files here */
1024 OSL_TRACE("osl_openFile(%s): not a regular file",
1025 cpFilePath);
1026 (void) close(fd);
1027 return osl_File_E_INVAL;
1030 if (osl_file_queryLocking (uFlags))
1032 #ifdef MACOSX
1033 if (-1 == flock (fd, LOCK_EX | LOCK_NB))
1035 /* Mac OSX returns ENOTSUP for webdav drives. We should try read lock */
1036 if ((errno != ENOTSUP) || ((-1 == flock (fd, LOCK_SH | LOCK_NB)) && (errno != ENOTSUP)))
1038 eRet = oslTranslateFileError (OSL_FET_ERROR, errno);
1039 (void) close(fd);
1040 return eRet;
1043 #else /* F_SETLK */
1045 struct flock aflock;
1047 aflock.l_type = F_WRLCK;
1048 aflock.l_whence = SEEK_SET;
1049 aflock.l_start = 0;
1050 aflock.l_len = 0;
1052 if (-1 == fcntl (fd, F_SETLK, &aflock))
1054 int saved_errno = errno;
1055 OSL_TRACE("osl_openFile(%s, %s): fcntl(%d, F_SETLK) failed: %s",
1056 cpFilePath,
1057 flags & O_RDWR ? "writeable":"readonly",
1059 strerror(saved_errno));
1060 eRet = oslTranslateFileError (OSL_FET_ERROR, saved_errno);
1061 (void) close(fd);
1062 return eRet;
1065 #endif /* F_SETLK */
1068 /* allocate memory for impl structure */
1069 FileHandle_Impl * pImpl = new FileHandle_Impl (fd, FileHandle_Impl::KIND_FD, cpFilePath);
1070 if (!pImpl)
1072 eRet = oslTranslateFileError (OSL_FET_ERROR, ENOMEM);
1073 (void) close(fd);
1074 return eRet;
1076 if (flags & O_RDWR)
1077 pImpl->m_state |= FileHandle_Impl::STATE_WRITEABLE;
1078 pImpl->m_size = sal::static_int_cast< sal_uInt64 >(aFileStat.st_size);
1080 OSL_TRACE("osl_openFile(%s, %s) => %d",
1081 rtl_string_getStr(pImpl->m_strFilePath),
1082 flags & O_RDWR ? "writeable":"readonly",
1083 pImpl->m_fd);
1085 *pHandle = (oslFileHandle)(pImpl);
1086 return osl_File_E_None;
1089 oslFileError
1090 SAL_CALL osl_openFile( rtl_uString* ustrFileURL, oslFileHandle* pHandle, sal_uInt32 uFlags )
1092 oslFileError eRet;
1094 if ((ustrFileURL == 0) || (ustrFileURL->length == 0) || (pHandle == 0))
1095 return osl_File_E_INVAL;
1097 /* convert file URL to system path */
1098 char buffer[PATH_MAX];
1099 eRet = FileURLToPath (buffer, sizeof(buffer), ustrFileURL);
1100 if (eRet != osl_File_E_None)
1101 return eRet;
1103 #ifdef MACOSX
1104 if (macxp_resolveAlias (buffer, sizeof(buffer)) != 0)
1105 return oslTranslateFileError (OSL_FET_ERROR, errno);
1106 #endif /* MACOSX */
1108 return osl_openFilePath (buffer, pHandle, uFlags);
1111 /****************************************************************************/
1112 /* osl_closeFile */
1113 /****************************************************************************/
1114 oslFileError
1115 SAL_CALL osl_closeFile( oslFileHandle Handle )
1117 FileHandle_Impl* pImpl = static_cast<FileHandle_Impl*>(Handle);
1119 if (pImpl == 0)
1120 return osl_File_E_INVAL;
1122 OSL_TRACE("osl_closeFile(%s:%d)", rtl_string_getStr(pImpl->m_strFilePath), pImpl->m_fd);
1124 if (pImpl->m_kind == FileHandle_Impl::KIND_MEM)
1126 delete pImpl;
1127 return osl_File_E_None;
1130 if (pImpl->m_fd < 0)
1131 return osl_File_E_INVAL;
1133 (void) pthread_mutex_lock (&(pImpl->m_mutex));
1135 /* close(2) implicitly (and unconditionally) unlocks */
1136 oslFileError result = pImpl->syncFile();
1137 if (result != osl_File_E_None)
1139 /* close, ignoring double failure */
1140 (void) close (pImpl->m_fd);
1142 else if (-1 == close (pImpl->m_fd))
1144 /* translate error code */
1145 result = oslTranslateFileError (OSL_FET_ERROR, errno);
1148 (void) pthread_mutex_unlock (&(pImpl->m_mutex));
1149 delete pImpl;
1150 return (result);
1153 /************************************************
1154 * osl_syncFile
1155 ***********************************************/
1156 oslFileError
1157 SAL_CALL osl_syncFile(oslFileHandle Handle)
1159 FileHandle_Impl* pImpl = static_cast<FileHandle_Impl*>(Handle);
1161 if ((0 == pImpl) || ((pImpl->m_kind == FileHandle_Impl::KIND_FD) && (-1 == pImpl->m_fd)))
1162 return osl_File_E_INVAL;
1164 if (pImpl->m_kind == FileHandle_Impl::KIND_MEM)
1165 return osl_File_E_None;
1167 FileHandle_Impl::Guard lock (&(pImpl->m_mutex));
1169 OSL_TRACE("osl_syncFile(%d)", pImpl->m_fd);
1170 oslFileError result = pImpl->syncFile();
1171 if (result != osl_File_E_None)
1172 return (result);
1173 if (-1 == fsync (pImpl->m_fd))
1174 return oslTranslateFileError (OSL_FET_ERROR, errno);
1176 return osl_File_E_None;
1179 /************************************************
1180 * osl_fileGetOSHandle
1181 ***********************************************/
1182 oslFileError
1183 SAL_CALL osl_getFileOSHandle(
1184 oslFileHandle Handle,
1185 sal_IntPtr *piFileHandle )
1187 FileHandle_Impl* pImpl = static_cast<FileHandle_Impl*>(Handle);
1189 if (0 == pImpl || pImpl->m_kind != FileHandle_Impl::KIND_FD || -1 == pImpl->m_fd)
1190 return osl_File_E_INVAL;
1192 *piFileHandle = pImpl->m_fd;
1194 return osl_File_E_None;
1197 /*******************************************
1198 osl_mapFile
1199 ********************************************/
1200 oslFileError
1201 SAL_CALL osl_mapFile (
1202 oslFileHandle Handle,
1203 void** ppAddr,
1204 sal_uInt64 uLength,
1205 sal_uInt64 uOffset,
1206 sal_uInt32 uFlags
1209 FileHandle_Impl* pImpl = static_cast<FileHandle_Impl*>(Handle);
1211 if ((0 == pImpl) || ((pImpl->m_kind == FileHandle_Impl::KIND_FD) && (-1 == pImpl->m_fd)) || (0 == ppAddr))
1212 return osl_File_E_INVAL;
1213 *ppAddr = 0;
1215 static sal_uInt64 const g_limit_size_t = std::numeric_limits< size_t >::max();
1216 if (g_limit_size_t < uLength)
1217 return osl_File_E_OVERFLOW;
1218 size_t const nLength = sal::static_int_cast< size_t >(uLength);
1220 static sal_uInt64 const g_limit_off_t = std::numeric_limits< off_t >::max();
1221 if (g_limit_off_t < uOffset)
1222 return osl_File_E_OVERFLOW;
1224 if (pImpl->m_kind == FileHandle_Impl::KIND_MEM)
1226 *ppAddr = pImpl->m_buffer + uOffset;
1227 return osl_File_E_None;
1230 off_t const nOffset = sal::static_int_cast< off_t >(uOffset);
1232 void* p = mmap(NULL, nLength, PROT_READ, MAP_SHARED, pImpl->m_fd, nOffset);
1233 if (MAP_FAILED == p)
1234 return oslTranslateFileError(OSL_FET_ERROR, errno);
1235 *ppAddr = p;
1237 if (uFlags & osl_File_MapFlag_RandomAccess)
1239 // Determine memory pagesize.
1240 size_t const nPageSize = FileHandle_Impl::getpagesize();
1241 if (size_t(-1) != nPageSize)
1244 * Pagein, touching first byte of every memory page.
1245 * Note: volatile disables optimizing the loop away.
1247 sal_uInt8 * pData (reinterpret_cast<sal_uInt8*>(*ppAddr));
1248 size_t nSize (nLength);
1250 volatile sal_uInt8 c = 0;
1251 while (nSize > nPageSize)
1253 c ^= pData[0];
1254 pData += nPageSize;
1255 nSize -= nPageSize;
1257 if (nSize > 0)
1259 c^= pData[0];
1263 if (uFlags & osl_File_MapFlag_WillNeed)
1265 // On Linux, madvise(..., MADV_WILLNEED) appears to have the undesirable
1266 // effect of not returning until the data has actually been paged in, so
1267 // that its net effect would typically be to slow down the process
1268 // (which could start processing at the beginning of the data while the
1269 // OS simultaneously pages in the rest); on other platforms, it remains
1270 // to be evaluated whether madvise or equivalent is available and
1271 // actually useful:
1272 #if defined MACOSX
1273 int e = posix_madvise(p, nLength, POSIX_MADV_WILLNEED);
1274 if (e != 0)
1276 OSL_TRACE(
1277 "posix_madvise(..., POSIX_MADV_WILLNEED) failed with %d", e);
1279 #elif defined SOLARIS
1280 if (madvise(static_cast< caddr_t >(p), nLength, MADV_WILLNEED) != 0)
1282 OSL_TRACE("madvise(..., MADV_WILLNEED) failed with %d", errno);
1284 #endif
1286 return osl_File_E_None;
1289 static
1290 oslFileError
1291 unmapFile (void* pAddr, sal_uInt64 uLength)
1293 if (0 == pAddr)
1294 return osl_File_E_INVAL;
1296 static sal_uInt64 const g_limit_size_t = std::numeric_limits< size_t >::max();
1297 if (g_limit_size_t < uLength)
1298 return osl_File_E_OVERFLOW;
1299 size_t const nLength = sal::static_int_cast< size_t >(uLength);
1301 if (-1 == munmap(static_cast<char*>(pAddr), nLength))
1302 return oslTranslateFileError(OSL_FET_ERROR, errno);
1304 return osl_File_E_None;
1307 #ifndef ANDROID
1309 // Note that osl_unmapFile() just won't work on Android in general
1310 // where for (uncompressed) files inside the .apk, in the /assets
1311 // folder osl_mapFile just returns a pointer to the file inside the
1312 // already mmapped .apk archive.
1314 /*******************************************
1315 osl_unmapFile
1316 ********************************************/
1317 oslFileError
1318 SAL_CALL osl_unmapFile (void* pAddr, sal_uInt64 uLength)
1320 return unmapFile (pAddr, uLength);
1323 #endif
1325 /*******************************************
1326 osl_unmapMappedFile
1327 ********************************************/
1328 oslFileError
1329 SAL_CALL osl_unmapMappedFile (oslFileHandle Handle, void* pAddr, sal_uInt64 uLength)
1331 FileHandle_Impl * pImpl = static_cast<FileHandle_Impl*>(Handle);
1333 if (pImpl == 0)
1334 return osl_File_E_INVAL;
1336 if (pImpl->m_kind == FileHandle_Impl::KIND_FD)
1337 return unmapFile (pAddr, uLength);
1339 // For parts of already mmapped "parent" files, whose mapping we
1340 // can't change, not much we can or should do...
1341 return osl_File_E_None;
1344 /*******************************************
1345 osl_readLine
1346 ********************************************/
1347 oslFileError
1348 SAL_CALL osl_readLine (
1349 oslFileHandle Handle,
1350 sal_Sequence ** ppSequence)
1352 FileHandle_Impl * pImpl = static_cast<FileHandle_Impl*>(Handle);
1354 if ((0 == pImpl) || ((pImpl->m_kind == FileHandle_Impl::KIND_FD) && (-1 == pImpl->m_fd)) || (0 == ppSequence))
1355 return osl_File_E_INVAL;
1356 sal_uInt64 uBytesRead = 0;
1358 // read at current fileptr; fileptr += uBytesRead;
1359 FileHandle_Impl::Guard lock (&(pImpl->m_mutex));
1360 oslFileError result = pImpl->readLineAt (
1361 pImpl->m_fileptr, ppSequence, &uBytesRead);
1362 if (result == osl_File_E_None)
1363 pImpl->m_fileptr += uBytesRead;
1364 return (result);
1367 /*******************************************
1368 osl_readFile
1369 ********************************************/
1370 oslFileError
1371 SAL_CALL osl_readFile (
1372 oslFileHandle Handle,
1373 void * pBuffer,
1374 sal_uInt64 uBytesRequested,
1375 sal_uInt64 * pBytesRead)
1377 FileHandle_Impl* pImpl = static_cast<FileHandle_Impl*>(Handle);
1379 if ((0 == pImpl) || ((pImpl->m_kind == FileHandle_Impl::KIND_FD) && (-1 == pImpl->m_fd)) || (0 == pBuffer) || (0 == pBytesRead))
1380 return osl_File_E_INVAL;
1382 static sal_uInt64 const g_limit_ssize_t = std::numeric_limits< ssize_t >::max();
1383 if (g_limit_ssize_t < uBytesRequested)
1384 return osl_File_E_OVERFLOW;
1385 size_t const nBytesRequested = sal::static_int_cast< size_t >(uBytesRequested);
1387 // read at current fileptr; fileptr += *pBytesRead;
1388 FileHandle_Impl::Guard lock (&(pImpl->m_mutex));
1389 oslFileError result = pImpl->readFileAt (
1390 pImpl->m_fileptr, pBuffer, nBytesRequested, pBytesRead);
1391 if (result == osl_File_E_None)
1392 pImpl->m_fileptr += *pBytesRead;
1393 return (result);
1396 /*******************************************
1397 osl_writeFile
1398 ********************************************/
1399 oslFileError
1400 SAL_CALL osl_writeFile (
1401 oslFileHandle Handle,
1402 const void * pBuffer,
1403 sal_uInt64 uBytesToWrite,
1404 sal_uInt64 * pBytesWritten)
1406 FileHandle_Impl* pImpl = static_cast<FileHandle_Impl*>(Handle);
1408 if ((0 == pImpl) || (-1 == pImpl->m_fd) || (0 == pBuffer) || (0 == pBytesWritten))
1409 return osl_File_E_INVAL;
1410 if (0 == (pImpl->m_state & FileHandle_Impl::STATE_WRITEABLE))
1411 return osl_File_E_BADF;
1413 static sal_uInt64 const g_limit_ssize_t = std::numeric_limits< ssize_t >::max();
1414 if (g_limit_ssize_t < uBytesToWrite)
1415 return osl_File_E_OVERFLOW;
1416 size_t const nBytesToWrite = sal::static_int_cast< size_t >(uBytesToWrite);
1418 // write at current fileptr; fileptr += *pBytesWritten;
1419 FileHandle_Impl::Guard lock (&(pImpl->m_mutex));
1420 oslFileError result = pImpl->writeFileAt (
1421 pImpl->m_fileptr, pBuffer, nBytesToWrite, pBytesWritten);
1422 if (result == osl_File_E_None)
1423 pImpl->m_fileptr += *pBytesWritten;
1424 return (result);
1427 /*******************************************
1428 osl_readFileAt
1429 ********************************************/
1430 oslFileError
1431 SAL_CALL osl_readFileAt (
1432 oslFileHandle Handle,
1433 sal_uInt64 uOffset,
1434 void* pBuffer,
1435 sal_uInt64 uBytesRequested,
1436 sal_uInt64* pBytesRead)
1438 FileHandle_Impl* pImpl = static_cast<FileHandle_Impl*>(Handle);
1440 if ((0 == pImpl) || ((pImpl->m_kind == FileHandle_Impl::KIND_FD) && (-1 == pImpl->m_fd)) || (0 == pBuffer) || (0 == pBytesRead))
1441 return osl_File_E_INVAL;
1442 if (0 == (pImpl->m_state & FileHandle_Impl::STATE_SEEKABLE))
1443 return osl_File_E_SPIPE;
1445 static sal_uInt64 const g_limit_off_t = std::numeric_limits< off_t >::max();
1446 if (g_limit_off_t < uOffset)
1447 return osl_File_E_OVERFLOW;
1448 off_t const nOffset = sal::static_int_cast< off_t >(uOffset);
1450 static sal_uInt64 const g_limit_ssize_t = std::numeric_limits< ssize_t >::max();
1451 if (g_limit_ssize_t < uBytesRequested)
1452 return osl_File_E_OVERFLOW;
1453 size_t const nBytesRequested = sal::static_int_cast< size_t >(uBytesRequested);
1455 // read at specified fileptr
1456 FileHandle_Impl::Guard lock (&(pImpl->m_mutex));
1457 return pImpl->readFileAt (nOffset, pBuffer, nBytesRequested, pBytesRead);
1460 /*******************************************
1461 osl_writeFileAt
1462 ********************************************/
1463 oslFileError
1464 SAL_CALL osl_writeFileAt (
1465 oslFileHandle Handle,
1466 sal_uInt64 uOffset,
1467 const void* pBuffer,
1468 sal_uInt64 uBytesToWrite,
1469 sal_uInt64* pBytesWritten)
1471 FileHandle_Impl* pImpl = static_cast<FileHandle_Impl*>(Handle);
1473 if ((0 == pImpl) || (-1 == pImpl->m_fd) || (0 == pBuffer) || (0 == pBytesWritten))
1474 return osl_File_E_INVAL;
1475 if (0 == (pImpl->m_state & FileHandle_Impl::STATE_SEEKABLE))
1476 return osl_File_E_SPIPE;
1477 if (0 == (pImpl->m_state & FileHandle_Impl::STATE_WRITEABLE))
1478 return osl_File_E_BADF;
1480 static sal_uInt64 const g_limit_off_t = std::numeric_limits< off_t >::max();
1481 if (g_limit_off_t < uOffset)
1482 return osl_File_E_OVERFLOW;
1483 off_t const nOffset = sal::static_int_cast< off_t >(uOffset);
1485 static sal_uInt64 const g_limit_ssize_t = std::numeric_limits< ssize_t >::max();
1486 if (g_limit_ssize_t < uBytesToWrite)
1487 return osl_File_E_OVERFLOW;
1488 size_t const nBytesToWrite = sal::static_int_cast< size_t >(uBytesToWrite);
1490 // write at specified fileptr
1491 FileHandle_Impl::Guard lock (&(pImpl->m_mutex));
1492 return pImpl->writeFileAt (nOffset, pBuffer, nBytesToWrite, pBytesWritten);
1495 /****************************************************************************/
1496 /* osl_isEndOfFile */
1497 /****************************************************************************/
1498 oslFileError
1499 SAL_CALL osl_isEndOfFile( oslFileHandle Handle, sal_Bool *pIsEOF )
1501 FileHandle_Impl* pImpl = static_cast<FileHandle_Impl*>(Handle);
1503 if ((0 == pImpl) || ((pImpl->m_kind == FileHandle_Impl::KIND_FD) && (-1 == pImpl->m_fd)) || (0 == pIsEOF))
1504 return osl_File_E_INVAL;
1506 FileHandle_Impl::Guard lock (&(pImpl->m_mutex));
1507 *pIsEOF = (pImpl->getPos() == pImpl->getSize());
1508 return osl_File_E_None;
1511 /************************************************
1512 * osl_getFilePos
1513 ***********************************************/
1514 oslFileError
1515 SAL_CALL osl_getFilePos( oslFileHandle Handle, sal_uInt64* pPos )
1517 FileHandle_Impl* pImpl = static_cast<FileHandle_Impl*>(Handle);
1519 if ((0 == pImpl) || ((pImpl->m_kind == FileHandle_Impl::KIND_FD) && (-1 == pImpl->m_fd)) || (0 == pPos))
1520 return osl_File_E_INVAL;
1522 FileHandle_Impl::Guard lock (&(pImpl->m_mutex));
1523 *pPos = pImpl->getPos();
1524 return osl_File_E_None;
1527 /*******************************************
1528 osl_setFilePos
1529 ********************************************/
1530 oslFileError
1531 SAL_CALL osl_setFilePos (oslFileHandle Handle, sal_uInt32 uHow, sal_Int64 uOffset)
1533 FileHandle_Impl* pImpl = static_cast<FileHandle_Impl*>(Handle);
1535 if ((0 == pImpl) || ((pImpl->m_kind == FileHandle_Impl::KIND_FD) && (-1 == pImpl->m_fd)))
1536 return osl_File_E_INVAL;
1538 static sal_Int64 const g_limit_off_t = std::numeric_limits< off_t >::max();
1539 if (g_limit_off_t < uOffset)
1540 return osl_File_E_OVERFLOW;
1541 off_t nPos = 0, nOffset = sal::static_int_cast< off_t >(uOffset);
1543 FileHandle_Impl::Guard lock (&(pImpl->m_mutex));
1544 switch(uHow)
1546 case osl_Pos_Absolut:
1547 if (0 > nOffset)
1548 return osl_File_E_INVAL;
1549 break;
1551 case osl_Pos_Current:
1552 nPos = sal::static_int_cast< off_t >(pImpl->getPos());
1553 if ((0 > nOffset) && (-1*nOffset > nPos))
1554 return osl_File_E_INVAL;
1555 if (g_limit_off_t < nPos + nOffset)
1556 return osl_File_E_OVERFLOW;
1557 break;
1559 case osl_Pos_End:
1560 nPos = sal::static_int_cast< off_t >(pImpl->getSize());
1561 if ((0 > nOffset) && (-1*nOffset > nPos))
1562 return osl_File_E_INVAL;
1563 if (g_limit_off_t < nPos + nOffset)
1564 return osl_File_E_OVERFLOW;
1565 break;
1567 default:
1568 return osl_File_E_INVAL;
1571 return pImpl->setPos (nPos + nOffset);
1574 /****************************************************************************
1575 * osl_getFileSize
1576 ****************************************************************************/
1577 oslFileError
1578 SAL_CALL osl_getFileSize( oslFileHandle Handle, sal_uInt64* pSize )
1580 FileHandle_Impl* pImpl = static_cast<FileHandle_Impl*>(Handle);
1582 if ((0 == pImpl) || ((pImpl->m_kind == FileHandle_Impl::KIND_FD) && (-1 == pImpl->m_fd)) || (0 == pSize))
1583 return osl_File_E_INVAL;
1585 FileHandle_Impl::Guard lock (&(pImpl->m_mutex));
1586 *pSize = pImpl->getSize();
1587 return osl_File_E_None;
1590 /************************************************
1591 * osl_setFileSize
1592 ***********************************************/
1593 oslFileError
1594 SAL_CALL osl_setFileSize( oslFileHandle Handle, sal_uInt64 uSize )
1596 FileHandle_Impl* pImpl = static_cast<FileHandle_Impl*>(Handle);
1598 if ((0 == pImpl) || (-1 == pImpl->m_fd))
1599 return osl_File_E_INVAL;
1600 if (0 == (pImpl->m_state & FileHandle_Impl::STATE_WRITEABLE))
1601 return osl_File_E_BADF;
1603 static sal_uInt64 const g_limit_off_t = std::numeric_limits< off_t >::max();
1604 if (g_limit_off_t < uSize)
1605 return osl_File_E_OVERFLOW;
1607 oslFileError result = pImpl->syncFile();
1608 if (result != osl_File_E_None)
1609 return (result);
1610 pImpl->m_bufptr = -1, pImpl->m_buflen = 0;
1612 return pImpl->setSize (uSize);
1615 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */