1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2000, 2010 Oracle and/or its affiliates.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * This file is part of OpenOffice.org.
11 * OpenOffice.org is free software: you can redistribute it and/or modify
12 * it under the terms of the GNU Lesser General Public License version 3
13 * only, as published by the Free Software Foundation.
15 * OpenOffice.org is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Lesser General Public License version 3 for more details
19 * (a copy is included in the LICENSE file that accompanied this code).
21 * You should have received a copy of the GNU Lesser General Public License
22 * version 3 along with OpenOffice.org. If not, see
23 * <http://www.openoffice.org/license.html>
24 * for a copy of the LGPLv3 License.
26 ************************************************************************/
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_sal.hxx"
31 #include "osl/file.hxx"
33 #include "osl/diagnose.h"
34 #include "rtl/alloc.h"
37 #include "file_error_transl.h"
49 #include <sys/param.h>
50 #include <sys/mount.h>
53 // add MACOSX Time Value
54 #define TimeValue CFTimeValue
55 #include <CoreFoundation/CoreFoundation.h>
61 # define OSL_FILE_TRACE 0 ? (void)(0) : osl_trace
62 # define PERROR( a, b ) perror( a ); fprintf( stderr, b )
64 # define OSL_FILE_TRACE 1 ? (void)(0) : osl_trace
65 # define PERROR( a, b )
68 /*******************************************************************
70 * FileHandle_Impl interface
72 ******************************************************************/
73 struct FileHandle_Impl
75 pthread_mutex_t m_mutex
;
76 rtl_String
* m_strFilePath
; /* holds native file path */
83 STATE_SEEKABLE
= 1, /* default */
84 STATE_READABLE
= 2, /* default */
85 STATE_WRITEABLE
= 4, /* open() sets, write() requires, else osl_File_E_BADF */
86 STATE_MODIFIED
= 8 /* write() sets, flush() resets */
90 sal_uInt64 m_size
; /* file size */
91 off_t m_offset
; /* physical offset from begin of file */
92 off_t m_fileptr
; /* logical offset from begin of file */
94 off_t m_bufptr
; /* buffer offset from begin of file */
95 size_t m_buflen
; /* buffer filled [0, m_bufsiz - 1] */
100 explicit FileHandle_Impl (int fd
, char const * path
= "<anon>");
103 static void* operator new (size_t n
);
104 static void operator delete (void * p
, size_t);
106 static size_t getpagesize();
108 sal_uInt64
getPos() const;
109 oslFileError
setPos (sal_uInt64 uPos
);
111 sal_uInt64
getSize() const;
112 oslFileError
setSize (sal_uInt64 uSize
);
114 oslFileError
readAt (
117 size_t nBytesRequested
,
118 sal_uInt64
* pBytesRead
);
120 oslFileError
writeAt (
122 void const * pBuffer
,
123 size_t nBytesToWrite
,
124 sal_uInt64
* pBytesWritten
);
126 oslFileError
readFileAt (
129 size_t nBytesRequested
,
130 sal_uInt64
* pBytesRead
);
132 oslFileError
writeFileAt (
134 void const * pBuffer
,
135 size_t nBytesToWrite
,
136 sal_uInt64
* pBytesWritten
);
138 oslFileError
readLineAt (
140 sal_Sequence
** ppSequence
,
141 sal_uInt64
* pBytesRead
);
143 oslFileError
writeSequence_Impl (
144 sal_Sequence
** ppSequence
,
146 const void * pBuffer
,
149 oslFileError
syncFile();
151 /** Buffer cache / allocator.
155 rtl_cache_type
* m_cache
;
158 Allocator (Allocator
const &);
159 Allocator
& operator= (Allocator
const &);
162 static Allocator
& get();
164 void allocate (sal_uInt8
** ppBuffer
, size_t * pnSize
);
165 void deallocate (sal_uInt8
* pBuffer
);
176 pthread_mutex_t
* m_mutex
;
179 explicit Guard(pthread_mutex_t
* pMutex
);
184 /*******************************************************************
186 * FileHandle_Impl implementation
188 ******************************************************************/
190 FileHandle_Impl::Allocator
&
191 FileHandle_Impl::Allocator::get()
193 static Allocator g_aBufferAllocator
;
194 return g_aBufferAllocator
;
197 FileHandle_Impl::Allocator::Allocator()
201 size_t const pagesize
= FileHandle_Impl::getpagesize();
202 if (size_t(-1) != pagesize
)
204 m_cache
= rtl_cache_create (
205 "osl_file_buffer_cache", pagesize
, 0, 0, 0, 0, 0, 0, 0);
210 FileHandle_Impl::Allocator::~Allocator()
212 rtl_cache_destroy (m_cache
), m_cache
= 0;
215 void FileHandle_Impl::Allocator::allocate (sal_uInt8
** ppBuffer
, size_t * pnSize
)
217 OSL_PRECOND((0 != ppBuffer
) && (0 != pnSize
), "FileHandle_Impl::Allocator::allocate(): contract violation");
218 if ((0 != ppBuffer
) && (0 != pnSize
))
219 *ppBuffer
= static_cast< sal_uInt8
* >(rtl_cache_alloc(m_cache
)), *pnSize
= m_bufsiz
;
221 void FileHandle_Impl::Allocator::deallocate (sal_uInt8
* pBuffer
)
224 rtl_cache_free (m_cache
, pBuffer
);
227 FileHandle_Impl::Guard::Guard(pthread_mutex_t
* pMutex
)
230 OSL_PRECOND (m_mutex
!= 0, "FileHandle_Impl::Guard::Guard(): null pointer.");
231 (void) pthread_mutex_lock (m_mutex
); // ignoring EINVAL ...
233 FileHandle_Impl::Guard::~Guard()
235 OSL_PRECOND (m_mutex
!= 0, "FileHandle_Impl::Guard::~Guard(): null pointer.");
236 (void) pthread_mutex_unlock (m_mutex
);
239 FileHandle_Impl::FileHandle_Impl (int fd
, char const * path
)
242 m_state (STATE_SEEKABLE
| STATE_READABLE
),
251 (void) pthread_mutex_init(&m_mutex
, 0);
252 rtl_string_newFromStr (&m_strFilePath
, path
);
253 Allocator::get().allocate (&m_buffer
, &m_bufsiz
);
255 memset (m_buffer
, 0, m_bufsiz
);
257 FileHandle_Impl::~FileHandle_Impl()
259 Allocator::get().deallocate (m_buffer
), m_buffer
= 0;
260 rtl_string_release (m_strFilePath
), m_strFilePath
= 0;
261 (void) pthread_mutex_destroy(&m_mutex
); // ignoring EBUSY ...
264 void* FileHandle_Impl::operator new (size_t n
)
266 return rtl_allocateMemory(n
);
268 void FileHandle_Impl::operator delete (void * p
, size_t)
273 size_t FileHandle_Impl::getpagesize()
275 #if defined(FREEBSD) || defined(NETBSD) || defined(MACOSX)
276 return sal::static_int_cast
< size_t >(::getpagesize());
278 return sal::static_int_cast
< size_t >(::sysconf(_SC_PAGESIZE
));
279 #endif /* xBSD || POSIX */
282 sal_uInt64
FileHandle_Impl::getPos() const
284 return sal::static_int_cast
< sal_uInt64
>(m_fileptr
);
287 oslFileError
FileHandle_Impl::setPos (sal_uInt64 uPos
)
289 OSL_FILE_TRACE("FileHandle_Impl::setPos(%d, %lld) => %lld", m_fd
, getPos(), uPos
);
290 m_fileptr
= sal::static_int_cast
< off_t
>(uPos
);
291 return osl_File_E_None
;
294 sal_uInt64
FileHandle_Impl::getSize() const
296 off_t
const bufend
= std::max((off_t
)(0), m_bufptr
) + m_buflen
;
297 return std::max(m_size
, sal::static_int_cast
< sal_uInt64
>(bufend
));
300 oslFileError
FileHandle_Impl::setSize (sal_uInt64 uSize
)
302 off_t
const nSize
= sal::static_int_cast
< off_t
>(uSize
);
303 if (-1 == ftruncate (m_fd
, nSize
))
305 /* Failure. Save original result. Try fallback algorithm */
306 oslFileError result
= oslTranslateFileError (OSL_FET_ERROR
, errno
);
308 /* Check against current size. Fail upon 'shrink' */
309 if (uSize
<= getSize())
311 /* Failure upon 'shrink'. Return original result */
315 /* Save current position */
316 off_t
const nCurPos
= (off_t
)lseek (m_fd
, (off_t
)0, SEEK_CUR
);
317 if (nCurPos
== (off_t
)(-1))
320 /* Try 'expand' via 'lseek()' and 'write()' */
321 if (-1 == lseek (m_fd
, (off_t
)(nSize
- 1), SEEK_SET
))
324 if (-1 == write (m_fd
, (char*)"", (size_t)1))
326 /* Failure. Restore saved position */
327 (void) lseek (m_fd
, (off_t
)(nCurPos
), SEEK_SET
);
331 /* Success. Restore saved position */
332 if (-1 == lseek (m_fd
, (off_t
)nCurPos
, SEEK_SET
))
336 OSL_FILE_TRACE("osl_setFileSize(%d, %lld) => %ld", m_fd
, getSize(), nSize
);
337 m_size
= sal::static_int_cast
< sal_uInt64
>(nSize
);
338 return osl_File_E_None
;
341 oslFileError
FileHandle_Impl::readAt (
344 size_t nBytesRequested
,
345 sal_uInt64
* pBytesRead
)
347 OSL_PRECOND((m_state
& STATE_SEEKABLE
), "FileHandle_Impl::readAt(): not seekable");
348 if (!(m_state
& STATE_SEEKABLE
))
349 return osl_File_E_SPIPE
;
351 OSL_PRECOND((m_state
& STATE_READABLE
), "FileHandle_Impl::readAt(): not readable");
352 if (!(m_state
& STATE_READABLE
))
353 return osl_File_E_BADF
;
355 #if defined(LINUX) || defined(SOLARIS)
357 ssize_t nBytes
= ::pread (m_fd
, pBuffer
, nBytesRequested
, nOffset
);
358 if ((-1 == nBytes
) && (EOVERFLOW
== errno
))
360 /* Some 'pread()'s fail with EOVERFLOW when reading at (or past)
361 * end-of-file, different from 'lseek() + read()' behaviour.
362 * Returning '0 bytes read' and 'osl_File_E_None' instead.
367 return oslTranslateFileError (OSL_FET_ERROR
, errno
);
369 #else /* !(LINUX || SOLARIS) */
371 if (nOffset
!= m_offset
)
373 if (-1 == ::lseek (m_fd
, nOffset
, SEEK_SET
))
374 return oslTranslateFileError (OSL_FET_ERROR
, errno
);
378 ssize_t nBytes
= ::read (m_fd
, pBuffer
, nBytesRequested
);
380 return oslTranslateFileError (OSL_FET_ERROR
, errno
);
383 #endif /* !(LINUX || SOLARIS) */
385 OSL_FILE_TRACE("FileHandle_Impl::readAt(%d, %lld, %ld)", m_fd
, nOffset
, nBytes
);
386 *pBytesRead
= nBytes
;
387 return osl_File_E_None
;
390 oslFileError
FileHandle_Impl::writeAt (
392 void const * pBuffer
,
393 size_t nBytesToWrite
,
394 sal_uInt64
* pBytesWritten
)
396 OSL_PRECOND((m_state
& STATE_SEEKABLE
), "FileHandle_Impl::writeAt(): not seekable");
397 if (!(m_state
& STATE_SEEKABLE
))
398 return osl_File_E_SPIPE
;
400 OSL_PRECOND((m_state
& STATE_WRITEABLE
), "FileHandle_Impl::writeAt(): not writeable");
401 if (!(m_state
& STATE_WRITEABLE
))
402 return osl_File_E_BADF
;
404 #if defined(LINUX) || defined(SOLARIS)
406 ssize_t nBytes
= ::pwrite (m_fd
, pBuffer
, nBytesToWrite
, nOffset
);
408 return oslTranslateFileError (OSL_FET_ERROR
, errno
);
410 #else /* !(LINUX || SOLARIS) */
412 if (nOffset
!= m_offset
)
414 if (-1 == ::lseek (m_fd
, nOffset
, SEEK_SET
))
415 return oslTranslateFileError (OSL_FET_ERROR
, errno
);
419 ssize_t nBytes
= ::write (m_fd
, pBuffer
, nBytesToWrite
);
421 return oslTranslateFileError (OSL_FET_ERROR
, errno
);
424 #endif /* !(LINUX || SOLARIS) */
426 OSL_FILE_TRACE("FileHandle_Impl::writeAt(%d, %lld, %ld)", m_fd
, nOffset
, nBytes
);
427 m_size
= std::max (m_size
, sal::static_int_cast
< sal_uInt64
>(nOffset
+ nBytes
));
429 *pBytesWritten
= nBytes
;
430 return osl_File_E_None
;
433 oslFileError
FileHandle_Impl::readFileAt (
436 size_t nBytesRequested
,
437 sal_uInt64
* pBytesRead
)
439 if (0 == (m_state
& STATE_SEEKABLE
))
441 // not seekable (pipe)
442 ssize_t nBytes
= ::read (m_fd
, pBuffer
, nBytesRequested
);
444 return oslTranslateFileError (OSL_FET_ERROR
, errno
);
445 *pBytesRead
= nBytes
;
446 return osl_File_E_None
;
448 else if (0 == m_buffer
)
451 return readAt (nOffset
, pBuffer
, nBytesRequested
, pBytesRead
);
455 sal_uInt8
* buffer
= static_cast<sal_uInt8
*>(pBuffer
);
456 for (*pBytesRead
= 0; nBytesRequested
> 0; )
458 off_t
const bufptr
= (nOffset
/ m_bufsiz
) * m_bufsiz
;
459 size_t const bufpos
= (nOffset
% m_bufsiz
);
461 if (bufptr
!= m_bufptr
)
463 // flush current buffer
464 oslFileError result
= syncFile();
465 if (result
!= osl_File_E_None
)
467 m_bufptr
= -1, m_buflen
= 0;
469 if (nBytesRequested
>= m_bufsiz
)
471 // buffer too small, read through from file
472 sal_uInt64 uDone
= 0;
473 result
= readAt (nOffset
, &(buffer
[*pBytesRead
]), nBytesRequested
, &uDone
);
474 if (result
!= osl_File_E_None
)
477 nBytesRequested
-= uDone
, *pBytesRead
+= uDone
;
478 return osl_File_E_None
;
481 // update buffer (pointer)
482 sal_uInt64 uDone
= 0;
483 result
= readAt (bufptr
, m_buffer
, m_bufsiz
, &uDone
);
484 if (result
!= osl_File_E_None
)
486 m_bufptr
= bufptr
, m_buflen
= uDone
;
488 if (bufpos
>= m_buflen
)
491 return osl_File_E_None
;
494 size_t const bytes
= std::min (m_buflen
- bufpos
, nBytesRequested
);
495 OSL_FILE_TRACE("FileHandle_Impl::readFileAt(%d, %lld, %ld)", m_fd
, nOffset
, bytes
);
497 memcpy (&(buffer
[*pBytesRead
]), &(m_buffer
[bufpos
]), bytes
);
498 nBytesRequested
-= bytes
, *pBytesRead
+= bytes
, nOffset
+= bytes
;
500 return osl_File_E_None
;
504 oslFileError
FileHandle_Impl::writeFileAt (
506 void const * pBuffer
,
507 size_t nBytesToWrite
,
508 sal_uInt64
* pBytesWritten
)
510 if (0 == (m_state
& STATE_SEEKABLE
))
512 // not seekable (pipe)
513 ssize_t nBytes
= ::write (m_fd
, pBuffer
, nBytesToWrite
);
515 return oslTranslateFileError (OSL_FET_ERROR
, errno
);
516 *pBytesWritten
= nBytes
;
517 return osl_File_E_None
;
519 else if (0 == m_buffer
)
522 return writeAt (nOffset
, pBuffer
, nBytesToWrite
, pBytesWritten
);
526 sal_uInt8
const * buffer
= static_cast<sal_uInt8
const *>(pBuffer
);
527 for (*pBytesWritten
= 0; nBytesToWrite
> 0; )
529 off_t
const bufptr
= (nOffset
/ m_bufsiz
) * m_bufsiz
;
530 size_t const bufpos
= (nOffset
% m_bufsiz
);
531 if (bufptr
!= m_bufptr
)
533 // flush current buffer
534 oslFileError result
= syncFile();
535 if (result
!= osl_File_E_None
)
537 m_bufptr
= -1, m_buflen
= 0;
539 if (nBytesToWrite
>= m_bufsiz
)
541 // buffer to small, write through to file
542 sal_uInt64 uDone
= 0;
543 result
= writeAt (nOffset
, &(buffer
[*pBytesWritten
]), nBytesToWrite
, &uDone
);
544 if (result
!= osl_File_E_None
)
546 if (uDone
!= nBytesToWrite
)
547 return osl_File_E_IO
;
549 nBytesToWrite
-= uDone
, *pBytesWritten
+= uDone
;
550 return osl_File_E_None
;
553 // update buffer (pointer)
554 sal_uInt64 uDone
= 0;
555 result
= readAt (bufptr
, m_buffer
, m_bufsiz
, &uDone
);
556 if (result
!= osl_File_E_None
)
558 m_bufptr
= bufptr
, m_buflen
= uDone
;
561 size_t const bytes
= std::min (m_bufsiz
- bufpos
, nBytesToWrite
);
562 OSL_FILE_TRACE("FileHandle_Impl::writeFileAt(%d, %lld, %ld)", m_fd
, nOffset
, bytes
);
564 memcpy (&(m_buffer
[bufpos
]), &(buffer
[*pBytesWritten
]), bytes
);
565 nBytesToWrite
-= bytes
, *pBytesWritten
+= bytes
, nOffset
+= bytes
;
567 m_buflen
= std::max(m_buflen
, bufpos
+ bytes
);
568 m_state
|= STATE_MODIFIED
;
570 return osl_File_E_None
;
574 oslFileError
FileHandle_Impl::readLineAt (
576 sal_Sequence
** ppSequence
,
577 sal_uInt64
* pBytesRead
)
579 oslFileError result
= osl_File_E_None
;
581 off_t bufptr
= nOffset
/ m_bufsiz
* m_bufsiz
;
582 if (bufptr
!= m_bufptr
)
584 /* flush current buffer */
586 if (result
!= 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
)
595 m_bufptr
= bufptr
, m_buflen
= uDone
;
598 static int const LINE_STATE_BEGIN
= 0;
599 static int const LINE_STATE_CR
= 1;
600 static int const LINE_STATE_LF
= 2;
602 size_t bufpos
= nOffset
- m_bufptr
, curpos
= bufpos
, dstpos
= 0;
603 int state
= (bufpos
>= m_buflen
) ? LINE_STATE_LF
: LINE_STATE_BEGIN
;
605 for ( ; state
!= LINE_STATE_LF
; )
607 if (curpos
>= m_buflen
)
609 /* buffer examined */
610 if (0 < (curpos
- bufpos
))
612 /* flush buffer to sequence */
613 result
= writeSequence_Impl (
614 ppSequence
, &dstpos
, &(m_buffer
[bufpos
]), curpos
- bufpos
);
615 if (result
!= osl_File_E_None
)
617 *pBytesRead
+= curpos
- bufpos
, nOffset
+= curpos
- bufpos
;
620 bufptr
= nOffset
/ m_bufsiz
* m_bufsiz
;
621 if (bufptr
!= m_bufptr
)
623 /* update buffer (pointer) */
624 sal_uInt64 uDone
= 0;
625 result
= readAt (bufptr
, m_buffer
, m_bufsiz
, &uDone
);
626 if (result
!= osl_File_E_None
)
628 m_bufptr
= bufptr
, m_buflen
= uDone
;
631 bufpos
= nOffset
- m_bufptr
, curpos
= bufpos
;
632 if (bufpos
>= m_buflen
)
638 state
= LINE_STATE_LF
;
639 switch (m_buffer
[curpos
])
641 case 0x0A: /* CRLF */
642 /* eat current char */
645 default: /* single CR */
646 /* keep current char */
651 /* determine next state */
652 switch (m_buffer
[curpos
])
654 case 0x0A: /* single LF */
655 state
= LINE_STATE_LF
;
658 state
= LINE_STATE_CR
;
660 default: /* advance to next char */
664 if (state
!= LINE_STATE_BEGIN
)
666 /* store (and eat) the newline char */
667 m_buffer
[curpos
] = 0x0A, curpos
++;
669 /* flush buffer to sequence */
670 result
= writeSequence_Impl (
671 ppSequence
, &dstpos
, &(m_buffer
[bufpos
]), curpos
- bufpos
- 1);
672 if (result
!= osl_File_E_None
)
674 *pBytesRead
+= curpos
- bufpos
, nOffset
+= curpos
- bufpos
;
680 result
= writeSequence_Impl (ppSequence
, &dstpos
, 0, 0);
681 if (result
!= osl_File_E_None
)
684 return osl_File_E_None
;
685 if (bufpos
>= m_buflen
)
686 return osl_File_E_AGAIN
;
687 return osl_File_E_None
;
690 oslFileError
FileHandle_Impl::writeSequence_Impl (
691 sal_Sequence
** ppSequence
,
693 const void * pBuffer
,
696 sal_Int32 nElements
= *pnOffset
+ nBytes
;
699 /* construct sequence */
700 rtl_byte_sequence_constructNoDefault(ppSequence
, nElements
);
702 else if (nElements
!= (*ppSequence
)->nElements
)
704 /* resize sequence */
705 rtl_byte_sequence_realloc(ppSequence
, nElements
);
707 if (*ppSequence
!= 0)
710 memcpy(&((*ppSequence
)->elements
[*pnOffset
]), pBuffer
, nBytes
), *pnOffset
+= nBytes
;
712 return (*ppSequence
!= 0) ? osl_File_E_None
: osl_File_E_NOMEM
;
715 oslFileError
FileHandle_Impl::syncFile()
717 oslFileError result
= osl_File_E_None
;
718 if (m_state
& STATE_MODIFIED
)
720 sal_uInt64 uDone
= 0;
721 result
= writeAt (m_bufptr
, m_buffer
, m_buflen
, &uDone
);
722 if (result
!= osl_File_E_None
)
724 if (uDone
!= m_buflen
)
725 return osl_File_E_IO
;
726 m_state
&= ~STATE_MODIFIED
;
731 /****************************************************************************
732 * osl_createFileHandleFromFD
733 ***************************************************************************/
734 extern "C" oslFileHandle
osl_createFileHandleFromFD( int fd
)
739 struct stat aFileStat
;
740 if (-1 == fstat (fd
, &aFileStat
))
743 FileHandle_Impl
* pImpl
= new FileHandle_Impl (fd
);
748 pImpl
->m_state
|= FileHandle_Impl::STATE_WRITEABLE
;
749 if (!S_ISREG(aFileStat
.st_mode
))
751 /* not a regular file, mark not seekable */
752 pImpl
->m_state
&= ~FileHandle_Impl::STATE_SEEKABLE
;
756 /* regular file, init current size */
757 pImpl
->m_size
= sal::static_int_cast
< sal_uInt64
>(aFileStat
.st_size
);
760 OSL_FILE_TRACE("osl_createFileHandleFromFD(%d, writeable) => %s",
761 pImpl
->m_fd
, rtl_string_getStr(pImpl
->m_strFilePath
));
762 return (oslFileHandle
)(pImpl
);
765 /*******************************************************************
766 * osl_file_adjustLockFlags
767 ******************************************************************/
768 static int osl_file_adjustLockFlags (const char * path
, int flags
)
772 * The AFP implementation of MacOS X 10.4 treats O_EXLOCK in a way
773 * that makes it impossible for OOo to create a backup copy of the
774 * file it keeps opened. OTOH O_SHLOCK for AFP behaves as desired by
775 * the OOo file handling, so we need to check the path of the file
776 * for the filesystem name.
779 if( 0 <= statfs( path
, &s
) )
781 if( 0 == strncmp("afpfs", s
.f_fstypename
, 5) )
788 /* Needed flags to allow opening a webdav file */
789 flags
&= ~(O_EXLOCK
| O_SHLOCK
| O_NONBLOCK
);
798 /****************************************************************************
799 * osl_file_queryLocking
800 ***************************************************************************/
804 Locking_Impl() : m_enabled(0)
806 #ifndef HAVE_O_EXLOCK
807 m_enabled
= ((getenv("SAL_ENABLE_FILE_LOCKING") != 0) || (getenv("STAR_ENABLE_FILE_LOCKING") != 0));
808 #endif /* HAVE_O_EXLOCK */
811 static int osl_file_queryLocking (sal_uInt32 uFlags
)
813 if (!(uFlags
& osl_File_OpenFlag_NoLock
))
815 if ((uFlags
& osl_File_OpenFlag_Write
) || (uFlags
& osl_File_OpenFlag_Create
))
817 static Locking_Impl g_locking
;
818 return (g_locking
.m_enabled
!= 0);
824 /****************************************************************************
826 ***************************************************************************/
828 #define OPEN_WRITE_FLAGS ( O_RDWR | O_EXLOCK | O_NONBLOCK )
829 #define OPEN_CREATE_FLAGS ( O_CREAT | O_EXCL | O_RDWR | O_EXLOCK | O_NONBLOCK )
831 #define OPEN_WRITE_FLAGS ( O_RDWR )
832 #define OPEN_CREATE_FLAGS ( O_CREAT | O_EXCL | O_RDWR )
836 SAL_CALL
osl_openFile( rtl_uString
* ustrFileURL
, oslFileHandle
* pHandle
, sal_uInt32 uFlags
)
840 if ((ustrFileURL
== 0) || (ustrFileURL
->length
== 0) || (pHandle
== 0))
841 return osl_File_E_INVAL
;
843 /* convert file URL to system path */
844 char buffer
[PATH_MAX
];
845 eRet
= FileURLToPath (buffer
, sizeof(buffer
), ustrFileURL
);
846 if (eRet
!= osl_File_E_None
)
849 if (macxp_resolveAlias (buffer
, sizeof(buffer
)) != 0)
850 return oslTranslateFileError (OSL_FET_ERROR
, errno
);
853 /* set mode and flags */
854 int mode
= S_IRUSR
| S_IRGRP
| S_IROTH
;
855 int flags
= O_RDONLY
;
856 if (uFlags
& osl_File_OpenFlag_Write
)
858 mode
|= S_IWUSR
| S_IWGRP
| S_IWOTH
;
859 flags
= OPEN_WRITE_FLAGS
;
861 if (uFlags
& osl_File_OpenFlag_Create
)
863 mode
|= S_IWUSR
| S_IWGRP
| S_IWOTH
;
864 flags
= OPEN_CREATE_FLAGS
;
866 if (uFlags
& osl_File_OpenFlag_NoLock
)
869 flags
&= ~(O_EXLOCK
| O_SHLOCK
| O_NONBLOCK
);
870 #endif /* HAVE_O_EXLOCK */
874 flags
= osl_file_adjustLockFlags (buffer
, flags
);
878 int fd
= open( buffer
, flags
, mode
);
880 return oslTranslateFileError (OSL_FET_ERROR
, errno
);
882 /* reset O_NONBLOCK flag */
883 if (flags
& O_NONBLOCK
)
885 int f
= fcntl (fd
, F_GETFL
, 0);
888 eRet
= oslTranslateFileError (OSL_FET_ERROR
, errno
);
892 if (-1 == fcntl (fd
, F_SETFL
, (f
& ~O_NONBLOCK
)))
894 eRet
= oslTranslateFileError (OSL_FET_ERROR
, errno
);
900 /* get file status (mode, size) */
901 struct stat aFileStat
;
902 if (-1 == fstat (fd
, &aFileStat
))
904 eRet
= oslTranslateFileError (OSL_FET_ERROR
, errno
);
908 if (!S_ISREG(aFileStat
.st_mode
))
910 /* we only open regular files here */
912 return osl_File_E_INVAL
;
915 if (osl_file_queryLocking (uFlags
))
918 if (-1 == flock (fd
, LOCK_EX
| LOCK_NB
))
920 /* Mac OSX returns ENOTSUP for webdav drives. We should try read lock */
921 if ((errno
!= ENOTSUP
) || ((-1 == flock (fd
, LOCK_SH
| LOCK_NB
)) && (errno
!= ENOTSUP
)))
923 eRet
= oslTranslateFileError (OSL_FET_ERROR
, errno
);
932 aflock
.l_type
= F_WRLCK
;
933 aflock
.l_whence
= SEEK_SET
;
937 if (-1 == fcntl (fd
, F_SETLK
, &aflock
))
939 eRet
= oslTranslateFileError (OSL_FET_ERROR
, errno
);
947 /* allocate memory for impl structure */
948 FileHandle_Impl
* pImpl
= new FileHandle_Impl (fd
, buffer
);
951 eRet
= oslTranslateFileError (OSL_FET_ERROR
, ENOMEM
);
956 pImpl
->m_state
|= FileHandle_Impl::STATE_WRITEABLE
;
957 pImpl
->m_size
= sal::static_int_cast
< sal_uInt64
>(aFileStat
.st_size
);
959 OSL_TRACE("osl_openFile(%d, %s) => %s", pImpl
->m_fd
,
960 flags
& O_RDWR
? "writeable":"readonly",
961 rtl_string_getStr(pImpl
->m_strFilePath
));
963 *pHandle
= (oslFileHandle
)(pImpl
);
964 return osl_File_E_None
;
967 /****************************************************************************/
969 /****************************************************************************/
971 SAL_CALL
osl_closeFile( oslFileHandle Handle
)
973 FileHandle_Impl
* pImpl
= static_cast<FileHandle_Impl
*>(Handle
);
975 if ((pImpl
== 0) || (pImpl
->m_fd
< 0))
976 return osl_File_E_INVAL
;
978 (void) pthread_mutex_lock (&(pImpl
->m_mutex
));
980 /* close(2) implicitly (and unconditionally) unlocks */
981 OSL_TRACE("osl_closeFile(%d) => %s", pImpl
->m_fd
, rtl_string_getStr(pImpl
->m_strFilePath
));
982 oslFileError result
= pImpl
->syncFile();
983 if (result
!= osl_File_E_None
)
985 /* close, ignoring double failure */
986 (void) close (pImpl
->m_fd
);
988 else if (-1 == close (pImpl
->m_fd
))
990 /* translate error code */
991 result
= oslTranslateFileError (OSL_FET_ERROR
, errno
);
994 (void) pthread_mutex_unlock (&(pImpl
->m_mutex
));
999 /************************************************
1001 ***********************************************/
1003 SAL_CALL
osl_syncFile(oslFileHandle Handle
)
1005 FileHandle_Impl
* pImpl
= static_cast<FileHandle_Impl
*>(Handle
);
1007 if ((0 == pImpl
) || (-1 == pImpl
->m_fd
))
1008 return osl_File_E_INVAL
;
1010 FileHandle_Impl::Guard
lock (&(pImpl
->m_mutex
));
1012 OSL_TRACE("osl_syncFile(%d)", pImpl
->m_fd
);
1013 oslFileError result
= pImpl
->syncFile();
1014 if (result
!= osl_File_E_None
)
1016 if (-1 == fsync (pImpl
->m_fd
))
1017 return oslTranslateFileError (OSL_FET_ERROR
, errno
);
1019 return osl_File_E_None
;
1022 /*******************************************
1024 ********************************************/
1026 SAL_CALL
osl_mapFile (
1027 oslFileHandle Handle
,
1034 FileHandle_Impl
* pImpl
= static_cast<FileHandle_Impl
*>(Handle
);
1036 if ((0 == pImpl
) || (-1 == pImpl
->m_fd
) || (0 == ppAddr
))
1037 return osl_File_E_INVAL
;
1040 static sal_uInt64
const g_limit_size_t
= std::numeric_limits
< size_t >::max();
1041 if (g_limit_size_t
< uLength
)
1042 return osl_File_E_OVERFLOW
;
1043 size_t const nLength
= sal::static_int_cast
< size_t >(uLength
);
1045 static sal_uInt64
const g_limit_off_t
= std::numeric_limits
< off_t
>::max();
1046 if (g_limit_off_t
< uOffset
)
1047 return osl_File_E_OVERFLOW
;
1048 off_t
const nOffset
= sal::static_int_cast
< off_t
>(uOffset
);
1050 void* p
= mmap(NULL
, nLength
, PROT_READ
, MAP_SHARED
, pImpl
->m_fd
, nOffset
);
1051 if (MAP_FAILED
== p
)
1052 return oslTranslateFileError(OSL_FET_ERROR
, errno
);
1055 if (uFlags
& osl_File_MapFlag_RandomAccess
)
1057 // Determine memory pagesize.
1058 size_t const nPageSize
= FileHandle_Impl::getpagesize();
1059 if (size_t(-1) != nPageSize
)
1062 * Pagein, touching first byte of every memory page.
1063 * Note: volatile disables optimizing the loop away.
1065 sal_uInt8
* pData (reinterpret_cast<sal_uInt8
*>(*ppAddr
));
1066 size_t nSize (nLength
);
1068 volatile sal_uInt8 c
= 0;
1069 while (nSize
> nPageSize
)
1083 if (uFlags
& osl_File_MapFlag_WillNeed
)
1085 // On Linux, madvise(..., MADV_WILLNEED) appears to have the undesirable
1086 // effect of not returning until the data has actually been paged in, so
1087 // that its net effect would typically be to slow down the process
1088 // (which could start processing at the beginning of the data while the
1089 // OS simultaneously pages in the rest); on other platforms, it remains
1090 // to be evaluated whether madvise or equivalent is available and
1093 int e
= posix_madvise(p
, nLength
, POSIX_MADV_WILLNEED
);
1097 "posix_madvise(..., POSIX_MADV_WILLNEED) failed with %d", e
);
1099 #elif defined SOLARIS
1100 if (madvise(static_cast< caddr_t
>(p
), nLength
, MADV_WILLNEED
) != 0)
1102 OSL_TRACE("madvise(..., MADV_WILLNEED) failed with %d", errno
);
1106 return osl_File_E_None
;
1109 /*******************************************
1111 ********************************************/
1113 SAL_CALL
osl_unmapFile (void* pAddr
, sal_uInt64 uLength
)
1116 return osl_File_E_INVAL
;
1118 static sal_uInt64
const g_limit_size_t
= std::numeric_limits
< size_t >::max();
1119 if (g_limit_size_t
< uLength
)
1120 return osl_File_E_OVERFLOW
;
1121 size_t const nLength
= sal::static_int_cast
< size_t >(uLength
);
1123 if (-1 == munmap(static_cast<char*>(pAddr
), nLength
))
1124 return oslTranslateFileError(OSL_FET_ERROR
, errno
);
1126 return osl_File_E_None
;
1129 /*******************************************
1131 ********************************************/
1133 SAL_CALL
osl_readLine (
1134 oslFileHandle Handle
,
1135 sal_Sequence
** ppSequence
)
1137 FileHandle_Impl
* pImpl
= static_cast<FileHandle_Impl
*>(Handle
);
1139 if ((0 == pImpl
) || (-1 == pImpl
->m_fd
) || (0 == ppSequence
))
1140 return osl_File_E_INVAL
;
1141 sal_uInt64 uBytesRead
= 0;
1143 // read at current fileptr; fileptr += uBytesRead;
1144 FileHandle_Impl::Guard
lock (&(pImpl
->m_mutex
));
1145 oslFileError result
= pImpl
->readLineAt (
1146 pImpl
->m_fileptr
, ppSequence
, &uBytesRead
);
1147 if (result
== osl_File_E_None
)
1148 pImpl
->m_fileptr
+= uBytesRead
;
1152 /*******************************************
1154 ********************************************/
1156 SAL_CALL
osl_readFile (
1157 oslFileHandle Handle
,
1159 sal_uInt64 uBytesRequested
,
1160 sal_uInt64
* pBytesRead
)
1162 FileHandle_Impl
* pImpl
= static_cast<FileHandle_Impl
*>(Handle
);
1164 if ((0 == pImpl
) || (-1 == pImpl
->m_fd
) || (0 == pBuffer
) || (0 == pBytesRead
))
1165 return osl_File_E_INVAL
;
1167 static sal_uInt64
const g_limit_ssize_t
= std::numeric_limits
< ssize_t
>::max();
1168 if (g_limit_ssize_t
< uBytesRequested
)
1169 return osl_File_E_OVERFLOW
;
1170 size_t const nBytesRequested
= sal::static_int_cast
< size_t >(uBytesRequested
);
1172 // read at current fileptr; fileptr += *pBytesRead;
1173 FileHandle_Impl::Guard
lock (&(pImpl
->m_mutex
));
1174 oslFileError result
= pImpl
->readFileAt (
1175 pImpl
->m_fileptr
, pBuffer
, nBytesRequested
, pBytesRead
);
1176 if (result
== osl_File_E_None
)
1177 pImpl
->m_fileptr
+= *pBytesRead
;
1181 /*******************************************
1183 ********************************************/
1185 SAL_CALL
osl_writeFile (
1186 oslFileHandle Handle
,
1187 const void * pBuffer
,
1188 sal_uInt64 uBytesToWrite
,
1189 sal_uInt64
* pBytesWritten
)
1191 FileHandle_Impl
* pImpl
= static_cast<FileHandle_Impl
*>(Handle
);
1193 if ((0 == pImpl
) || (-1 == pImpl
->m_fd
) || (0 == pBuffer
) || (0 == pBytesWritten
))
1194 return osl_File_E_INVAL
;
1195 if (0 == (pImpl
->m_state
& FileHandle_Impl::STATE_WRITEABLE
))
1196 return osl_File_E_BADF
;
1198 static sal_uInt64
const g_limit_ssize_t
= std::numeric_limits
< ssize_t
>::max();
1199 if (g_limit_ssize_t
< uBytesToWrite
)
1200 return osl_File_E_OVERFLOW
;
1201 size_t const nBytesToWrite
= sal::static_int_cast
< size_t >(uBytesToWrite
);
1203 // write at current fileptr; fileptr += *pBytesWritten;
1204 FileHandle_Impl::Guard
lock (&(pImpl
->m_mutex
));
1205 oslFileError result
= pImpl
->writeFileAt (
1206 pImpl
->m_fileptr
, pBuffer
, nBytesToWrite
, pBytesWritten
);
1207 if (result
== osl_File_E_None
)
1208 pImpl
->m_fileptr
+= *pBytesWritten
;
1212 /*******************************************
1214 ********************************************/
1216 SAL_CALL
osl_readFileAt (
1217 oslFileHandle Handle
,
1220 sal_uInt64 uBytesRequested
,
1221 sal_uInt64
* pBytesRead
)
1223 FileHandle_Impl
* pImpl
= static_cast<FileHandle_Impl
*>(Handle
);
1225 if ((0 == pImpl
) || (-1 == pImpl
->m_fd
) || (0 == pBuffer
) || (0 == pBytesRead
))
1226 return osl_File_E_INVAL
;
1227 if (0 == (pImpl
->m_state
& FileHandle_Impl::STATE_SEEKABLE
))
1228 return osl_File_E_SPIPE
;
1230 static sal_uInt64
const g_limit_off_t
= std::numeric_limits
< off_t
>::max();
1231 if (g_limit_off_t
< uOffset
)
1232 return osl_File_E_OVERFLOW
;
1233 off_t
const nOffset
= sal::static_int_cast
< off_t
>(uOffset
);
1235 static sal_uInt64
const g_limit_ssize_t
= std::numeric_limits
< ssize_t
>::max();
1236 if (g_limit_ssize_t
< uBytesRequested
)
1237 return osl_File_E_OVERFLOW
;
1238 size_t const nBytesRequested
= sal::static_int_cast
< size_t >(uBytesRequested
);
1240 // read at specified fileptr
1241 FileHandle_Impl::Guard
lock (&(pImpl
->m_mutex
));
1242 return pImpl
->readFileAt (nOffset
, pBuffer
, nBytesRequested
, pBytesRead
);
1245 /*******************************************
1247 ********************************************/
1249 SAL_CALL
osl_writeFileAt (
1250 oslFileHandle Handle
,
1252 const void* pBuffer
,
1253 sal_uInt64 uBytesToWrite
,
1254 sal_uInt64
* pBytesWritten
)
1256 FileHandle_Impl
* pImpl
= static_cast<FileHandle_Impl
*>(Handle
);
1258 if ((0 == pImpl
) || (-1 == pImpl
->m_fd
) || (0 == pBuffer
) || (0 == pBytesWritten
))
1259 return osl_File_E_INVAL
;
1260 if (0 == (pImpl
->m_state
& FileHandle_Impl::STATE_SEEKABLE
))
1261 return osl_File_E_SPIPE
;
1262 if (0 == (pImpl
->m_state
& FileHandle_Impl::STATE_WRITEABLE
))
1263 return osl_File_E_BADF
;
1265 static sal_uInt64
const g_limit_off_t
= std::numeric_limits
< off_t
>::max();
1266 if (g_limit_off_t
< uOffset
)
1267 return osl_File_E_OVERFLOW
;
1268 off_t
const nOffset
= sal::static_int_cast
< off_t
>(uOffset
);
1270 static sal_uInt64
const g_limit_ssize_t
= std::numeric_limits
< ssize_t
>::max();
1271 if (g_limit_ssize_t
< uBytesToWrite
)
1272 return osl_File_E_OVERFLOW
;
1273 size_t const nBytesToWrite
= sal::static_int_cast
< size_t >(uBytesToWrite
);
1275 // write at specified fileptr
1276 FileHandle_Impl::Guard
lock (&(pImpl
->m_mutex
));
1277 return pImpl
->writeFileAt (nOffset
, pBuffer
, nBytesToWrite
, pBytesWritten
);
1280 /****************************************************************************/
1281 /* osl_isEndOfFile */
1282 /****************************************************************************/
1284 SAL_CALL
osl_isEndOfFile( oslFileHandle Handle
, sal_Bool
*pIsEOF
)
1286 FileHandle_Impl
* pImpl
= static_cast<FileHandle_Impl
*>(Handle
);
1288 if ((0 == pImpl
) || (-1 == pImpl
->m_fd
) || (0 == pIsEOF
))
1289 return osl_File_E_INVAL
;
1291 FileHandle_Impl::Guard
lock (&(pImpl
->m_mutex
));
1292 *pIsEOF
= (pImpl
->getPos() == pImpl
->getSize());
1293 return osl_File_E_None
;
1296 /************************************************
1298 ***********************************************/
1300 SAL_CALL
osl_getFilePos( oslFileHandle Handle
, sal_uInt64
* pPos
)
1302 FileHandle_Impl
* pImpl
= static_cast<FileHandle_Impl
*>(Handle
);
1304 if ((0 == pImpl
) || (-1 == pImpl
->m_fd
) || (0 == pPos
))
1305 return osl_File_E_INVAL
;
1307 FileHandle_Impl::Guard
lock (&(pImpl
->m_mutex
));
1308 *pPos
= pImpl
->getPos();
1309 return osl_File_E_None
;
1312 /*******************************************
1314 ********************************************/
1316 SAL_CALL
osl_setFilePos (oslFileHandle Handle
, sal_uInt32 uHow
, sal_Int64 uOffset
)
1318 FileHandle_Impl
* pImpl
= static_cast<FileHandle_Impl
*>(Handle
);
1320 if ((0 == pImpl
) || (-1 == pImpl
->m_fd
))
1321 return osl_File_E_INVAL
;
1323 static sal_Int64
const g_limit_off_t
= std::numeric_limits
< off_t
>::max();
1324 if (g_limit_off_t
< uOffset
)
1325 return osl_File_E_OVERFLOW
;
1326 off_t nPos
= 0, nOffset
= sal::static_int_cast
< off_t
>(uOffset
);
1328 FileHandle_Impl::Guard
lock (&(pImpl
->m_mutex
));
1331 case osl_Pos_Absolut
:
1333 return osl_File_E_INVAL
;
1336 case osl_Pos_Current
:
1337 nPos
= sal::static_int_cast
< off_t
>(pImpl
->getPos());
1338 if ((0 > nOffset
) && (-1*nOffset
> nPos
))
1339 return osl_File_E_INVAL
;
1340 if (g_limit_off_t
< nPos
+ nOffset
)
1341 return osl_File_E_OVERFLOW
;
1345 nPos
= sal::static_int_cast
< off_t
>(pImpl
->getSize());
1346 if ((0 > nOffset
) && (-1*nOffset
> nPos
))
1347 return osl_File_E_INVAL
;
1348 if (g_limit_off_t
< nPos
+ nOffset
)
1349 return osl_File_E_OVERFLOW
;
1353 return osl_File_E_INVAL
;
1356 return pImpl
->setPos (nPos
+ nOffset
);
1359 /****************************************************************************
1361 ****************************************************************************/
1363 SAL_CALL
osl_getFileSize( oslFileHandle Handle
, sal_uInt64
* pSize
)
1365 FileHandle_Impl
* pImpl
= static_cast<FileHandle_Impl
*>(Handle
);
1367 if ((0 == pImpl
) || (-1 == pImpl
->m_fd
) || (0 == pSize
))
1368 return osl_File_E_INVAL
;
1370 FileHandle_Impl::Guard
lock (&(pImpl
->m_mutex
));
1371 *pSize
= pImpl
->getSize();
1372 return osl_File_E_None
;
1375 /************************************************
1377 ***********************************************/
1379 SAL_CALL
osl_setFileSize( oslFileHandle Handle
, sal_uInt64 uSize
)
1381 FileHandle_Impl
* pImpl
= static_cast<FileHandle_Impl
*>(Handle
);
1383 if ((0 == pImpl
) || (-1 == pImpl
->m_fd
))
1384 return osl_File_E_INVAL
;
1385 if (0 == (pImpl
->m_state
& FileHandle_Impl::STATE_WRITEABLE
))
1386 return osl_File_E_BADF
;
1388 static sal_uInt64
const g_limit_off_t
= std::numeric_limits
< off_t
>::max();
1389 if (g_limit_off_t
< uSize
)
1390 return osl_File_E_OVERFLOW
;
1392 oslFileError result
= pImpl
->syncFile();
1393 if (result
!= osl_File_E_None
)
1395 pImpl
->m_bufptr
= -1, pImpl
->m_buflen
= 0;
1397 return pImpl
->setSize (uSize
);