tdf#130857 qt weld: Implement QtInstanceWidget::get_text_height
[LibreOffice.git] / sal / osl / unx / file.cxx
blobae1e4cdd876efc561353c08ed4983f5b4408a613
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/typed_flags_set.hxx>
23 #include <sal/log.hxx>
24 #include <osl/detail/file.h>
25 #include <rtl/byteseq.h>
26 #include <rtl/string.hxx>
28 #include "system.hxx"
29 #include "createfilehandlefromfd.hxx"
30 #include "file_error_transl.hxx"
31 #include "file_impl.hxx"
32 #include "file_url.hxx"
33 #include "uunxapi.hxx"
34 #include "unixerrnostring.hxx"
36 #include <algorithm>
37 #include <atomic>
38 #include <cassert>
39 #include <fcntl.h>
40 #include <limits>
41 #include <limits.h>
42 #include <utility>
44 #include <string.h>
45 #include <pthread.h>
46 #include <sys/mman.h>
47 #include <sys/stat.h>
48 #include <unistd.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 #include <o3tl/string_view.hxx>
65 #include <vector>
66 #endif
68 #ifdef LINUX
69 #include <sys/vfs.h>
70 // As documented by the kernel
71 constexpr decltype(std::declval<struct statfs>().f_type) SMB_SUPER_MAGIC = 0x517B;
72 constexpr decltype(std::declval<struct statfs>().f_type) CIFS_SUPER_MAGIC = 0xFF534D42;
73 constexpr decltype(std::declval<struct statfs>().f_type) SMB2_SUPER_MAGIC = 0xFE534D42;
74 #endif
76 namespace {
78 enum class State
80 Seekable = 1, /*< default */
81 Readable = 2, /*< default */
82 Writeable = 4, /*< open() sets, write() requires, else osl_File_E_BADF */
83 Modified = 8 /*< write() sets, flush() resets */
88 template<> struct o3tl::typed_flags<State>: o3tl::is_typed_flags<State, 15> {};
90 namespace {
92 struct FileHandle_Impl
94 pthread_mutex_t m_mutex;
95 OString m_strFilePath; /*< holds native file path */
96 int m_fd;
98 enum Kind
100 KIND_FD = 1,
101 KIND_MEM = 2
103 int m_kind;
104 /** State
106 State m_state;
108 sal_uInt64 m_size; /*< file size */
109 off_t m_offset; /*< physical offset from begin of file */
110 // m_fileptr is hit hard in some situations, where the overhead of a mutex starts to show up, so use an atomic
111 std::atomic<off_t> m_fileptr; /*< logical offset from begin of file */
113 off_t m_bufptr; /*< buffer offset from begin of file */
114 size_t m_buflen; /*< buffer filled [0, m_bufsiz - 1] */
116 size_t m_bufsiz;
117 sal_uInt8 * m_buffer;
118 #ifdef ANDROID
119 rtl_String* m_memstreambuf; /*< used for in-memory streams */
120 #endif
122 explicit FileHandle_Impl(int fd, Kind kind = KIND_FD, OString path = "<anon>"_ostr);
123 ~FileHandle_Impl();
125 static size_t getpagesize();
127 sal_uInt64 getPos() const;
128 void setPos(sal_uInt64 uPos);
130 sal_uInt64 getSize() const;
131 oslFileError setSize(sal_uInt64 uSize);
133 oslFileError readAt(
134 off_t nOffset,
135 void* pBuffer,
136 size_t nBytesRequested,
137 sal_uInt64* pBytesRead);
139 oslFileError writeAt(
140 off_t nOffset,
141 void const* pBuffer,
142 size_t nBytesToWrite,
143 sal_uInt64* pBytesWritten);
145 oslFileError readFileAt(
146 off_t nOffset,
147 void* pBuffer,
148 size_t nBytesRequested,
149 sal_uInt64* pBytesRead);
151 oslFileError writeFileAt(
152 off_t nOffset,
153 void const* pBuffer,
154 size_t nBytesToWrite,
155 sal_uInt64* pBytesWritten);
157 oslFileError readLineAt(
158 off_t nOffset,
159 sal_Sequence** ppSequence,
160 sal_uInt64* pBytesRead);
162 static oslFileError writeSequence_Impl(
163 sal_Sequence** ppSequence,
164 size_t* pnOffset,
165 const void* pBuffer,
166 size_t nBytes);
168 oslFileError syncFile();
170 class Guard
172 pthread_mutex_t *m_mutex;
174 public:
175 explicit Guard(pthread_mutex_t *pMutex);
176 ~Guard();
182 FileHandle_Impl::Guard::Guard(pthread_mutex_t * pMutex)
183 : m_mutex(pMutex)
185 assert(m_mutex);
186 (void) pthread_mutex_lock(m_mutex); // ignoring EINVAL if a null mutex is passed ...
189 FileHandle_Impl::Guard::~Guard()
191 assert(m_mutex);
192 (void) pthread_mutex_unlock(m_mutex);
195 FileHandle_Impl::FileHandle_Impl(int fd, enum Kind kind, OString path)
196 : m_strFilePath(std::move(path)),
197 m_fd (fd),
198 m_kind (kind),
199 m_state (State::Seekable | State::Readable),
200 m_size (0),
201 m_offset (0),
202 m_fileptr (0),
203 m_bufptr (-1),
204 m_buflen (0),
205 m_bufsiz (0),
206 m_buffer (nullptr)
208 (void) pthread_mutex_init(&m_mutex, nullptr);
209 if (m_kind == KIND_FD)
211 size_t const pagesize = getpagesize();
212 if (pagesize != size_t(-1))
214 m_bufsiz = pagesize;
215 m_buffer = static_cast<sal_uInt8 *>(calloc(1, m_bufsiz));
220 FileHandle_Impl::~FileHandle_Impl()
222 if (m_kind == KIND_FD)
224 free(m_buffer);
225 m_buffer = nullptr;
228 (void) pthread_mutex_destroy(&m_mutex); // ignoring EBUSY ...
231 size_t FileHandle_Impl::getpagesize()
233 return sal::static_int_cast< size_t >(::sysconf(_SC_PAGESIZE));
236 sal_uInt64 FileHandle_Impl::getPos() const
238 return sal::static_int_cast< sal_uInt64 >(m_fileptr.load());
241 void FileHandle_Impl::setPos(sal_uInt64 uPos)
243 m_fileptr = sal::static_int_cast< off_t >(uPos);
246 sal_uInt64 FileHandle_Impl::getSize() const
248 off_t const bufend = std::max(off_t(0), m_bufptr) + m_buflen;
249 return std::max(m_size, sal::static_int_cast< sal_uInt64 >(bufend));
252 oslFileError FileHandle_Impl::setSize(sal_uInt64 uSize)
254 off_t const nSize = sal::static_int_cast< off_t >(uSize);
255 if (ftruncate_with_name(m_fd, nSize, m_strFilePath) == -1)
257 /* Failure. Save original result. Try fallback algorithm */
258 oslFileError result = oslTranslateFileError(errno);
260 /* Check against current size. Fail upon 'shrink' */
261 if (uSize <= getSize())
263 /* Failure upon 'shrink'. Return original result */
264 return result;
267 /* Save current position */
268 off_t const nCurPos = lseek(m_fd, off_t(0), SEEK_CUR);
269 if (nCurPos == off_t(-1))
271 int e = errno;
272 SAL_INFO("sal.file", "lseek(" << m_fd << ",0,SEEK_CUR): " << UnixErrnoString(e));
273 return result;
275 else
276 SAL_INFO("sal.file", "lseek(" << m_fd << ",0,SEEK_CUR): OK");
278 /* Try 'expand' via 'lseek()' and 'write()' */
279 if (lseek(m_fd, static_cast<off_t>(nSize - 1), SEEK_SET) == -1)
281 int e = errno;
282 SAL_INFO("sal.file", "lseek(" << m_fd << "," << nSize - 1 << ",SEEK_SET): " << UnixErrnoString(e));
283 return result;
285 else
286 SAL_INFO("sal.file", "lseek(" << m_fd << "," << nSize - 1 << ",SEEK_SET): OK");
288 if (write(m_fd, "", size_t(1)) == -1)
290 /* Failure. Restore saved position */
291 int e = errno;
292 SAL_INFO("sal.file", "write(" << m_fd << ",\"\",1): " << UnixErrnoString(e));
293 (void) lseek(m_fd, nCurPos, SEEK_SET);
294 return result;
296 else
297 SAL_INFO("sal.file", "write(" << m_fd << ",\"\",1): OK");
299 /* Success. Restore saved position */
300 if (lseek(m_fd, nCurPos, SEEK_SET) == -1)
301 return result;
304 m_size = sal::static_int_cast< sal_uInt64 >(nSize);
305 return osl_File_E_None;
308 oslFileError FileHandle_Impl::readAt(
309 off_t nOffset,
310 void * pBuffer,
311 size_t nBytesRequested,
312 sal_uInt64 * pBytesRead)
314 SAL_WARN_IF(!(m_state & State::Seekable), "sal.osl", "FileHandle_Impl::readAt(): not seekable");
315 if (!(m_state & State::Seekable))
316 return osl_File_E_SPIPE;
318 SAL_WARN_IF(!(m_state & State::Readable), "sal.osl", "FileHandle_Impl::readAt(): not readable");
319 if (!(m_state & State::Readable))
320 return osl_File_E_BADF;
322 if (m_kind == KIND_MEM)
324 ssize_t nBytes;
326 m_offset = nOffset;
328 if (o3tl::make_unsigned(m_offset) >= m_size)
330 nBytes = 0;
332 else
334 nBytes = std::min(nBytesRequested, static_cast<size_t>(m_size - m_offset));
335 memmove(pBuffer, m_buffer + m_offset, nBytes);
336 m_offset += nBytes;
338 *pBytesRead = nBytes;
339 return osl_File_E_None;
342 ssize_t nBytes = ::pread(m_fd, pBuffer, nBytesRequested, nOffset);
343 if ((nBytes == -1) && (errno == EOVERFLOW))
345 /* Some 'pread()'s fail with EOVERFLOW when reading at (or past)
346 * end-of-file, different from 'lseek() + read()' behaviour.
347 * Returning '0 bytes read' and 'osl_File_E_None' instead.
349 nBytes = 0;
352 if (nBytes == -1)
353 return oslTranslateFileError(errno);
355 *pBytesRead = nBytes;
357 return osl_File_E_None;
360 oslFileError FileHandle_Impl::writeAt(
361 off_t nOffset,
362 void const * pBuffer,
363 size_t nBytesToWrite,
364 sal_uInt64 * pBytesWritten)
366 SAL_WARN_IF(!(m_state & State::Seekable), "sal.osl", "FileHandle_Impl::writeAt(): not seekable");
367 if (!(m_state & State::Seekable))
368 return osl_File_E_SPIPE;
370 SAL_WARN_IF(!(m_state & State::Writeable), "sal.osl", "FileHandle_Impl::writeAt(): not writeable");
371 if (!(m_state & State::Writeable))
372 return osl_File_E_BADF;
374 ssize_t nBytes = ::pwrite(m_fd, pBuffer, nBytesToWrite, nOffset);
375 if (nBytes == -1)
376 return oslTranslateFileError(errno);
378 m_size = std::max(m_size, sal::static_int_cast< sal_uInt64 >(nOffset + nBytes));
380 *pBytesWritten = nBytes;
382 return osl_File_E_None;
385 oslFileError FileHandle_Impl::readFileAt(
386 off_t nOffset,
387 void* pBuffer,
388 size_t nBytesRequested,
389 sal_uInt64* pBytesRead)
391 if (!(m_state & State::Seekable))
393 // not seekable (pipe)
394 ssize_t nBytes = ::read(m_fd, pBuffer, nBytesRequested);
395 if (nBytes == -1)
396 return oslTranslateFileError(errno);
398 *pBytesRead = nBytes;
400 return osl_File_E_None;
403 if (m_kind == KIND_MEM || !m_buffer)
405 // not buffered
406 return readAt(nOffset, pBuffer, nBytesRequested, pBytesRead);
409 sal_uInt8 *buffer = static_cast<sal_uInt8*>(pBuffer);
410 for (*pBytesRead = 0; nBytesRequested > 0; )
412 off_t const bufptr = (nOffset / m_bufsiz) * m_bufsiz;
413 size_t const bufpos = nOffset % m_bufsiz;
415 if (bufptr != m_bufptr)
417 // flush current buffer
418 oslFileError result = syncFile();
419 if (result != osl_File_E_None)
420 return result;
422 m_bufptr = -1;
423 m_buflen = 0;
425 if (nBytesRequested >= m_bufsiz)
427 // buffer too small, read through from file
428 sal_uInt64 uDone = 0;
429 result = readAt(nOffset, &(buffer[*pBytesRead]), nBytesRequested, &uDone);
430 if (result != osl_File_E_None)
431 return result;
433 *pBytesRead += uDone;
435 return osl_File_E_None;
438 // update buffer (pointer)
439 sal_uInt64 uDone = 0;
440 result = readAt(bufptr, m_buffer, m_bufsiz, &uDone);
441 if (result != osl_File_E_None)
442 return result;
444 m_bufptr = bufptr;
445 m_buflen = uDone;
448 if (bufpos >= m_buflen)
450 // end of file
451 return osl_File_E_None;
454 size_t const bytes = std::min(m_buflen - bufpos, nBytesRequested);
455 SAL_INFO("sal.fileio", "FileHandle_Impl::readFileAt(" << m_fd << ", " << nOffset << ", " << bytes << ")");
457 memcpy(&(buffer[*pBytesRead]), &(m_buffer[bufpos]), bytes);
458 nBytesRequested -= bytes;
459 *pBytesRead += bytes;
460 nOffset += bytes;
463 return osl_File_E_None;
466 oslFileError FileHandle_Impl::writeFileAt(
467 off_t nOffset,
468 void const * pBuffer,
469 size_t nBytesToWrite,
470 sal_uInt64 * pBytesWritten)
472 if (!(m_state & State::Seekable))
474 // not seekable (pipe)
475 ssize_t nBytes = ::write(m_fd, pBuffer, nBytesToWrite);
476 if (nBytes == -1)
477 return oslTranslateFileError(errno);
479 *pBytesWritten = nBytes;
481 return osl_File_E_None;
483 if (!m_buffer)
485 // not buffered
486 return writeAt(nOffset, pBuffer, nBytesToWrite, pBytesWritten);
489 sal_uInt8 const * buffer = static_cast<sal_uInt8 const *>(pBuffer);
490 for (*pBytesWritten = 0; nBytesToWrite > 0;)
492 off_t const bufptr = (nOffset / m_bufsiz) * m_bufsiz;
493 size_t const bufpos = nOffset % m_bufsiz;
494 if (bufptr != m_bufptr)
496 // flush current buffer
497 oslFileError result = syncFile();
498 if (result != osl_File_E_None)
499 return result;
500 m_bufptr = -1;
501 m_buflen = 0;
503 if (nBytesToWrite >= m_bufsiz)
505 // buffer too small, write through to file
506 sal_uInt64 uDone = 0;
507 result = writeAt(nOffset, &(buffer[*pBytesWritten]), nBytesToWrite, &uDone);
508 if (result != osl_File_E_None)
509 return result;
511 if (uDone != nBytesToWrite)
512 return osl_File_E_IO;
514 *pBytesWritten += uDone;
516 return osl_File_E_None;
519 // update buffer (pointer)
520 sal_uInt64 uDone = 0;
521 result = readAt(bufptr, m_buffer, m_bufsiz, &uDone);
522 if (result != osl_File_E_None)
523 return result;
525 m_bufptr = bufptr;
526 m_buflen = uDone;
529 size_t const bytes = std::min(m_bufsiz - bufpos, nBytesToWrite);
530 SAL_INFO("sal.fileio", "FileHandle_Impl::writeFileAt(" << m_fd << ", " << nOffset << ", " << bytes << ")");
532 memcpy(&(m_buffer[bufpos]), &(buffer[*pBytesWritten]), bytes);
533 nBytesToWrite -= bytes;
534 *pBytesWritten += bytes;
535 nOffset += bytes;
537 m_buflen = std::max(m_buflen, bufpos + bytes);
538 m_state |= State::Modified;
541 return osl_File_E_None;
544 oslFileError FileHandle_Impl::readLineAt(
545 off_t nOffset,
546 sal_Sequence ** ppSequence,
547 sal_uInt64 * pBytesRead)
549 oslFileError result = osl_File_E_None;
551 off_t bufptr = nOffset / m_bufsiz * m_bufsiz;
552 if (bufptr != m_bufptr)
554 /* flush current buffer */
555 result = syncFile();
556 if (result != osl_File_E_None)
557 return result;
559 /* update buffer (pointer) */
560 sal_uInt64 uDone = 0;
561 result = readAt(bufptr, m_buffer, m_bufsiz, &uDone);
562 if (result != osl_File_E_None)
563 return result;
565 m_bufptr = bufptr;
566 m_buflen = uDone;
569 static int const LINE_STATE_BEGIN = 0;
570 static int const LINE_STATE_CR = 1;
571 static int const LINE_STATE_LF = 2;
573 size_t bufpos = nOffset - m_bufptr, curpos = bufpos, dstpos = 0;
574 int state = (bufpos >= m_buflen) ? LINE_STATE_LF : LINE_STATE_BEGIN;
576 while (state != LINE_STATE_LF)
578 if (curpos >= m_buflen)
580 /* buffer examined */
581 if (curpos > bufpos)
583 /* flush buffer to sequence */
584 result = writeSequence_Impl(
585 ppSequence, &dstpos, &(m_buffer[bufpos]), curpos - bufpos);
586 if (result != osl_File_E_None)
587 return result;
589 *pBytesRead += curpos - bufpos;
590 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;
602 m_bufptr = bufptr;
603 m_buflen = uDone;
606 bufpos = nOffset - m_bufptr;
607 curpos = bufpos;
608 if (bufpos >= m_buflen)
609 break;
612 switch (state)
614 case LINE_STATE_CR:
615 state = LINE_STATE_LF;
616 switch (m_buffer[curpos])
618 case 0x0A: /* CRLF */
619 /* eat current char */
620 curpos++;
621 break;
622 default: /* single CR */
623 /* keep current char */
624 break;
626 break;
627 default:
628 /* determine next state */
629 switch (m_buffer[curpos])
631 case 0x0A: /* single LF */
632 state = LINE_STATE_LF;
633 break;
634 case 0x0D: /* CR */
635 state = LINE_STATE_CR;
636 break;
637 default: /* advance to next char */
638 curpos++;
639 break;
641 if (state != LINE_STATE_BEGIN)
643 /* skip the newline char */
644 curpos++;
646 /* flush buffer to sequence */
647 result = writeSequence_Impl(
648 ppSequence, &dstpos, &(m_buffer[bufpos]), curpos - bufpos - 1);
649 if (result != osl_File_E_None)
650 return result;
652 *pBytesRead += curpos - bufpos;
653 nOffset += curpos - bufpos;
655 break;
659 result = writeSequence_Impl(ppSequence, &dstpos, nullptr, 0);
660 if (result != osl_File_E_None)
661 return result;
663 if (dstpos > 0)
664 return osl_File_E_None;
666 if (bufpos >= m_buflen)
667 return osl_File_E_AGAIN;
669 return osl_File_E_None;
672 oslFileError FileHandle_Impl::writeSequence_Impl(
673 sal_Sequence ** ppSequence,
674 size_t * pnOffset,
675 const void * pBuffer,
676 size_t nBytes)
678 sal_Int32 nElements = *pnOffset + nBytes;
679 if (!*ppSequence)
681 /* construct sequence */
682 rtl_byte_sequence_constructNoDefault(ppSequence, nElements);
684 else if (nElements != (*ppSequence)->nElements)
686 /* resize sequence */
687 rtl_byte_sequence_realloc(ppSequence, nElements);
690 if (*ppSequence && nBytes != 0)
692 /* fill sequence */
693 memcpy(&((*ppSequence)->elements[*pnOffset]), pBuffer, nBytes);
694 *pnOffset += nBytes;
697 return (*ppSequence) ? osl_File_E_None : osl_File_E_NOMEM;
700 oslFileError FileHandle_Impl::syncFile()
702 oslFileError result = osl_File_E_None;
703 if (m_state & State::Modified)
705 sal_uInt64 uDone = 0;
706 result = writeAt(m_bufptr, m_buffer, m_buflen, &uDone);
707 if (result != osl_File_E_None)
708 return result;
710 if (uDone != m_buflen)
711 return osl_File_E_IO;
713 m_state &= ~State::Modified;
716 return result;
719 oslFileHandle osl::detail::createFileHandleFromFD(int fd)
721 if (fd == -1)
722 return nullptr; // EINVAL
724 struct stat aFileStat;
725 if (fstat(fd, &aFileStat) == -1)
726 return nullptr; // EBADF
728 FileHandle_Impl *pImpl = new FileHandle_Impl(fd);
730 // assume writeable
731 pImpl->m_state |= State::Writeable;
732 if (!S_ISREG(aFileStat.st_mode))
734 /* not a regular file, mark not seekable */
735 pImpl->m_state &= ~State::Seekable;
737 else
739 /* regular file, init current size */
740 pImpl->m_size = sal::static_int_cast< sal_uInt64 >(aFileStat.st_size);
743 SAL_INFO("sal.file", "osl::detail::createFileHandleFromFD(" << pImpl->m_fd << ", writeable) => " << pImpl->m_strFilePath);
745 return static_cast<oslFileHandle>(pImpl);
748 static void osl_file_adjustLockFlags(const OString& path, int *flags, sal_uInt32 *uFlags)
750 #ifdef MACOSX
751 (void) uFlags;
754 * The AFP implementation of MacOS X 10.4 treats O_EXLOCK in a way
755 * that makes it impossible for OOo to create a backup copy of the
756 * file it keeps opened. OTOH O_SHLOCK for AFP behaves as desired by
757 * the OOo file handling, so we need to check the path of the file
758 * for the filesystem name.
760 struct statfs s;
761 if(statfs(path.getStr(), &s) >= 0)
763 if(strncmp("afpfs", s.f_fstypename, 5) == 0)
765 *flags &= ~O_EXLOCK;
766 *flags |= O_SHLOCK;
768 else
770 /* Needed flags to allow opening a webdav file */
771 *flags &= ~(O_EXLOCK | O_SHLOCK | O_NONBLOCK);
774 #elif defined(LINUX)
775 (void) flags;
777 /* get filesystem info */
778 struct statfs aFileStatFs;
779 if (statfs(path.getStr(), &aFileStatFs) < 0)
781 int e = errno;
782 SAL_INFO("sal.file", "statfs(" << path << "): " << UnixErrnoString(e));
784 else
786 SAL_INFO("sal.file", "statfs(" << path << "): OK");
788 // We avoid locking if on a Linux CIFS mount otherwise this
789 // fill fail later on when opening the file for reading
790 // during backup creation at save time (even though this is a
791 // write lock and not a read lock).
792 // Fixes the following bug:
793 // https://bugs.documentfoundation.org/show_bug.cgi?id=55004
794 switch (aFileStatFs.f_type) {
795 case SMB_SUPER_MAGIC:
796 case CIFS_SUPER_MAGIC:
797 case SMB2_SUPER_MAGIC:
798 *uFlags |= osl_File_OpenFlag_NoLock;
799 break;
800 default:
801 break;
804 #else
805 (void) path;
806 (void) flags;
807 (void) uFlags;
808 #endif
811 static bool osl_file_queryLocking(sal_uInt32 uFlags)
813 #if !defined HAVE_O_EXLOCK
814 if (!(uFlags & osl_File_OpenFlag_NoLock)
815 && ((uFlags & osl_File_OpenFlag_Write)
816 || (uFlags & osl_File_OpenFlag_Create)))
818 static bool enabled = getenv("SAL_ENABLE_FILE_LOCKING") != nullptr;
819 // getenv is not thread safe, so minimize use of result
820 return enabled;
822 #else
823 (void) uFlags;
824 #endif
825 return false;
828 #ifdef HAVE_O_EXLOCK
829 #define OPEN_WRITE_FLAGS ( O_RDWR | O_EXLOCK | O_NONBLOCK )
830 #define OPEN_CREATE_FLAGS ( O_CREAT | O_RDWR | O_EXLOCK | O_NONBLOCK )
831 #else
832 #define OPEN_WRITE_FLAGS ( O_RDWR )
833 #define OPEN_CREATE_FLAGS ( O_CREAT | O_RDWR )
834 #endif
836 #if defined ANDROID
838 namespace {
840 static oslFileError openMemoryAsFile(const OString &rData,
841 oslFileHandle *pHandle,
842 const OString& path)
844 const char *address = rData.getStr();
845 size_t size = rData.getLength();
847 FileHandle_Impl *pImpl = new FileHandle_Impl(-1, FileHandle_Impl::KIND_MEM, path);
848 pImpl->m_size = sal::static_int_cast< sal_uInt64 >(size);
850 *pHandle = (oslFileHandle)(pImpl);
852 pImpl->m_bufptr = 0;
853 pImpl->m_buflen = size;
854 pImpl->m_memstreambuf = rData.pData;
855 rtl_string_acquire(pImpl->m_memstreambuf);
857 pImpl->m_bufsiz = size;
858 pImpl->m_buffer = reinterpret_cast<sal_uInt8*>(const_cast<char *>(address));
860 return osl_File_E_None;
864 * Reading files from /assets/ on Android via a transition into the VM
865 * shows on profiles and is rather slow; so we cache small files as
866 * used by UNO, UI-builder etc.
868 class AndroidFileCache {
869 public:
870 struct Entry {
871 OString maFilePath;
872 OString maData;
874 AndroidFileCache(size_t nElements)
875 : mnCur(0)
877 maEntries.resize(nElements);
878 assert (maEntries.size() == nElements);
880 Entry *find(const char *cpFilePath)
882 for (auto &it : maEntries)
884 if (!strcmp(it.maFilePath.getStr(), cpFilePath))
885 return &it;
887 return nullptr;
889 // no clever LRU - but - good enough for now.
890 void insert(const char *cpFilePath, OString &rData)
892 assert (maEntries.size() > 0);
893 if (++mnCur >= maEntries.size())
894 mnCur = 0;
895 maEntries[mnCur].maFilePath = OString(cpFilePath, strlen(cpFilePath));
896 maEntries[mnCur].maData = rData;
898 static AndroidFileCache &getHitCache()
900 static AndroidFileCache *pCache = new AndroidFileCache(16);
901 return *pCache;
903 static AndroidFileCache &getMissCache()
905 static AndroidFileCache *pCache = new AndroidFileCache(32);
906 return *pCache;
908 private:
909 size_t mnCur;
910 std::vector<Entry> maEntries;
913 } // namespace
915 #endif
917 oslFileError openFilePath(const OString& filePath, oslFileHandle* pHandle,
918 sal_uInt32 uFlags, mode_t mode)
920 oslFileError eRet;
922 #ifdef ANDROID
923 /* Opening a file from /assets read-only means
924 * we should mmap it from the .apk file
926 if (o3tl::starts_with(filePath, "/assets/"))
928 OString aData;
929 bool bCache = true;
931 const char *cpAssetsPath = filePath.getStr() + sizeof("/assets/") - 1;
932 // some requests are /assets//foo...
933 if (cpAssetsPath[0] == '/')
935 __android_log_print(ANDROID_LOG_DEBUG,"libo:sal/osl/unx/file", "double-slash in path: %s", filePath.getStr());
936 cpAssetsPath++;
939 AndroidFileCache::Entry *pHit = AndroidFileCache::getHitCache().find(cpAssetsPath);
940 if (pHit)
941 aData = pHit->maData;
943 else
945 bCache = false;
946 AndroidFileCache::Entry *pMiss = AndroidFileCache::getMissCache().find(cpAssetsPath);
947 if (pMiss)
949 errno = ENOENT;
950 __android_log_print(ANDROID_LOG_ERROR,"libo:sal/osl/unx/file", "miss cache: failed to open %s", filePath.getStr());
951 return osl_File_E_NOENT;
953 AAssetManager* mgr = lo_get_native_assetmgr();
954 AAsset* asset = AAssetManager_open(mgr, cpAssetsPath, AASSET_MODE_BUFFER);
955 if (!asset)
957 AndroidFileCache::getMissCache().insert(cpAssetsPath, aData);
958 errno = ENOENT;
959 __android_log_print(ANDROID_LOG_ERROR,"libo:sal/osl/unx/file", "failed to open %s", filePath.getStr());
960 return osl_File_E_NOENT;
962 else
964 rtl_String *pData = nullptr;
965 size_t size = AAsset_getLength(asset);
966 rtl_string_new_WithLength(&pData, size);
967 pData->length = size;
968 AAsset_read(asset, pData->buffer, size);
969 AAsset_close(asset);
971 aData = OString(pData, SAL_NO_ACQUIRE);
973 if (pData->length < 50 * 1024)
974 AndroidFileCache::getHitCache().insert(cpAssetsPath, aData);
978 if (uFlags & osl_File_OpenFlag_Write)
980 // It seems to work better to silently "open" it read-only
981 // and let write attempts, if any, fail later. Otherwise
982 // loading a document from /assets fails with that idiotic
983 // "General Error" dialog...
985 SAL_INFO("sal.file", "osl_openFile(" << filePath << ") => '" << cpAssetsPath << "'"
986 << aData.getLength() << " bytes from file " << (bCache ? "cache" : "system"));
987 return openMemoryAsFile(aData, pHandle, filePath);
989 #endif
991 /* set mode and flags */
992 int defmode = (uFlags & osl_File_OpenFlag_Private) ? S_IRUSR : S_IRUSR | S_IRGRP | S_IROTH;
993 int flags = O_RDONLY;
995 if (uFlags & osl_File_OpenFlag_Write)
997 defmode |= (uFlags & osl_File_OpenFlag_Private) ? S_IWUSR : S_IWUSR | S_IWGRP | S_IWOTH;
998 flags = OPEN_WRITE_FLAGS;
1001 if (uFlags & osl_File_OpenFlag_Create)
1003 defmode |= (uFlags & osl_File_OpenFlag_Private) ? S_IWUSR : S_IWUSR | S_IWGRP | S_IWOTH;
1004 flags = OPEN_CREATE_FLAGS;
1007 if (mode == mode_t(-1))
1008 mode = defmode;
1010 /* Check for flags passed in from SvFileStream::Open() */
1011 if (uFlags & osl_File_OpenFlag_Trunc)
1012 flags |= O_TRUNC;
1014 if (!(uFlags & osl_File_OpenFlag_NoExcl))
1015 flags |= O_EXCL;
1017 if (uFlags & osl_File_OpenFlag_NoLock)
1019 #ifdef HAVE_O_EXLOCK
1020 flags &= ~(O_EXLOCK | O_SHLOCK | O_NONBLOCK);
1021 #endif /* HAVE_O_EXLOCK */
1023 else
1025 osl_file_adjustLockFlags (filePath, &flags, &uFlags);
1028 // O_EXCL can be set only when O_CREAT is set
1029 if (flags & O_EXCL && !(flags & O_CREAT))
1030 flags &= ~O_EXCL;
1032 // set close-on-exec by default
1033 flags |= O_CLOEXEC;
1035 /* open the file */
1036 int fd = open_c( filePath, flags, mode );
1037 if (fd == -1)
1039 return oslTranslateFileError(errno);
1042 #if !HAVE_FEATURE_MACOSX_SANDBOX
1043 /* reset O_NONBLOCK flag */
1044 if (flags & O_NONBLOCK)
1046 int f = fcntl(fd, F_GETFL, 0);
1047 if (f == -1)
1049 int e = errno;
1050 SAL_INFO("sal.file", "fcntl(" << fd << ",F_GETFL,0): " << UnixErrnoString(e));
1051 eRet = oslTranslateFileError(e);
1052 (void) close(fd);
1053 SAL_INFO("sal.file", "close(" << fd << ")");
1054 return eRet;
1056 else
1057 SAL_INFO("sal.file", "fcntl(" << fd << ",F_GETFL,0): OK");
1059 if (fcntl(fd, F_SETFL, (f & ~O_NONBLOCK)) == -1)
1061 int e = errno;
1062 SAL_INFO("sal.file", "fcntl(" << fd << ",F_SETFL,(f & ~O_NONBLOCK)): " << UnixErrnoString(e));
1063 eRet = oslTranslateFileError(e);
1064 (void) close(fd);
1065 SAL_INFO("sal.file", "close(" << fd << ")");
1066 return eRet;
1068 else
1069 SAL_INFO("sal.file", "fcntl(" << fd << ",F_SETFL,(f & ~O_NONBLOCK)): OK");
1071 #endif
1073 /* get file status (mode, size) */
1074 struct stat aFileStat;
1075 if (fstat(fd, &aFileStat) == -1)
1077 int e = errno;
1078 SAL_INFO("sal.file", "fstat(" << fd << "): " << UnixErrnoString(e));
1079 eRet = oslTranslateFileError(e);
1080 (void) close(fd);
1081 SAL_INFO("sal.file", "close(" << fd << ")");
1082 return eRet;
1084 else
1085 SAL_INFO("sal.file", "fstat(" << fd << "): OK");
1087 if (!S_ISREG(aFileStat.st_mode))
1089 /* we only open regular files here */
1090 SAL_INFO("sal.file", "osl_openFile(" << filePath << "): not a regular file");
1091 (void) close(fd);
1092 SAL_INFO("sal.file", "close(" << fd << ")");
1093 return osl_File_E_INVAL;
1096 if (osl_file_queryLocking(uFlags))
1098 #ifdef MACOSX
1099 if (flock(fd, LOCK_EX | LOCK_NB) == -1)
1101 int e = errno;
1102 SAL_INFO("sal.file", "flock(" << fd << ",LOCK_EX|LOCK_NB): " << UnixErrnoString(e));
1103 /* Mac OSX returns ENOTSUP for webdav drives. We should try read lock */
1105 // Restore errno after possibly having been overwritten by the SAL_INFO above...
1106 errno = e;
1107 if ((errno != ENOTSUP) || ((flock(fd, LOCK_SH | LOCK_NB) == 1) && (errno != ENOTSUP)))
1109 eRet = oslTranslateFileError(errno);
1110 (void) close(fd);
1111 SAL_INFO("sal.file", "close(" << fd << ")");
1112 return eRet;
1115 else
1116 SAL_INFO("sal.file", "flock(" << fd << ",LOCK_EX|LOCK_NB): OK");
1117 #else /* F_SETLK */
1118 struct flock aflock;
1120 aflock.l_type = F_WRLCK;
1121 aflock.l_whence = SEEK_SET;
1122 aflock.l_start = 0;
1123 aflock.l_len = 0;
1125 if (fcntl(fd, F_SETLK, &aflock) == -1)
1127 int e = errno;
1128 SAL_INFO("sal.file", "fcntl(" << fd << ",F_SETLK): " << UnixErrnoString(e));
1129 eRet = oslTranslateFileError(e);
1130 (void) close(fd);
1131 SAL_INFO("sal.file", "close(" << fd << ")");
1132 return eRet;
1134 #endif /* F_SETLK */
1137 /* allocate memory for impl structure */
1138 FileHandle_Impl *pImpl = new FileHandle_Impl(fd, FileHandle_Impl::KIND_FD, filePath);
1139 if (flags & O_RDWR)
1140 pImpl->m_state |= State::Writeable;
1142 pImpl->m_size = sal::static_int_cast< sal_uInt64 >(aFileStat.st_size);
1144 *pHandle = static_cast<oslFileHandle>(pImpl);
1146 return osl_File_E_None;
1149 oslFileError SAL_CALL osl_openFile(rtl_uString* ustrFileURL, oslFileHandle* pHandle, sal_uInt32 uFlags)
1151 return openFile(ustrFileURL, pHandle, uFlags, mode_t(-1));
1154 oslFileError openFile(rtl_uString* ustrFileURL, oslFileHandle* pHandle, sal_uInt32 uFlags, mode_t mode)
1156 oslFileError eRet;
1158 if ((!ustrFileURL) || (ustrFileURL->length == 0) || (!pHandle))
1159 return osl_File_E_INVAL;
1161 /* convert file URL to system path */
1162 char buffer[PATH_MAX];
1163 eRet = FileURLToPath(buffer, sizeof(buffer), ustrFileURL);
1164 if (eRet != osl_File_E_None)
1165 return eRet;
1167 #ifdef MACOSX
1168 if (macxp_resolveAlias(buffer, sizeof(buffer)) != 0)
1169 return oslTranslateFileError(errno);
1170 #endif /* MACOSX */
1172 return openFilePath(buffer, pHandle, uFlags, mode);
1175 oslFileError SAL_CALL osl_closeFile(oslFileHandle Handle)
1177 FileHandle_Impl* pImpl = static_cast< FileHandle_Impl* >(Handle);
1179 if (!pImpl)
1180 return osl_File_E_INVAL;
1182 if (pImpl->m_kind == FileHandle_Impl::KIND_MEM)
1184 #ifdef ANDROID
1185 rtl_string_release(pImpl->m_memstreambuf);
1186 pImpl->m_memstreambuf = nullptr;
1188 pImpl->m_buffer = NULL;
1189 #endif
1190 delete pImpl;
1191 return osl_File_E_None;
1194 if (pImpl->m_fd < 0)
1195 return osl_File_E_INVAL;
1197 (void) pthread_mutex_lock(&(pImpl->m_mutex));
1199 /* close(2) implicitly (and unconditionally) unlocks */
1200 oslFileError result = pImpl->syncFile();
1201 if (result != osl_File_E_None)
1203 /* close, ignoring double failure */
1204 (void) close(pImpl->m_fd);
1205 SAL_INFO("sal.file", "close(" << pImpl->m_fd << ")");
1207 else if (close(pImpl->m_fd) == -1)
1209 int e = errno;
1210 SAL_INFO("sal.file", "close(" << pImpl->m_fd << "): " << UnixErrnoString(e));
1211 /* translate error code */
1212 result = oslTranslateFileError(e);
1214 else
1215 SAL_INFO("sal.file", "close(" << pImpl->m_fd << "): OK");
1217 (void) pthread_mutex_unlock(&(pImpl->m_mutex));
1218 delete pImpl;
1219 return result;
1222 oslFileError SAL_CALL osl_syncFile(oslFileHandle Handle)
1224 FileHandle_Impl* pImpl = static_cast<FileHandle_Impl*>(Handle);
1226 if ((!pImpl) || ((pImpl->m_kind == FileHandle_Impl::KIND_FD) && (pImpl->m_fd == -1)))
1227 return osl_File_E_INVAL;
1229 if (pImpl->m_kind == FileHandle_Impl::KIND_MEM)
1230 return osl_File_E_None;
1232 FileHandle_Impl::Guard lock(&(pImpl->m_mutex));
1234 oslFileError result = pImpl->syncFile();
1236 if (result != osl_File_E_None)
1237 return result;
1239 static bool disabled = getenv("SAL_DISABLE_FSYNC") != nullptr;
1241 if (disabled)
1242 SAL_INFO("sal.file", "fsync(" << pImpl->m_fd << "): Disabled");
1243 else if (fsync(pImpl->m_fd) == -1)
1245 int e = errno;
1246 SAL_INFO("sal.file", "fsync(" << pImpl->m_fd << "): " << UnixErrnoString(e));
1247 return oslTranslateFileError(e);
1249 else
1250 SAL_INFO("sal.file", "fsync(" << pImpl->m_fd << "): OK");
1252 return osl_File_E_None;
1255 const off_t MAX_OFF_T = std::numeric_limits< off_t >::max();
1257 namespace {
1259 // coverity[result_independent_of_operands] - crossplatform requirement
1260 template<typename T> bool exceedsMaxOffT(T n) { return n > MAX_OFF_T; }
1262 // coverity[result_independent_of_operands] - crossplatform requirement
1263 template<typename T> bool exceedsMinOffT(T n)
1264 { return n < std::numeric_limits<off_t>::min(); }
1268 oslFileError SAL_CALL osl_mapFile(
1269 oslFileHandle Handle,
1270 void** ppAddr,
1271 sal_uInt64 uLength,
1272 sal_uInt64 uOffset,
1273 sal_uInt32 uFlags
1276 FileHandle_Impl* pImpl = static_cast< FileHandle_Impl* >(Handle);
1278 if ((!pImpl) || ((pImpl->m_kind == FileHandle_Impl::KIND_FD) && (pImpl->m_fd == -1)) || (!ppAddr))
1279 return osl_File_E_INVAL;
1281 *ppAddr = nullptr;
1283 if (uLength > SAL_MAX_SIZE)
1284 return osl_File_E_OVERFLOW;
1286 size_t const nLength = sal::static_int_cast< size_t >(uLength);
1288 if (exceedsMaxOffT(uOffset))
1289 return osl_File_E_OVERFLOW;
1291 if (pImpl->m_kind == FileHandle_Impl::KIND_MEM)
1293 *ppAddr = pImpl->m_buffer + uOffset;
1294 return osl_File_E_None;
1297 off_t const nOffset = sal::static_int_cast< off_t >(uOffset);
1299 void* p = mmap(nullptr, nLength, PROT_READ, MAP_SHARED, pImpl->m_fd, nOffset);
1301 if (p == MAP_FAILED)
1302 return oslTranslateFileError(errno);
1304 *ppAddr = p;
1306 if (uFlags & osl_File_MapFlag_RandomAccess)
1308 // Determine memory pagesize.
1309 size_t const nPageSize = FileHandle_Impl::getpagesize();
1310 if (nPageSize != size_t(-1))
1313 * Pagein, touching first byte of every memory page.
1314 * Note: volatile disables optimizing the loop away.
1316 sal_uInt8 volatile *pData(static_cast<sal_uInt8*>(*ppAddr));
1317 size_t nSize(nLength);
1319 while (nSize > nPageSize)
1321 pData[0];
1322 pData += nPageSize;
1323 nSize -= nPageSize;
1326 if (nSize > 0)
1327 pData[0];
1331 if (uFlags & osl_File_MapFlag_WillNeed)
1333 // On Linux, madvise(..., MADV_WILLNEED) appears to have the undesirable
1334 // effect of not returning until the data has actually been paged in, so
1335 // that its net effect would typically be to slow down the process
1336 // (which could start processing at the beginning of the data while the
1337 // OS simultaneously pages in the rest); on other platforms, it remains
1338 // to be evaluated whether madvise or equivalent is available and
1339 // actually useful:
1340 #if defined MACOSX || (defined(__sun) && (!defined(__XOPEN_OR_POSIX) || defined(_XPG6) || defined(__EXTENSIONS__)))
1341 int e = posix_madvise(p, nLength, POSIX_MADV_WILLNEED);
1342 if (e != 0)
1343 SAL_INFO("sal.file", "posix_madvise(..., POSIX_MADV_WILLNEED) failed with " << e);
1345 #elif defined __sun
1346 if (madvise(static_cast< caddr_t >(p), nLength, MADV_WILLNEED) != 0)
1347 SAL_INFO("sal.file", "madvise(..., MADV_WILLNEED) failed with " << UnixErrnoString(errno));
1348 #endif
1351 return osl_File_E_None;
1354 static oslFileError unmapFile(void* pAddr, sal_uInt64 uLength)
1356 if (!pAddr)
1357 return osl_File_E_INVAL;
1359 if (uLength > SAL_MAX_SIZE)
1360 return osl_File_E_OVERFLOW;
1362 size_t const nLength = sal::static_int_cast< size_t >(uLength);
1364 if (munmap(pAddr, nLength) == -1)
1365 return oslTranslateFileError(errno);
1367 return osl_File_E_None;
1370 #ifndef ANDROID
1372 // Note that osl_unmapFile() just won't work on Android in general
1373 // where for (uncompressed) files inside the .apk, in the /assets
1374 // folder osl_mapFile just returns a pointer to the file inside the
1375 // already mmapped .apk archive.
1377 oslFileError SAL_CALL osl_unmapFile(void* pAddr, sal_uInt64 uLength)
1379 return unmapFile(pAddr, uLength);
1382 #endif
1384 oslFileError SAL_CALL osl_unmapMappedFile(oslFileHandle Handle, void* pAddr, sal_uInt64 uLength)
1386 FileHandle_Impl *pImpl = static_cast<FileHandle_Impl*>(Handle);
1388 if (!pImpl)
1389 return osl_File_E_INVAL;
1391 if (pImpl->m_kind == FileHandle_Impl::KIND_FD)
1392 return unmapFile(pAddr, uLength);
1394 // For parts of already mmapped "parent" files, whose mapping we
1395 // can't change, not much we can or should do...
1396 return osl_File_E_None;
1399 oslFileError SAL_CALL osl_readLine(
1400 oslFileHandle Handle,
1401 sal_Sequence ** ppSequence)
1403 FileHandle_Impl *pImpl = static_cast<FileHandle_Impl*>(Handle);
1405 if ((!pImpl) || ((pImpl->m_kind == FileHandle_Impl::KIND_FD) && (pImpl->m_fd == -1)) || (!ppSequence))
1406 return osl_File_E_INVAL;
1408 sal_uInt64 uBytesRead = 0;
1410 // read at current fileptr; fileptr += uBytesRead;
1411 FileHandle_Impl::Guard lock(&(pImpl->m_mutex));
1412 oslFileError result = pImpl->readLineAt(pImpl->m_fileptr, ppSequence, &uBytesRead);
1414 if (result == osl_File_E_None)
1415 pImpl->m_fileptr += uBytesRead;
1417 return result;
1420 oslFileError SAL_CALL osl_readFile(
1421 oslFileHandle Handle,
1422 void * pBuffer,
1423 sal_uInt64 uBytesRequested,
1424 sal_uInt64 * pBytesRead)
1426 FileHandle_Impl* pImpl = static_cast< FileHandle_Impl* >(Handle);
1428 if ((!pImpl) || ((pImpl->m_kind == FileHandle_Impl::KIND_FD) && (pImpl->m_fd == -1)) || (!pBuffer) || (!pBytesRead))
1429 return osl_File_E_INVAL;
1431 static sal_uInt64 const g_limit_ssize_t = std::numeric_limits< ssize_t >::max();
1432 if (g_limit_ssize_t < uBytesRequested)
1433 return osl_File_E_OVERFLOW;
1435 size_t const nBytesRequested = sal::static_int_cast< size_t >(uBytesRequested);
1437 // read at current fileptr; fileptr += *pBytesRead;
1438 FileHandle_Impl::Guard lock(&(pImpl->m_mutex));
1439 oslFileError result = pImpl->readFileAt(pImpl->m_fileptr, pBuffer, nBytesRequested, pBytesRead);
1441 if (result == osl_File_E_None)
1442 pImpl->m_fileptr += *pBytesRead;
1444 return result;
1447 oslFileError SAL_CALL osl_writeFile(
1448 oslFileHandle Handle,
1449 const void * pBuffer,
1450 sal_uInt64 uBytesToWrite,
1451 sal_uInt64 * pBytesWritten)
1453 FileHandle_Impl* pImpl = static_cast< FileHandle_Impl* >(Handle);
1455 if ((!pImpl) || (pImpl->m_fd == -1) || (!pBuffer) || (!pBytesWritten))
1456 return osl_File_E_INVAL;
1458 if (!(pImpl->m_state & State::Writeable))
1459 return osl_File_E_BADF;
1461 static sal_uInt64 const g_limit_ssize_t = std::numeric_limits< ssize_t >::max();
1462 if (g_limit_ssize_t < uBytesToWrite)
1463 return osl_File_E_OVERFLOW;
1465 size_t const nBytesToWrite = sal::static_int_cast< size_t >(uBytesToWrite);
1467 // write at current fileptr; fileptr += *pBytesWritten;
1468 FileHandle_Impl::Guard lock(&(pImpl->m_mutex));
1469 oslFileError result = pImpl->writeFileAt(pImpl->m_fileptr, pBuffer, nBytesToWrite, pBytesWritten);
1470 if (result == osl_File_E_None)
1471 pImpl->m_fileptr += *pBytesWritten;
1473 return result;
1476 oslFileError SAL_CALL osl_readFileAt(
1477 oslFileHandle Handle,
1478 sal_uInt64 uOffset,
1479 void* pBuffer,
1480 sal_uInt64 uBytesRequested,
1481 sal_uInt64* pBytesRead)
1483 FileHandle_Impl* pImpl = static_cast< FileHandle_Impl* >(Handle);
1485 if ((!pImpl) || ((pImpl->m_kind == FileHandle_Impl::KIND_FD) && (pImpl->m_fd == -1)) || (!pBuffer) || (!pBytesRead))
1486 return osl_File_E_INVAL;
1488 if (!(pImpl->m_state & State::Seekable))
1489 return osl_File_E_SPIPE;
1491 if (exceedsMaxOffT(uOffset))
1492 return osl_File_E_OVERFLOW;
1494 off_t const nOffset = sal::static_int_cast< off_t >(uOffset);
1496 static sal_uInt64 const g_limit_ssize_t = std::numeric_limits< ssize_t >::max();
1497 if (g_limit_ssize_t < uBytesRequested)
1498 return osl_File_E_OVERFLOW;
1500 size_t const nBytesRequested = sal::static_int_cast< size_t >(uBytesRequested);
1502 // read at specified fileptr
1503 FileHandle_Impl::Guard lock(&(pImpl->m_mutex));
1505 return pImpl->readFileAt(nOffset, pBuffer, nBytesRequested, pBytesRead);
1508 oslFileError SAL_CALL osl_writeFileAt(
1509 oslFileHandle Handle,
1510 sal_uInt64 uOffset,
1511 const void* pBuffer,
1512 sal_uInt64 uBytesToWrite,
1513 sal_uInt64* pBytesWritten)
1515 FileHandle_Impl* pImpl = static_cast<FileHandle_Impl*>(Handle);
1517 if ((!pImpl) || (pImpl->m_fd == -1) || (!pBuffer) || (!pBytesWritten))
1518 return osl_File_E_INVAL;
1520 if (!(pImpl->m_state & State::Seekable))
1521 return osl_File_E_SPIPE;
1523 if (!(pImpl->m_state & State::Writeable))
1524 return osl_File_E_BADF;
1526 if (exceedsMaxOffT(uOffset))
1527 return osl_File_E_OVERFLOW;
1529 off_t const nOffset = sal::static_int_cast< off_t >(uOffset);
1531 static sal_uInt64 const g_limit_ssize_t = std::numeric_limits< ssize_t >::max();
1532 if (g_limit_ssize_t < uBytesToWrite)
1533 return osl_File_E_OVERFLOW;
1535 size_t const nBytesToWrite = sal::static_int_cast< size_t >(uBytesToWrite);
1537 // write at specified fileptr
1538 FileHandle_Impl::Guard lock(&(pImpl->m_mutex));
1540 return pImpl->writeFileAt(nOffset, pBuffer, nBytesToWrite, pBytesWritten);
1543 oslFileError SAL_CALL osl_isEndOfFile(oslFileHandle Handle, sal_Bool *pIsEOF)
1545 FileHandle_Impl* pImpl = static_cast< FileHandle_Impl* >(Handle);
1547 if ((!pImpl) || ((pImpl->m_kind == FileHandle_Impl::KIND_FD) && (pImpl->m_fd == -1)) || (!pIsEOF))
1548 return osl_File_E_INVAL;
1550 FileHandle_Impl::Guard lock(&(pImpl->m_mutex));
1551 *pIsEOF = (pImpl->getPos() == pImpl->getSize());
1553 return osl_File_E_None;
1556 oslFileError SAL_CALL osl_getFilePos(oslFileHandle Handle, sal_uInt64* pPos)
1558 FileHandle_Impl* pImpl = static_cast< FileHandle_Impl* >(Handle);
1560 if ((!pImpl) || ((pImpl->m_kind == FileHandle_Impl::KIND_FD) && (pImpl->m_fd == -1)) || (!pPos))
1561 return osl_File_E_INVAL;
1563 // no need to lock because pos is atomic
1564 *pPos = pImpl->getPos();
1566 return osl_File_E_None;
1569 oslFileError SAL_CALL osl_setFilePos(oslFileHandle Handle, sal_uInt32 uHow, sal_Int64 uOffset)
1571 FileHandle_Impl* pImpl = static_cast< FileHandle_Impl* >(Handle);
1573 if ((!pImpl) || ((pImpl->m_kind == FileHandle_Impl::KIND_FD) && (pImpl->m_fd == -1)))
1574 return osl_File_E_INVAL;
1576 if (exceedsMaxOffT(uOffset) || exceedsMinOffT(uOffset))
1577 return osl_File_E_OVERFLOW;
1579 off_t nPos = 0, nOffset = sal::static_int_cast< off_t >(uOffset);
1581 FileHandle_Impl::Guard lock(&(pImpl->m_mutex));
1582 switch (uHow)
1584 case osl_Pos_Absolut:
1585 if (nOffset < 0)
1586 return osl_File_E_INVAL;
1587 break;
1589 case osl_Pos_Current:
1590 nPos = sal::static_int_cast< off_t >(pImpl->getPos());
1591 if ((nOffset < 0) && (nPos < -1*nOffset))
1592 return osl_File_E_INVAL;
1594 assert(nPos >= 0);
1595 if (nOffset > MAX_OFF_T - nPos)
1596 return osl_File_E_OVERFLOW;
1597 break;
1599 case osl_Pos_End:
1600 nPos = sal::static_int_cast< off_t >(pImpl->getSize());
1601 if ((nOffset < 0) && (nPos < -1*nOffset))
1602 return osl_File_E_INVAL;
1604 assert(nPos >= 0);
1605 if (nOffset > MAX_OFF_T - nPos)
1606 return osl_File_E_OVERFLOW;
1607 break;
1609 default:
1610 return osl_File_E_INVAL;
1613 pImpl->setPos(nPos + nOffset);
1614 return osl_File_E_None;
1617 oslFileError SAL_CALL osl_getFileSize(oslFileHandle Handle, sal_uInt64* pSize)
1619 FileHandle_Impl* pImpl = static_cast< FileHandle_Impl* >(Handle);
1621 if ((!pImpl) || ((pImpl->m_kind == FileHandle_Impl::KIND_FD) && (pImpl->m_fd == -1)) || (!pSize))
1622 return osl_File_E_INVAL;
1624 FileHandle_Impl::Guard lock(&(pImpl->m_mutex));
1625 *pSize = pImpl->getSize();
1627 return osl_File_E_None;
1630 oslFileError SAL_CALL osl_setFileSize(oslFileHandle Handle, sal_uInt64 uSize)
1632 FileHandle_Impl* pImpl = static_cast< FileHandle_Impl* >(Handle);
1634 if ((!pImpl) || (pImpl->m_fd == -1))
1635 return osl_File_E_INVAL;
1637 if (!(pImpl->m_state & State::Writeable))
1638 return osl_File_E_BADF;
1640 if (exceedsMaxOffT(uSize))
1641 return osl_File_E_OVERFLOW;
1643 oslFileError result = pImpl->syncFile();
1644 if (result != osl_File_E_None)
1645 return result;
1647 pImpl->m_bufptr = -1;
1648 pImpl->m_buflen = 0;
1650 return pImpl->setSize(uSize);
1653 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */