tdf#154546 skip dispatch when presenter controller is not set
[LibreOffice.git] / sal / osl / unx / file.cxx
bloba39365b9b115b3049f051c4efb64bba5d8291b4d
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <config_features.h>
21 #include <o3tl/safeint.hxx>
22 #include <o3tl/string_view.hxx>
23 #include <o3tl/typed_flags_set.hxx>
24 #include <sal/log.hxx>
25 #include <osl/diagnose.h>
26 #include <osl/file.hxx>
27 #include <osl/detail/file.h>
28 #include <rtl/alloc.h>
29 #include <rtl/byteseq.hxx>
30 #include <rtl/string.hxx>
32 #include "system.hxx"
33 #include "createfilehandlefromfd.hxx"
34 #include "file_error_transl.hxx"
35 #include "file_impl.hxx"
36 #include "file_url.hxx"
37 #include "uunxapi.hxx"
38 #include "unixerrnostring.hxx"
40 #include <algorithm>
41 #include <atomic>
42 #include <vector>
43 #include <cassert>
44 #include <limits>
46 #include <string.h>
47 #include <pthread.h>
48 #include <sys/mman.h>
50 #if defined(MACOSX)
52 #include <sys/param.h>
53 #include <sys/mount.h>
54 #define HAVE_O_EXLOCK
56 #include <CoreFoundation/CoreFoundation.h>
58 #endif /* MACOSX */
60 #ifdef ANDROID
61 #include <osl/detail/android-bootstrap.h>
62 #include <android/log.h>
63 #include <android/asset_manager.h>
64 #endif
66 namespace {
68 enum class State
70 Seekable = 1, /*< default */
71 Readable = 2, /*< default */
72 Writeable = 4, /*< open() sets, write() requires, else osl_File_E_BADF */
73 Modified = 8 /*< write() sets, flush() resets */
78 template<> struct o3tl::typed_flags<State>: o3tl::is_typed_flags<State, 15> {};
80 namespace {
82 struct FileHandle_Impl
84 pthread_mutex_t m_mutex;
85 OString m_strFilePath; /*< holds native file path */
86 int m_fd;
88 enum Kind
90 KIND_FD = 1,
91 KIND_MEM = 2
93 int m_kind;
94 /** State
96 State m_state;
98 sal_uInt64 m_size; /*< file size */
99 off_t m_offset; /*< physical offset from begin of file */
100 // m_fileptr is hit hard in some situations, where the overhead of a mutex starts to show up, so use an atomic
101 std::atomic<off_t> m_fileptr; /*< logical offset from begin of file */
103 off_t m_bufptr; /*< buffer offset from begin of file */
104 size_t m_buflen; /*< buffer filled [0, m_bufsiz - 1] */
106 size_t m_bufsiz;
107 sal_uInt8 * m_buffer;
108 #ifdef ANDROID
109 rtl_String* m_memstreambuf; /*< used for in-memory streams */
110 #endif
112 explicit FileHandle_Impl(int fd, Kind kind = KIND_FD, OString path = "<anon>");
113 ~FileHandle_Impl();
115 static size_t getpagesize();
117 sal_uInt64 getPos() const;
118 void setPos(sal_uInt64 uPos);
120 sal_uInt64 getSize() const;
121 oslFileError setSize(sal_uInt64 uSize);
123 oslFileError readAt(
124 off_t nOffset,
125 void* pBuffer,
126 size_t nBytesRequested,
127 sal_uInt64* pBytesRead);
129 oslFileError writeAt(
130 off_t nOffset,
131 void const* pBuffer,
132 size_t nBytesToWrite,
133 sal_uInt64* pBytesWritten);
135 oslFileError readFileAt(
136 off_t nOffset,
137 void* pBuffer,
138 size_t nBytesRequested,
139 sal_uInt64* pBytesRead);
141 oslFileError writeFileAt(
142 off_t nOffset,
143 void const* pBuffer,
144 size_t nBytesToWrite,
145 sal_uInt64* pBytesWritten);
147 oslFileError readLineAt(
148 off_t nOffset,
149 sal_Sequence** ppSequence,
150 sal_uInt64* pBytesRead);
152 static oslFileError writeSequence_Impl(
153 sal_Sequence** ppSequence,
154 size_t* pnOffset,
155 const void* pBuffer,
156 size_t nBytes);
158 oslFileError syncFile();
160 class Guard
162 pthread_mutex_t *m_mutex;
164 public:
165 explicit Guard(pthread_mutex_t *pMutex);
166 ~Guard();
172 FileHandle_Impl::Guard::Guard(pthread_mutex_t * pMutex)
173 : m_mutex(pMutex)
175 assert(m_mutex);
176 (void) pthread_mutex_lock(m_mutex); // ignoring EINVAL if a null mutex is passed ...
179 FileHandle_Impl::Guard::~Guard()
181 assert(m_mutex);
182 (void) pthread_mutex_unlock(m_mutex);
185 FileHandle_Impl::FileHandle_Impl(int fd, enum Kind kind, OString path)
186 : m_strFilePath(std::move(path)),
187 m_fd (fd),
188 m_kind (kind),
189 m_state (State::Seekable | State::Readable),
190 m_size (0),
191 m_offset (0),
192 m_fileptr (0),
193 m_bufptr (-1),
194 m_buflen (0),
195 m_bufsiz (0),
196 m_buffer (nullptr)
198 (void) pthread_mutex_init(&m_mutex, nullptr);
199 if (m_kind == KIND_FD)
201 size_t const pagesize = getpagesize();
202 if (pagesize != size_t(-1))
204 m_bufsiz = pagesize;
205 m_buffer = static_cast<sal_uInt8 *>(calloc(1, m_bufsiz));
210 FileHandle_Impl::~FileHandle_Impl()
212 if (m_kind == KIND_FD)
214 free(m_buffer);
215 m_buffer = nullptr;
218 (void) pthread_mutex_destroy(&m_mutex); // ignoring EBUSY ...
221 size_t FileHandle_Impl::getpagesize()
223 return sal::static_int_cast< size_t >(::sysconf(_SC_PAGESIZE));
226 sal_uInt64 FileHandle_Impl::getPos() const
228 return sal::static_int_cast< sal_uInt64 >(m_fileptr.load());
231 void FileHandle_Impl::setPos(sal_uInt64 uPos)
233 m_fileptr = sal::static_int_cast< off_t >(uPos);
236 sal_uInt64 FileHandle_Impl::getSize() const
238 off_t const bufend = std::max(off_t(0), m_bufptr) + m_buflen;
239 return std::max(m_size, sal::static_int_cast< sal_uInt64 >(bufend));
242 oslFileError FileHandle_Impl::setSize(sal_uInt64 uSize)
244 off_t const nSize = sal::static_int_cast< off_t >(uSize);
245 if (ftruncate_with_name(m_fd, nSize, m_strFilePath) == -1)
247 /* Failure. Save original result. Try fallback algorithm */
248 oslFileError result = oslTranslateFileError(errno);
250 /* Check against current size. Fail upon 'shrink' */
251 if (uSize <= getSize())
253 /* Failure upon 'shrink'. Return original result */
254 return result;
257 /* Save current position */
258 off_t const nCurPos = lseek(m_fd, off_t(0), SEEK_CUR);
259 if (nCurPos == off_t(-1))
261 int e = errno;
262 SAL_INFO("sal.file", "lseek(" << m_fd << ",0,SEEK_CUR): " << UnixErrnoString(e));
263 return result;
265 else
266 SAL_INFO("sal.file", "lseek(" << m_fd << ",0,SEEK_CUR): OK");
268 /* Try 'expand' via 'lseek()' and 'write()' */
269 if (lseek(m_fd, static_cast<off_t>(nSize - 1), SEEK_SET) == -1)
271 int e = errno;
272 SAL_INFO("sal.file", "lseek(" << m_fd << "," << nSize - 1 << ",SEEK_SET): " << UnixErrnoString(e));
273 return result;
275 else
276 SAL_INFO("sal.file", "lseek(" << m_fd << "," << nSize - 1 << ",SEEK_SET): OK");
278 if (write(m_fd, "", size_t(1)) == -1)
280 /* Failure. Restore saved position */
281 int e = errno;
282 SAL_INFO("sal.file", "write(" << m_fd << ",\"\",1): " << UnixErrnoString(e));
283 (void) lseek(m_fd, nCurPos, SEEK_SET);
284 return result;
286 else
287 SAL_INFO("sal.file", "write(" << m_fd << ",\"\",1): OK");
289 /* Success. Restore saved position */
290 if (lseek(m_fd, nCurPos, SEEK_SET) == -1)
291 return result;
294 m_size = sal::static_int_cast< sal_uInt64 >(nSize);
295 return osl_File_E_None;
298 oslFileError FileHandle_Impl::readAt(
299 off_t nOffset,
300 void * pBuffer,
301 size_t nBytesRequested,
302 sal_uInt64 * pBytesRead)
304 SAL_WARN_IF(!(m_state & State::Seekable), "sal.osl", "FileHandle_Impl::readAt(): not seekable");
305 if (!(m_state & State::Seekable))
306 return osl_File_E_SPIPE;
308 SAL_WARN_IF(!(m_state & State::Readable), "sal.osl", "FileHandle_Impl::readAt(): not readable");
309 if (!(m_state & State::Readable))
310 return osl_File_E_BADF;
312 if (m_kind == KIND_MEM)
314 ssize_t nBytes;
316 m_offset = nOffset;
318 if (o3tl::make_unsigned(m_offset) >= m_size)
320 nBytes = 0;
322 else
324 nBytes = std::min(nBytesRequested, static_cast<size_t>(m_size - m_offset));
325 memmove(pBuffer, m_buffer + m_offset, nBytes);
326 m_offset += nBytes;
328 *pBytesRead = nBytes;
329 return osl_File_E_None;
332 ssize_t nBytes = ::pread(m_fd, pBuffer, nBytesRequested, nOffset);
333 if ((nBytes == -1) && (errno == EOVERFLOW))
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;
342 if (nBytes == -1)
343 return oslTranslateFileError(errno);
345 *pBytesRead = nBytes;
347 return osl_File_E_None;
350 oslFileError FileHandle_Impl::writeAt(
351 off_t nOffset,
352 void const * pBuffer,
353 size_t nBytesToWrite,
354 sal_uInt64 * pBytesWritten)
356 SAL_WARN_IF(!(m_state & State::Seekable), "sal.osl", "FileHandle_Impl::writeAt(): not seekable");
357 if (!(m_state & State::Seekable))
358 return osl_File_E_SPIPE;
360 SAL_WARN_IF(!(m_state & State::Writeable), "sal.osl", "FileHandle_Impl::writeAt(): not writeable");
361 if (!(m_state & State::Writeable))
362 return osl_File_E_BADF;
364 ssize_t nBytes = ::pwrite(m_fd, pBuffer, nBytesToWrite, nOffset);
365 if (nBytes == -1)
366 return oslTranslateFileError(errno);
368 m_size = std::max(m_size, sal::static_int_cast< sal_uInt64 >(nOffset + nBytes));
370 *pBytesWritten = nBytes;
372 return osl_File_E_None;
375 oslFileError FileHandle_Impl::readFileAt(
376 off_t nOffset,
377 void* pBuffer,
378 size_t nBytesRequested,
379 sal_uInt64* pBytesRead)
381 if (!(m_state & State::Seekable))
383 // not seekable (pipe)
384 ssize_t nBytes = ::read(m_fd, pBuffer, nBytesRequested);
385 if (nBytes == -1)
386 return oslTranslateFileError(errno);
388 *pBytesRead = nBytes;
390 return osl_File_E_None;
393 if (m_kind == KIND_MEM || !m_buffer)
395 // not buffered
396 return readAt(nOffset, pBuffer, nBytesRequested, pBytesRead);
399 sal_uInt8 *buffer = static_cast<sal_uInt8*>(pBuffer);
400 for (*pBytesRead = 0; nBytesRequested > 0; )
402 off_t const bufptr = (nOffset / m_bufsiz) * m_bufsiz;
403 size_t const bufpos = nOffset % m_bufsiz;
405 if (bufptr != m_bufptr)
407 // flush current buffer
408 oslFileError result = syncFile();
409 if (result != osl_File_E_None)
410 return result;
412 m_bufptr = -1;
413 m_buflen = 0;
415 if (nBytesRequested >= m_bufsiz)
417 // buffer too small, read through from file
418 sal_uInt64 uDone = 0;
419 result = readAt(nOffset, &(buffer[*pBytesRead]), nBytesRequested, &uDone);
420 if (result != osl_File_E_None)
421 return result;
423 *pBytesRead += uDone;
425 return osl_File_E_None;
428 // update buffer (pointer)
429 sal_uInt64 uDone = 0;
430 result = readAt(bufptr, m_buffer, m_bufsiz, &uDone);
431 if (result != osl_File_E_None)
432 return result;
434 m_bufptr = bufptr;
435 m_buflen = uDone;
438 if (bufpos >= m_buflen)
440 // end of file
441 return osl_File_E_None;
444 size_t const bytes = std::min(m_buflen - bufpos, nBytesRequested);
445 SAL_INFO("sal.fileio", "FileHandle_Impl::readFileAt(" << m_fd << ", " << nOffset << ", " << bytes << ")");
447 memcpy(&(buffer[*pBytesRead]), &(m_buffer[bufpos]), bytes);
448 nBytesRequested -= bytes;
449 *pBytesRead += bytes;
450 nOffset += bytes;
453 return osl_File_E_None;
456 oslFileError FileHandle_Impl::writeFileAt(
457 off_t nOffset,
458 void const * pBuffer,
459 size_t nBytesToWrite,
460 sal_uInt64 * pBytesWritten)
462 if (!(m_state & State::Seekable))
464 // not seekable (pipe)
465 ssize_t nBytes = ::write(m_fd, pBuffer, nBytesToWrite);
466 if (nBytes == -1)
467 return oslTranslateFileError(errno);
469 *pBytesWritten = nBytes;
471 return osl_File_E_None;
473 if (!m_buffer)
475 // not buffered
476 return writeAt(nOffset, pBuffer, nBytesToWrite, pBytesWritten);
479 sal_uInt8 const * buffer = static_cast<sal_uInt8 const *>(pBuffer);
480 for (*pBytesWritten = 0; nBytesToWrite > 0;)
482 off_t const bufptr = (nOffset / m_bufsiz) * m_bufsiz;
483 size_t const bufpos = nOffset % m_bufsiz;
484 if (bufptr != m_bufptr)
486 // flush current buffer
487 oslFileError result = syncFile();
488 if (result != osl_File_E_None)
489 return result;
490 m_bufptr = -1;
491 m_buflen = 0;
493 if (nBytesToWrite >= m_bufsiz)
495 // buffer too small, write through to file
496 sal_uInt64 uDone = 0;
497 result = writeAt(nOffset, &(buffer[*pBytesWritten]), nBytesToWrite, &uDone);
498 if (result != osl_File_E_None)
499 return result;
501 if (uDone != nBytesToWrite)
502 return osl_File_E_IO;
504 *pBytesWritten += uDone;
506 return osl_File_E_None;
509 // update buffer (pointer)
510 sal_uInt64 uDone = 0;
511 result = readAt(bufptr, m_buffer, m_bufsiz, &uDone);
512 if (result != osl_File_E_None)
513 return result;
515 m_bufptr = bufptr;
516 m_buflen = uDone;
519 size_t const bytes = std::min(m_bufsiz - bufpos, nBytesToWrite);
520 SAL_INFO("sal.fileio", "FileHandle_Impl::writeFileAt(" << m_fd << ", " << nOffset << ", " << bytes << ")");
522 memcpy(&(m_buffer[bufpos]), &(buffer[*pBytesWritten]), bytes);
523 nBytesToWrite -= bytes;
524 *pBytesWritten += bytes;
525 nOffset += bytes;
527 m_buflen = std::max(m_buflen, bufpos + bytes);
528 m_state |= State::Modified;
531 return osl_File_E_None;
534 oslFileError FileHandle_Impl::readLineAt(
535 off_t nOffset,
536 sal_Sequence ** ppSequence,
537 sal_uInt64 * pBytesRead)
539 oslFileError result = osl_File_E_None;
541 off_t bufptr = nOffset / m_bufsiz * m_bufsiz;
542 if (bufptr != m_bufptr)
544 /* flush current buffer */
545 result = syncFile();
546 if (result != osl_File_E_None)
547 return result;
549 /* update buffer (pointer) */
550 sal_uInt64 uDone = 0;
551 result = readAt(bufptr, m_buffer, m_bufsiz, &uDone);
552 if (result != osl_File_E_None)
553 return result;
555 m_bufptr = bufptr;
556 m_buflen = uDone;
559 static int const LINE_STATE_BEGIN = 0;
560 static int const LINE_STATE_CR = 1;
561 static int const LINE_STATE_LF = 2;
563 size_t bufpos = nOffset - m_bufptr, curpos = bufpos, dstpos = 0;
564 int state = (bufpos >= m_buflen) ? LINE_STATE_LF : LINE_STATE_BEGIN;
566 while (state != LINE_STATE_LF)
568 if (curpos >= m_buflen)
570 /* buffer examined */
571 if ((curpos - bufpos) > 0)
573 /* flush buffer to sequence */
574 result = writeSequence_Impl(
575 ppSequence, &dstpos, &(m_buffer[bufpos]), curpos - bufpos);
576 if (result != osl_File_E_None)
577 return result;
579 *pBytesRead += curpos - bufpos;
580 nOffset += curpos - bufpos;
583 bufptr = nOffset / m_bufsiz * m_bufsiz;
584 if (bufptr != m_bufptr)
586 /* update buffer (pointer) */
587 sal_uInt64 uDone = 0;
588 result = readAt(bufptr, m_buffer, m_bufsiz, &uDone);
589 if (result != osl_File_E_None)
590 return result;
592 m_bufptr = bufptr;
593 m_buflen = uDone;
596 bufpos = nOffset - m_bufptr;
597 curpos = bufpos;
598 if (bufpos >= m_buflen)
599 break;
602 switch (state)
604 case LINE_STATE_CR:
605 state = LINE_STATE_LF;
606 switch (m_buffer[curpos])
608 case 0x0A: /* CRLF */
609 /* eat current char */
610 curpos++;
611 break;
612 default: /* single CR */
613 /* keep current char */
614 break;
616 break;
617 default:
618 /* determine next state */
619 switch (m_buffer[curpos])
621 case 0x0A: /* single LF */
622 state = LINE_STATE_LF;
623 break;
624 case 0x0D: /* CR */
625 state = LINE_STATE_CR;
626 break;
627 default: /* advance to next char */
628 curpos++;
629 break;
631 if (state != LINE_STATE_BEGIN)
633 /* skip the newline char */
634 curpos++;
636 /* flush buffer to sequence */
637 result = writeSequence_Impl(
638 ppSequence, &dstpos, &(m_buffer[bufpos]), curpos - bufpos - 1);
639 if (result != osl_File_E_None)
640 return result;
642 *pBytesRead += curpos - bufpos;
643 nOffset += curpos - bufpos;
645 break;
649 result = writeSequence_Impl(ppSequence, &dstpos, nullptr, 0);
650 if (result != osl_File_E_None)
651 return result;
653 if (dstpos > 0)
654 return osl_File_E_None;
656 if (bufpos >= m_buflen)
657 return osl_File_E_AGAIN;
659 return osl_File_E_None;
662 oslFileError FileHandle_Impl::writeSequence_Impl(
663 sal_Sequence ** ppSequence,
664 size_t * pnOffset,
665 const void * pBuffer,
666 size_t nBytes)
668 sal_Int32 nElements = *pnOffset + nBytes;
669 if (!*ppSequence)
671 /* construct sequence */
672 rtl_byte_sequence_constructNoDefault(ppSequence, nElements);
674 else if (nElements != (*ppSequence)->nElements)
676 /* resize sequence */
677 rtl_byte_sequence_realloc(ppSequence, nElements);
680 if (*ppSequence && nBytes != 0)
682 /* fill sequence */
683 memcpy(&((*ppSequence)->elements[*pnOffset]), pBuffer, nBytes);
684 *pnOffset += nBytes;
687 return (*ppSequence) ? osl_File_E_None : osl_File_E_NOMEM;
690 oslFileError FileHandle_Impl::syncFile()
692 oslFileError result = osl_File_E_None;
693 if (m_state & State::Modified)
695 sal_uInt64 uDone = 0;
696 result = writeAt(m_bufptr, m_buffer, m_buflen, &uDone);
697 if (result != osl_File_E_None)
698 return result;
700 if (uDone != m_buflen)
701 return osl_File_E_IO;
703 m_state &= ~State::Modified;
706 return result;
709 oslFileHandle osl::detail::createFileHandleFromFD(int fd)
711 if (fd == -1)
712 return nullptr; // EINVAL
714 struct stat aFileStat;
715 if (fstat(fd, &aFileStat) == -1)
716 return nullptr; // EBADF
718 FileHandle_Impl *pImpl = new FileHandle_Impl(fd);
720 // assume writeable
721 pImpl->m_state |= State::Writeable;
722 if (!S_ISREG(aFileStat.st_mode))
724 /* not a regular file, mark not seekable */
725 pImpl->m_state &= ~State::Seekable;
727 else
729 /* regular file, init current size */
730 pImpl->m_size = sal::static_int_cast< sal_uInt64 >(aFileStat.st_size);
733 SAL_INFO("sal.file", "osl::detail::createFileHandleFromFD(" << pImpl->m_fd << ", writeable) => " << pImpl->m_strFilePath);
735 return static_cast<oslFileHandle>(pImpl);
738 static int osl_file_adjustLockFlags(const OString& path, int flags)
740 #ifdef MACOSX
742 * The AFP implementation of MacOS X 10.4 treats O_EXLOCK in a way
743 * that makes it impossible for OOo to create a backup copy of the
744 * file it keeps opened. OTOH O_SHLOCK for AFP behaves as desired by
745 * the OOo file handling, so we need to check the path of the file
746 * for the filesystem name.
748 struct statfs s;
749 if(statfs(path.getStr(), &s) >= 0)
751 if(strncmp("afpfs", s.f_fstypename, 5) == 0)
753 flags &= ~O_EXLOCK;
754 flags |= O_SHLOCK;
756 else
758 /* Needed flags to allow opening a webdav file */
759 flags &= ~(O_EXLOCK | O_SHLOCK | O_NONBLOCK);
762 #else
763 (void) path;
764 #endif
766 return flags;
769 static bool osl_file_queryLocking(sal_uInt32 uFlags)
771 #if !defined HAVE_O_EXLOCK
772 if (!(uFlags & osl_File_OpenFlag_NoLock)
773 && ((uFlags & osl_File_OpenFlag_Write)
774 || (uFlags & osl_File_OpenFlag_Create)))
776 static bool enabled = getenv("SAL_ENABLE_FILE_LOCKING") != nullptr;
777 // getenv is not thread safe, so minimize use of result
778 return enabled;
780 #else
781 (void) uFlags;
782 #endif
783 return false;
786 #ifdef HAVE_O_EXLOCK
787 #define OPEN_WRITE_FLAGS ( O_RDWR | O_EXLOCK | O_NONBLOCK )
788 #define OPEN_CREATE_FLAGS ( O_CREAT | O_RDWR | O_EXLOCK | O_NONBLOCK )
789 #else
790 #define OPEN_WRITE_FLAGS ( O_RDWR )
791 #define OPEN_CREATE_FLAGS ( O_CREAT | O_RDWR )
792 #endif
794 #if defined ANDROID
796 namespace {
798 static oslFileError openMemoryAsFile(const OString &rData,
799 oslFileHandle *pHandle,
800 const OString& path)
802 const char *address = rData.getStr();
803 size_t size = rData.getLength();
805 FileHandle_Impl *pImpl = new FileHandle_Impl(-1, FileHandle_Impl::KIND_MEM, path);
806 pImpl->m_size = sal::static_int_cast< sal_uInt64 >(size);
808 *pHandle = (oslFileHandle)(pImpl);
810 pImpl->m_bufptr = 0;
811 pImpl->m_buflen = size;
812 pImpl->m_memstreambuf = rData.pData;
813 rtl_string_acquire(pImpl->m_memstreambuf);
815 pImpl->m_bufsiz = size;
816 pImpl->m_buffer = reinterpret_cast<sal_uInt8*>(const_cast<char *>(address));
818 return osl_File_E_None;
822 * Reading files from /assets/ on Android via a transition into the VM
823 * shows on profiles and is rather slow; so we cache small files as
824 * used by UNO, UI-builder etc.
826 class AndroidFileCache {
827 public:
828 struct Entry {
829 OString maFilePath;
830 OString maData;
832 AndroidFileCache(size_t nElements)
833 : mnCur(0)
835 maEntries.resize(nElements);
836 assert (maEntries.size() == nElements);
838 Entry *find(const char *cpFilePath)
840 for (auto &it : maEntries)
842 if (!strcmp(it.maFilePath.getStr(), cpFilePath))
843 return &it;
845 return nullptr;
847 // no clever LRU - but - good enough for now.
848 void insert(const char *cpFilePath, OString &rData)
850 assert (maEntries.size() > 0);
851 if (++mnCur >= maEntries.size())
852 mnCur = 0;
853 maEntries[mnCur].maFilePath = OString(cpFilePath, strlen(cpFilePath));
854 maEntries[mnCur].maData = rData;
856 static AndroidFileCache &getHitCache()
858 static AndroidFileCache *pCache = new AndroidFileCache(16);
859 return *pCache;
861 static AndroidFileCache &getMissCache()
863 static AndroidFileCache *pCache = new AndroidFileCache(32);
864 return *pCache;
866 private:
867 size_t mnCur;
868 std::vector<Entry> maEntries;
871 } // namespace
873 #endif
875 oslFileError openFilePath(const OString& filePath, oslFileHandle* pHandle,
876 sal_uInt32 uFlags, mode_t mode)
878 oslFileError eRet;
880 #ifdef ANDROID
881 /* Opening a file from /assets read-only means
882 * we should mmap it from the .apk file
884 if (o3tl::starts_with(filePath, "/assets/"))
886 OString aData;
887 bool bCache = true;
889 const char *cpAssetsPath = filePath.getStr() + sizeof("/assets/") - 1;
890 // some requests are /assets//foo...
891 if (cpAssetsPath[0] == '/')
893 __android_log_print(ANDROID_LOG_DEBUG,"libo:sal/osl/unx/file", "double-slash in path: %s", filePath.getStr());
894 cpAssetsPath++;
897 AndroidFileCache::Entry *pHit = AndroidFileCache::getHitCache().find(cpAssetsPath);
898 if (pHit)
899 aData = pHit->maData;
901 else
903 bCache = false;
904 AndroidFileCache::Entry *pMiss = AndroidFileCache::getMissCache().find(cpAssetsPath);
905 if (pMiss)
907 errno = ENOENT;
908 __android_log_print(ANDROID_LOG_ERROR,"libo:sal/osl/unx/file", "miss cache: failed to open %s", filePath.getStr());
909 return osl_File_E_NOENT;
911 AAssetManager* mgr = lo_get_native_assetmgr();
912 AAsset* asset = AAssetManager_open(mgr, cpAssetsPath, AASSET_MODE_BUFFER);
913 if (!asset)
915 AndroidFileCache::getMissCache().insert(cpAssetsPath, aData);
916 errno = ENOENT;
917 __android_log_print(ANDROID_LOG_ERROR,"libo:sal/osl/unx/file", "failed to open %s", filePath.getStr());
918 return osl_File_E_NOENT;
920 else
922 rtl_String *pData = nullptr;
923 size_t size = AAsset_getLength(asset);
924 rtl_string_new_WithLength(&pData, size);
925 pData->length = size;
926 AAsset_read(asset, pData->buffer, size);
927 AAsset_close(asset);
929 aData = OString(pData, SAL_NO_ACQUIRE);
931 if (pData->length < 50 * 1024)
932 AndroidFileCache::getHitCache().insert(cpAssetsPath, aData);
936 if (uFlags & osl_File_OpenFlag_Write)
938 // It seems to work better to silently "open" it read-only
939 // and let write attempts, if any, fail later. Otherwise
940 // loading a document from /assets fails with that idiotic
941 // "General Error" dialog...
943 SAL_INFO("sal.file", "osl_openFile(" << filePath << ") => '" << cpAssetsPath << "'"
944 << aData.getLength() << " bytes from file " << (bCache ? "cache" : "system"));
945 return openMemoryAsFile(aData, pHandle, filePath);
947 #endif
949 /* set mode and flags */
950 int defmode = (uFlags & osl_File_OpenFlag_Private) ? S_IRUSR : S_IRUSR | S_IRGRP | S_IROTH;
951 int flags = O_RDONLY;
953 if (uFlags & osl_File_OpenFlag_Write)
955 defmode |= (uFlags & osl_File_OpenFlag_Private) ? S_IWUSR : S_IWUSR | S_IWGRP | S_IWOTH;
956 flags = OPEN_WRITE_FLAGS;
959 if (uFlags & osl_File_OpenFlag_Create)
961 defmode |= (uFlags & osl_File_OpenFlag_Private) ? S_IWUSR : S_IWUSR | S_IWGRP | S_IWOTH;
962 flags = OPEN_CREATE_FLAGS;
965 if (mode == mode_t(-1))
966 mode = defmode;
968 /* Check for flags passed in from SvFileStream::Open() */
969 if (uFlags & osl_File_OpenFlag_Trunc)
970 flags |= O_TRUNC;
972 if (!(uFlags & osl_File_OpenFlag_NoExcl))
973 flags |= O_EXCL;
975 if (uFlags & osl_File_OpenFlag_NoLock)
977 #ifdef HAVE_O_EXLOCK
978 flags &= ~(O_EXLOCK | O_SHLOCK | O_NONBLOCK);
979 #endif /* HAVE_O_EXLOCK */
981 else
983 flags = osl_file_adjustLockFlags (filePath, flags);
986 // O_EXCL can be set only when O_CREAT is set
987 if (flags & O_EXCL && !(flags & O_CREAT))
988 flags &= ~O_EXCL;
990 /* open the file */
991 int fd = open_c( filePath, flags, mode );
992 if (fd == -1)
994 return oslTranslateFileError(errno);
997 #if !HAVE_FEATURE_MACOSX_SANDBOX
998 /* reset O_NONBLOCK flag */
999 if (flags & O_NONBLOCK)
1001 int f = fcntl(fd, F_GETFL, 0);
1002 if (f == -1)
1004 int e = errno;
1005 SAL_INFO("sal.file", "fcntl(" << fd << ",F_GETFL,0): " << UnixErrnoString(e));
1006 eRet = oslTranslateFileError(e);
1007 (void) close(fd);
1008 SAL_INFO("sal.file", "close(" << fd << ")");
1009 return eRet;
1011 else
1012 SAL_INFO("sal.file", "fcntl(" << fd << ",F_GETFL,0): OK");
1014 if (fcntl(fd, F_SETFL, (f & ~O_NONBLOCK)) == -1)
1016 int e = errno;
1017 SAL_INFO("sal.file", "fcntl(" << fd << ",F_SETFL,(f & ~O_NONBLOCK)): " << UnixErrnoString(e));
1018 eRet = oslTranslateFileError(e);
1019 (void) close(fd);
1020 SAL_INFO("sal.file", "close(" << fd << ")");
1021 return eRet;
1023 else
1024 SAL_INFO("sal.file", "fcntl(" << fd << ",F_SETFL,(f & ~O_NONBLOCK)): OK");
1026 #endif
1028 /* get file status (mode, size) */
1029 struct stat aFileStat;
1030 if (fstat(fd, &aFileStat) == -1)
1032 int e = errno;
1033 SAL_INFO("sal.file", "fstat(" << fd << "): " << UnixErrnoString(e));
1034 eRet = oslTranslateFileError(e);
1035 (void) close(fd);
1036 SAL_INFO("sal.file", "close(" << fd << ")");
1037 return eRet;
1039 else
1040 SAL_INFO("sal.file", "fstat(" << fd << "): OK");
1042 if (!S_ISREG(aFileStat.st_mode))
1044 /* we only open regular files here */
1045 SAL_INFO("sal.file", "osl_openFile(" << filePath << "): not a regular file");
1046 (void) close(fd);
1047 SAL_INFO("sal.file", "close(" << fd << ")");
1048 return osl_File_E_INVAL;
1051 if (osl_file_queryLocking(uFlags))
1053 #ifdef MACOSX
1054 if (flock(fd, LOCK_EX | LOCK_NB) == -1)
1056 int e = errno;
1057 SAL_INFO("sal.file", "flock(" << fd << ",LOCK_EX|LOCK_NB): " << UnixErrnoString(e));
1058 /* Mac OSX returns ENOTSUP for webdav drives. We should try read lock */
1060 // Restore errno after possibly having been overwritten by the SAL_INFO above...
1061 errno = e;
1062 if ((errno != ENOTSUP) || ((flock(fd, LOCK_SH | LOCK_NB) == 1) && (errno != ENOTSUP)))
1064 eRet = oslTranslateFileError(errno);
1065 (void) close(fd);
1066 SAL_INFO("sal.file", "close(" << fd << ")");
1067 return eRet;
1070 else
1071 SAL_INFO("sal.file", "flock(" << fd << ",LOCK_EX|LOCK_NB): OK");
1072 #else /* F_SETLK */
1073 struct flock aflock;
1075 aflock.l_type = F_WRLCK;
1076 aflock.l_whence = SEEK_SET;
1077 aflock.l_start = 0;
1078 aflock.l_len = 0;
1080 if (fcntl(fd, F_SETLK, &aflock) == -1)
1082 int e = errno;
1083 SAL_INFO("sal.file", "fcntl(" << fd << ",F_SETLK): " << UnixErrnoString(e));
1084 eRet = oslTranslateFileError(e);
1085 (void) close(fd);
1086 SAL_INFO("sal.file", "close(" << fd << ")");
1087 return eRet;
1089 #endif /* F_SETLK */
1092 /* allocate memory for impl structure */
1093 FileHandle_Impl *pImpl = new FileHandle_Impl(fd, FileHandle_Impl::KIND_FD, filePath);
1094 if (flags & O_RDWR)
1095 pImpl->m_state |= State::Writeable;
1097 pImpl->m_size = sal::static_int_cast< sal_uInt64 >(aFileStat.st_size);
1099 *pHandle = static_cast<oslFileHandle>(pImpl);
1101 return osl_File_E_None;
1104 oslFileError SAL_CALL osl_openFile(rtl_uString* ustrFileURL, oslFileHandle* pHandle, sal_uInt32 uFlags)
1106 return openFile(ustrFileURL, pHandle, uFlags, mode_t(-1));
1109 oslFileError openFile(rtl_uString* ustrFileURL, oslFileHandle* pHandle, sal_uInt32 uFlags, mode_t mode)
1111 oslFileError eRet;
1113 if ((!ustrFileURL) || (ustrFileURL->length == 0) || (!pHandle))
1114 return osl_File_E_INVAL;
1116 /* convert file URL to system path */
1117 char buffer[PATH_MAX];
1118 eRet = FileURLToPath(buffer, sizeof(buffer), ustrFileURL);
1119 if (eRet != osl_File_E_None)
1120 return eRet;
1122 #ifdef MACOSX
1123 if (macxp_resolveAlias(buffer, sizeof(buffer)) != 0)
1124 return oslTranslateFileError(errno);
1125 #endif /* MACOSX */
1127 return openFilePath(buffer, pHandle, uFlags, mode);
1130 oslFileError SAL_CALL osl_closeFile(oslFileHandle Handle)
1132 FileHandle_Impl* pImpl = static_cast< FileHandle_Impl* >(Handle);
1134 if (!pImpl)
1135 return osl_File_E_INVAL;
1137 if (pImpl->m_kind == FileHandle_Impl::KIND_MEM)
1139 #ifdef ANDROID
1140 rtl_string_release(pImpl->m_memstreambuf);
1141 pImpl->m_memstreambuf = nullptr;
1143 pImpl->m_buffer = NULL;
1144 #endif
1145 delete pImpl;
1146 return osl_File_E_None;
1149 if (pImpl->m_fd < 0)
1150 return osl_File_E_INVAL;
1152 (void) pthread_mutex_lock(&(pImpl->m_mutex));
1154 /* close(2) implicitly (and unconditionally) unlocks */
1155 oslFileError result = pImpl->syncFile();
1156 if (result != osl_File_E_None)
1158 /* close, ignoring double failure */
1159 (void) close(pImpl->m_fd);
1160 SAL_INFO("sal.file", "close(" << pImpl->m_fd << ")");
1162 else if (close(pImpl->m_fd) == -1)
1164 int e = errno;
1165 SAL_INFO("sal.file", "close(" << pImpl->m_fd << "): " << UnixErrnoString(e));
1166 /* translate error code */
1167 result = oslTranslateFileError(e);
1169 else
1170 SAL_INFO("sal.file", "close(" << pImpl->m_fd << "): OK");
1172 (void) pthread_mutex_unlock(&(pImpl->m_mutex));
1173 delete pImpl;
1174 return result;
1177 oslFileError SAL_CALL osl_syncFile(oslFileHandle Handle)
1179 FileHandle_Impl* pImpl = static_cast<FileHandle_Impl*>(Handle);
1181 if ((!pImpl) || ((pImpl->m_kind == FileHandle_Impl::KIND_FD) && (pImpl->m_fd == -1)))
1182 return osl_File_E_INVAL;
1184 if (pImpl->m_kind == FileHandle_Impl::KIND_MEM)
1185 return osl_File_E_None;
1187 FileHandle_Impl::Guard lock(&(pImpl->m_mutex));
1189 oslFileError result = pImpl->syncFile();
1191 if (result != osl_File_E_None)
1192 return result;
1194 if (fsync(pImpl->m_fd) == -1)
1196 int e = errno;
1197 SAL_INFO("sal.file", "fsync(" << pImpl->m_fd << "): " << UnixErrnoString(e));
1198 return oslTranslateFileError(e);
1200 else
1201 SAL_INFO("sal.file", "fsync(" << pImpl->m_fd << "): OK");
1203 return osl_File_E_None;
1206 const off_t MAX_OFF_T = std::numeric_limits< off_t >::max();
1208 namespace {
1210 // coverity[result_independent_of_operands] - crossplatform requirement
1211 template<typename T> bool exceedsMaxOffT(T n) { return n > MAX_OFF_T; }
1213 // coverity[result_independent_of_operands] - crossplatform requirement
1214 template<typename T> bool exceedsMinOffT(T n)
1215 { return n < std::numeric_limits<off_t>::min(); }
1219 oslFileError SAL_CALL osl_mapFile(
1220 oslFileHandle Handle,
1221 void** ppAddr,
1222 sal_uInt64 uLength,
1223 sal_uInt64 uOffset,
1224 sal_uInt32 uFlags
1227 FileHandle_Impl* pImpl = static_cast< FileHandle_Impl* >(Handle);
1229 if ((!pImpl) || ((pImpl->m_kind == FileHandle_Impl::KIND_FD) && (pImpl->m_fd == -1)) || (!ppAddr))
1230 return osl_File_E_INVAL;
1232 *ppAddr = nullptr;
1234 if (uLength > SAL_MAX_SIZE)
1235 return osl_File_E_OVERFLOW;
1237 size_t const nLength = sal::static_int_cast< size_t >(uLength);
1239 if (exceedsMaxOffT(uOffset))
1240 return osl_File_E_OVERFLOW;
1242 if (pImpl->m_kind == FileHandle_Impl::KIND_MEM)
1244 *ppAddr = pImpl->m_buffer + uOffset;
1245 return osl_File_E_None;
1248 off_t const nOffset = sal::static_int_cast< off_t >(uOffset);
1250 void* p = mmap(nullptr, nLength, PROT_READ, MAP_SHARED, pImpl->m_fd, nOffset);
1252 if (p == MAP_FAILED)
1253 return oslTranslateFileError(errno);
1255 *ppAddr = p;
1257 if (uFlags & osl_File_MapFlag_RandomAccess)
1259 // Determine memory pagesize.
1260 size_t const nPageSize = FileHandle_Impl::getpagesize();
1261 if (nPageSize != size_t(-1))
1264 * Pagein, touching first byte of every memory page.
1265 * Note: volatile disables optimizing the loop away.
1267 sal_uInt8 volatile *pData(static_cast<sal_uInt8*>(*ppAddr));
1268 size_t nSize(nLength);
1270 while (nSize > nPageSize)
1272 pData[0];
1273 pData += nPageSize;
1274 nSize -= nPageSize;
1277 if (nSize > 0)
1278 pData[0];
1282 if (uFlags & osl_File_MapFlag_WillNeed)
1284 // On Linux, madvise(..., MADV_WILLNEED) appears to have the undesirable
1285 // effect of not returning until the data has actually been paged in, so
1286 // that its net effect would typically be to slow down the process
1287 // (which could start processing at the beginning of the data while the
1288 // OS simultaneously pages in the rest); on other platforms, it remains
1289 // to be evaluated whether madvise or equivalent is available and
1290 // actually useful:
1291 #if defined MACOSX || (defined(__sun) && (!defined(__XOPEN_OR_POSIX) || defined(_XPG6) || defined(__EXTENSIONS__)))
1292 int e = posix_madvise(p, nLength, POSIX_MADV_WILLNEED);
1293 if (e != 0)
1294 SAL_INFO("sal.file", "posix_madvise(..., POSIX_MADV_WILLNEED) failed with " << e);
1296 #elif defined __sun
1297 if (madvise(static_cast< caddr_t >(p), nLength, MADV_WILLNEED) != 0)
1298 SAL_INFO("sal.file", "madvise(..., MADV_WILLNEED) failed with " << UnixErrnoString(errno));
1299 #endif
1302 return osl_File_E_None;
1305 static oslFileError unmapFile(void* pAddr, sal_uInt64 uLength)
1307 if (!pAddr)
1308 return osl_File_E_INVAL;
1310 if (uLength > SAL_MAX_SIZE)
1311 return osl_File_E_OVERFLOW;
1313 size_t const nLength = sal::static_int_cast< size_t >(uLength);
1315 if (munmap(pAddr, nLength) == -1)
1316 return oslTranslateFileError(errno);
1318 return osl_File_E_None;
1321 #ifndef ANDROID
1323 // Note that osl_unmapFile() just won't work on Android in general
1324 // where for (uncompressed) files inside the .apk, in the /assets
1325 // folder osl_mapFile just returns a pointer to the file inside the
1326 // already mmapped .apk archive.
1328 oslFileError SAL_CALL osl_unmapFile(void* pAddr, sal_uInt64 uLength)
1330 return unmapFile(pAddr, uLength);
1333 #endif
1335 oslFileError SAL_CALL osl_unmapMappedFile(oslFileHandle Handle, void* pAddr, sal_uInt64 uLength)
1337 FileHandle_Impl *pImpl = static_cast<FileHandle_Impl*>(Handle);
1339 if (!pImpl)
1340 return osl_File_E_INVAL;
1342 if (pImpl->m_kind == FileHandle_Impl::KIND_FD)
1343 return unmapFile(pAddr, uLength);
1345 // For parts of already mmapped "parent" files, whose mapping we
1346 // can't change, not much we can or should do...
1347 return osl_File_E_None;
1350 oslFileError SAL_CALL osl_readLine(
1351 oslFileHandle Handle,
1352 sal_Sequence ** ppSequence)
1354 FileHandle_Impl *pImpl = static_cast<FileHandle_Impl*>(Handle);
1356 if ((!pImpl) || ((pImpl->m_kind == FileHandle_Impl::KIND_FD) && (pImpl->m_fd == -1)) || (!ppSequence))
1357 return osl_File_E_INVAL;
1359 sal_uInt64 uBytesRead = 0;
1361 // read at current fileptr; fileptr += uBytesRead;
1362 FileHandle_Impl::Guard lock(&(pImpl->m_mutex));
1363 oslFileError result = pImpl->readLineAt(pImpl->m_fileptr, ppSequence, &uBytesRead);
1365 if (result == osl_File_E_None)
1366 pImpl->m_fileptr += uBytesRead;
1368 return result;
1371 oslFileError SAL_CALL osl_readFile(
1372 oslFileHandle Handle,
1373 void * pBuffer,
1374 sal_uInt64 uBytesRequested,
1375 sal_uInt64 * pBytesRead)
1377 FileHandle_Impl* pImpl = static_cast< FileHandle_Impl* >(Handle);
1379 if ((!pImpl) || ((pImpl->m_kind == FileHandle_Impl::KIND_FD) && (pImpl->m_fd == -1)) || (!pBuffer) || (!pBytesRead))
1380 return osl_File_E_INVAL;
1382 static sal_uInt64 const g_limit_ssize_t = std::numeric_limits< ssize_t >::max();
1383 if (g_limit_ssize_t < uBytesRequested)
1384 return osl_File_E_OVERFLOW;
1386 size_t const nBytesRequested = sal::static_int_cast< size_t >(uBytesRequested);
1388 // read at current fileptr; fileptr += *pBytesRead;
1389 FileHandle_Impl::Guard lock(&(pImpl->m_mutex));
1390 oslFileError result = pImpl->readFileAt(pImpl->m_fileptr, pBuffer, nBytesRequested, pBytesRead);
1392 if (result == osl_File_E_None)
1393 pImpl->m_fileptr += *pBytesRead;
1395 return result;
1398 oslFileError SAL_CALL osl_writeFile(
1399 oslFileHandle Handle,
1400 const void * pBuffer,
1401 sal_uInt64 uBytesToWrite,
1402 sal_uInt64 * pBytesWritten)
1404 FileHandle_Impl* pImpl = static_cast< FileHandle_Impl* >(Handle);
1406 if ((!pImpl) || (pImpl->m_fd == -1) || (!pBuffer) || (!pBytesWritten))
1407 return osl_File_E_INVAL;
1409 if (!(pImpl->m_state & State::Writeable))
1410 return osl_File_E_BADF;
1412 static sal_uInt64 const g_limit_ssize_t = std::numeric_limits< ssize_t >::max();
1413 if (g_limit_ssize_t < uBytesToWrite)
1414 return osl_File_E_OVERFLOW;
1416 size_t const nBytesToWrite = sal::static_int_cast< size_t >(uBytesToWrite);
1418 // write at current fileptr; fileptr += *pBytesWritten;
1419 FileHandle_Impl::Guard lock(&(pImpl->m_mutex));
1420 oslFileError result = pImpl->writeFileAt(pImpl->m_fileptr, pBuffer, nBytesToWrite, pBytesWritten);
1421 if (result == osl_File_E_None)
1422 pImpl->m_fileptr += *pBytesWritten;
1424 return result;
1427 oslFileError SAL_CALL osl_readFileAt(
1428 oslFileHandle Handle,
1429 sal_uInt64 uOffset,
1430 void* pBuffer,
1431 sal_uInt64 uBytesRequested,
1432 sal_uInt64* pBytesRead)
1434 FileHandle_Impl* pImpl = static_cast< FileHandle_Impl* >(Handle);
1436 if ((!pImpl) || ((pImpl->m_kind == FileHandle_Impl::KIND_FD) && (pImpl->m_fd == -1)) || (!pBuffer) || (!pBytesRead))
1437 return osl_File_E_INVAL;
1439 if (!(pImpl->m_state & State::Seekable))
1440 return osl_File_E_SPIPE;
1442 if (exceedsMaxOffT(uOffset))
1443 return osl_File_E_OVERFLOW;
1445 off_t const nOffset = sal::static_int_cast< off_t >(uOffset);
1447 static sal_uInt64 const g_limit_ssize_t = std::numeric_limits< ssize_t >::max();
1448 if (g_limit_ssize_t < uBytesRequested)
1449 return osl_File_E_OVERFLOW;
1451 size_t const nBytesRequested = sal::static_int_cast< size_t >(uBytesRequested);
1453 // read at specified fileptr
1454 FileHandle_Impl::Guard lock(&(pImpl->m_mutex));
1456 return pImpl->readFileAt(nOffset, pBuffer, nBytesRequested, pBytesRead);
1459 oslFileError SAL_CALL osl_writeFileAt(
1460 oslFileHandle Handle,
1461 sal_uInt64 uOffset,
1462 const void* pBuffer,
1463 sal_uInt64 uBytesToWrite,
1464 sal_uInt64* pBytesWritten)
1466 FileHandle_Impl* pImpl = static_cast<FileHandle_Impl*>(Handle);
1468 if ((!pImpl) || (pImpl->m_fd == -1) || (!pBuffer) || (!pBytesWritten))
1469 return osl_File_E_INVAL;
1471 if (!(pImpl->m_state & State::Seekable))
1472 return osl_File_E_SPIPE;
1474 if (!(pImpl->m_state & State::Writeable))
1475 return osl_File_E_BADF;
1477 if (exceedsMaxOffT(uOffset))
1478 return osl_File_E_OVERFLOW;
1480 off_t const nOffset = sal::static_int_cast< off_t >(uOffset);
1482 static sal_uInt64 const g_limit_ssize_t = std::numeric_limits< ssize_t >::max();
1483 if (g_limit_ssize_t < uBytesToWrite)
1484 return osl_File_E_OVERFLOW;
1486 size_t const nBytesToWrite = sal::static_int_cast< size_t >(uBytesToWrite);
1488 // write at specified fileptr
1489 FileHandle_Impl::Guard lock(&(pImpl->m_mutex));
1491 return pImpl->writeFileAt(nOffset, pBuffer, nBytesToWrite, pBytesWritten);
1494 oslFileError SAL_CALL osl_isEndOfFile(oslFileHandle Handle, sal_Bool *pIsEOF)
1496 FileHandle_Impl* pImpl = static_cast< FileHandle_Impl* >(Handle);
1498 if ((!pImpl) || ((pImpl->m_kind == FileHandle_Impl::KIND_FD) && (pImpl->m_fd == -1)) || (!pIsEOF))
1499 return osl_File_E_INVAL;
1501 FileHandle_Impl::Guard lock(&(pImpl->m_mutex));
1502 *pIsEOF = (pImpl->getPos() == pImpl->getSize());
1504 return osl_File_E_None;
1507 oslFileError SAL_CALL osl_getFilePos(oslFileHandle Handle, sal_uInt64* pPos)
1509 FileHandle_Impl* pImpl = static_cast< FileHandle_Impl* >(Handle);
1511 if ((!pImpl) || ((pImpl->m_kind == FileHandle_Impl::KIND_FD) && (pImpl->m_fd == -1)) || (!pPos))
1512 return osl_File_E_INVAL;
1514 // no need to lock because pos is atomic
1515 *pPos = pImpl->getPos();
1517 return osl_File_E_None;
1520 oslFileError SAL_CALL osl_setFilePos(oslFileHandle Handle, sal_uInt32 uHow, sal_Int64 uOffset)
1522 FileHandle_Impl* pImpl = static_cast< FileHandle_Impl* >(Handle);
1524 if ((!pImpl) || ((pImpl->m_kind == FileHandle_Impl::KIND_FD) && (pImpl->m_fd == -1)))
1525 return osl_File_E_INVAL;
1527 if (exceedsMaxOffT(uOffset) || exceedsMinOffT(uOffset))
1528 return osl_File_E_OVERFLOW;
1530 off_t nPos = 0, nOffset = sal::static_int_cast< off_t >(uOffset);
1532 FileHandle_Impl::Guard lock(&(pImpl->m_mutex));
1533 switch (uHow)
1535 case osl_Pos_Absolut:
1536 if (nOffset < 0)
1537 return osl_File_E_INVAL;
1538 break;
1540 case osl_Pos_Current:
1541 nPos = sal::static_int_cast< off_t >(pImpl->getPos());
1542 if ((nOffset < 0) && (nPos < -1*nOffset))
1543 return osl_File_E_INVAL;
1545 assert(nPos >= 0);
1546 if (nOffset > MAX_OFF_T - nPos)
1547 return osl_File_E_OVERFLOW;
1548 break;
1550 case osl_Pos_End:
1551 nPos = sal::static_int_cast< off_t >(pImpl->getSize());
1552 if ((nOffset < 0) && (nPos < -1*nOffset))
1553 return osl_File_E_INVAL;
1555 assert(nPos >= 0);
1556 if (nOffset > MAX_OFF_T - nPos)
1557 return osl_File_E_OVERFLOW;
1558 break;
1560 default:
1561 return osl_File_E_INVAL;
1564 pImpl->setPos(nPos + nOffset);
1565 return osl_File_E_None;
1568 oslFileError SAL_CALL osl_getFileSize(oslFileHandle Handle, sal_uInt64* pSize)
1570 FileHandle_Impl* pImpl = static_cast< FileHandle_Impl* >(Handle);
1572 if ((!pImpl) || ((pImpl->m_kind == FileHandle_Impl::KIND_FD) && (pImpl->m_fd == -1)) || (!pSize))
1573 return osl_File_E_INVAL;
1575 FileHandle_Impl::Guard lock(&(pImpl->m_mutex));
1576 *pSize = pImpl->getSize();
1578 return osl_File_E_None;
1581 oslFileError SAL_CALL osl_setFileSize(oslFileHandle Handle, sal_uInt64 uSize)
1583 FileHandle_Impl* pImpl = static_cast< FileHandle_Impl* >(Handle);
1585 if ((!pImpl) || (pImpl->m_fd == -1))
1586 return osl_File_E_INVAL;
1588 if (!(pImpl->m_state & State::Writeable))
1589 return osl_File_E_BADF;
1591 if (exceedsMaxOffT(uSize))
1592 return osl_File_E_OVERFLOW;
1594 oslFileError result = pImpl->syncFile();
1595 if (result != osl_File_E_None)
1596 return result;
1598 pImpl->m_bufptr = -1;
1599 pImpl->m_buflen = 0;
1601 return pImpl->setSize(uSize);
1604 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */