merge the formfield patch from ooo-build
[ooovba.git] / sal / osl / unx / file.cxx
blobb8627b8c1a2d435d45e711023d226901379be783
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: file.cxx,v $
10 * $Revision: 1.21 $
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"
39 #include "system.h"
40 #include "file_error_transl.h"
41 #include "file_url.h"
43 #include <algorithm>
44 #include <limits>
46 #include <string.h>
47 #include <sys/mman.h>
49 #if defined(MACOSX)
51 #include <sys/param.h>
52 #include <sys/mount.h>
53 #define HAVE_O_EXLOCK
55 // add MACOSX Time Value
56 #define TimeValue CFTimeValue
57 #include <CoreFoundation/CoreFoundation.h>
58 #undef TimeValue
60 #endif /* MACOSX */
62 #ifdef DEBUG_OSL_FILE
63 # define OSL_FILE_TRACE 0 ? (void)(0) : osl_trace
64 # define PERROR( a, b ) perror( a ); fprintf( stderr, b )
65 #else
66 # define OSL_FILE_TRACE 1 ? (void)(0) : osl_trace
67 # define PERROR( a, b )
68 #endif
70 /*******************************************************************
72 * FileHandle_Impl interface
74 ******************************************************************/
75 struct FileHandle_Impl
77 rtl_String * m_strFilePath; /* holds native file path */
78 int m_fd;
80 /** State
82 enum StateBits
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 */
89 int m_state;
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] */
98 size_t m_bufsiz;
99 sal_uInt8 * m_buffer;
101 explicit FileHandle_Impl (int fd, char const * path = "<anon>");
102 ~FileHandle_Impl();
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 (
116 off_t nOffset,
117 void * pBuffer,
118 size_t nBytesRequested,
119 sal_uInt64 * pBytesRead);
121 oslFileError writeAt (
122 off_t nOffset,
123 void const * pBuffer,
124 size_t nBytesToWrite,
125 sal_uInt64 * pBytesWritten);
127 oslFileError readFileAt (
128 off_t nOffset,
129 void * pBuffer,
130 size_t nBytesRequested,
131 sal_uInt64 * pBytesRead);
133 oslFileError writeFileAt (
134 off_t nOffset,
135 void const * pBuffer,
136 size_t nBytesToWrite,
137 sal_uInt64 * pBytesWritten);
139 oslFileError readLineAt (
140 off_t nOffset,
141 sal_Sequence ** ppSequence,
142 sal_uInt64 * pBytesRead);
144 oslFileError writeSequence_Impl (
145 sal_Sequence ** ppSequence,
146 size_t * pnOffset,
147 const void * pBuffer,
148 size_t nBytes);
150 oslFileError syncFile();
152 /** Buffer cache / allocator.
154 class Allocator
156 rtl_cache_type * m_cache;
157 size_t m_bufsiz;
159 Allocator (Allocator const &);
160 Allocator & operator= (Allocator const &);
162 public:
163 static Allocator & get();
165 void allocate (sal_uInt8 ** ppBuffer, size_t * pnSize);
166 void deallocate (sal_uInt8 * pBuffer);
168 protected:
169 Allocator();
170 ~Allocator();
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()
188 : m_cache (0),
189 m_bufsiz (0)
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);
196 if (0 != m_cache)
197 m_bufsiz = pagesize;
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)
212 if (0 != pBuffer)
213 rtl_cache_free (m_cache, pBuffer);
216 FileHandle_Impl::FileHandle_Impl (int fd, char const * path)
217 : m_strFilePath (0),
218 m_fd (fd),
219 m_state (STATE_SEEKABLE | STATE_READABLE),
220 m_size (0),
221 m_offset (0),
222 m_fileptr (0),
223 m_bufptr (-1),
224 m_buflen (0),
225 m_bufsiz (0),
226 m_buffer (0)
228 rtl_string_newFromStr (&m_strFilePath, path);
229 Allocator::get().allocate (&m_buffer, &m_bufsiz);
230 if (0 != m_buffer)
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)
245 rtl_freeMemory(p);
248 size_t FileHandle_Impl::getpagesize()
250 #if defined(FREEBSD) || defined(NETBSD) || defined(MACOSX)
251 return sal::static_int_cast< size_t >(::getpagesize());
252 #else /* POSIX */
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 */
287 return (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))
293 return (result);
295 /* Try 'expand' via 'lseek()' and 'write()' */
296 if (-1 == lseek (m_fd, (off_t)(nSize - 1), SEEK_SET))
297 return (result);
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);
303 return (result);
306 /* Success. Restore saved position */
307 if (-1 == lseek (m_fd, (off_t)nCurPos, SEEK_SET))
308 return (result);
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 (
317 off_t nOffset,
318 void * pBuffer,
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.
339 nBytes = 0;
341 if (-1 == nBytes)
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);
350 m_offset = nOffset;
353 ssize_t nBytes = ::read (m_fd, pBuffer, nBytesRequested);
354 if (-1 == nBytes)
355 return oslTranslateFileError (OSL_FET_ERROR, errno);
356 m_offset += nBytes;
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 (
366 off_t nOffset,
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);
382 if (-1 == nBytes)
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);
391 m_offset = nOffset;
394 ssize_t nBytes = ::write (m_fd, pBuffer, nBytesToWrite);
395 if (-1 == nBytes)
396 return oslTranslateFileError (OSL_FET_ERROR, errno);
397 m_offset += nBytes;
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 (
409 off_t nOffset,
410 void * pBuffer,
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);
418 if (-1 == nBytes)
419 return oslTranslateFileError (OSL_FET_ERROR, errno);
420 *pBytesRead = nBytes;
421 return osl_File_E_None;
423 else if (0 == m_buffer)
425 // not buffered
426 return readAt (nOffset, pBuffer, nBytesRequested, pBytesRead);
428 else
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)
441 return (result);
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)
449 return (result);
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)
459 return (result);
460 m_bufptr = bufptr, m_buflen = uDone;
462 if (bufpos >= m_buflen)
464 // end of file
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 (
479 off_t nOffset,
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);
488 if (-1 == nBytes)
489 return oslTranslateFileError (OSL_FET_ERROR, errno);
490 *pBytesWritten = nBytes;
491 return osl_File_E_None;
493 else if (0 == m_buffer)
495 // not buffered
496 return writeAt (nOffset, pBuffer, nBytesToWrite, pBytesWritten);
498 else
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)
510 return (result);
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)
518 return (result);
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)
530 return (result);
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 (
548 off_t nOffset,
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 */
558 result = syncFile();
559 if (result != osl_File_E_None)
560 return (result);
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)
566 return (result);
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)
589 return (result);
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)
600 return (result);
601 m_bufptr = bufptr, m_buflen = uDone;
604 bufpos = nOffset - m_bufptr, curpos = bufpos;
605 if (bufpos >= m_buflen)
606 break;
608 switch (state)
610 case LINE_STATE_CR:
611 state = LINE_STATE_LF;
612 switch (m_buffer[curpos])
614 case 0x0A: /* CRLF */
615 /* eat current char */
616 curpos++;
617 break;
618 default: /* single CR */
619 /* keep current char */
620 break;
622 break;
623 default:
624 /* determine next state */
625 switch (m_buffer[curpos])
627 case 0x0A: /* single LF */
628 state = LINE_STATE_LF;
629 break;
630 case 0x0D: /* CR */
631 state = LINE_STATE_CR;
632 break;
633 default: /* advance to next char */
634 curpos++;
635 break;
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)
646 return (result);
647 *pBytesRead += curpos - bufpos, nOffset += curpos - bufpos;
649 break;
653 result = writeSequence_Impl (ppSequence, &dstpos, 0, 0);
654 if (result != osl_File_E_None)
655 return (result);
656 if (0 < dstpos)
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,
665 size_t * pnOffset,
666 const void * pBuffer,
667 size_t nBytes)
669 sal_Int32 nElements = *pnOffset + nBytes;
670 if (!*ppSequence)
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)
682 /* fill sequence */
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)
696 return (result);
697 if (uDone != m_buflen)
698 return osl_File_E_IO;
699 m_state &= ~STATE_MODIFIED;
701 return (result);
704 /****************************************************************************
705 * osl_createFileHandleFromFD
706 ***************************************************************************/
707 extern "C" oslFileHandle osl_createFileHandleFromFD( int fd )
709 if (-1 == fd)
710 return 0; // EINVAL
712 struct stat aFileStat;
713 if (-1 == fstat (fd, &aFileStat))
714 return 0; // EBADF
716 FileHandle_Impl * pImpl = new FileHandle_Impl (fd);
717 if (0 == pImpl)
718 return 0; // ENOMEM
720 // assume writeable
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;
727 else
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)
743 #ifdef MACOSX
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.
751 struct statfs s;
752 if( 0 <= statfs( path, &s ) )
754 if( 0 == strncmp("afpfs", s.f_fstypename, 5) )
756 flags &= ~O_EXLOCK;
757 flags |= O_SHLOCK;
759 else
761 /* Needed flags to allow opening a webdav file */
762 flags &= ~(O_EXLOCK | O_SHLOCK | O_NONBLOCK);
765 #endif /* MACOSX */
767 (void) path;
768 return flags;
771 /****************************************************************************
772 * osl_file_queryLocking
773 ***************************************************************************/
774 struct Locking_Impl
776 int m_enabled;
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);
794 return 0;
797 /****************************************************************************
798 * osl_openFile
799 ***************************************************************************/
800 #ifdef HAVE_O_EXLOCK
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 )
803 #else
804 #define OPEN_WRITE_FLAGS ( O_RDWR )
805 #define OPEN_CREATE_FLAGS ( O_CREAT | O_EXCL | O_RDWR )
806 #endif
808 oslFileError
809 SAL_CALL osl_openFile( rtl_uString* ustrFileURL, oslFileHandle* pHandle, sal_uInt32 uFlags )
811 oslFileError eRet;
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)
820 return eRet;
821 #ifdef MACOSX
822 if (macxp_resolveAlias (buffer, sizeof(buffer)) != 0)
823 return oslTranslateFileError (OSL_FET_ERROR, errno);
824 #endif /* MACOSX */
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)
841 #ifdef HAVE_O_EXLOCK
842 flags &= ~(O_EXLOCK | O_SHLOCK | O_NONBLOCK);
843 #endif /* HAVE_O_EXLOCK */
845 else
847 flags = osl_file_adjustLockFlags (buffer, flags);
850 /* open the file */
851 int fd = open( buffer, flags, mode );
852 if (-1 == fd)
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);
859 if (-1 == f)
861 eRet = oslTranslateFileError (OSL_FET_ERROR, errno);
862 (void) close(fd);
863 return eRet;
865 if (-1 == fcntl (fd, F_SETFL, (f & ~O_NONBLOCK)))
867 eRet = oslTranslateFileError (OSL_FET_ERROR, errno);
868 (void) close(fd);
869 return eRet;
873 /* get file status (mode, size) */
874 struct stat aFileStat;
875 if (-1 == fstat (fd, &aFileStat))
877 eRet = oslTranslateFileError (OSL_FET_ERROR, errno);
878 (void) close(fd);
879 return eRet;
881 if (!S_ISREG(aFileStat.st_mode))
883 /* we only open regular files here */
884 (void) close(fd);
885 return osl_File_E_INVAL;
888 if (osl_file_queryLocking (uFlags))
890 #ifdef MACOSX
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);
897 (void) close(fd);
898 return eRet;
901 #else /* F_SETLK */
903 struct flock aflock;
905 aflock.l_type = F_WRLCK;
906 aflock.l_whence = SEEK_SET;
907 aflock.l_start = 0;
908 aflock.l_len = 0;
910 if (-1 == fcntl (fd, F_SETLK, &aflock))
912 eRet = oslTranslateFileError (OSL_FET_ERROR, errno);
913 (void) close(fd);
914 return eRet;
917 #endif /* F_SETLK */
920 /* allocate memory for impl structure */
921 FileHandle_Impl * pImpl = new FileHandle_Impl (fd, buffer);
922 if (!pImpl)
924 eRet = oslTranslateFileError (OSL_FET_ERROR, ENOMEM);
925 (void) close(fd);
926 return eRet;
928 if (flags & O_RDWR)
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 /****************************************************************************/
941 /* osl_closeFile */
942 /****************************************************************************/
943 oslFileError
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);
965 delete pImpl;
966 return (result);
969 /************************************************
970 * osl_syncFile
971 ***********************************************/
972 oslFileError
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)
983 return (result);
984 if (-1 == fsync (pImpl->m_fd))
985 return oslTranslateFileError (OSL_FET_ERROR, errno);
987 return osl_File_E_None;
990 /*******************************************
991 osl_mapFile
992 ********************************************/
993 oslFileError
994 SAL_CALL osl_mapFile (
995 oslFileHandle Handle,
996 void** ppAddr,
997 sal_uInt64 uLength,
998 sal_uInt64 uOffset,
999 sal_uInt32 uFlags
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;
1006 *ppAddr = 0;
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);
1021 *ppAddr = p;
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)
1039 c ^= pData[0];
1040 pData += nPageSize;
1041 nSize -= nPageSize;
1043 if (nSize > 0)
1045 c^= pData[0];
1046 pData += nSize;
1047 nSize -= nSize;
1051 return osl_File_E_None;
1054 /*******************************************
1055 osl_unmapFile
1056 ********************************************/
1057 oslFileError
1058 SAL_CALL osl_unmapFile (void* pAddr, sal_uInt64 uLength)
1060 if (0 == pAddr)
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 /*******************************************
1075 osl_readLine
1076 ********************************************/
1077 oslFileError
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;
1093 return (result);
1096 /*******************************************
1097 osl_readFile
1098 ********************************************/
1099 oslFileError
1100 SAL_CALL osl_readFile (
1101 oslFileHandle Handle,
1102 void * pBuffer,
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;
1121 return (result);
1124 /*******************************************
1125 osl_writeFile
1126 ********************************************/
1127 oslFileError
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;
1151 return (result);
1154 /*******************************************
1155 osl_readFileAt
1156 ********************************************/
1157 oslFileError
1158 SAL_CALL osl_readFileAt (
1159 oslFileHandle Handle,
1160 sal_uInt64 uOffset,
1161 void* pBuffer,
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 /*******************************************
1187 osl_writeFileAt
1188 ********************************************/
1189 oslFileError
1190 SAL_CALL osl_writeFileAt (
1191 oslFileHandle Handle,
1192 sal_uInt64 uOffset,
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 /****************************************************************************/
1223 oslFileError
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 /************************************************
1236 * osl_getFilePos
1237 ***********************************************/
1238 oslFileError
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 /*******************************************
1251 osl_setFilePos
1252 ********************************************/
1253 oslFileError
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);
1266 switch(uHow)
1268 case osl_Pos_Absolut:
1269 if (0 > nOffset)
1270 return osl_File_E_INVAL;
1271 break;
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;
1279 break;
1281 case osl_Pos_End:
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;
1287 break;
1289 default:
1290 return osl_File_E_INVAL;
1293 return pImpl->setPos (nPos + nOffset);
1296 /****************************************************************************
1297 * osl_getFileSize
1298 ****************************************************************************/
1299 oslFileError
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 /************************************************
1312 * osl_setFileSize
1313 ***********************************************/
1314 oslFileError
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)
1330 return (result);
1331 pImpl->m_bufptr = -1, pImpl->m_buflen = 0;
1333 return pImpl->setSize (uSize);