1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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>
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"
53 #include <sys/param.h>
54 #include <sys/mount.h>
57 #include <CoreFoundation/CoreFoundation.h>
62 #include <osl/detail/android-bootstrap.h>
63 #include <android/log.h>
64 #include <android/asset_manager.h>
65 #include <o3tl/string_view.hxx>
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)
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> {};
92 struct FileHandle_Impl
94 pthread_mutex_t m_mutex
;
95 OString m_strFilePath
; /*< holds native file path */
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] */
117 sal_uInt8
* m_buffer
;
119 rtl_String
* m_memstreambuf
; /*< used for in-memory streams */
122 explicit FileHandle_Impl(int fd
, Kind kind
= KIND_FD
, OString path
= "<anon>"_ostr
);
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
);
136 size_t nBytesRequested
,
137 sal_uInt64
* pBytesRead
);
139 oslFileError
writeAt(
142 size_t nBytesToWrite
,
143 sal_uInt64
* pBytesWritten
);
145 oslFileError
readFileAt(
148 size_t nBytesRequested
,
149 sal_uInt64
* pBytesRead
);
151 oslFileError
writeFileAt(
154 size_t nBytesToWrite
,
155 sal_uInt64
* pBytesWritten
);
157 oslFileError
readLineAt(
159 sal_Sequence
** ppSequence
,
160 sal_uInt64
* pBytesRead
);
162 static oslFileError
writeSequence_Impl(
163 sal_Sequence
** ppSequence
,
168 oslFileError
syncFile();
172 pthread_mutex_t
*m_mutex
;
175 explicit Guard(pthread_mutex_t
*pMutex
);
182 FileHandle_Impl::Guard::Guard(pthread_mutex_t
* pMutex
)
186 (void) pthread_mutex_lock(m_mutex
); // ignoring EINVAL if a null mutex is passed ...
189 FileHandle_Impl::Guard::~Guard()
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
)),
199 m_state (State::Seekable
| State::Readable
),
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))
215 m_buffer
= static_cast<sal_uInt8
*>(calloc(1, m_bufsiz
));
220 FileHandle_Impl::~FileHandle_Impl()
222 if (m_kind
== KIND_FD
)
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 */
267 /* Save current position */
268 off_t
const nCurPos
= lseek(m_fd
, off_t(0), SEEK_CUR
);
269 if (nCurPos
== off_t(-1))
272 SAL_INFO("sal.file", "lseek(" << m_fd
<< ",0,SEEK_CUR): " << UnixErrnoString(e
));
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)
282 SAL_INFO("sal.file", "lseek(" << m_fd
<< "," << nSize
- 1 << ",SEEK_SET): " << UnixErrnoString(e
));
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 */
292 SAL_INFO("sal.file", "write(" << m_fd
<< ",\"\",1): " << UnixErrnoString(e
));
293 (void) lseek(m_fd
, nCurPos
, SEEK_SET
);
297 SAL_INFO("sal.file", "write(" << m_fd
<< ",\"\",1): OK");
299 /* Success. Restore saved position */
300 if (lseek(m_fd
, nCurPos
, SEEK_SET
) == -1)
304 m_size
= sal::static_int_cast
< sal_uInt64
>(nSize
);
305 return osl_File_E_None
;
308 oslFileError
FileHandle_Impl::readAt(
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
)
328 if (o3tl::make_unsigned(m_offset
) >= m_size
)
334 nBytes
= std::min(nBytesRequested
, static_cast<size_t>(m_size
- m_offset
));
335 memmove(pBuffer
, m_buffer
+ 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.
353 return oslTranslateFileError(errno
);
355 *pBytesRead
= nBytes
;
357 return osl_File_E_None
;
360 oslFileError
FileHandle_Impl::writeAt(
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
);
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(
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
);
396 return oslTranslateFileError(errno
);
398 *pBytesRead
= nBytes
;
400 return osl_File_E_None
;
403 if (m_kind
== KIND_MEM
|| !m_buffer
)
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
)
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
)
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
)
448 if (bufpos
>= m_buflen
)
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
;
463 return osl_File_E_None
;
466 oslFileError
FileHandle_Impl::writeFileAt(
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
);
477 return oslTranslateFileError(errno
);
479 *pBytesWritten
= nBytes
;
481 return osl_File_E_None
;
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
)
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
)
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
)
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
;
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(
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 */
556 if (result
!= osl_File_E_None
)
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
)
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
)
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
)
606 bufpos
= nOffset
- m_bufptr
;
608 if (bufpos
>= m_buflen
)
615 state
= LINE_STATE_LF
;
616 switch (m_buffer
[curpos
])
618 case 0x0A: /* CRLF */
619 /* eat current char */
622 default: /* single CR */
623 /* keep current char */
628 /* determine next state */
629 switch (m_buffer
[curpos
])
631 case 0x0A: /* single LF */
632 state
= LINE_STATE_LF
;
635 state
= LINE_STATE_CR
;
637 default: /* advance to next char */
641 if (state
!= LINE_STATE_BEGIN
)
643 /* skip the newline char */
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
)
652 *pBytesRead
+= curpos
- bufpos
;
653 nOffset
+= curpos
- bufpos
;
659 result
= writeSequence_Impl(ppSequence
, &dstpos
, nullptr, 0);
660 if (result
!= osl_File_E_None
)
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
,
675 const void * pBuffer
,
678 sal_Int32 nElements
= *pnOffset
+ nBytes
;
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)
693 memcpy(&((*ppSequence
)->elements
[*pnOffset
]), pBuffer
, 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
)
710 if (uDone
!= m_buflen
)
711 return osl_File_E_IO
;
713 m_state
&= ~State::Modified
;
719 oslFileHandle
osl::detail::createFileHandleFromFD(int fd
)
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
);
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
;
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
)
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.
761 if(statfs(path
.getStr(), &s
) >= 0)
763 if(strncmp("afpfs", s
.f_fstypename
, 5) == 0)
770 /* Needed flags to allow opening a webdav file */
771 *flags
&= ~(O_EXLOCK
| O_SHLOCK
| O_NONBLOCK
);
777 /* get filesystem info */
778 struct statfs aFileStatFs
;
779 if (statfs(path
.getStr(), &aFileStatFs
) < 0)
782 SAL_INFO("sal.file", "statfs(" << path
<< "): " << UnixErrnoString(e
));
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
;
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
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('/');
838 folderPath
= "."_ostr
;
840 folderPath
= OString(rFilePath
.substr(0, n
));
845 SAL_DLLPUBLIC
void osl_setAllowedPaths(
846 rtl_uString
*pustrFilePaths
849 allowedPathsRead
.clear();
850 allowedPathsReadWrite
.clear();
851 allowedPathsExecute
.clear();
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)
868 if (aPath
.getLength() == 1)
874 char resolvedPath
[PATH_MAX
];
875 bool isResolved
= !!realpath(aPath
.getStr(), resolvedPath
);
876 bool notExists
= !isResolved
&& errno
== ENOENT
;
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
)
888 strcat(resolvedPath
, aPath
.getStr() + n
);
893 OString
aPushPath(resolvedPath
, strlen(resolvedPath
));
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)
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
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()))
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.
966 SAL_DLLPUBLIC sal_Bool SAL_CALL
osl_isForbiddenPath(
967 rtl_uString
*pustrFileURL
, int nFlags
971 rtl::OUStringToOString(OUString(pustrFileURL
),
972 RTL_TEXTENCODING_UTF8
), nFlags
);
976 #define OPEN_WRITE_FLAGS ( O_RDWR | O_EXLOCK | O_NONBLOCK )
977 #define OPEN_CREATE_FLAGS ( O_CREAT | O_RDWR | O_EXLOCK | O_NONBLOCK )
979 #define OPEN_WRITE_FLAGS ( O_RDWR )
980 #define OPEN_CREATE_FLAGS ( O_CREAT | O_RDWR )
987 static oslFileError
openMemoryAsFile(const OString
&rData
,
988 oslFileHandle
*pHandle
,
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
);
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
{
1021 AndroidFileCache(size_t nElements
)
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
))
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())
1042 maEntries
[mnCur
].maFilePath
= OString(cpFilePath
, strlen(cpFilePath
));
1043 maEntries
[mnCur
].maData
= rData
;
1045 static AndroidFileCache
&getHitCache()
1047 static AndroidFileCache
*pCache
= new AndroidFileCache(16);
1050 static AndroidFileCache
&getMissCache()
1052 static AndroidFileCache
*pCache
= new AndroidFileCache(32);
1057 std::vector
<Entry
> maEntries
;
1064 oslFileError
openFilePath(const OString
& filePath
, oslFileHandle
* pHandle
,
1065 sal_uInt32 uFlags
, mode_t mode
)
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/"))
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());
1086 AndroidFileCache::Entry
*pHit
= AndroidFileCache::getHitCache().find(cpAssetsPath
);
1088 aData
= pHit
->maData
;
1093 AndroidFileCache::Entry
*pMiss
= AndroidFileCache::getMissCache().find(cpAssetsPath
);
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
);
1104 AndroidFileCache::getMissCache().insert(cpAssetsPath
, aData
);
1106 __android_log_print(ANDROID_LOG_ERROR
,"libo:sal/osl/unx/file", "failed to open %s", filePath
.getStr());
1107 return osl_File_E_NOENT
;
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
);
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))
1157 /* Check for flags passed in from SvFileStream::Open() */
1158 if (uFlags
& osl_File_OpenFlag_Trunc
)
1161 if (!(uFlags
& osl_File_OpenFlag_NoExcl
))
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 */
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
))
1180 if (isForbidden( filePath
, uFlags
))
1181 return osl_File_E_ACCES
;
1183 // set close-on-exec by default
1187 int fd
= open_c( filePath
, flags
, mode
);
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);
1201 SAL_INFO("sal.file", "fcntl(" << fd
<< ",F_GETFL,0): " << UnixErrnoString(e
));
1202 eRet
= oslTranslateFileError(e
);
1204 SAL_INFO("sal.file", "close(" << fd
<< ")");
1208 SAL_INFO("sal.file", "fcntl(" << fd
<< ",F_GETFL,0): OK");
1210 if (fcntl(fd
, F_SETFL
, (f
& ~O_NONBLOCK
)) == -1)
1213 SAL_INFO("sal.file", "fcntl(" << fd
<< ",F_SETFL,(f & ~O_NONBLOCK)): " << UnixErrnoString(e
));
1214 eRet
= oslTranslateFileError(e
);
1216 SAL_INFO("sal.file", "close(" << fd
<< ")");
1220 SAL_INFO("sal.file", "fcntl(" << fd
<< ",F_SETFL,(f & ~O_NONBLOCK)): OK");
1224 /* get file status (mode, size) */
1225 struct stat aFileStat
;
1226 if (fstat(fd
, &aFileStat
) == -1)
1229 SAL_INFO("sal.file", "fstat(" << fd
<< "): " << UnixErrnoString(e
));
1230 eRet
= oslTranslateFileError(e
);
1232 SAL_INFO("sal.file", "close(" << fd
<< ")");
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");
1243 SAL_INFO("sal.file", "close(" << fd
<< ")");
1244 return osl_File_E_INVAL
;
1247 if (osl_file_queryLocking(uFlags
))
1250 if (flock(fd
, LOCK_EX
| LOCK_NB
) == -1)
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...
1258 if ((errno
!= ENOTSUP
) || ((flock(fd
, LOCK_SH
| LOCK_NB
) == 1) && (errno
!= ENOTSUP
)))
1260 eRet
= oslTranslateFileError(errno
);
1262 SAL_INFO("sal.file", "close(" << fd
<< ")");
1267 SAL_INFO("sal.file", "flock(" << fd
<< ",LOCK_EX|LOCK_NB): OK");
1269 struct flock aflock
;
1271 aflock
.l_type
= F_WRLCK
;
1272 aflock
.l_whence
= SEEK_SET
;
1276 if (fcntl(fd
, F_SETLK
, &aflock
) == -1)
1279 SAL_INFO("sal.file", "fcntl(" << fd
<< ",F_SETLK): " << UnixErrnoString(e
));
1280 eRet
= oslTranslateFileError(e
);
1282 SAL_INFO("sal.file", "close(" << fd
<< ")");
1285 #endif /* F_SETLK */
1288 /* allocate memory for impl structure */
1289 FileHandle_Impl
*pImpl
= new FileHandle_Impl(fd
, FileHandle_Impl::KIND_FD
, filePath
);
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
)
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
)
1319 if (macxp_resolveAlias(buffer
, sizeof(buffer
)) != 0)
1320 return oslTranslateFileError(errno
);
1323 return openFilePath(buffer
, pHandle
, uFlags
, mode
);
1326 oslFileError SAL_CALL
osl_closeFile(oslFileHandle Handle
)
1328 FileHandle_Impl
* pImpl
= static_cast< FileHandle_Impl
* >(Handle
);
1331 return osl_File_E_INVAL
;
1333 if (pImpl
->m_kind
== FileHandle_Impl::KIND_MEM
)
1336 rtl_string_release(pImpl
->m_memstreambuf
);
1337 pImpl
->m_memstreambuf
= nullptr;
1339 pImpl
->m_buffer
= NULL
;
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)
1361 SAL_INFO("sal.file", "close(" << pImpl
->m_fd
<< "): " << UnixErrnoString(e
));
1362 /* translate error code */
1363 result
= oslTranslateFileError(e
);
1366 SAL_INFO("sal.file", "close(" << pImpl
->m_fd
<< "): OK");
1368 (void) pthread_mutex_unlock(&(pImpl
->m_mutex
));
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
)
1390 static bool disabled
= getenv("SAL_DISABLE_FSYNC") != nullptr;
1393 SAL_INFO("sal.file", "fsync(" << pImpl
->m_fd
<< "): Disabled");
1394 else if (fsync(pImpl
->m_fd
) == -1)
1397 SAL_INFO("sal.file", "fsync(" << pImpl
->m_fd
<< "): " << UnixErrnoString(e
));
1398 return oslTranslateFileError(e
);
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();
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
,
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
;
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
);
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
)
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
1491 #if defined MACOSX || (defined(__sun) && (!defined(__XOPEN_OR_POSIX) || defined(_XPG6) || defined(__EXTENSIONS__)))
1492 int e
= posix_madvise(p
, nLength
, POSIX_MADV_WILLNEED
);
1494 SAL_INFO("sal.file", "posix_madvise(..., POSIX_MADV_WILLNEED) failed with " << e
);
1497 if (madvise(static_cast< caddr_t
>(p
), nLength
, MADV_WILLNEED
) != 0)
1498 SAL_INFO("sal.file", "madvise(..., MADV_WILLNEED) failed with " << UnixErrnoString(errno
));
1502 return osl_File_E_None
;
1505 static oslFileError
unmapFile(void* pAddr
, sal_uInt64 uLength
)
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
;
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
);
1535 oslFileError SAL_CALL
osl_unmapMappedFile(oslFileHandle Handle
, void* pAddr
, sal_uInt64 uLength
)
1537 FileHandle_Impl
*pImpl
= static_cast<FileHandle_Impl
*>(Handle
);
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
;
1571 oslFileError SAL_CALL
osl_readFile(
1572 oslFileHandle Handle
,
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
;
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
;
1627 oslFileError SAL_CALL
osl_readFileAt(
1628 oslFileHandle Handle
,
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
,
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
));
1735 case osl_Pos_Absolut
:
1737 return osl_File_E_INVAL
;
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
;
1746 if (nOffset
> MAX_OFF_T
- nPos
)
1747 return osl_File_E_OVERFLOW
;
1751 nPos
= sal::static_int_cast
< off_t
>(pImpl
->getSize());
1752 if ((nOffset
< 0) && (nPos
< -1*nOffset
))
1753 return osl_File_E_INVAL
;
1756 if (nOffset
> MAX_OFF_T
- nPos
)
1757 return osl_File_E_OVERFLOW
;
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
)
1798 pImpl
->m_bufptr
= -1;
1799 pImpl
->m_buflen
= 0;
1801 return pImpl
->setSize(uSize
);
1805 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */