Avoid potential negative array index access to cached text.
[LibreOffice.git] / sal / osl / unx / file.cxx
bloba82a0bcf7f71db78213a36548ca45d2fbf6764b0
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>
27 #include <o3tl/string_view.hxx>
29 #include "system.hxx"
30 #include "createfilehandlefromfd.hxx"
31 #include "file_error_transl.hxx"
32 #include "file_impl.hxx"
33 #include "file_url.hxx"
34 #include "uunxapi.hxx"
35 #include "unixerrnostring.hxx"
37 #include <algorithm>
38 #include <atomic>
39 #include <vector>
40 #include <cassert>
41 #include <fcntl.h>
42 #include <limits>
43 #include <limits.h>
45 #include <string.h>
46 #include <pthread.h>
47 #include <sys/mman.h>
48 #include <sys/stat.h>
49 #include <unistd.h>
51 #if defined(MACOSX)
53 #include <sys/param.h>
54 #include <sys/mount.h>
55 #define HAVE_O_EXLOCK
57 #include <CoreFoundation/CoreFoundation.h>
59 #endif /* MACOSX */
61 #ifdef ANDROID
62 #include <osl/detail/android-bootstrap.h>
63 #include <android/log.h>
64 #include <android/asset_manager.h>
65 #include <o3tl/string_view.hxx>
66 #endif
68 #ifdef LINUX
69 #include <sys/vfs.h>
70 // As documented by the kernel
71 #define SMB_SUPER_MAGIC static_cast<__fsword_t>(0x517B)
72 #define CIFS_SUPER_MAGIC static_cast<__fsword_t>(0xFF534D42)
73 #define SMB2_SUPER_MAGIC static_cast<__fsword_t>(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) > 0)
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 static bool abortOnForbidden = false;
829 static std::vector<OString> allowedPathsRead;
830 static std::vector<OString> allowedPathsReadWrite;
831 static std::vector<OString> allowedPathsExecute;
833 static OString getParentFolder(std::string_view rFilePath)
835 sal_Int32 n = rFilePath.rfind('/');
836 OString folderPath;
837 if (n < 1)
838 folderPath = "."_ostr;
839 else
840 folderPath = OString(rFilePath.substr(0, n));
842 return folderPath;
845 SAL_DLLPUBLIC void osl_setAllowedPaths(
846 rtl_uString *pustrFilePaths
849 allowedPathsRead.clear();
850 allowedPathsReadWrite.clear();
851 allowedPathsExecute.clear();
853 if (!pustrFilePaths)
854 return;
856 char eType = 'r';
857 sal_Int32 nIndex = 0;
858 OUString aPaths(pustrFilePaths);
861 OString aPath = rtl::OUStringToOString(
862 o3tl::getToken(aPaths, 0, ':', nIndex),
863 RTL_TEXTENCODING_UTF8);
865 if (aPath.getLength() == 0)
866 continue;
868 if (aPath.getLength() == 1)
870 eType = aPath[0];
871 continue;
874 char resolvedPath[PATH_MAX];
875 bool isResolved = !!realpath(aPath.getStr(), resolvedPath);
876 bool notExists = !isResolved && errno == ENOENT;
878 if (notExists)
880 sal_Int32 n = aPath.lastIndexOf('/');
881 OString folderPath = getParentFolder(aPath);
882 isResolved = !!realpath(folderPath.getStr(), resolvedPath);
883 notExists = !isResolved && errno == ENOENT;
885 if (notExists || !isResolved || strlen(resolvedPath) + aPath.getLength() - n + 1 >= PATH_MAX)
886 return; // too bad
887 else
888 strcat(resolvedPath, aPath.getStr() + n);
891 if (isResolved)
893 OString aPushPath(resolvedPath, strlen(resolvedPath));
894 if (eType == 'r')
895 allowedPathsRead.push_back(aPushPath);
896 else if (eType == 'w')
898 allowedPathsRead.push_back(aPushPath);
899 allowedPathsReadWrite.push_back(aPushPath);
901 else if (eType == 'x')
902 allowedPathsExecute.push_back(aPushPath);
905 while (nIndex != -1);
907 abortOnForbidden = !!getenv("SAL_ABORT_ON_FORBIDDEN");
910 bool isForbidden(const OString &filePath, int nFlags)
912 // avoid realpath cost unless configured
913 if (allowedPathsRead.size() == 0)
914 return false;
916 char resolvedPath[PATH_MAX];
917 if (!realpath(filePath.getStr(), resolvedPath))
919 // write calls path a non-existent path that realpath will
920 // fail to resolve. Thankfully our I/O APIs don't allow
921 // symlink creation to race here.
922 sal_Int32 n = filePath.lastIndexOf('/');
923 OString folderPath = getParentFolder(filePath);
925 bool isResolved = !!realpath(folderPath.getStr(), resolvedPath);
926 bool notExists = !isResolved && errno == ENOENT;
927 if (notExists) // folder doesn't exist, check parent, in the end of chain checks "."
928 return isForbidden(folderPath, nFlags);
929 else if (!isResolved || strlen(resolvedPath) + filePath.getLength() - n + 1 >= PATH_MAX)
930 return true; // too bad
931 else
932 strcat(resolvedPath, filePath.getStr() + n);
935 const std::vector<OString> *pCheckPaths = &allowedPathsRead;
936 if (nFlags & osl_File_OpenFlag_Write ||
937 nFlags & osl_File_OpenFlag_Create)
938 pCheckPaths = &allowedPathsReadWrite;
939 else if (nFlags & 0x80)
940 pCheckPaths = &allowedPathsExecute;
942 bool allowed = false;
943 for (const auto &it : *pCheckPaths) {
944 if (!strncmp(resolvedPath, it.getStr(), it.getLength()))
946 allowed = true;
947 break;
951 if (!allowed)
952 SAL_WARN("sal.osl", "access outside sandbox to " <<
953 ((nFlags & osl_File_OpenFlag_Write ||
954 nFlags & osl_File_OpenFlag_Create) ? "w" :
955 (nFlags & 0x80) ? "x" : "r") << ":" <<
956 filePath << " which is really " << resolvedPath <<
957 (allowed ? " allowed " : " forbidden") <<
958 " check list: " << pCheckPaths->size());
960 if (abortOnForbidden && !allowed)
961 abort(); // a bit abrupt - but don't try to escape.
963 return !allowed;
966 SAL_DLLPUBLIC sal_Bool SAL_CALL osl_isForbiddenPath(
967 rtl_uString *pustrFileURL, int nFlags
970 return isForbidden(
971 rtl::OUStringToOString(OUString(pustrFileURL),
972 RTL_TEXTENCODING_UTF8), nFlags);
975 #ifdef HAVE_O_EXLOCK
976 #define OPEN_WRITE_FLAGS ( O_RDWR | O_EXLOCK | O_NONBLOCK )
977 #define OPEN_CREATE_FLAGS ( O_CREAT | O_RDWR | O_EXLOCK | O_NONBLOCK )
978 #else
979 #define OPEN_WRITE_FLAGS ( O_RDWR )
980 #define OPEN_CREATE_FLAGS ( O_CREAT | O_RDWR )
981 #endif
983 #if defined ANDROID
985 namespace {
987 static oslFileError openMemoryAsFile(const OString &rData,
988 oslFileHandle *pHandle,
989 const OString& path)
991 const char *address = rData.getStr();
992 size_t size = rData.getLength();
994 FileHandle_Impl *pImpl = new FileHandle_Impl(-1, FileHandle_Impl::KIND_MEM, path);
995 pImpl->m_size = sal::static_int_cast< sal_uInt64 >(size);
997 *pHandle = (oslFileHandle)(pImpl);
999 pImpl->m_bufptr = 0;
1000 pImpl->m_buflen = size;
1001 pImpl->m_memstreambuf = rData.pData;
1002 rtl_string_acquire(pImpl->m_memstreambuf);
1004 pImpl->m_bufsiz = size;
1005 pImpl->m_buffer = reinterpret_cast<sal_uInt8*>(const_cast<char *>(address));
1007 return osl_File_E_None;
1011 * Reading files from /assets/ on Android via a transition into the VM
1012 * shows on profiles and is rather slow; so we cache small files as
1013 * used by UNO, UI-builder etc.
1015 class AndroidFileCache {
1016 public:
1017 struct Entry {
1018 OString maFilePath;
1019 OString maData;
1021 AndroidFileCache(size_t nElements)
1022 : mnCur(0)
1024 maEntries.resize(nElements);
1025 assert (maEntries.size() == nElements);
1027 Entry *find(const char *cpFilePath)
1029 for (auto &it : maEntries)
1031 if (!strcmp(it.maFilePath.getStr(), cpFilePath))
1032 return &it;
1034 return nullptr;
1036 // no clever LRU - but - good enough for now.
1037 void insert(const char *cpFilePath, OString &rData)
1039 assert (maEntries.size() > 0);
1040 if (++mnCur >= maEntries.size())
1041 mnCur = 0;
1042 maEntries[mnCur].maFilePath = OString(cpFilePath, strlen(cpFilePath));
1043 maEntries[mnCur].maData = rData;
1045 static AndroidFileCache &getHitCache()
1047 static AndroidFileCache *pCache = new AndroidFileCache(16);
1048 return *pCache;
1050 static AndroidFileCache &getMissCache()
1052 static AndroidFileCache *pCache = new AndroidFileCache(32);
1053 return *pCache;
1055 private:
1056 size_t mnCur;
1057 std::vector<Entry> maEntries;
1060 } // namespace
1062 #endif
1064 oslFileError openFilePath(const OString& filePath, oslFileHandle* pHandle,
1065 sal_uInt32 uFlags, mode_t mode)
1067 oslFileError eRet;
1069 #ifdef ANDROID
1070 /* Opening a file from /assets read-only means
1071 * we should mmap it from the .apk file
1073 if (o3tl::starts_with(filePath, "/assets/"))
1075 OString aData;
1076 bool bCache = true;
1078 const char *cpAssetsPath = filePath.getStr() + sizeof("/assets/") - 1;
1079 // some requests are /assets//foo...
1080 if (cpAssetsPath[0] == '/')
1082 __android_log_print(ANDROID_LOG_DEBUG,"libo:sal/osl/unx/file", "double-slash in path: %s", filePath.getStr());
1083 cpAssetsPath++;
1086 AndroidFileCache::Entry *pHit = AndroidFileCache::getHitCache().find(cpAssetsPath);
1087 if (pHit)
1088 aData = pHit->maData;
1090 else
1092 bCache = false;
1093 AndroidFileCache::Entry *pMiss = AndroidFileCache::getMissCache().find(cpAssetsPath);
1094 if (pMiss)
1096 errno = ENOENT;
1097 __android_log_print(ANDROID_LOG_ERROR,"libo:sal/osl/unx/file", "miss cache: failed to open %s", filePath.getStr());
1098 return osl_File_E_NOENT;
1100 AAssetManager* mgr = lo_get_native_assetmgr();
1101 AAsset* asset = AAssetManager_open(mgr, cpAssetsPath, AASSET_MODE_BUFFER);
1102 if (!asset)
1104 AndroidFileCache::getMissCache().insert(cpAssetsPath, aData);
1105 errno = ENOENT;
1106 __android_log_print(ANDROID_LOG_ERROR,"libo:sal/osl/unx/file", "failed to open %s", filePath.getStr());
1107 return osl_File_E_NOENT;
1109 else
1111 rtl_String *pData = nullptr;
1112 size_t size = AAsset_getLength(asset);
1113 rtl_string_new_WithLength(&pData, size);
1114 pData->length = size;
1115 AAsset_read(asset, pData->buffer, size);
1116 AAsset_close(asset);
1118 aData = OString(pData, SAL_NO_ACQUIRE);
1120 if (pData->length < 50 * 1024)
1121 AndroidFileCache::getHitCache().insert(cpAssetsPath, aData);
1125 if (uFlags & osl_File_OpenFlag_Write)
1127 // It seems to work better to silently "open" it read-only
1128 // and let write attempts, if any, fail later. Otherwise
1129 // loading a document from /assets fails with that idiotic
1130 // "General Error" dialog...
1132 SAL_INFO("sal.file", "osl_openFile(" << filePath << ") => '" << cpAssetsPath << "'"
1133 << aData.getLength() << " bytes from file " << (bCache ? "cache" : "system"));
1134 return openMemoryAsFile(aData, pHandle, filePath);
1136 #endif
1138 /* set mode and flags */
1139 int defmode = (uFlags & osl_File_OpenFlag_Private) ? S_IRUSR : S_IRUSR | S_IRGRP | S_IROTH;
1140 int flags = O_RDONLY;
1142 if (uFlags & osl_File_OpenFlag_Write)
1144 defmode |= (uFlags & osl_File_OpenFlag_Private) ? S_IWUSR : S_IWUSR | S_IWGRP | S_IWOTH;
1145 flags = OPEN_WRITE_FLAGS;
1148 if (uFlags & osl_File_OpenFlag_Create)
1150 defmode |= (uFlags & osl_File_OpenFlag_Private) ? S_IWUSR : S_IWUSR | S_IWGRP | S_IWOTH;
1151 flags = OPEN_CREATE_FLAGS;
1154 if (mode == mode_t(-1))
1155 mode = defmode;
1157 /* Check for flags passed in from SvFileStream::Open() */
1158 if (uFlags & osl_File_OpenFlag_Trunc)
1159 flags |= O_TRUNC;
1161 if (!(uFlags & osl_File_OpenFlag_NoExcl))
1162 flags |= O_EXCL;
1164 if (uFlags & osl_File_OpenFlag_NoLock)
1166 #ifdef HAVE_O_EXLOCK
1167 flags &= ~(O_EXLOCK | O_SHLOCK | O_NONBLOCK);
1168 #endif /* HAVE_O_EXLOCK */
1170 else
1172 osl_file_adjustLockFlags (filePath, &flags, &uFlags);
1175 // O_EXCL can be set only when O_CREAT is set
1176 if (flags & O_EXCL && !(flags & O_CREAT))
1177 flags &= ~O_EXCL;
1179 // Sandboxing hook
1180 if (isForbidden( filePath, uFlags ))
1181 return osl_File_E_ACCES;
1183 // set close-on-exec by default
1184 flags |= O_CLOEXEC;
1186 /* open the file */
1187 int fd = open_c( filePath, flags, mode );
1188 if (fd == -1)
1190 return oslTranslateFileError(errno);
1193 #if !HAVE_FEATURE_MACOSX_SANDBOX
1194 /* reset O_NONBLOCK flag */
1195 if (flags & O_NONBLOCK)
1197 int f = fcntl(fd, F_GETFL, 0);
1198 if (f == -1)
1200 int e = errno;
1201 SAL_INFO("sal.file", "fcntl(" << fd << ",F_GETFL,0): " << UnixErrnoString(e));
1202 eRet = oslTranslateFileError(e);
1203 (void) close(fd);
1204 SAL_INFO("sal.file", "close(" << fd << ")");
1205 return eRet;
1207 else
1208 SAL_INFO("sal.file", "fcntl(" << fd << ",F_GETFL,0): OK");
1210 if (fcntl(fd, F_SETFL, (f & ~O_NONBLOCK)) == -1)
1212 int e = errno;
1213 SAL_INFO("sal.file", "fcntl(" << fd << ",F_SETFL,(f & ~O_NONBLOCK)): " << UnixErrnoString(e));
1214 eRet = oslTranslateFileError(e);
1215 (void) close(fd);
1216 SAL_INFO("sal.file", "close(" << fd << ")");
1217 return eRet;
1219 else
1220 SAL_INFO("sal.file", "fcntl(" << fd << ",F_SETFL,(f & ~O_NONBLOCK)): OK");
1222 #endif
1224 /* get file status (mode, size) */
1225 struct stat aFileStat;
1226 if (fstat(fd, &aFileStat) == -1)
1228 int e = errno;
1229 SAL_INFO("sal.file", "fstat(" << fd << "): " << UnixErrnoString(e));
1230 eRet = oslTranslateFileError(e);
1231 (void) close(fd);
1232 SAL_INFO("sal.file", "close(" << fd << ")");
1233 return eRet;
1235 else
1236 SAL_INFO("sal.file", "fstat(" << fd << "): OK");
1238 if (!S_ISREG(aFileStat.st_mode))
1240 /* we only open regular files here */
1241 SAL_INFO("sal.file", "osl_openFile(" << filePath << "): not a regular file");
1242 (void) close(fd);
1243 SAL_INFO("sal.file", "close(" << fd << ")");
1244 return osl_File_E_INVAL;
1247 if (osl_file_queryLocking(uFlags))
1249 #ifdef MACOSX
1250 if (flock(fd, LOCK_EX | LOCK_NB) == -1)
1252 int e = errno;
1253 SAL_INFO("sal.file", "flock(" << fd << ",LOCK_EX|LOCK_NB): " << UnixErrnoString(e));
1254 /* Mac OSX returns ENOTSUP for webdav drives. We should try read lock */
1256 // Restore errno after possibly having been overwritten by the SAL_INFO above...
1257 errno = e;
1258 if ((errno != ENOTSUP) || ((flock(fd, LOCK_SH | LOCK_NB) == 1) && (errno != ENOTSUP)))
1260 eRet = oslTranslateFileError(errno);
1261 (void) close(fd);
1262 SAL_INFO("sal.file", "close(" << fd << ")");
1263 return eRet;
1266 else
1267 SAL_INFO("sal.file", "flock(" << fd << ",LOCK_EX|LOCK_NB): OK");
1268 #else /* F_SETLK */
1269 struct flock aflock;
1271 aflock.l_type = F_WRLCK;
1272 aflock.l_whence = SEEK_SET;
1273 aflock.l_start = 0;
1274 aflock.l_len = 0;
1276 if (fcntl(fd, F_SETLK, &aflock) == -1)
1278 int e = errno;
1279 SAL_INFO("sal.file", "fcntl(" << fd << ",F_SETLK): " << UnixErrnoString(e));
1280 eRet = oslTranslateFileError(e);
1281 (void) close(fd);
1282 SAL_INFO("sal.file", "close(" << fd << ")");
1283 return eRet;
1285 #endif /* F_SETLK */
1288 /* allocate memory for impl structure */
1289 FileHandle_Impl *pImpl = new FileHandle_Impl(fd, FileHandle_Impl::KIND_FD, filePath);
1290 if (flags & O_RDWR)
1291 pImpl->m_state |= State::Writeable;
1293 pImpl->m_size = sal::static_int_cast< sal_uInt64 >(aFileStat.st_size);
1295 *pHandle = static_cast<oslFileHandle>(pImpl);
1297 return osl_File_E_None;
1300 oslFileError SAL_CALL osl_openFile(rtl_uString* ustrFileURL, oslFileHandle* pHandle, sal_uInt32 uFlags)
1302 return openFile(ustrFileURL, pHandle, uFlags, mode_t(-1));
1305 oslFileError openFile(rtl_uString* ustrFileURL, oslFileHandle* pHandle, sal_uInt32 uFlags, mode_t mode)
1307 oslFileError eRet;
1309 if ((!ustrFileURL) || (ustrFileURL->length == 0) || (!pHandle))
1310 return osl_File_E_INVAL;
1312 /* convert file URL to system path */
1313 char buffer[PATH_MAX];
1314 eRet = FileURLToPath(buffer, sizeof(buffer), ustrFileURL);
1315 if (eRet != osl_File_E_None)
1316 return eRet;
1318 #ifdef MACOSX
1319 if (macxp_resolveAlias(buffer, sizeof(buffer)) != 0)
1320 return oslTranslateFileError(errno);
1321 #endif /* MACOSX */
1323 return openFilePath(buffer, pHandle, uFlags, mode);
1326 oslFileError SAL_CALL osl_closeFile(oslFileHandle Handle)
1328 FileHandle_Impl* pImpl = static_cast< FileHandle_Impl* >(Handle);
1330 if (!pImpl)
1331 return osl_File_E_INVAL;
1333 if (pImpl->m_kind == FileHandle_Impl::KIND_MEM)
1335 #ifdef ANDROID
1336 rtl_string_release(pImpl->m_memstreambuf);
1337 pImpl->m_memstreambuf = nullptr;
1339 pImpl->m_buffer = NULL;
1340 #endif
1341 delete pImpl;
1342 return osl_File_E_None;
1345 if (pImpl->m_fd < 0)
1346 return osl_File_E_INVAL;
1348 (void) pthread_mutex_lock(&(pImpl->m_mutex));
1350 /* close(2) implicitly (and unconditionally) unlocks */
1351 oslFileError result = pImpl->syncFile();
1352 if (result != osl_File_E_None)
1354 /* close, ignoring double failure */
1355 (void) close(pImpl->m_fd);
1356 SAL_INFO("sal.file", "close(" << pImpl->m_fd << ")");
1358 else if (close(pImpl->m_fd) == -1)
1360 int e = errno;
1361 SAL_INFO("sal.file", "close(" << pImpl->m_fd << "): " << UnixErrnoString(e));
1362 /* translate error code */
1363 result = oslTranslateFileError(e);
1365 else
1366 SAL_INFO("sal.file", "close(" << pImpl->m_fd << "): OK");
1368 (void) pthread_mutex_unlock(&(pImpl->m_mutex));
1369 delete pImpl;
1370 return result;
1373 oslFileError SAL_CALL osl_syncFile(oslFileHandle Handle)
1375 FileHandle_Impl* pImpl = static_cast<FileHandle_Impl*>(Handle);
1377 if ((!pImpl) || ((pImpl->m_kind == FileHandle_Impl::KIND_FD) && (pImpl->m_fd == -1)))
1378 return osl_File_E_INVAL;
1380 if (pImpl->m_kind == FileHandle_Impl::KIND_MEM)
1381 return osl_File_E_None;
1383 FileHandle_Impl::Guard lock(&(pImpl->m_mutex));
1385 oslFileError result = pImpl->syncFile();
1387 if (result != osl_File_E_None)
1388 return result;
1390 static bool disabled = getenv("SAL_DISABLE_FSYNC") != nullptr;
1392 if (disabled)
1393 SAL_INFO("sal.file", "fsync(" << pImpl->m_fd << "): Disabled");
1394 else if (fsync(pImpl->m_fd) == -1)
1396 int e = errno;
1397 SAL_INFO("sal.file", "fsync(" << pImpl->m_fd << "): " << UnixErrnoString(e));
1398 return oslTranslateFileError(e);
1400 else
1401 SAL_INFO("sal.file", "fsync(" << pImpl->m_fd << "): OK");
1403 return osl_File_E_None;
1406 const off_t MAX_OFF_T = std::numeric_limits< off_t >::max();
1408 namespace {
1410 // coverity[result_independent_of_operands] - crossplatform requirement
1411 template<typename T> bool exceedsMaxOffT(T n) { return n > MAX_OFF_T; }
1413 // coverity[result_independent_of_operands] - crossplatform requirement
1414 template<typename T> bool exceedsMinOffT(T n)
1415 { return n < std::numeric_limits<off_t>::min(); }
1419 oslFileError SAL_CALL osl_mapFile(
1420 oslFileHandle Handle,
1421 void** ppAddr,
1422 sal_uInt64 uLength,
1423 sal_uInt64 uOffset,
1424 sal_uInt32 uFlags
1427 FileHandle_Impl* pImpl = static_cast< FileHandle_Impl* >(Handle);
1429 if ((!pImpl) || ((pImpl->m_kind == FileHandle_Impl::KIND_FD) && (pImpl->m_fd == -1)) || (!ppAddr))
1430 return osl_File_E_INVAL;
1432 *ppAddr = nullptr;
1434 if (uLength > SAL_MAX_SIZE)
1435 return osl_File_E_OVERFLOW;
1437 size_t const nLength = sal::static_int_cast< size_t >(uLength);
1439 if (exceedsMaxOffT(uOffset))
1440 return osl_File_E_OVERFLOW;
1442 if (pImpl->m_kind == FileHandle_Impl::KIND_MEM)
1444 *ppAddr = pImpl->m_buffer + uOffset;
1445 return osl_File_E_None;
1448 off_t const nOffset = sal::static_int_cast< off_t >(uOffset);
1450 void* p = mmap(nullptr, nLength, PROT_READ, MAP_SHARED, pImpl->m_fd, nOffset);
1452 if (p == MAP_FAILED)
1453 return oslTranslateFileError(errno);
1455 *ppAddr = p;
1457 if (uFlags & osl_File_MapFlag_RandomAccess)
1459 // Determine memory pagesize.
1460 size_t const nPageSize = FileHandle_Impl::getpagesize();
1461 if (nPageSize != size_t(-1))
1464 * Pagein, touching first byte of every memory page.
1465 * Note: volatile disables optimizing the loop away.
1467 sal_uInt8 volatile *pData(static_cast<sal_uInt8*>(*ppAddr));
1468 size_t nSize(nLength);
1470 while (nSize > nPageSize)
1472 pData[0];
1473 pData += nPageSize;
1474 nSize -= nPageSize;
1477 if (nSize > 0)
1478 pData[0];
1482 if (uFlags & osl_File_MapFlag_WillNeed)
1484 // On Linux, madvise(..., MADV_WILLNEED) appears to have the undesirable
1485 // effect of not returning until the data has actually been paged in, so
1486 // that its net effect would typically be to slow down the process
1487 // (which could start processing at the beginning of the data while the
1488 // OS simultaneously pages in the rest); on other platforms, it remains
1489 // to be evaluated whether madvise or equivalent is available and
1490 // actually useful:
1491 #if defined MACOSX || (defined(__sun) && (!defined(__XOPEN_OR_POSIX) || defined(_XPG6) || defined(__EXTENSIONS__)))
1492 int e = posix_madvise(p, nLength, POSIX_MADV_WILLNEED);
1493 if (e != 0)
1494 SAL_INFO("sal.file", "posix_madvise(..., POSIX_MADV_WILLNEED) failed with " << e);
1496 #elif defined __sun
1497 if (madvise(static_cast< caddr_t >(p), nLength, MADV_WILLNEED) != 0)
1498 SAL_INFO("sal.file", "madvise(..., MADV_WILLNEED) failed with " << UnixErrnoString(errno));
1499 #endif
1502 return osl_File_E_None;
1505 static oslFileError unmapFile(void* pAddr, sal_uInt64 uLength)
1507 if (!pAddr)
1508 return osl_File_E_INVAL;
1510 if (uLength > SAL_MAX_SIZE)
1511 return osl_File_E_OVERFLOW;
1513 size_t const nLength = sal::static_int_cast< size_t >(uLength);
1515 if (munmap(pAddr, nLength) == -1)
1516 return oslTranslateFileError(errno);
1518 return osl_File_E_None;
1521 #ifndef ANDROID
1523 // Note that osl_unmapFile() just won't work on Android in general
1524 // where for (uncompressed) files inside the .apk, in the /assets
1525 // folder osl_mapFile just returns a pointer to the file inside the
1526 // already mmapped .apk archive.
1528 oslFileError SAL_CALL osl_unmapFile(void* pAddr, sal_uInt64 uLength)
1530 return unmapFile(pAddr, uLength);
1533 #endif
1535 oslFileError SAL_CALL osl_unmapMappedFile(oslFileHandle Handle, void* pAddr, sal_uInt64 uLength)
1537 FileHandle_Impl *pImpl = static_cast<FileHandle_Impl*>(Handle);
1539 if (!pImpl)
1540 return osl_File_E_INVAL;
1542 if (pImpl->m_kind == FileHandle_Impl::KIND_FD)
1543 return unmapFile(pAddr, uLength);
1545 // For parts of already mmapped "parent" files, whose mapping we
1546 // can't change, not much we can or should do...
1547 return osl_File_E_None;
1550 oslFileError SAL_CALL osl_readLine(
1551 oslFileHandle Handle,
1552 sal_Sequence ** ppSequence)
1554 FileHandle_Impl *pImpl = static_cast<FileHandle_Impl*>(Handle);
1556 if ((!pImpl) || ((pImpl->m_kind == FileHandle_Impl::KIND_FD) && (pImpl->m_fd == -1)) || (!ppSequence))
1557 return osl_File_E_INVAL;
1559 sal_uInt64 uBytesRead = 0;
1561 // read at current fileptr; fileptr += uBytesRead;
1562 FileHandle_Impl::Guard lock(&(pImpl->m_mutex));
1563 oslFileError result = pImpl->readLineAt(pImpl->m_fileptr, ppSequence, &uBytesRead);
1565 if (result == osl_File_E_None)
1566 pImpl->m_fileptr += uBytesRead;
1568 return result;
1571 oslFileError SAL_CALL osl_readFile(
1572 oslFileHandle Handle,
1573 void * pBuffer,
1574 sal_uInt64 uBytesRequested,
1575 sal_uInt64 * pBytesRead)
1577 FileHandle_Impl* pImpl = static_cast< FileHandle_Impl* >(Handle);
1579 if ((!pImpl) || ((pImpl->m_kind == FileHandle_Impl::KIND_FD) && (pImpl->m_fd == -1)) || (!pBuffer) || (!pBytesRead))
1580 return osl_File_E_INVAL;
1582 static sal_uInt64 const g_limit_ssize_t = std::numeric_limits< ssize_t >::max();
1583 if (g_limit_ssize_t < uBytesRequested)
1584 return osl_File_E_OVERFLOW;
1586 size_t const nBytesRequested = sal::static_int_cast< size_t >(uBytesRequested);
1588 // read at current fileptr; fileptr += *pBytesRead;
1589 FileHandle_Impl::Guard lock(&(pImpl->m_mutex));
1590 oslFileError result = pImpl->readFileAt(pImpl->m_fileptr, pBuffer, nBytesRequested, pBytesRead);
1592 if (result == osl_File_E_None)
1593 pImpl->m_fileptr += *pBytesRead;
1595 return result;
1598 oslFileError SAL_CALL osl_writeFile(
1599 oslFileHandle Handle,
1600 const void * pBuffer,
1601 sal_uInt64 uBytesToWrite,
1602 sal_uInt64 * pBytesWritten)
1604 FileHandle_Impl* pImpl = static_cast< FileHandle_Impl* >(Handle);
1606 if ((!pImpl) || (pImpl->m_fd == -1) || (!pBuffer) || (!pBytesWritten))
1607 return osl_File_E_INVAL;
1609 if (!(pImpl->m_state & State::Writeable))
1610 return osl_File_E_BADF;
1612 static sal_uInt64 const g_limit_ssize_t = std::numeric_limits< ssize_t >::max();
1613 if (g_limit_ssize_t < uBytesToWrite)
1614 return osl_File_E_OVERFLOW;
1616 size_t const nBytesToWrite = sal::static_int_cast< size_t >(uBytesToWrite);
1618 // write at current fileptr; fileptr += *pBytesWritten;
1619 FileHandle_Impl::Guard lock(&(pImpl->m_mutex));
1620 oslFileError result = pImpl->writeFileAt(pImpl->m_fileptr, pBuffer, nBytesToWrite, pBytesWritten);
1621 if (result == osl_File_E_None)
1622 pImpl->m_fileptr += *pBytesWritten;
1624 return result;
1627 oslFileError SAL_CALL osl_readFileAt(
1628 oslFileHandle Handle,
1629 sal_uInt64 uOffset,
1630 void* pBuffer,
1631 sal_uInt64 uBytesRequested,
1632 sal_uInt64* pBytesRead)
1634 FileHandle_Impl* pImpl = static_cast< FileHandle_Impl* >(Handle);
1636 if ((!pImpl) || ((pImpl->m_kind == FileHandle_Impl::KIND_FD) && (pImpl->m_fd == -1)) || (!pBuffer) || (!pBytesRead))
1637 return osl_File_E_INVAL;
1639 if (!(pImpl->m_state & State::Seekable))
1640 return osl_File_E_SPIPE;
1642 if (exceedsMaxOffT(uOffset))
1643 return osl_File_E_OVERFLOW;
1645 off_t const nOffset = sal::static_int_cast< off_t >(uOffset);
1647 static sal_uInt64 const g_limit_ssize_t = std::numeric_limits< ssize_t >::max();
1648 if (g_limit_ssize_t < uBytesRequested)
1649 return osl_File_E_OVERFLOW;
1651 size_t const nBytesRequested = sal::static_int_cast< size_t >(uBytesRequested);
1653 // read at specified fileptr
1654 FileHandle_Impl::Guard lock(&(pImpl->m_mutex));
1656 return pImpl->readFileAt(nOffset, pBuffer, nBytesRequested, pBytesRead);
1659 oslFileError SAL_CALL osl_writeFileAt(
1660 oslFileHandle Handle,
1661 sal_uInt64 uOffset,
1662 const void* pBuffer,
1663 sal_uInt64 uBytesToWrite,
1664 sal_uInt64* pBytesWritten)
1666 FileHandle_Impl* pImpl = static_cast<FileHandle_Impl*>(Handle);
1668 if ((!pImpl) || (pImpl->m_fd == -1) || (!pBuffer) || (!pBytesWritten))
1669 return osl_File_E_INVAL;
1671 if (!(pImpl->m_state & State::Seekable))
1672 return osl_File_E_SPIPE;
1674 if (!(pImpl->m_state & State::Writeable))
1675 return osl_File_E_BADF;
1677 if (exceedsMaxOffT(uOffset))
1678 return osl_File_E_OVERFLOW;
1680 off_t const nOffset = sal::static_int_cast< off_t >(uOffset);
1682 static sal_uInt64 const g_limit_ssize_t = std::numeric_limits< ssize_t >::max();
1683 if (g_limit_ssize_t < uBytesToWrite)
1684 return osl_File_E_OVERFLOW;
1686 size_t const nBytesToWrite = sal::static_int_cast< size_t >(uBytesToWrite);
1688 // write at specified fileptr
1689 FileHandle_Impl::Guard lock(&(pImpl->m_mutex));
1691 return pImpl->writeFileAt(nOffset, pBuffer, nBytesToWrite, pBytesWritten);
1694 oslFileError SAL_CALL osl_isEndOfFile(oslFileHandle Handle, sal_Bool *pIsEOF)
1696 FileHandle_Impl* pImpl = static_cast< FileHandle_Impl* >(Handle);
1698 if ((!pImpl) || ((pImpl->m_kind == FileHandle_Impl::KIND_FD) && (pImpl->m_fd == -1)) || (!pIsEOF))
1699 return osl_File_E_INVAL;
1701 FileHandle_Impl::Guard lock(&(pImpl->m_mutex));
1702 *pIsEOF = (pImpl->getPos() == pImpl->getSize());
1704 return osl_File_E_None;
1707 oslFileError SAL_CALL osl_getFilePos(oslFileHandle Handle, sal_uInt64* pPos)
1709 FileHandle_Impl* pImpl = static_cast< FileHandle_Impl* >(Handle);
1711 if ((!pImpl) || ((pImpl->m_kind == FileHandle_Impl::KIND_FD) && (pImpl->m_fd == -1)) || (!pPos))
1712 return osl_File_E_INVAL;
1714 // no need to lock because pos is atomic
1715 *pPos = pImpl->getPos();
1717 return osl_File_E_None;
1720 oslFileError SAL_CALL osl_setFilePos(oslFileHandle Handle, sal_uInt32 uHow, sal_Int64 uOffset)
1722 FileHandle_Impl* pImpl = static_cast< FileHandle_Impl* >(Handle);
1724 if ((!pImpl) || ((pImpl->m_kind == FileHandle_Impl::KIND_FD) && (pImpl->m_fd == -1)))
1725 return osl_File_E_INVAL;
1727 if (exceedsMaxOffT(uOffset) || exceedsMinOffT(uOffset))
1728 return osl_File_E_OVERFLOW;
1730 off_t nPos = 0, nOffset = sal::static_int_cast< off_t >(uOffset);
1732 FileHandle_Impl::Guard lock(&(pImpl->m_mutex));
1733 switch (uHow)
1735 case osl_Pos_Absolut:
1736 if (nOffset < 0)
1737 return osl_File_E_INVAL;
1738 break;
1740 case osl_Pos_Current:
1741 nPos = sal::static_int_cast< off_t >(pImpl->getPos());
1742 if ((nOffset < 0) && (nPos < -1*nOffset))
1743 return osl_File_E_INVAL;
1745 assert(nPos >= 0);
1746 if (nOffset > MAX_OFF_T - nPos)
1747 return osl_File_E_OVERFLOW;
1748 break;
1750 case osl_Pos_End:
1751 nPos = sal::static_int_cast< off_t >(pImpl->getSize());
1752 if ((nOffset < 0) && (nPos < -1*nOffset))
1753 return osl_File_E_INVAL;
1755 assert(nPos >= 0);
1756 if (nOffset > MAX_OFF_T - nPos)
1757 return osl_File_E_OVERFLOW;
1758 break;
1760 default:
1761 return osl_File_E_INVAL;
1764 pImpl->setPos(nPos + nOffset);
1765 return osl_File_E_None;
1768 oslFileError SAL_CALL osl_getFileSize(oslFileHandle Handle, sal_uInt64* pSize)
1770 FileHandle_Impl* pImpl = static_cast< FileHandle_Impl* >(Handle);
1772 if ((!pImpl) || ((pImpl->m_kind == FileHandle_Impl::KIND_FD) && (pImpl->m_fd == -1)) || (!pSize))
1773 return osl_File_E_INVAL;
1775 FileHandle_Impl::Guard lock(&(pImpl->m_mutex));
1776 *pSize = pImpl->getSize();
1778 return osl_File_E_None;
1781 oslFileError SAL_CALL osl_setFileSize(oslFileHandle Handle, sal_uInt64 uSize)
1783 FileHandle_Impl* pImpl = static_cast< FileHandle_Impl* >(Handle);
1785 if ((!pImpl) || (pImpl->m_fd == -1))
1786 return osl_File_E_INVAL;
1788 if (!(pImpl->m_state & State::Writeable))
1789 return osl_File_E_BADF;
1791 if (exceedsMaxOffT(uSize))
1792 return osl_File_E_OVERFLOW;
1794 oslFileError result = pImpl->syncFile();
1795 if (result != osl_File_E_None)
1796 return result;
1798 pImpl->m_bufptr = -1;
1799 pImpl->m_buflen = 0;
1801 return pImpl->setSize(uSize);
1805 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */