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;
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
);
173 /*******************************************************************
175 * FileHandle_Impl implementation
177 ******************************************************************/
179 FileHandle_Impl::Allocator
&
180 FileHandle_Impl::Allocator::get()
182 static Allocator g_aBufferAllocator
;
183 return g_aBufferAllocator
;
186 FileHandle_Impl::Allocator::Allocator()
190 size_t const pagesize
= FileHandle_Impl::getpagesize();
191 if (size_t(-1) != pagesize
)
193 m_cache
= rtl_cache_create (
194 "osl_file_buffer_cache", pagesize
, 0, 0, 0, 0, 0, 0, 0);
199 FileHandle_Impl::Allocator::~Allocator()
201 rtl_cache_destroy (m_cache
), m_cache
= 0;
204 void FileHandle_Impl::Allocator::allocate (sal_uInt8
** ppBuffer
, size_t * pnSize
)
206 OSL_PRECOND((0 != ppBuffer
) && (0 != pnSize
), "FileHandle_Impl::Allocator::allocate(): contract violation");
207 *ppBuffer
= static_cast< sal_uInt8
* >(rtl_cache_alloc(m_cache
)), *pnSize
= m_bufsiz
;
209 void FileHandle_Impl::Allocator::deallocate (sal_uInt8
* pBuffer
)
212 rtl_cache_free (m_cache
, pBuffer
);
215 FileHandle_Impl::FileHandle_Impl (int fd
, char const * path
)
218 m_state (STATE_SEEKABLE
| STATE_READABLE
),
227 rtl_string_newFromStr (&m_strFilePath
, path
);
228 Allocator::get().allocate (&m_buffer
, &m_bufsiz
);
230 memset (m_buffer
, 0, m_bufsiz
);
232 FileHandle_Impl::~FileHandle_Impl()
234 Allocator::get().deallocate (m_buffer
), m_buffer
= 0;
235 rtl_string_release (m_strFilePath
), m_strFilePath
= 0;
238 void* FileHandle_Impl::operator new (size_t n
)
240 return rtl_allocateMemory(n
);
242 void FileHandle_Impl::operator delete (void * p
, size_t)
247 size_t FileHandle_Impl::getpagesize()
249 #if defined(FREEBSD) || defined(NETBSD) || defined(MACOSX)
250 return sal::static_int_cast
< size_t >(::getpagesize());
252 return sal::static_int_cast
< size_t >(::sysconf(_SC_PAGESIZE
));
253 #endif /* xBSD || POSIX */
256 sal_uInt64
FileHandle_Impl::getPos() const
258 return sal::static_int_cast
< sal_uInt64
>(m_fileptr
);
261 oslFileError
FileHandle_Impl::setPos (sal_uInt64 uPos
)
263 OSL_FILE_TRACE("FileHandle_Impl::setPos(%d, %lld) => %lld", m_fd
, getPos(), uPos
);
264 m_fileptr
= sal::static_int_cast
< off_t
>(uPos
);
265 return osl_File_E_None
;
268 sal_uInt64
FileHandle_Impl::getSize() const
270 off_t
const bufend
= std::max((off_t
)(0), m_bufptr
) + m_buflen
;
271 return std::max(m_size
, sal::static_int_cast
< sal_uInt64
>(bufend
));
274 oslFileError
FileHandle_Impl::readAt (
277 size_t nBytesRequested
,
278 sal_uInt64
* pBytesRead
)
280 OSL_PRECOND((m_state
& STATE_SEEKABLE
), "FileHandle_Impl::readAt(): not seekable");
281 if (!(m_state
& STATE_SEEKABLE
))
282 return osl_File_E_SPIPE
;
284 OSL_PRECOND((m_state
& STATE_READABLE
), "FileHandle_Impl::readAt(): not readable");
285 if (!(m_state
& STATE_READABLE
))
286 return osl_File_E_BADF
;
288 #if defined(LINUX) || defined(SOLARIS)
290 ssize_t nBytes
= ::pread (m_fd
, pBuffer
, nBytesRequested
, nOffset
);
291 if ((-1 == nBytes
) && (EOVERFLOW
== errno
))
293 /* Some 'pread()'s fail with EOVERFLOW when reading at (or past)
294 * end-of-file, different from 'lseek() + read()' behaviour.
295 * Returning '0 bytes read' and 'osl_File_E_None' instead.
300 return oslTranslateFileError (OSL_FET_ERROR
, errno
);
302 #else /* !(LINUX || SOLARIS) */
304 if (nOffset
!= m_offset
)
306 if (-1 == ::lseek (m_fd
, nOffset
, SEEK_SET
))
307 return oslTranslateFileError (OSL_FET_ERROR
, errno
);
311 ssize_t nBytes
= ::read (m_fd
, pBuffer
, nBytesRequested
);
313 return oslTranslateFileError (OSL_FET_ERROR
, errno
);
316 #endif /* !(LINUX || SOLARIS) */
318 OSL_FILE_TRACE("FileHandle_Impl::readAt(%d, %lld, %ld)", m_fd
, nOffset
, nBytes
);
319 *pBytesRead
= nBytes
;
320 return osl_File_E_None
;
323 oslFileError
FileHandle_Impl::writeAt (
325 void const * pBuffer
,
326 size_t nBytesToWrite
,
327 sal_uInt64
* pBytesWritten
)
329 OSL_PRECOND((m_state
& STATE_SEEKABLE
), "FileHandle_Impl::writeAt(): not seekable");
330 if (!(m_state
& STATE_SEEKABLE
))
331 return osl_File_E_SPIPE
;
333 OSL_PRECOND((m_state
& STATE_WRITEABLE
), "FileHandle_Impl::writeAt(): not writeable");
334 if (!(m_state
& STATE_WRITEABLE
))
335 return osl_File_E_BADF
;
337 #if defined(LINUX) || defined(SOLARIS)
339 ssize_t nBytes
= ::pwrite (m_fd
, pBuffer
, nBytesToWrite
, nOffset
);
341 return oslTranslateFileError (OSL_FET_ERROR
, errno
);
343 #else /* !(LINUX || SOLARIS) */
345 if (nOffset
!= m_offset
)
347 if (-1 == ::lseek (m_fd
, nOffset
, SEEK_SET
))
348 return oslTranslateFileError (OSL_FET_ERROR
, errno
);
352 ssize_t nBytes
= ::write (m_fd
, pBuffer
, nBytesToWrite
);
354 return oslTranslateFileError (OSL_FET_ERROR
, errno
);
357 #endif /* !(LINUX || SOLARIS) */
359 OSL_FILE_TRACE("FileHandle_Impl::writeAt(%d, %lld, %ld)", m_fd
, nOffset
, nBytes
);
360 m_size
= std::max (m_size
, sal::static_int_cast
< sal_uInt64
>(nOffset
+ nBytes
));
362 *pBytesWritten
= nBytes
;
363 return osl_File_E_None
;
366 oslFileError
FileHandle_Impl::readFileAt (
369 size_t nBytesRequested
,
370 sal_uInt64
* pBytesRead
)
372 if (0 == (m_state
& STATE_SEEKABLE
))
374 // not seekable (pipe)
375 ssize_t nBytes
= ::read (m_fd
, pBuffer
, nBytesRequested
);
377 return oslTranslateFileError (OSL_FET_ERROR
, errno
);
378 *pBytesRead
= nBytes
;
379 return osl_File_E_None
;
381 else if (0 == m_buffer
)
384 return readAt (nOffset
, pBuffer
, nBytesRequested
, pBytesRead
);
388 sal_uInt8
* buffer
= static_cast<sal_uInt8
*>(pBuffer
);
389 for (*pBytesRead
= 0; nBytesRequested
> 0; )
391 off_t
const bufptr
= (nOffset
/ m_bufsiz
) * m_bufsiz
;
392 size_t const bufpos
= (nOffset
% m_bufsiz
);
394 if (bufptr
!= m_bufptr
)
396 // flush current buffer
397 oslFileError result
= syncFile();
398 if (result
!= osl_File_E_None
)
401 if (nBytesRequested
>= m_bufsiz
)
403 // buffer too small, read through from file
404 sal_uInt64 uDone
= 0;
405 result
= readAt (nOffset
, &(buffer
[*pBytesRead
]), nBytesRequested
, &uDone
);
406 if (result
!= osl_File_E_None
)
409 nBytesRequested
-= uDone
, *pBytesRead
+= uDone
;
410 return osl_File_E_None
;
413 // update buffer (pointer)
414 sal_uInt64 uDone
= 0;
415 result
= readAt (bufptr
, m_buffer
, m_bufsiz
, &uDone
);
416 if (result
!= osl_File_E_None
)
418 m_bufptr
= bufptr
, m_buflen
= uDone
;
420 if (bufpos
>= m_buflen
)
423 return osl_File_E_None
;
426 size_t const bytes
= std::min (m_buflen
- bufpos
, nBytesRequested
);
427 OSL_FILE_TRACE("FileHandle_Impl::readFileAt(%d, %lld, %ld)", m_fd
, nOffset
, bytes
);
429 memcpy (&(buffer
[*pBytesRead
]), &(m_buffer
[bufpos
]), bytes
);
430 nBytesRequested
-= bytes
, *pBytesRead
+= bytes
, nOffset
+= bytes
;
432 return osl_File_E_None
;
436 oslFileError
FileHandle_Impl::writeFileAt (
438 void const * pBuffer
,
439 size_t nBytesToWrite
,
440 sal_uInt64
* pBytesWritten
)
442 if (0 == (m_state
& STATE_SEEKABLE
))
444 // not seekable (pipe)
445 ssize_t nBytes
= ::write (m_fd
, pBuffer
, nBytesToWrite
);
447 return oslTranslateFileError (OSL_FET_ERROR
, errno
);
448 *pBytesWritten
= nBytes
;
449 return osl_File_E_None
;
451 else if (0 == m_buffer
)
454 return writeAt (nOffset
, pBuffer
, nBytesToWrite
, pBytesWritten
);
458 sal_uInt8
const * buffer
= static_cast<sal_uInt8
const *>(pBuffer
);
459 for (*pBytesWritten
= 0; nBytesToWrite
> 0; )
461 off_t
const bufptr
= (nOffset
/ m_bufsiz
) * m_bufsiz
;
462 size_t const bufpos
= (nOffset
% m_bufsiz
);
463 if (bufptr
!= m_bufptr
)
465 // flush current buffer
466 oslFileError result
= syncFile();
467 if (result
!= osl_File_E_None
)
470 if (nBytesToWrite
>= m_bufsiz
)
472 // buffer to small, write through to file
473 sal_uInt64 uDone
= 0;
474 result
= writeAt (nOffset
, &(buffer
[*pBytesWritten
]), nBytesToWrite
, &uDone
);
475 if (result
!= osl_File_E_None
)
477 if (uDone
!= nBytesToWrite
)
478 return osl_File_E_IO
;
480 nBytesToWrite
-= uDone
, *pBytesWritten
+= uDone
;
481 return osl_File_E_None
;
484 // update buffer (pointer)
485 sal_uInt64 uDone
= 0;
486 result
= readAt (bufptr
, m_buffer
, m_bufsiz
, &uDone
);
487 if (result
!= osl_File_E_None
)
489 m_bufptr
= bufptr
, m_buflen
= uDone
;
492 size_t const bytes
= std::min (m_bufsiz
- bufpos
, nBytesToWrite
);
493 OSL_FILE_TRACE("FileHandle_Impl::writeFileAt(%d, %lld, %ld)", m_fd
, nOffset
, bytes
);
495 memcpy (&(m_buffer
[bufpos
]), &(buffer
[*pBytesWritten
]), bytes
);
496 nBytesToWrite
-= bytes
, *pBytesWritten
+= bytes
, nOffset
+= bytes
;
498 m_buflen
= std::max(m_buflen
, bufpos
+ bytes
);
499 m_state
|= STATE_MODIFIED
;
501 return osl_File_E_None
;
505 oslFileError
FileHandle_Impl::readLineAt (
507 sal_Sequence
** ppSequence
,
508 sal_uInt64
* pBytesRead
)
510 oslFileError result
= osl_File_E_None
;
512 off_t bufptr
= nOffset
/ m_bufsiz
* m_bufsiz
;
513 if (bufptr
!= m_bufptr
)
515 /* flush current buffer */
517 if (result
!= osl_File_E_None
)
520 /* update buffer (pointer) */
521 sal_uInt64 uDone
= 0;
522 result
= readAt (bufptr
, m_buffer
, m_bufsiz
, &uDone
);
523 if (result
!= osl_File_E_None
)
526 m_bufptr
= bufptr
, m_buflen
= uDone
;
529 static int const LINE_STATE_BEGIN
= 0;
530 static int const LINE_STATE_CR
= 1;
531 static int const LINE_STATE_LF
= 2;
533 size_t bufpos
= nOffset
- m_bufptr
, curpos
= bufpos
, dstpos
= 0;
534 int state
= (bufpos
>= m_buflen
) ? LINE_STATE_LF
: LINE_STATE_BEGIN
;
536 for ( ; state
!= LINE_STATE_LF
; )
538 if (curpos
>= m_buflen
)
540 /* buffer examined */
541 if (0 < (curpos
- bufpos
))
543 /* flush buffer to sequence */
544 result
= writeSequence_Impl (
545 ppSequence
, &dstpos
, &(m_buffer
[bufpos
]), curpos
- bufpos
);
546 if (result
!= osl_File_E_None
)
548 *pBytesRead
+= curpos
- bufpos
, nOffset
+= curpos
- bufpos
;
551 bufptr
= nOffset
/ m_bufsiz
* m_bufsiz
;
552 if (bufptr
!= m_bufptr
)
554 /* update buffer (pointer) */
555 sal_uInt64 uDone
= 0;
556 result
= readAt (bufptr
, m_buffer
, m_bufsiz
, &uDone
);
557 if (result
!= osl_File_E_None
)
559 m_bufptr
= bufptr
, m_buflen
= uDone
;
562 bufpos
= nOffset
- m_bufptr
, curpos
= bufpos
;
563 if (bufpos
>= m_buflen
)
569 state
= LINE_STATE_LF
;
570 switch (m_buffer
[curpos
])
572 case 0x0A: /* CRLF */
573 /* eat current char */
576 default: /* single CR */
577 /* keep current char */
582 /* determine next state */
583 switch (m_buffer
[curpos
])
585 case 0x0A: /* single LF */
586 state
= LINE_STATE_LF
;
589 state
= LINE_STATE_CR
;
591 default: /* advance to next char */
595 if (state
!= LINE_STATE_BEGIN
)
597 /* store (and eat) the newline char */
598 m_buffer
[curpos
] = 0x0A, curpos
++;
600 /* flush buffer to sequence */
601 result
= writeSequence_Impl (
602 ppSequence
, &dstpos
, &(m_buffer
[bufpos
]), curpos
- bufpos
- 1);
603 if (result
!= osl_File_E_None
)
605 *pBytesRead
+= curpos
- bufpos
, nOffset
+= curpos
- bufpos
;
611 result
= writeSequence_Impl (ppSequence
, &dstpos
, 0, 0);
612 if (result
!= osl_File_E_None
)
615 return osl_File_E_None
;
616 if (bufpos
>= m_buflen
)
617 return osl_File_E_AGAIN
;
618 return osl_File_E_None
;
621 oslFileError
FileHandle_Impl::writeSequence_Impl (
622 sal_Sequence
** ppSequence
,
624 const void * pBuffer
,
627 sal_Int32 nElements
= *pnOffset
+ nBytes
;
630 /* construct sequence */
631 rtl_byte_sequence_constructNoDefault(ppSequence
, nElements
);
633 else if (nElements
!= (*ppSequence
)->nElements
)
635 /* resize sequence */
636 rtl_byte_sequence_realloc(ppSequence
, nElements
);
638 if (*ppSequence
!= 0)
641 memcpy(&((*ppSequence
)->elements
[*pnOffset
]), pBuffer
, nBytes
), *pnOffset
+= nBytes
;
643 return (*ppSequence
!= 0) ? osl_File_E_None
: osl_File_E_NOMEM
;
646 oslFileError
FileHandle_Impl::syncFile()
648 oslFileError result
= osl_File_E_None
;
649 if (m_state
& STATE_MODIFIED
)
651 sal_uInt64 uDone
= 0;
652 result
= writeAt (m_bufptr
, m_buffer
, m_buflen
, &uDone
);
653 if (result
!= osl_File_E_None
)
655 if (uDone
!= m_buflen
)
656 return osl_File_E_IO
;
657 m_state
&= ~STATE_MODIFIED
;
662 /****************************************************************************
663 * osl_createFileHandleFromFD
664 ***************************************************************************/
665 extern "C" oslFileHandle
osl_createFileHandleFromFD( int fd
)
670 struct stat aFileStat
;
671 if (-1 == fstat (fd
, &aFileStat
))
674 FileHandle_Impl
* pImpl
= new FileHandle_Impl (fd
);
679 pImpl
->m_state
|= FileHandle_Impl::STATE_WRITEABLE
;
680 if (!S_ISREG(aFileStat
.st_mode
))
682 /* not a regular file, mark not seekable */
683 pImpl
->m_state
&= ~FileHandle_Impl::STATE_SEEKABLE
;
687 /* regular file, init current size */
688 pImpl
->m_size
= sal::static_int_cast
< sal_uInt64
>(aFileStat
.st_size
);
691 OSL_FILE_TRACE("osl_createFileHandleFromFD(%d, writeable) => %s",
692 pImpl
->m_fd
, rtl_string_getStr(pImpl
->m_strFilePath
));
693 return (oslFileHandle
)(pImpl
);
696 /*******************************************************************
697 * osl_file_adjustLockFlags
698 ******************************************************************/
699 static int osl_file_adjustLockFlags (const char * path
, int flags
)
703 * The AFP implementation of MacOS X 10.4 treats O_EXLOCK in a way
704 * that makes it impossible for OOo to create a backup copy of the
705 * file it keeps opened. OTOH O_SHLOCK for AFP behaves as desired by
706 * the OOo file handling, so we need to check the path of the file
707 * for the filesystem name.
710 if( 0 <= statfs( path
, &s
) )
712 if( 0 == strncmp("afpfs", s
.f_fstypename
, 5) )
719 /* Needed flags to allow opening a webdav file */
720 flags
&= ~(O_EXLOCK
| O_SHLOCK
| O_NONBLOCK
);
729 /****************************************************************************
730 * osl_file_queryLocking
731 ***************************************************************************/
735 Locking_Impl() : m_enabled(0)
737 #ifndef HAVE_O_EXLOCK
738 m_enabled
= ((getenv("SAL_ENABLE_FILE_LOCKING") != 0) || (getenv("STAR_ENABLE_FILE_LOCKING") != 0));
739 #endif /* HAVE_O_EXLOCK */
742 static int osl_file_queryLocking (sal_uInt32 uFlags
)
744 if (!(uFlags
& osl_File_OpenFlag_NoLock
))
746 if ((uFlags
& osl_File_OpenFlag_Write
) || (uFlags
& osl_File_OpenFlag_Create
))
748 static Locking_Impl g_locking
;
749 return (g_locking
.m_enabled
!= 0);
755 /****************************************************************************
757 ***************************************************************************/
759 #define OPEN_WRITE_FLAGS ( O_RDWR | O_EXLOCK | O_NONBLOCK )
760 #define OPEN_CREATE_FLAGS ( O_CREAT | O_EXCL | O_RDWR | O_EXLOCK | O_NONBLOCK )
762 #define OPEN_WRITE_FLAGS ( O_RDWR )
763 #define OPEN_CREATE_FLAGS ( O_CREAT | O_EXCL | O_RDWR )
767 SAL_CALL
osl_openFile( rtl_uString
* ustrFileURL
, oslFileHandle
* pHandle
, sal_uInt32 uFlags
)
771 if ((ustrFileURL
== 0) || (ustrFileURL
->length
== 0) || (pHandle
== 0))
772 return osl_File_E_INVAL
;
774 /* convert file URL to system path */
775 char buffer
[PATH_MAX
];
776 eRet
= FileURLToPath (buffer
, sizeof(buffer
), ustrFileURL
);
777 if (eRet
!= osl_File_E_None
)
780 if (macxp_resolveAlias (buffer
, sizeof(buffer
)) != 0)
781 return oslTranslateFileError (OSL_FET_ERROR
, errno
);
784 /* set mode and flags */
785 int mode
= S_IRUSR
| S_IRGRP
| S_IROTH
;
786 int flags
= O_RDONLY
;
787 if (uFlags
& osl_File_OpenFlag_Write
)
789 mode
|= S_IWUSR
| S_IWGRP
| S_IWOTH
;
790 flags
= OPEN_WRITE_FLAGS
;
792 if (uFlags
& osl_File_OpenFlag_Create
)
794 mode
|= S_IWUSR
| S_IWGRP
| S_IWOTH
;
795 flags
= OPEN_CREATE_FLAGS
;
797 if (uFlags
& osl_File_OpenFlag_NoLock
)
800 flags
&= ~(O_EXLOCK
| O_SHLOCK
| O_NONBLOCK
);
801 #endif /* HAVE_O_EXLOCK */
805 flags
= osl_file_adjustLockFlags (buffer
, flags
);
809 int fd
= open( buffer
, flags
, mode
);
811 return oslTranslateFileError (OSL_FET_ERROR
, errno
);
813 /* reset O_NONBLOCK flag */
814 if (flags
& O_NONBLOCK
)
816 int f
= fcntl (fd
, F_GETFL
, 0);
819 eRet
= oslTranslateFileError (OSL_FET_ERROR
, errno
);
823 if (-1 == fcntl (fd
, F_SETFL
, (f
& ~O_NONBLOCK
)))
825 eRet
= oslTranslateFileError (OSL_FET_ERROR
, errno
);
831 /* get file status (mode, size) */
832 struct stat aFileStat
;
833 if (-1 == fstat (fd
, &aFileStat
))
835 eRet
= oslTranslateFileError (OSL_FET_ERROR
, errno
);
839 if (!S_ISREG(aFileStat
.st_mode
))
841 /* we only open regular files here */
843 return osl_File_E_INVAL
;
846 if (osl_file_queryLocking (uFlags
))
849 if (-1 == flock (fd
, LOCK_EX
| LOCK_NB
))
851 /* Mac OSX returns ENOTSUP for webdav drives. We should try read lock */
852 if ((errno
!= ENOTSUP
) || ((-1 == flock (fd
, LOCK_SH
| LOCK_NB
)) && (errno
!= ENOTSUP
)))
854 eRet
= oslTranslateFileError (OSL_FET_ERROR
, errno
);
863 aflock
.l_type
= F_WRLCK
;
864 aflock
.l_whence
= SEEK_SET
;
868 if (-1 == fcntl (fd
, F_SETLK
, &aflock
))
870 eRet
= oslTranslateFileError (OSL_FET_ERROR
, errno
);
878 /* allocate memory for impl structure */
879 FileHandle_Impl
* pImpl
= new FileHandle_Impl (fd
, buffer
);
882 eRet
= oslTranslateFileError (OSL_FET_ERROR
, ENOMEM
);
887 pImpl
->m_state
|= FileHandle_Impl::STATE_WRITEABLE
;
888 pImpl
->m_size
= sal::static_int_cast
< sal_uInt64
>(aFileStat
.st_size
);
890 OSL_TRACE("osl_openFile(%d, %s) => %s", pImpl
->m_fd
,
891 flags
& O_RDWR
? "writeable":"readonly",
892 rtl_string_getStr(pImpl
->m_strFilePath
));
894 *pHandle
= (oslFileHandle
)(pImpl
);
895 return osl_File_E_None
;
898 /****************************************************************************/
900 /****************************************************************************/
902 SAL_CALL
osl_closeFile( oslFileHandle Handle
)
904 FileHandle_Impl
* pImpl
= static_cast<FileHandle_Impl
*>(Handle
);
906 if ((pImpl
== 0) || (pImpl
->m_fd
< 0))
907 return osl_File_E_INVAL
;
909 /* close(2) implicitly (and unconditionally) unlocks */
910 OSL_TRACE("osl_closeFile(%d) => %s", pImpl
->m_fd
, rtl_string_getStr(pImpl
->m_strFilePath
));
911 oslFileError result
= pImpl
->syncFile();
912 if (result
!= osl_File_E_None
)
914 /* close, ignoring double failure */
915 (void) close (pImpl
->m_fd
);
917 else if (-1 == close (pImpl
->m_fd
))
919 /* translate error code */
920 result
= oslTranslateFileError (OSL_FET_ERROR
, errno
);
927 /************************************************
929 ***********************************************/
931 SAL_CALL
osl_syncFile(oslFileHandle Handle
)
933 FileHandle_Impl
* pImpl
= static_cast<FileHandle_Impl
*>(Handle
);
935 if ((0 == pImpl
) || (-1 == pImpl
->m_fd
))
936 return osl_File_E_INVAL
;
938 OSL_FILE_TRACE("osl_syncFile(%d)", pImpl
->m_fd
);
939 oslFileError result
= pImpl
->syncFile();
940 if (result
!= osl_File_E_None
)
942 if (-1 == fsync (pImpl
->m_fd
))
943 return oslTranslateFileError (OSL_FET_ERROR
, errno
);
945 return osl_File_E_None
;
948 /*******************************************
950 ********************************************/
952 SAL_CALL
osl_mapFile (
953 oslFileHandle Handle
,
960 FileHandle_Impl
* pImpl
= static_cast<FileHandle_Impl
*>(Handle
);
962 if ((0 == pImpl
) || (-1 == pImpl
->m_fd
) || (0 == ppAddr
))
963 return osl_File_E_INVAL
;
966 static sal_uInt64
const g_limit_size_t
= std::numeric_limits
< size_t >::max();
967 if (g_limit_size_t
< uLength
)
968 return osl_File_E_OVERFLOW
;
969 size_t const nLength
= sal::static_int_cast
< size_t >(uLength
);
971 static sal_uInt64
const g_limit_off_t
= std::numeric_limits
< off_t
>::max();
972 if (g_limit_off_t
< uOffset
)
973 return osl_File_E_OVERFLOW
;
974 off_t
const nOffset
= sal::static_int_cast
< off_t
>(uOffset
);
976 void* p
= mmap(NULL
, nLength
, PROT_READ
, MAP_SHARED
, pImpl
->m_fd
, nOffset
);
978 return oslTranslateFileError(OSL_FET_ERROR
, errno
);
981 if (uFlags
& osl_File_MapFlag_RandomAccess
)
983 // Determine memory pagesize.
984 size_t const nPageSize
= FileHandle_Impl::getpagesize();
985 if (size_t(-1) != nPageSize
)
988 * Pagein, touching first byte of every memory page.
989 * Note: volatile disables optimizing the loop away.
991 sal_uInt8
* pData (reinterpret_cast<sal_uInt8
*>(*ppAddr
));
992 size_t nSize (nLength
);
994 volatile sal_uInt8 c
= 0;
995 while (nSize
> nPageSize
)
1009 return osl_File_E_None
;
1012 /*******************************************
1014 ********************************************/
1016 SAL_CALL
osl_unmapFile (void* pAddr
, sal_uInt64 uLength
)
1019 return osl_File_E_INVAL
;
1021 static sal_uInt64
const g_limit_size_t
= std::numeric_limits
< size_t >::max();
1022 if (g_limit_size_t
< uLength
)
1023 return osl_File_E_OVERFLOW
;
1024 size_t const nLength
= sal::static_int_cast
< size_t >(uLength
);
1026 if (-1 == munmap(static_cast<char*>(pAddr
), nLength
))
1027 return oslTranslateFileError(OSL_FET_ERROR
, errno
);
1029 return osl_File_E_None
;
1032 /*******************************************
1034 ********************************************/
1036 SAL_CALL
osl_readLine (
1037 oslFileHandle Handle
,
1038 sal_Sequence
** ppSequence
)
1040 FileHandle_Impl
* pImpl
= static_cast<FileHandle_Impl
*>(Handle
);
1042 if ((0 == pImpl
) || (-1 == pImpl
->m_fd
) || (0 == ppSequence
))
1043 return osl_File_E_INVAL
;
1044 sal_uInt64 uBytesRead
= 0;
1046 // read at current fileptr; fileptr += uBytesRead;
1047 oslFileError result
= pImpl
->readLineAt (
1048 pImpl
->m_fileptr
, ppSequence
, &uBytesRead
);
1049 if (result
== osl_File_E_None
)
1050 pImpl
->m_fileptr
+= uBytesRead
;
1054 /*******************************************
1056 ********************************************/
1058 SAL_CALL
osl_readFile (
1059 oslFileHandle Handle
,
1061 sal_uInt64 uBytesRequested
,
1062 sal_uInt64
* pBytesRead
)
1064 FileHandle_Impl
* pImpl
= static_cast<FileHandle_Impl
*>(Handle
);
1066 if ((0 == pImpl
) || (-1 == pImpl
->m_fd
) || (0 == pBuffer
) || (0 == pBytesRead
))
1067 return osl_File_E_INVAL
;
1069 static sal_uInt64
const g_limit_ssize_t
= std::numeric_limits
< ssize_t
>::max();
1070 if (g_limit_ssize_t
< uBytesRequested
)
1071 return osl_File_E_OVERFLOW
;
1072 size_t const nBytesRequested
= sal::static_int_cast
< size_t >(uBytesRequested
);
1074 // read at current fileptr; fileptr += *pBytesRead;
1075 oslFileError result
= pImpl
->readFileAt (
1076 pImpl
->m_fileptr
, pBuffer
, nBytesRequested
, pBytesRead
);
1077 if (result
== osl_File_E_None
)
1078 pImpl
->m_fileptr
+= *pBytesRead
;
1082 /*******************************************
1084 ********************************************/
1086 SAL_CALL
osl_writeFile (
1087 oslFileHandle Handle
,
1088 const void * pBuffer
,
1089 sal_uInt64 uBytesToWrite
,
1090 sal_uInt64
* pBytesWritten
)
1092 FileHandle_Impl
* pImpl
= static_cast<FileHandle_Impl
*>(Handle
);
1094 if ((0 == pImpl
) || (-1 == pImpl
->m_fd
) || (0 == pBuffer
) || (0 == pBytesWritten
))
1095 return osl_File_E_INVAL
;
1096 if (0 == (pImpl
->m_state
& FileHandle_Impl::STATE_WRITEABLE
))
1097 return osl_File_E_BADF
;
1099 static sal_uInt64
const g_limit_ssize_t
= std::numeric_limits
< ssize_t
>::max();
1100 if (g_limit_ssize_t
< uBytesToWrite
)
1101 return osl_File_E_OVERFLOW
;
1102 size_t const nBytesToWrite
= sal::static_int_cast
< size_t >(uBytesToWrite
);
1104 // write at current fileptr; fileptr += *pBytesWritten;
1105 oslFileError result
= pImpl
->writeFileAt (
1106 pImpl
->m_fileptr
, pBuffer
, nBytesToWrite
, pBytesWritten
);
1107 if (result
== osl_File_E_None
)
1108 pImpl
->m_fileptr
+= *pBytesWritten
;
1112 /*******************************************
1114 ********************************************/
1116 SAL_CALL
osl_readFileAt (
1117 oslFileHandle Handle
,
1120 sal_uInt64 uBytesRequested
,
1121 sal_uInt64
* pBytesRead
)
1123 FileHandle_Impl
* pImpl
= static_cast<FileHandle_Impl
*>(Handle
);
1125 if ((0 == pImpl
) || (-1 == pImpl
->m_fd
) || (0 == pBuffer
) || (0 == pBytesRead
))
1126 return osl_File_E_INVAL
;
1127 if (0 == (pImpl
->m_state
& FileHandle_Impl::STATE_SEEKABLE
))
1128 return osl_File_E_SPIPE
;
1130 static sal_uInt64
const g_limit_off_t
= std::numeric_limits
< off_t
>::max();
1131 if (g_limit_off_t
< uOffset
)
1132 return osl_File_E_OVERFLOW
;
1133 off_t
const nOffset
= sal::static_int_cast
< off_t
>(uOffset
);
1135 static sal_uInt64
const g_limit_ssize_t
= std::numeric_limits
< ssize_t
>::max();
1136 if (g_limit_ssize_t
< uBytesRequested
)
1137 return osl_File_E_OVERFLOW
;
1138 size_t const nBytesRequested
= sal::static_int_cast
< size_t >(uBytesRequested
);
1140 // read at specified fileptr
1141 return pImpl
->readFileAt (nOffset
, pBuffer
, nBytesRequested
, pBytesRead
);
1144 /*******************************************
1146 ********************************************/
1148 SAL_CALL
osl_writeFileAt (
1149 oslFileHandle Handle
,
1151 const void* pBuffer
,
1152 sal_uInt64 uBytesToWrite
,
1153 sal_uInt64
* pBytesWritten
)
1155 FileHandle_Impl
* pImpl
= static_cast<FileHandle_Impl
*>(Handle
);
1157 if ((0 == pImpl
) || (-1 == pImpl
->m_fd
) || (0 == pBuffer
) || (0 == pBytesWritten
))
1158 return osl_File_E_INVAL
;
1159 if (0 == (pImpl
->m_state
& FileHandle_Impl::STATE_SEEKABLE
))
1160 return osl_File_E_SPIPE
;
1161 if (0 == (pImpl
->m_state
& FileHandle_Impl::STATE_WRITEABLE
))
1162 return osl_File_E_BADF
;
1164 static sal_uInt64
const g_limit_off_t
= std::numeric_limits
< off_t
>::max();
1165 if (g_limit_off_t
< uOffset
)
1166 return osl_File_E_OVERFLOW
;
1167 off_t
const nOffset
= sal::static_int_cast
< off_t
>(uOffset
);
1169 static sal_uInt64
const g_limit_ssize_t
= std::numeric_limits
< ssize_t
>::max();
1170 if (g_limit_ssize_t
< uBytesToWrite
)
1171 return osl_File_E_OVERFLOW
;
1172 size_t const nBytesToWrite
= sal::static_int_cast
< size_t >(uBytesToWrite
);
1174 // write at specified fileptr
1175 return pImpl
->writeFileAt (nOffset
, pBuffer
, nBytesToWrite
, pBytesWritten
);
1178 /****************************************************************************/
1179 /* osl_isEndOfFile */
1180 /****************************************************************************/
1182 SAL_CALL
osl_isEndOfFile( oslFileHandle Handle
, sal_Bool
*pIsEOF
)
1184 FileHandle_Impl
* pImpl
= static_cast<FileHandle_Impl
*>(Handle
);
1186 if ((0 == pImpl
) || (-1 == pImpl
->m_fd
) || (0 == pIsEOF
))
1187 return osl_File_E_INVAL
;
1189 *pIsEOF
= (pImpl
->getPos() == pImpl
->getSize());
1190 return osl_File_E_None
;
1193 /************************************************
1195 ***********************************************/
1197 SAL_CALL
osl_getFilePos( oslFileHandle Handle
, sal_uInt64
* pPos
)
1199 FileHandle_Impl
* pImpl
= static_cast<FileHandle_Impl
*>(Handle
);
1201 if ((0 == pImpl
) || (-1 == pImpl
->m_fd
) || (0 == pPos
))
1202 return osl_File_E_INVAL
;
1204 *pPos
= pImpl
->getPos();
1205 return osl_File_E_None
;
1208 /*******************************************
1210 ********************************************/
1212 SAL_CALL
osl_setFilePos (oslFileHandle Handle
, sal_uInt32 uHow
, sal_Int64 uOffset
)
1214 FileHandle_Impl
* pImpl
= static_cast<FileHandle_Impl
*>(Handle
);
1216 if ((0 == pImpl
) || (-1 == pImpl
->m_fd
))
1217 return osl_File_E_INVAL
;
1219 static sal_Int64
const g_limit_off_t
= std::numeric_limits
< off_t
>::max();
1220 if (g_limit_off_t
< uOffset
)
1221 return osl_File_E_OVERFLOW
;
1222 off_t nPos
= 0, nOffset
= sal::static_int_cast
< off_t
>(uOffset
);
1226 case osl_Pos_Absolut
:
1228 return osl_File_E_INVAL
;
1231 case osl_Pos_Current
:
1232 nPos
= sal::static_int_cast
< off_t
>(pImpl
->getPos());
1233 if ((0 > nOffset
) && (-1*nOffset
> nPos
))
1234 return osl_File_E_INVAL
;
1235 if (g_limit_off_t
< nPos
+ nOffset
)
1236 return osl_File_E_OVERFLOW
;
1240 nPos
= sal::static_int_cast
< off_t
>(pImpl
->getSize());
1241 if ((0 > nOffset
) && (-1*nOffset
> nPos
))
1242 return osl_File_E_INVAL
;
1243 if (g_limit_off_t
< nPos
+ nOffset
)
1244 return osl_File_E_OVERFLOW
;
1248 return osl_File_E_INVAL
;
1251 return pImpl
->setPos (nPos
+ nOffset
);
1254 /****************************************************************************
1256 ****************************************************************************/
1258 SAL_CALL
osl_getFileSize( oslFileHandle Handle
, sal_uInt64
* pSize
)
1260 FileHandle_Impl
* pImpl
= static_cast<FileHandle_Impl
*>(Handle
);
1262 if ((0 == pImpl
) || (-1 == pImpl
->m_fd
) || (0 == pSize
))
1263 return osl_File_E_INVAL
;
1265 *pSize
= pImpl
->getSize();
1266 return osl_File_E_None
;
1269 /************************************************
1271 ***********************************************/
1273 SAL_CALL
osl_setFileSize( oslFileHandle Handle
, sal_uInt64 uSize
)
1275 FileHandle_Impl
* pImpl
= static_cast<FileHandle_Impl
*>(Handle
);
1277 if ((0 == pImpl
) || (-1 == pImpl
->m_fd
))
1278 return osl_File_E_INVAL
;
1279 if (0 == (pImpl
->m_state
& FileHandle_Impl::STATE_WRITEABLE
))
1280 return osl_File_E_BADF
;
1282 static sal_uInt64
const g_limit_off_t
= std::numeric_limits
< off_t
>::max();
1283 if (g_limit_off_t
< uSize
)
1284 return osl_File_E_OVERFLOW
;
1285 off_t
const nSize
= sal::static_int_cast
< off_t
>(uSize
);
1287 oslFileError result
= pImpl
->syncFile();
1288 if (result
!= osl_File_E_None
)
1291 if (-1 == ftruncate (pImpl
->m_fd
, nSize
))
1293 /* Failure. Try fallback algorithm */
1296 /* Save original result */
1297 result
= oslTranslateFileError (OSL_FET_ERROR
, errno
);
1298 PERROR("ftruncate", "Try osl_setFileSize [fallback]\n");
1300 /* Check against current size. Fail upon 'shrink' */
1301 if (uSize
<= pImpl
->getSize())
1303 /* Failure upon 'shrink'. Return original result */
1307 /* Save current position *//* @@@ pImpl->m_offset @@@ */
1308 nCurPos
= (off_t
)lseek (pImpl
->m_fd
, (off_t
)0, SEEK_CUR
);
1309 if (nCurPos
== (off_t
)(-1))
1311 PERROR("ftruncate: lseek", "Out osl_setFileSize [error]\n");
1315 /* Try 'expand' via 'lseek()' and 'write()' */
1316 if (lseek (pImpl
->m_fd
, (off_t
)(nSize
- 1), SEEK_SET
) < 0)
1318 PERROR("ftruncate: lseek", "Out osl_setFileSize [error]\n");
1321 if (write (pImpl
->m_fd
, (char*)"", (size_t)1) < 0)
1323 /* Failure. Restore saved position */
1324 PERROR("ftruncate: write", "Out osl_setFileSize [error]\n");
1325 if (lseek (pImpl
->m_fd
, (off_t
)nCurPos
, SEEK_SET
) < 0)
1327 PERROR("ftruncate: lseek", "ignoring");
1332 /* Success. Restore saved position */
1333 if (lseek (pImpl
->m_fd
, (off_t
)nCurPos
, SEEK_SET
) < 0)
1335 PERROR("ftruncate: lseek", "Out osl_setFileSize [error]");
1340 OSL_FILE_TRACE("osl_setFileSize(%d, %lld) => %ld", pImpl
->m_fd
, pImpl
->getSize(), nSize
);
1341 pImpl
->m_size
= sal::static_int_cast
< sal_uInt64
>(nSize
);
1342 return osl_File_E_None
;