update dev300-m58
[ooovba.git] / sal / osl / unx / file.cxx
blob28cc35831c4c425cffea3de834e5d74708a03f95
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;
114 oslFileError readAt (
115 off_t nOffset,
116 void * pBuffer,
117 size_t nBytesRequested,
118 sal_uInt64 * pBytesRead);
120 oslFileError writeAt (
121 off_t nOffset,
122 void const * pBuffer,
123 size_t nBytesToWrite,
124 sal_uInt64 * pBytesWritten);
126 oslFileError readFileAt (
127 off_t nOffset,
128 void * pBuffer,
129 size_t nBytesRequested,
130 sal_uInt64 * pBytesRead);
132 oslFileError writeFileAt (
133 off_t nOffset,
134 void const * pBuffer,
135 size_t nBytesToWrite,
136 sal_uInt64 * pBytesWritten);
138 oslFileError readLineAt (
139 off_t nOffset,
140 sal_Sequence ** ppSequence,
141 sal_uInt64 * pBytesRead);
143 oslFileError writeSequence_Impl (
144 sal_Sequence ** ppSequence,
145 size_t * pnOffset,
146 const void * pBuffer,
147 size_t nBytes);
149 oslFileError syncFile();
151 /** Buffer cache / allocator.
153 class Allocator
155 rtl_cache_type * m_cache;
156 size_t m_bufsiz;
158 Allocator (Allocator const &);
159 Allocator & operator= (Allocator const &);
161 public:
162 static Allocator & get();
164 void allocate (sal_uInt8 ** ppBuffer, size_t * pnSize);
165 void deallocate (sal_uInt8 * pBuffer);
167 protected:
168 Allocator();
169 ~Allocator();
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()
187 : m_cache (0),
188 m_bufsiz (0)
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);
195 if (0 != m_cache)
196 m_bufsiz = pagesize;
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)
211 if (0 != pBuffer)
212 rtl_cache_free (m_cache, pBuffer);
215 FileHandle_Impl::FileHandle_Impl (int fd, char const * path)
216 : m_strFilePath (0),
217 m_fd (fd),
218 m_state (STATE_SEEKABLE | STATE_READABLE),
219 m_size (0),
220 m_offset (0),
221 m_fileptr (0),
222 m_bufptr (-1),
223 m_buflen (0),
224 m_bufsiz (0),
225 m_buffer (0)
227 rtl_string_newFromStr (&m_strFilePath, path);
228 Allocator::get().allocate (&m_buffer, &m_bufsiz);
229 if (0 != m_buffer)
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)
244 rtl_freeMemory(p);
247 size_t FileHandle_Impl::getpagesize()
249 #if defined(FREEBSD) || defined(NETBSD) || defined(MACOSX)
250 return sal::static_int_cast< size_t >(::getpagesize());
251 #else /* POSIX */
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 (
275 off_t nOffset,
276 void * pBuffer,
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.
297 nBytes = 0;
299 if (-1 == nBytes)
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);
308 m_offset = nOffset;
311 ssize_t nBytes = ::read (m_fd, pBuffer, nBytesRequested);
312 if (-1 == nBytes)
313 return oslTranslateFileError (OSL_FET_ERROR, errno);
314 m_offset += nBytes;
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 (
324 off_t nOffset,
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);
340 if (-1 == nBytes)
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);
349 m_offset = nOffset;
352 ssize_t nBytes = ::write (m_fd, pBuffer, nBytesToWrite);
353 if (-1 == nBytes)
354 return oslTranslateFileError (OSL_FET_ERROR, errno);
355 m_offset += nBytes;
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 (
367 off_t nOffset,
368 void * pBuffer,
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);
376 if (-1 == nBytes)
377 return oslTranslateFileError (OSL_FET_ERROR, errno);
378 *pBytesRead = nBytes;
379 return osl_File_E_None;
381 else if (0 == m_buffer)
383 // not buffered
384 return readAt (nOffset, pBuffer, nBytesRequested, pBytesRead);
386 else
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)
399 return (result);
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)
407 return (result);
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)
417 return (result);
418 m_bufptr = bufptr, m_buflen = uDone;
420 if (bufpos >= m_buflen)
422 // end of file
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 (
437 off_t nOffset,
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);
446 if (-1 == nBytes)
447 return oslTranslateFileError (OSL_FET_ERROR, errno);
448 *pBytesWritten = nBytes;
449 return osl_File_E_None;
451 else if (0 == m_buffer)
453 // not buffered
454 return writeAt (nOffset, pBuffer, nBytesToWrite, pBytesWritten);
456 else
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)
468 return (result);
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)
476 return (result);
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)
488 return (result);
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 (
506 off_t nOffset,
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 */
516 result = syncFile();
517 if (result != osl_File_E_None)
518 return (result);
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)
524 return (result);
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)
547 return (result);
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)
558 return (result);
559 m_bufptr = bufptr, m_buflen = uDone;
562 bufpos = nOffset - m_bufptr, curpos = bufpos;
563 if (bufpos >= m_buflen)
564 break;
566 switch (state)
568 case LINE_STATE_CR:
569 state = LINE_STATE_LF;
570 switch (m_buffer[curpos])
572 case 0x0A: /* CRLF */
573 /* eat current char */
574 curpos++;
575 break;
576 default: /* single CR */
577 /* keep current char */
578 break;
580 break;
581 default:
582 /* determine next state */
583 switch (m_buffer[curpos])
585 case 0x0A: /* single LF */
586 state = LINE_STATE_LF;
587 break;
588 case 0x0D: /* CR */
589 state = LINE_STATE_CR;
590 break;
591 default: /* advance to next char */
592 curpos++;
593 break;
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)
604 return (result);
605 *pBytesRead += curpos - bufpos, nOffset += curpos - bufpos;
607 break;
611 result = writeSequence_Impl (ppSequence, &dstpos, 0, 0);
612 if (result != osl_File_E_None)
613 return (result);
614 if (0 < dstpos)
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,
623 size_t * pnOffset,
624 const void * pBuffer,
625 size_t nBytes)
627 sal_Int32 nElements = *pnOffset + nBytes;
628 if (!*ppSequence)
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)
640 /* fill sequence */
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)
654 return (result);
655 if (uDone != m_buflen)
656 return osl_File_E_IO;
657 m_state &= ~STATE_MODIFIED;
659 return (result);
662 /****************************************************************************
663 * osl_createFileHandleFromFD
664 ***************************************************************************/
665 extern "C" oslFileHandle osl_createFileHandleFromFD( int fd )
667 if (-1 == fd)
668 return 0; // EINVAL
670 struct stat aFileStat;
671 if (-1 == fstat (fd, &aFileStat))
672 return 0; // EBADF
674 FileHandle_Impl * pImpl = new FileHandle_Impl (fd);
675 if (0 == pImpl)
676 return 0; // ENOMEM
678 // assume writeable
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;
685 else
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)
701 #ifdef MACOSX
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.
709 struct statfs s;
710 if( 0 <= statfs( path, &s ) )
712 if( 0 == strncmp("afpfs", s.f_fstypename, 5) )
714 flags &= ~O_EXLOCK;
715 flags |= O_SHLOCK;
717 else
719 /* Needed flags to allow opening a webdav file */
720 flags &= ~(O_EXLOCK | O_SHLOCK | O_NONBLOCK);
723 #endif /* MACOSX */
725 (void) path;
726 return flags;
729 /****************************************************************************
730 * osl_file_queryLocking
731 ***************************************************************************/
732 struct Locking_Impl
734 int m_enabled;
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);
752 return 0;
755 /****************************************************************************
756 * osl_openFile
757 ***************************************************************************/
758 #ifdef HAVE_O_EXLOCK
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 )
761 #else
762 #define OPEN_WRITE_FLAGS ( O_RDWR )
763 #define OPEN_CREATE_FLAGS ( O_CREAT | O_EXCL | O_RDWR )
764 #endif
766 oslFileError
767 SAL_CALL osl_openFile( rtl_uString* ustrFileURL, oslFileHandle* pHandle, sal_uInt32 uFlags )
769 oslFileError eRet;
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)
778 return eRet;
779 #ifdef MACOSX
780 if (macxp_resolveAlias (buffer, sizeof(buffer)) != 0)
781 return oslTranslateFileError (OSL_FET_ERROR, errno);
782 #endif /* MACOSX */
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)
799 #ifdef HAVE_O_EXLOCK
800 flags &= ~(O_EXLOCK | O_SHLOCK | O_NONBLOCK);
801 #endif /* HAVE_O_EXLOCK */
803 else
805 flags = osl_file_adjustLockFlags (buffer, flags);
808 /* open the file */
809 int fd = open( buffer, flags, mode );
810 if (-1 == fd)
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);
817 if (-1 == f)
819 eRet = oslTranslateFileError (OSL_FET_ERROR, errno);
820 (void) close(fd);
821 return eRet;
823 if (-1 == fcntl (fd, F_SETFL, (f & ~O_NONBLOCK)))
825 eRet = oslTranslateFileError (OSL_FET_ERROR, errno);
826 (void) close(fd);
827 return eRet;
831 /* get file status (mode, size) */
832 struct stat aFileStat;
833 if (-1 == fstat (fd, &aFileStat))
835 eRet = oslTranslateFileError (OSL_FET_ERROR, errno);
836 (void) close(fd);
837 return eRet;
839 if (!S_ISREG(aFileStat.st_mode))
841 /* we only open regular files here */
842 (void) close(fd);
843 return osl_File_E_INVAL;
846 if (osl_file_queryLocking (uFlags))
848 #ifdef MACOSX
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);
855 (void) close(fd);
856 return eRet;
859 #else /* F_SETLK */
861 struct flock aflock;
863 aflock.l_type = F_WRLCK;
864 aflock.l_whence = SEEK_SET;
865 aflock.l_start = 0;
866 aflock.l_len = 0;
868 if (-1 == fcntl (fd, F_SETLK, &aflock))
870 eRet = oslTranslateFileError (OSL_FET_ERROR, errno);
871 (void) close(fd);
872 return eRet;
875 #endif /* F_SETLK */
878 /* allocate memory for impl structure */
879 FileHandle_Impl * pImpl = new FileHandle_Impl (fd, buffer);
880 if (!pImpl)
882 eRet = oslTranslateFileError (OSL_FET_ERROR, ENOMEM);
883 (void) close(fd);
884 return eRet;
886 if (flags & O_RDWR)
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 /****************************************************************************/
899 /* osl_closeFile */
900 /****************************************************************************/
901 oslFileError
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);
923 delete pImpl;
924 return (result);
927 /************************************************
928 * osl_syncFile
929 ***********************************************/
930 oslFileError
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)
941 return (result);
942 if (-1 == fsync (pImpl->m_fd))
943 return oslTranslateFileError (OSL_FET_ERROR, errno);
945 return osl_File_E_None;
948 /*******************************************
949 osl_mapFile
950 ********************************************/
951 oslFileError
952 SAL_CALL osl_mapFile (
953 oslFileHandle Handle,
954 void** ppAddr,
955 sal_uInt64 uLength,
956 sal_uInt64 uOffset,
957 sal_uInt32 uFlags
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;
964 *ppAddr = 0;
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);
977 if (MAP_FAILED == p)
978 return oslTranslateFileError(OSL_FET_ERROR, errno);
979 *ppAddr = p;
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)
997 c ^= pData[0];
998 pData += nPageSize;
999 nSize -= nPageSize;
1001 if (nSize > 0)
1003 c^= pData[0];
1004 pData += nSize;
1005 nSize -= nSize;
1009 return osl_File_E_None;
1012 /*******************************************
1013 osl_unmapFile
1014 ********************************************/
1015 oslFileError
1016 SAL_CALL osl_unmapFile (void* pAddr, sal_uInt64 uLength)
1018 if (0 == pAddr)
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 /*******************************************
1033 osl_readLine
1034 ********************************************/
1035 oslFileError
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;
1051 return (result);
1054 /*******************************************
1055 osl_readFile
1056 ********************************************/
1057 oslFileError
1058 SAL_CALL osl_readFile (
1059 oslFileHandle Handle,
1060 void * pBuffer,
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;
1079 return (result);
1082 /*******************************************
1083 osl_writeFile
1084 ********************************************/
1085 oslFileError
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;
1109 return (result);
1112 /*******************************************
1113 osl_readFileAt
1114 ********************************************/
1115 oslFileError
1116 SAL_CALL osl_readFileAt (
1117 oslFileHandle Handle,
1118 sal_uInt64 uOffset,
1119 void* pBuffer,
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 /*******************************************
1145 osl_writeFileAt
1146 ********************************************/
1147 oslFileError
1148 SAL_CALL osl_writeFileAt (
1149 oslFileHandle Handle,
1150 sal_uInt64 uOffset,
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 /****************************************************************************/
1181 oslFileError
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 /************************************************
1194 * osl_getFilePos
1195 ***********************************************/
1196 oslFileError
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 /*******************************************
1209 osl_setFilePos
1210 ********************************************/
1211 oslFileError
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);
1224 switch(uHow)
1226 case osl_Pos_Absolut:
1227 if (0 > nOffset)
1228 return osl_File_E_INVAL;
1229 break;
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;
1237 break;
1239 case osl_Pos_End:
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;
1245 break;
1247 default:
1248 return osl_File_E_INVAL;
1251 return pImpl->setPos (nPos + nOffset);
1254 /****************************************************************************
1255 * osl_getFileSize
1256 ****************************************************************************/
1257 oslFileError
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 /************************************************
1270 * osl_setFileSize
1271 ***********************************************/
1272 oslFileError
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)
1289 return (result);
1291 if (-1 == ftruncate (pImpl->m_fd, nSize))
1293 /* Failure. Try fallback algorithm */
1294 off_t nCurPos;
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 */
1304 return (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");
1312 return (result);
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");
1319 return (result);
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");
1329 return (result);
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]");
1336 return (result);
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;