1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: file.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_sal.hxx"
34 #include "osl/file.hxx"
36 #include "osl/diagnose.h"
37 #include "rtl/alloc.h"
40 #include "file_error_transl.h"
51 #include <sys/param.h>
52 #include <sys/mount.h>
55 // add MACOSX Time Value
56 #define TimeValue CFTimeValue
57 #include <CoreFoundation/CoreFoundation.h>
63 # define OSL_FILE_TRACE 0 ? (void)(0) : osl_trace
64 # define PERROR( a, b ) perror( a ); fprintf( stderr, b )
66 # define OSL_FILE_TRACE 1 ? (void)(0) : osl_trace
67 # define PERROR( a, b )
70 /*******************************************************************
72 * FileHandle_Impl interface
74 ******************************************************************/
75 struct FileHandle_Impl
77 rtl_String
* m_strFilePath
; /* holds native file path */
84 STATE_SEEKABLE
= 1, /* default */
85 STATE_READABLE
= 2, /* default */
86 STATE_WRITEABLE
= 4, /* open() sets, write() requires, else osl_File_E_BADF */
87 STATE_MODIFIED
= 8 /* write() sets, flush() resets */
91 sal_uInt64 m_size
; /* file size */
92 off_t m_offset
; /* physical offset from begin of file */
93 off_t m_fileptr
; /* logical offset from begin of file */
95 off_t m_bufptr
; /* buffer offset from begin of file */
96 size_t m_buflen
; /* buffer filled [0, m_bufsiz - 1] */
101 explicit FileHandle_Impl (int fd
, char const * path
= "<anon>");
104 static void* operator new (size_t n
);
105 static void operator delete (void * p
, size_t);
107 static size_t getpagesize();
109 sal_uInt64
getPos() const;
110 oslFileError
setPos (sal_uInt64 uPos
);
112 sal_uInt64
getSize() const;
113 oslFileError
setSize (sal_uInt64 uSize
);
115 oslFileError
readAt (
118 size_t nBytesRequested
,
119 sal_uInt64
* pBytesRead
);
121 oslFileError
writeAt (
123 void const * pBuffer
,
124 size_t nBytesToWrite
,
125 sal_uInt64
* pBytesWritten
);
127 oslFileError
readFileAt (
130 size_t nBytesRequested
,
131 sal_uInt64
* pBytesRead
);
133 oslFileError
writeFileAt (
135 void const * pBuffer
,
136 size_t nBytesToWrite
,
137 sal_uInt64
* pBytesWritten
);
139 oslFileError
readLineAt (
141 sal_Sequence
** ppSequence
,
142 sal_uInt64
* pBytesRead
);
144 oslFileError
writeSequence_Impl (
145 sal_Sequence
** ppSequence
,
147 const void * pBuffer
,
150 oslFileError
syncFile();
152 /** Buffer cache / allocator.
156 rtl_cache_type
* m_cache
;
159 Allocator (Allocator
const &);
160 Allocator
& operator= (Allocator
const &);
163 static Allocator
& get();
165 void allocate (sal_uInt8
** ppBuffer
, size_t * pnSize
);
166 void deallocate (sal_uInt8
* pBuffer
);
174 /*******************************************************************
176 * FileHandle_Impl implementation
178 ******************************************************************/
180 FileHandle_Impl::Allocator
&
181 FileHandle_Impl::Allocator::get()
183 static Allocator g_aBufferAllocator
;
184 return g_aBufferAllocator
;
187 FileHandle_Impl::Allocator::Allocator()
191 size_t const pagesize
= FileHandle_Impl::getpagesize();
192 if (size_t(-1) != pagesize
)
194 m_cache
= rtl_cache_create (
195 "osl_file_buffer_cache", pagesize
, 0, 0, 0, 0, 0, 0, 0);
200 FileHandle_Impl::Allocator::~Allocator()
202 rtl_cache_destroy (m_cache
), m_cache
= 0;
205 void FileHandle_Impl::Allocator::allocate (sal_uInt8
** ppBuffer
, size_t * pnSize
)
207 OSL_PRECOND((0 != ppBuffer
) && (0 != pnSize
), "FileHandle_Impl::Allocator::allocate(): contract violation");
208 *ppBuffer
= static_cast< sal_uInt8
* >(rtl_cache_alloc(m_cache
)), *pnSize
= m_bufsiz
;
210 void FileHandle_Impl::Allocator::deallocate (sal_uInt8
* pBuffer
)
213 rtl_cache_free (m_cache
, pBuffer
);
216 FileHandle_Impl::FileHandle_Impl (int fd
, char const * path
)
219 m_state (STATE_SEEKABLE
| STATE_READABLE
),
228 rtl_string_newFromStr (&m_strFilePath
, path
);
229 Allocator::get().allocate (&m_buffer
, &m_bufsiz
);
231 memset (m_buffer
, 0, m_bufsiz
);
233 FileHandle_Impl::~FileHandle_Impl()
235 Allocator::get().deallocate (m_buffer
), m_buffer
= 0;
236 rtl_string_release (m_strFilePath
), m_strFilePath
= 0;
239 void* FileHandle_Impl::operator new (size_t n
)
241 return rtl_allocateMemory(n
);
243 void FileHandle_Impl::operator delete (void * p
, size_t)
248 size_t FileHandle_Impl::getpagesize()
250 #if defined(FREEBSD) || defined(NETBSD) || defined(MACOSX)
251 return sal::static_int_cast
< size_t >(::getpagesize());
253 return sal::static_int_cast
< size_t >(::sysconf(_SC_PAGESIZE
));
254 #endif /* xBSD || POSIX */
257 sal_uInt64
FileHandle_Impl::getPos() const
259 return sal::static_int_cast
< sal_uInt64
>(m_fileptr
);
262 oslFileError
FileHandle_Impl::setPos (sal_uInt64 uPos
)
264 OSL_FILE_TRACE("FileHandle_Impl::setPos(%d, %lld) => %lld", m_fd
, getPos(), uPos
);
265 m_fileptr
= sal::static_int_cast
< off_t
>(uPos
);
266 return osl_File_E_None
;
269 sal_uInt64
FileHandle_Impl::getSize() const
271 off_t
const bufend
= std::max((off_t
)(0), m_bufptr
) + m_buflen
;
272 return std::max(m_size
, sal::static_int_cast
< sal_uInt64
>(bufend
));
275 oslFileError
FileHandle_Impl::setSize (sal_uInt64 uSize
)
277 off_t
const nSize
= sal::static_int_cast
< off_t
>(uSize
);
278 if (-1 == ftruncate (m_fd
, nSize
))
280 /* Failure. Save original result. Try fallback algorithm */
281 oslFileError result
= oslTranslateFileError (OSL_FET_ERROR
, errno
);
283 /* Check against current size. Fail upon 'shrink' */
284 if (uSize
<= getSize())
286 /* Failure upon 'shrink'. Return original result */
290 /* Save current position */
291 off_t
const nCurPos
= (off_t
)lseek (m_fd
, (off_t
)0, SEEK_CUR
);
292 if (nCurPos
== (off_t
)(-1))
295 /* Try 'expand' via 'lseek()' and 'write()' */
296 if (-1 == lseek (m_fd
, (off_t
)(nSize
- 1), SEEK_SET
))
299 if (-1 == write (m_fd
, (char*)"", (size_t)1))
301 /* Failure. Restore saved position */
302 (void) lseek (m_fd
, (off_t
)(nCurPos
), SEEK_SET
);
306 /* Success. Restore saved position */
307 if (-1 == lseek (m_fd
, (off_t
)nCurPos
, SEEK_SET
))
311 OSL_FILE_TRACE("osl_setFileSize(%d, %lld) => %ld", m_fd
, getSize(), nSize
);
312 m_size
= sal::static_int_cast
< sal_uInt64
>(nSize
);
313 return osl_File_E_None
;
316 oslFileError
FileHandle_Impl::readAt (
319 size_t nBytesRequested
,
320 sal_uInt64
* pBytesRead
)
322 OSL_PRECOND((m_state
& STATE_SEEKABLE
), "FileHandle_Impl::readAt(): not seekable");
323 if (!(m_state
& STATE_SEEKABLE
))
324 return osl_File_E_SPIPE
;
326 OSL_PRECOND((m_state
& STATE_READABLE
), "FileHandle_Impl::readAt(): not readable");
327 if (!(m_state
& STATE_READABLE
))
328 return osl_File_E_BADF
;
330 #if defined(LINUX) || defined(SOLARIS)
332 ssize_t nBytes
= ::pread (m_fd
, pBuffer
, nBytesRequested
, nOffset
);
333 if ((-1 == nBytes
) && (EOVERFLOW
== errno
))
335 /* Some 'pread()'s fail with EOVERFLOW when reading at (or past)
336 * end-of-file, different from 'lseek() + read()' behaviour.
337 * Returning '0 bytes read' and 'osl_File_E_None' instead.
342 return oslTranslateFileError (OSL_FET_ERROR
, errno
);
344 #else /* !(LINUX || SOLARIS) */
346 if (nOffset
!= m_offset
)
348 if (-1 == ::lseek (m_fd
, nOffset
, SEEK_SET
))
349 return oslTranslateFileError (OSL_FET_ERROR
, errno
);
353 ssize_t nBytes
= ::read (m_fd
, pBuffer
, nBytesRequested
);
355 return oslTranslateFileError (OSL_FET_ERROR
, errno
);
358 #endif /* !(LINUX || SOLARIS) */
360 OSL_FILE_TRACE("FileHandle_Impl::readAt(%d, %lld, %ld)", m_fd
, nOffset
, nBytes
);
361 *pBytesRead
= nBytes
;
362 return osl_File_E_None
;
365 oslFileError
FileHandle_Impl::writeAt (
367 void const * pBuffer
,
368 size_t nBytesToWrite
,
369 sal_uInt64
* pBytesWritten
)
371 OSL_PRECOND((m_state
& STATE_SEEKABLE
), "FileHandle_Impl::writeAt(): not seekable");
372 if (!(m_state
& STATE_SEEKABLE
))
373 return osl_File_E_SPIPE
;
375 OSL_PRECOND((m_state
& STATE_WRITEABLE
), "FileHandle_Impl::writeAt(): not writeable");
376 if (!(m_state
& STATE_WRITEABLE
))
377 return osl_File_E_BADF
;
379 #if defined(LINUX) || defined(SOLARIS)
381 ssize_t nBytes
= ::pwrite (m_fd
, pBuffer
, nBytesToWrite
, nOffset
);
383 return oslTranslateFileError (OSL_FET_ERROR
, errno
);
385 #else /* !(LINUX || SOLARIS) */
387 if (nOffset
!= m_offset
)
389 if (-1 == ::lseek (m_fd
, nOffset
, SEEK_SET
))
390 return oslTranslateFileError (OSL_FET_ERROR
, errno
);
394 ssize_t nBytes
= ::write (m_fd
, pBuffer
, nBytesToWrite
);
396 return oslTranslateFileError (OSL_FET_ERROR
, errno
);
399 #endif /* !(LINUX || SOLARIS) */
401 OSL_FILE_TRACE("FileHandle_Impl::writeAt(%d, %lld, %ld)", m_fd
, nOffset
, nBytes
);
402 m_size
= std::max (m_size
, sal::static_int_cast
< sal_uInt64
>(nOffset
+ nBytes
));
404 *pBytesWritten
= nBytes
;
405 return osl_File_E_None
;
408 oslFileError
FileHandle_Impl::readFileAt (
411 size_t nBytesRequested
,
412 sal_uInt64
* pBytesRead
)
414 if (0 == (m_state
& STATE_SEEKABLE
))
416 // not seekable (pipe)
417 ssize_t nBytes
= ::read (m_fd
, pBuffer
, nBytesRequested
);
419 return oslTranslateFileError (OSL_FET_ERROR
, errno
);
420 *pBytesRead
= nBytes
;
421 return osl_File_E_None
;
423 else if (0 == m_buffer
)
426 return readAt (nOffset
, pBuffer
, nBytesRequested
, pBytesRead
);
430 sal_uInt8
* buffer
= static_cast<sal_uInt8
*>(pBuffer
);
431 for (*pBytesRead
= 0; nBytesRequested
> 0; )
433 off_t
const bufptr
= (nOffset
/ m_bufsiz
) * m_bufsiz
;
434 size_t const bufpos
= (nOffset
% m_bufsiz
);
436 if (bufptr
!= m_bufptr
)
438 // flush current buffer
439 oslFileError result
= syncFile();
440 if (result
!= osl_File_E_None
)
443 if (nBytesRequested
>= m_bufsiz
)
445 // buffer too small, read through from file
446 sal_uInt64 uDone
= 0;
447 result
= readAt (nOffset
, &(buffer
[*pBytesRead
]), nBytesRequested
, &uDone
);
448 if (result
!= osl_File_E_None
)
451 nBytesRequested
-= uDone
, *pBytesRead
+= uDone
;
452 return osl_File_E_None
;
455 // update buffer (pointer)
456 sal_uInt64 uDone
= 0;
457 result
= readAt (bufptr
, m_buffer
, m_bufsiz
, &uDone
);
458 if (result
!= osl_File_E_None
)
460 m_bufptr
= bufptr
, m_buflen
= uDone
;
462 if (bufpos
>= m_buflen
)
465 return osl_File_E_None
;
468 size_t const bytes
= std::min (m_buflen
- bufpos
, nBytesRequested
);
469 OSL_FILE_TRACE("FileHandle_Impl::readFileAt(%d, %lld, %ld)", m_fd
, nOffset
, bytes
);
471 memcpy (&(buffer
[*pBytesRead
]), &(m_buffer
[bufpos
]), bytes
);
472 nBytesRequested
-= bytes
, *pBytesRead
+= bytes
, nOffset
+= bytes
;
474 return osl_File_E_None
;
478 oslFileError
FileHandle_Impl::writeFileAt (
480 void const * pBuffer
,
481 size_t nBytesToWrite
,
482 sal_uInt64
* pBytesWritten
)
484 if (0 == (m_state
& STATE_SEEKABLE
))
486 // not seekable (pipe)
487 ssize_t nBytes
= ::write (m_fd
, pBuffer
, nBytesToWrite
);
489 return oslTranslateFileError (OSL_FET_ERROR
, errno
);
490 *pBytesWritten
= nBytes
;
491 return osl_File_E_None
;
493 else if (0 == m_buffer
)
496 return writeAt (nOffset
, pBuffer
, nBytesToWrite
, pBytesWritten
);
500 sal_uInt8
const * buffer
= static_cast<sal_uInt8
const *>(pBuffer
);
501 for (*pBytesWritten
= 0; nBytesToWrite
> 0; )
503 off_t
const bufptr
= (nOffset
/ m_bufsiz
) * m_bufsiz
;
504 size_t const bufpos
= (nOffset
% m_bufsiz
);
505 if (bufptr
!= m_bufptr
)
507 // flush current buffer
508 oslFileError result
= syncFile();
509 if (result
!= osl_File_E_None
)
512 if (nBytesToWrite
>= m_bufsiz
)
514 // buffer to small, write through to file
515 sal_uInt64 uDone
= 0;
516 result
= writeAt (nOffset
, &(buffer
[*pBytesWritten
]), nBytesToWrite
, &uDone
);
517 if (result
!= osl_File_E_None
)
519 if (uDone
!= nBytesToWrite
)
520 return osl_File_E_IO
;
522 nBytesToWrite
-= uDone
, *pBytesWritten
+= uDone
;
523 return osl_File_E_None
;
526 // update buffer (pointer)
527 sal_uInt64 uDone
= 0;
528 result
= readAt (bufptr
, m_buffer
, m_bufsiz
, &uDone
);
529 if (result
!= osl_File_E_None
)
531 m_bufptr
= bufptr
, m_buflen
= uDone
;
534 size_t const bytes
= std::min (m_bufsiz
- bufpos
, nBytesToWrite
);
535 OSL_FILE_TRACE("FileHandle_Impl::writeFileAt(%d, %lld, %ld)", m_fd
, nOffset
, bytes
);
537 memcpy (&(m_buffer
[bufpos
]), &(buffer
[*pBytesWritten
]), bytes
);
538 nBytesToWrite
-= bytes
, *pBytesWritten
+= bytes
, nOffset
+= bytes
;
540 m_buflen
= std::max(m_buflen
, bufpos
+ bytes
);
541 m_state
|= STATE_MODIFIED
;
543 return osl_File_E_None
;
547 oslFileError
FileHandle_Impl::readLineAt (
549 sal_Sequence
** ppSequence
,
550 sal_uInt64
* pBytesRead
)
552 oslFileError result
= osl_File_E_None
;
554 off_t bufptr
= nOffset
/ m_bufsiz
* m_bufsiz
;
555 if (bufptr
!= m_bufptr
)
557 /* flush current buffer */
559 if (result
!= osl_File_E_None
)
562 /* update buffer (pointer) */
563 sal_uInt64 uDone
= 0;
564 result
= readAt (bufptr
, m_buffer
, m_bufsiz
, &uDone
);
565 if (result
!= osl_File_E_None
)
568 m_bufptr
= bufptr
, m_buflen
= uDone
;
571 static int const LINE_STATE_BEGIN
= 0;
572 static int const LINE_STATE_CR
= 1;
573 static int const LINE_STATE_LF
= 2;
575 size_t bufpos
= nOffset
- m_bufptr
, curpos
= bufpos
, dstpos
= 0;
576 int state
= (bufpos
>= m_buflen
) ? LINE_STATE_LF
: LINE_STATE_BEGIN
;
578 for ( ; state
!= LINE_STATE_LF
; )
580 if (curpos
>= m_buflen
)
582 /* buffer examined */
583 if (0 < (curpos
- bufpos
))
585 /* flush buffer to sequence */
586 result
= writeSequence_Impl (
587 ppSequence
, &dstpos
, &(m_buffer
[bufpos
]), curpos
- bufpos
);
588 if (result
!= osl_File_E_None
)
590 *pBytesRead
+= curpos
- bufpos
, nOffset
+= curpos
- bufpos
;
593 bufptr
= nOffset
/ m_bufsiz
* m_bufsiz
;
594 if (bufptr
!= m_bufptr
)
596 /* update buffer (pointer) */
597 sal_uInt64 uDone
= 0;
598 result
= readAt (bufptr
, m_buffer
, m_bufsiz
, &uDone
);
599 if (result
!= osl_File_E_None
)
601 m_bufptr
= bufptr
, m_buflen
= uDone
;
604 bufpos
= nOffset
- m_bufptr
, curpos
= bufpos
;
605 if (bufpos
>= m_buflen
)
611 state
= LINE_STATE_LF
;
612 switch (m_buffer
[curpos
])
614 case 0x0A: /* CRLF */
615 /* eat current char */
618 default: /* single CR */
619 /* keep current char */
624 /* determine next state */
625 switch (m_buffer
[curpos
])
627 case 0x0A: /* single LF */
628 state
= LINE_STATE_LF
;
631 state
= LINE_STATE_CR
;
633 default: /* advance to next char */
637 if (state
!= LINE_STATE_BEGIN
)
639 /* store (and eat) the newline char */
640 m_buffer
[curpos
] = 0x0A, curpos
++;
642 /* flush buffer to sequence */
643 result
= writeSequence_Impl (
644 ppSequence
, &dstpos
, &(m_buffer
[bufpos
]), curpos
- bufpos
- 1);
645 if (result
!= osl_File_E_None
)
647 *pBytesRead
+= curpos
- bufpos
, nOffset
+= curpos
- bufpos
;
653 result
= writeSequence_Impl (ppSequence
, &dstpos
, 0, 0);
654 if (result
!= osl_File_E_None
)
657 return osl_File_E_None
;
658 if (bufpos
>= m_buflen
)
659 return osl_File_E_AGAIN
;
660 return osl_File_E_None
;
663 oslFileError
FileHandle_Impl::writeSequence_Impl (
664 sal_Sequence
** ppSequence
,
666 const void * pBuffer
,
669 sal_Int32 nElements
= *pnOffset
+ nBytes
;
672 /* construct sequence */
673 rtl_byte_sequence_constructNoDefault(ppSequence
, nElements
);
675 else if (nElements
!= (*ppSequence
)->nElements
)
677 /* resize sequence */
678 rtl_byte_sequence_realloc(ppSequence
, nElements
);
680 if (*ppSequence
!= 0)
683 memcpy(&((*ppSequence
)->elements
[*pnOffset
]), pBuffer
, nBytes
), *pnOffset
+= nBytes
;
685 return (*ppSequence
!= 0) ? osl_File_E_None
: osl_File_E_NOMEM
;
688 oslFileError
FileHandle_Impl::syncFile()
690 oslFileError result
= osl_File_E_None
;
691 if (m_state
& STATE_MODIFIED
)
693 sal_uInt64 uDone
= 0;
694 result
= writeAt (m_bufptr
, m_buffer
, m_buflen
, &uDone
);
695 if (result
!= osl_File_E_None
)
697 if (uDone
!= m_buflen
)
698 return osl_File_E_IO
;
699 m_state
&= ~STATE_MODIFIED
;
704 /****************************************************************************
705 * osl_createFileHandleFromFD
706 ***************************************************************************/
707 extern "C" oslFileHandle
osl_createFileHandleFromFD( int fd
)
712 struct stat aFileStat
;
713 if (-1 == fstat (fd
, &aFileStat
))
716 FileHandle_Impl
* pImpl
= new FileHandle_Impl (fd
);
721 pImpl
->m_state
|= FileHandle_Impl::STATE_WRITEABLE
;
722 if (!S_ISREG(aFileStat
.st_mode
))
724 /* not a regular file, mark not seekable */
725 pImpl
->m_state
&= ~FileHandle_Impl::STATE_SEEKABLE
;
729 /* regular file, init current size */
730 pImpl
->m_size
= sal::static_int_cast
< sal_uInt64
>(aFileStat
.st_size
);
733 OSL_FILE_TRACE("osl_createFileHandleFromFD(%d, writeable) => %s",
734 pImpl
->m_fd
, rtl_string_getStr(pImpl
->m_strFilePath
));
735 return (oslFileHandle
)(pImpl
);
738 /*******************************************************************
739 * osl_file_adjustLockFlags
740 ******************************************************************/
741 static int osl_file_adjustLockFlags (const char * path
, int flags
)
745 * The AFP implementation of MacOS X 10.4 treats O_EXLOCK in a way
746 * that makes it impossible for OOo to create a backup copy of the
747 * file it keeps opened. OTOH O_SHLOCK for AFP behaves as desired by
748 * the OOo file handling, so we need to check the path of the file
749 * for the filesystem name.
752 if( 0 <= statfs( path
, &s
) )
754 if( 0 == strncmp("afpfs", s
.f_fstypename
, 5) )
761 /* Needed flags to allow opening a webdav file */
762 flags
&= ~(O_EXLOCK
| O_SHLOCK
| O_NONBLOCK
);
771 /****************************************************************************
772 * osl_file_queryLocking
773 ***************************************************************************/
777 Locking_Impl() : m_enabled(0)
779 #ifndef HAVE_O_EXLOCK
780 m_enabled
= ((getenv("SAL_ENABLE_FILE_LOCKING") != 0) || (getenv("STAR_ENABLE_FILE_LOCKING") != 0));
781 #endif /* HAVE_O_EXLOCK */
784 static int osl_file_queryLocking (sal_uInt32 uFlags
)
786 if (!(uFlags
& osl_File_OpenFlag_NoLock
))
788 if ((uFlags
& osl_File_OpenFlag_Write
) || (uFlags
& osl_File_OpenFlag_Create
))
790 static Locking_Impl g_locking
;
791 return (g_locking
.m_enabled
!= 0);
797 /****************************************************************************
799 ***************************************************************************/
801 #define OPEN_WRITE_FLAGS ( O_RDWR | O_EXLOCK | O_NONBLOCK )
802 #define OPEN_CREATE_FLAGS ( O_CREAT | O_EXCL | O_RDWR | O_EXLOCK | O_NONBLOCK )
804 #define OPEN_WRITE_FLAGS ( O_RDWR )
805 #define OPEN_CREATE_FLAGS ( O_CREAT | O_EXCL | O_RDWR )
809 SAL_CALL
osl_openFile( rtl_uString
* ustrFileURL
, oslFileHandle
* pHandle
, sal_uInt32 uFlags
)
813 if ((ustrFileURL
== 0) || (ustrFileURL
->length
== 0) || (pHandle
== 0))
814 return osl_File_E_INVAL
;
816 /* convert file URL to system path */
817 char buffer
[PATH_MAX
];
818 eRet
= FileURLToPath (buffer
, sizeof(buffer
), ustrFileURL
);
819 if (eRet
!= osl_File_E_None
)
822 if (macxp_resolveAlias (buffer
, sizeof(buffer
)) != 0)
823 return oslTranslateFileError (OSL_FET_ERROR
, errno
);
826 /* set mode and flags */
827 int mode
= S_IRUSR
| S_IRGRP
| S_IROTH
;
828 int flags
= O_RDONLY
;
829 if (uFlags
& osl_File_OpenFlag_Write
)
831 mode
|= S_IWUSR
| S_IWGRP
| S_IWOTH
;
832 flags
= OPEN_WRITE_FLAGS
;
834 if (uFlags
& osl_File_OpenFlag_Create
)
836 mode
|= S_IWUSR
| S_IWGRP
| S_IWOTH
;
837 flags
= OPEN_CREATE_FLAGS
;
839 if (uFlags
& osl_File_OpenFlag_NoLock
)
842 flags
&= ~(O_EXLOCK
| O_SHLOCK
| O_NONBLOCK
);
843 #endif /* HAVE_O_EXLOCK */
847 flags
= osl_file_adjustLockFlags (buffer
, flags
);
851 int fd
= open( buffer
, flags
, mode
);
853 return oslTranslateFileError (OSL_FET_ERROR
, errno
);
855 /* reset O_NONBLOCK flag */
856 if (flags
& O_NONBLOCK
)
858 int f
= fcntl (fd
, F_GETFL
, 0);
861 eRet
= oslTranslateFileError (OSL_FET_ERROR
, errno
);
865 if (-1 == fcntl (fd
, F_SETFL
, (f
& ~O_NONBLOCK
)))
867 eRet
= oslTranslateFileError (OSL_FET_ERROR
, errno
);
873 /* get file status (mode, size) */
874 struct stat aFileStat
;
875 if (-1 == fstat (fd
, &aFileStat
))
877 eRet
= oslTranslateFileError (OSL_FET_ERROR
, errno
);
881 if (!S_ISREG(aFileStat
.st_mode
))
883 /* we only open regular files here */
885 return osl_File_E_INVAL
;
888 if (osl_file_queryLocking (uFlags
))
891 if (-1 == flock (fd
, LOCK_EX
| LOCK_NB
))
893 /* Mac OSX returns ENOTSUP for webdav drives. We should try read lock */
894 if ((errno
!= ENOTSUP
) || ((-1 == flock (fd
, LOCK_SH
| LOCK_NB
)) && (errno
!= ENOTSUP
)))
896 eRet
= oslTranslateFileError (OSL_FET_ERROR
, errno
);
905 aflock
.l_type
= F_WRLCK
;
906 aflock
.l_whence
= SEEK_SET
;
910 if (-1 == fcntl (fd
, F_SETLK
, &aflock
))
912 eRet
= oslTranslateFileError (OSL_FET_ERROR
, errno
);
920 /* allocate memory for impl structure */
921 FileHandle_Impl
* pImpl
= new FileHandle_Impl (fd
, buffer
);
924 eRet
= oslTranslateFileError (OSL_FET_ERROR
, ENOMEM
);
929 pImpl
->m_state
|= FileHandle_Impl::STATE_WRITEABLE
;
930 pImpl
->m_size
= sal::static_int_cast
< sal_uInt64
>(aFileStat
.st_size
);
932 OSL_TRACE("osl_openFile(%d, %s) => %s", pImpl
->m_fd
,
933 flags
& O_RDWR
? "writeable":"readonly",
934 rtl_string_getStr(pImpl
->m_strFilePath
));
936 *pHandle
= (oslFileHandle
)(pImpl
);
937 return osl_File_E_None
;
940 /****************************************************************************/
942 /****************************************************************************/
944 SAL_CALL
osl_closeFile( oslFileHandle Handle
)
946 FileHandle_Impl
* pImpl
= static_cast<FileHandle_Impl
*>(Handle
);
948 if ((pImpl
== 0) || (pImpl
->m_fd
< 0))
949 return osl_File_E_INVAL
;
951 /* close(2) implicitly (and unconditionally) unlocks */
952 OSL_TRACE("osl_closeFile(%d) => %s", pImpl
->m_fd
, rtl_string_getStr(pImpl
->m_strFilePath
));
953 oslFileError result
= pImpl
->syncFile();
954 if (result
!= osl_File_E_None
)
956 /* close, ignoring double failure */
957 (void) close (pImpl
->m_fd
);
959 else if (-1 == close (pImpl
->m_fd
))
961 /* translate error code */
962 result
= oslTranslateFileError (OSL_FET_ERROR
, errno
);
969 /************************************************
971 ***********************************************/
973 SAL_CALL
osl_syncFile(oslFileHandle Handle
)
975 FileHandle_Impl
* pImpl
= static_cast<FileHandle_Impl
*>(Handle
);
977 if ((0 == pImpl
) || (-1 == pImpl
->m_fd
))
978 return osl_File_E_INVAL
;
980 OSL_FILE_TRACE("osl_syncFile(%d)", pImpl
->m_fd
);
981 oslFileError result
= pImpl
->syncFile();
982 if (result
!= osl_File_E_None
)
984 if (-1 == fsync (pImpl
->m_fd
))
985 return oslTranslateFileError (OSL_FET_ERROR
, errno
);
987 return osl_File_E_None
;
990 /*******************************************
992 ********************************************/
994 SAL_CALL
osl_mapFile (
995 oslFileHandle Handle
,
1002 FileHandle_Impl
* pImpl
= static_cast<FileHandle_Impl
*>(Handle
);
1004 if ((0 == pImpl
) || (-1 == pImpl
->m_fd
) || (0 == ppAddr
))
1005 return osl_File_E_INVAL
;
1008 static sal_uInt64
const g_limit_size_t
= std::numeric_limits
< size_t >::max();
1009 if (g_limit_size_t
< uLength
)
1010 return osl_File_E_OVERFLOW
;
1011 size_t const nLength
= sal::static_int_cast
< size_t >(uLength
);
1013 static sal_uInt64
const g_limit_off_t
= std::numeric_limits
< off_t
>::max();
1014 if (g_limit_off_t
< uOffset
)
1015 return osl_File_E_OVERFLOW
;
1016 off_t
const nOffset
= sal::static_int_cast
< off_t
>(uOffset
);
1018 void* p
= mmap(NULL
, nLength
, PROT_READ
, MAP_SHARED
, pImpl
->m_fd
, nOffset
);
1019 if (MAP_FAILED
== p
)
1020 return oslTranslateFileError(OSL_FET_ERROR
, errno
);
1023 if (uFlags
& osl_File_MapFlag_RandomAccess
)
1025 // Determine memory pagesize.
1026 size_t const nPageSize
= FileHandle_Impl::getpagesize();
1027 if (size_t(-1) != nPageSize
)
1030 * Pagein, touching first byte of every memory page.
1031 * Note: volatile disables optimizing the loop away.
1033 sal_uInt8
* pData (reinterpret_cast<sal_uInt8
*>(*ppAddr
));
1034 size_t nSize (nLength
);
1036 volatile sal_uInt8 c
= 0;
1037 while (nSize
> nPageSize
)
1051 return osl_File_E_None
;
1054 /*******************************************
1056 ********************************************/
1058 SAL_CALL
osl_unmapFile (void* pAddr
, sal_uInt64 uLength
)
1061 return osl_File_E_INVAL
;
1063 static sal_uInt64
const g_limit_size_t
= std::numeric_limits
< size_t >::max();
1064 if (g_limit_size_t
< uLength
)
1065 return osl_File_E_OVERFLOW
;
1066 size_t const nLength
= sal::static_int_cast
< size_t >(uLength
);
1068 if (-1 == munmap(static_cast<char*>(pAddr
), nLength
))
1069 return oslTranslateFileError(OSL_FET_ERROR
, errno
);
1071 return osl_File_E_None
;
1074 /*******************************************
1076 ********************************************/
1078 SAL_CALL
osl_readLine (
1079 oslFileHandle Handle
,
1080 sal_Sequence
** ppSequence
)
1082 FileHandle_Impl
* pImpl
= static_cast<FileHandle_Impl
*>(Handle
);
1084 if ((0 == pImpl
) || (-1 == pImpl
->m_fd
) || (0 == ppSequence
))
1085 return osl_File_E_INVAL
;
1086 sal_uInt64 uBytesRead
= 0;
1088 // read at current fileptr; fileptr += uBytesRead;
1089 oslFileError result
= pImpl
->readLineAt (
1090 pImpl
->m_fileptr
, ppSequence
, &uBytesRead
);
1091 if (result
== osl_File_E_None
)
1092 pImpl
->m_fileptr
+= uBytesRead
;
1096 /*******************************************
1098 ********************************************/
1100 SAL_CALL
osl_readFile (
1101 oslFileHandle Handle
,
1103 sal_uInt64 uBytesRequested
,
1104 sal_uInt64
* pBytesRead
)
1106 FileHandle_Impl
* pImpl
= static_cast<FileHandle_Impl
*>(Handle
);
1108 if ((0 == pImpl
) || (-1 == pImpl
->m_fd
) || (0 == pBuffer
) || (0 == pBytesRead
))
1109 return osl_File_E_INVAL
;
1111 static sal_uInt64
const g_limit_ssize_t
= std::numeric_limits
< ssize_t
>::max();
1112 if (g_limit_ssize_t
< uBytesRequested
)
1113 return osl_File_E_OVERFLOW
;
1114 size_t const nBytesRequested
= sal::static_int_cast
< size_t >(uBytesRequested
);
1116 // read at current fileptr; fileptr += *pBytesRead;
1117 oslFileError result
= pImpl
->readFileAt (
1118 pImpl
->m_fileptr
, pBuffer
, nBytesRequested
, pBytesRead
);
1119 if (result
== osl_File_E_None
)
1120 pImpl
->m_fileptr
+= *pBytesRead
;
1124 /*******************************************
1126 ********************************************/
1128 SAL_CALL
osl_writeFile (
1129 oslFileHandle Handle
,
1130 const void * pBuffer
,
1131 sal_uInt64 uBytesToWrite
,
1132 sal_uInt64
* pBytesWritten
)
1134 FileHandle_Impl
* pImpl
= static_cast<FileHandle_Impl
*>(Handle
);
1136 if ((0 == pImpl
) || (-1 == pImpl
->m_fd
) || (0 == pBuffer
) || (0 == pBytesWritten
))
1137 return osl_File_E_INVAL
;
1138 if (0 == (pImpl
->m_state
& FileHandle_Impl::STATE_WRITEABLE
))
1139 return osl_File_E_BADF
;
1141 static sal_uInt64
const g_limit_ssize_t
= std::numeric_limits
< ssize_t
>::max();
1142 if (g_limit_ssize_t
< uBytesToWrite
)
1143 return osl_File_E_OVERFLOW
;
1144 size_t const nBytesToWrite
= sal::static_int_cast
< size_t >(uBytesToWrite
);
1146 // write at current fileptr; fileptr += *pBytesWritten;
1147 oslFileError result
= pImpl
->writeFileAt (
1148 pImpl
->m_fileptr
, pBuffer
, nBytesToWrite
, pBytesWritten
);
1149 if (result
== osl_File_E_None
)
1150 pImpl
->m_fileptr
+= *pBytesWritten
;
1154 /*******************************************
1156 ********************************************/
1158 SAL_CALL
osl_readFileAt (
1159 oslFileHandle Handle
,
1162 sal_uInt64 uBytesRequested
,
1163 sal_uInt64
* pBytesRead
)
1165 FileHandle_Impl
* pImpl
= static_cast<FileHandle_Impl
*>(Handle
);
1167 if ((0 == pImpl
) || (-1 == pImpl
->m_fd
) || (0 == pBuffer
) || (0 == pBytesRead
))
1168 return osl_File_E_INVAL
;
1169 if (0 == (pImpl
->m_state
& FileHandle_Impl::STATE_SEEKABLE
))
1170 return osl_File_E_SPIPE
;
1172 static sal_uInt64
const g_limit_off_t
= std::numeric_limits
< off_t
>::max();
1173 if (g_limit_off_t
< uOffset
)
1174 return osl_File_E_OVERFLOW
;
1175 off_t
const nOffset
= sal::static_int_cast
< off_t
>(uOffset
);
1177 static sal_uInt64
const g_limit_ssize_t
= std::numeric_limits
< ssize_t
>::max();
1178 if (g_limit_ssize_t
< uBytesRequested
)
1179 return osl_File_E_OVERFLOW
;
1180 size_t const nBytesRequested
= sal::static_int_cast
< size_t >(uBytesRequested
);
1182 // read at specified fileptr
1183 return pImpl
->readFileAt (nOffset
, pBuffer
, nBytesRequested
, pBytesRead
);
1186 /*******************************************
1188 ********************************************/
1190 SAL_CALL
osl_writeFileAt (
1191 oslFileHandle Handle
,
1193 const void* pBuffer
,
1194 sal_uInt64 uBytesToWrite
,
1195 sal_uInt64
* pBytesWritten
)
1197 FileHandle_Impl
* pImpl
= static_cast<FileHandle_Impl
*>(Handle
);
1199 if ((0 == pImpl
) || (-1 == pImpl
->m_fd
) || (0 == pBuffer
) || (0 == pBytesWritten
))
1200 return osl_File_E_INVAL
;
1201 if (0 == (pImpl
->m_state
& FileHandle_Impl::STATE_SEEKABLE
))
1202 return osl_File_E_SPIPE
;
1203 if (0 == (pImpl
->m_state
& FileHandle_Impl::STATE_WRITEABLE
))
1204 return osl_File_E_BADF
;
1206 static sal_uInt64
const g_limit_off_t
= std::numeric_limits
< off_t
>::max();
1207 if (g_limit_off_t
< uOffset
)
1208 return osl_File_E_OVERFLOW
;
1209 off_t
const nOffset
= sal::static_int_cast
< off_t
>(uOffset
);
1211 static sal_uInt64
const g_limit_ssize_t
= std::numeric_limits
< ssize_t
>::max();
1212 if (g_limit_ssize_t
< uBytesToWrite
)
1213 return osl_File_E_OVERFLOW
;
1214 size_t const nBytesToWrite
= sal::static_int_cast
< size_t >(uBytesToWrite
);
1216 // write at specified fileptr
1217 return pImpl
->writeFileAt (nOffset
, pBuffer
, nBytesToWrite
, pBytesWritten
);
1220 /****************************************************************************/
1221 /* osl_isEndOfFile */
1222 /****************************************************************************/
1224 SAL_CALL
osl_isEndOfFile( oslFileHandle Handle
, sal_Bool
*pIsEOF
)
1226 FileHandle_Impl
* pImpl
= static_cast<FileHandle_Impl
*>(Handle
);
1228 if ((0 == pImpl
) || (-1 == pImpl
->m_fd
) || (0 == pIsEOF
))
1229 return osl_File_E_INVAL
;
1231 *pIsEOF
= (pImpl
->getPos() == pImpl
->getSize());
1232 return osl_File_E_None
;
1235 /************************************************
1237 ***********************************************/
1239 SAL_CALL
osl_getFilePos( oslFileHandle Handle
, sal_uInt64
* pPos
)
1241 FileHandle_Impl
* pImpl
= static_cast<FileHandle_Impl
*>(Handle
);
1243 if ((0 == pImpl
) || (-1 == pImpl
->m_fd
) || (0 == pPos
))
1244 return osl_File_E_INVAL
;
1246 *pPos
= pImpl
->getPos();
1247 return osl_File_E_None
;
1250 /*******************************************
1252 ********************************************/
1254 SAL_CALL
osl_setFilePos (oslFileHandle Handle
, sal_uInt32 uHow
, sal_Int64 uOffset
)
1256 FileHandle_Impl
* pImpl
= static_cast<FileHandle_Impl
*>(Handle
);
1258 if ((0 == pImpl
) || (-1 == pImpl
->m_fd
))
1259 return osl_File_E_INVAL
;
1261 static sal_Int64
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 nPos
= 0, nOffset
= sal::static_int_cast
< off_t
>(uOffset
);
1268 case osl_Pos_Absolut
:
1270 return osl_File_E_INVAL
;
1273 case osl_Pos_Current
:
1274 nPos
= sal::static_int_cast
< off_t
>(pImpl
->getPos());
1275 if ((0 > nOffset
) && (-1*nOffset
> nPos
))
1276 return osl_File_E_INVAL
;
1277 if (g_limit_off_t
< nPos
+ nOffset
)
1278 return osl_File_E_OVERFLOW
;
1282 nPos
= sal::static_int_cast
< off_t
>(pImpl
->getSize());
1283 if ((0 > nOffset
) && (-1*nOffset
> nPos
))
1284 return osl_File_E_INVAL
;
1285 if (g_limit_off_t
< nPos
+ nOffset
)
1286 return osl_File_E_OVERFLOW
;
1290 return osl_File_E_INVAL
;
1293 return pImpl
->setPos (nPos
+ nOffset
);
1296 /****************************************************************************
1298 ****************************************************************************/
1300 SAL_CALL
osl_getFileSize( oslFileHandle Handle
, sal_uInt64
* pSize
)
1302 FileHandle_Impl
* pImpl
= static_cast<FileHandle_Impl
*>(Handle
);
1304 if ((0 == pImpl
) || (-1 == pImpl
->m_fd
) || (0 == pSize
))
1305 return osl_File_E_INVAL
;
1307 *pSize
= pImpl
->getSize();
1308 return osl_File_E_None
;
1311 /************************************************
1313 ***********************************************/
1315 SAL_CALL
osl_setFileSize( oslFileHandle Handle
, sal_uInt64 uSize
)
1317 FileHandle_Impl
* pImpl
= static_cast<FileHandle_Impl
*>(Handle
);
1319 if ((0 == pImpl
) || (-1 == pImpl
->m_fd
))
1320 return osl_File_E_INVAL
;
1321 if (0 == (pImpl
->m_state
& FileHandle_Impl::STATE_WRITEABLE
))
1322 return osl_File_E_BADF
;
1324 static sal_uInt64
const g_limit_off_t
= std::numeric_limits
< off_t
>::max();
1325 if (g_limit_off_t
< uSize
)
1326 return osl_File_E_OVERFLOW
;
1328 oslFileError result
= pImpl
->syncFile();
1329 if (result
!= osl_File_E_None
)
1331 pImpl
->m_bufptr
= -1, pImpl
->m_buflen
= 0;
1333 return pImpl
->setSize (uSize
);