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>
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"
52 #include <sys/param.h>
53 #include <sys/mount.h>
56 #include <CoreFoundation/CoreFoundation.h>
61 #include <osl/detail/android-bootstrap.h>
62 #include <android/log.h>
63 #include <android/asset_manager.h>
64 #include <o3tl/string_view.hxx>
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;
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 */
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
829 #define OPEN_WRITE_FLAGS ( O_RDWR | O_EXLOCK | O_NONBLOCK )
830 #define OPEN_CREATE_FLAGS ( O_CREAT | O_RDWR | O_EXLOCK | O_NONBLOCK )
832 #define OPEN_WRITE_FLAGS ( O_RDWR )
833 #define OPEN_CREATE_FLAGS ( O_CREAT | O_RDWR )
840 static oslFileError
openMemoryAsFile(const OString
&rData
,
841 oslFileHandle
*pHandle
,
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
);
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
{
874 AndroidFileCache(size_t nElements
)
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
))
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())
895 maEntries
[mnCur
].maFilePath
= OString(cpFilePath
, strlen(cpFilePath
));
896 maEntries
[mnCur
].maData
= rData
;
898 static AndroidFileCache
&getHitCache()
900 static AndroidFileCache
*pCache
= new AndroidFileCache(16);
903 static AndroidFileCache
&getMissCache()
905 static AndroidFileCache
*pCache
= new AndroidFileCache(32);
910 std::vector
<Entry
> maEntries
;
917 oslFileError
openFilePath(const OString
& filePath
, oslFileHandle
* pHandle
,
918 sal_uInt32 uFlags
, mode_t mode
)
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/"))
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());
939 AndroidFileCache::Entry
*pHit
= AndroidFileCache::getHitCache().find(cpAssetsPath
);
941 aData
= pHit
->maData
;
946 AndroidFileCache::Entry
*pMiss
= AndroidFileCache::getMissCache().find(cpAssetsPath
);
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
);
957 AndroidFileCache::getMissCache().insert(cpAssetsPath
, aData
);
959 __android_log_print(ANDROID_LOG_ERROR
,"libo:sal/osl/unx/file", "failed to open %s", filePath
.getStr());
960 return osl_File_E_NOENT
;
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
);
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
);
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))
1010 /* Check for flags passed in from SvFileStream::Open() */
1011 if (uFlags
& osl_File_OpenFlag_Trunc
)
1014 if (!(uFlags
& osl_File_OpenFlag_NoExcl
))
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 */
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
))
1032 // set close-on-exec by default
1036 int fd
= open_c( filePath
, flags
, mode
);
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);
1050 SAL_INFO("sal.file", "fcntl(" << fd
<< ",F_GETFL,0): " << UnixErrnoString(e
));
1051 eRet
= oslTranslateFileError(e
);
1053 SAL_INFO("sal.file", "close(" << fd
<< ")");
1057 SAL_INFO("sal.file", "fcntl(" << fd
<< ",F_GETFL,0): OK");
1059 if (fcntl(fd
, F_SETFL
, (f
& ~O_NONBLOCK
)) == -1)
1062 SAL_INFO("sal.file", "fcntl(" << fd
<< ",F_SETFL,(f & ~O_NONBLOCK)): " << UnixErrnoString(e
));
1063 eRet
= oslTranslateFileError(e
);
1065 SAL_INFO("sal.file", "close(" << fd
<< ")");
1069 SAL_INFO("sal.file", "fcntl(" << fd
<< ",F_SETFL,(f & ~O_NONBLOCK)): OK");
1073 /* get file status (mode, size) */
1074 struct stat aFileStat
;
1075 if (fstat(fd
, &aFileStat
) == -1)
1078 SAL_INFO("sal.file", "fstat(" << fd
<< "): " << UnixErrnoString(e
));
1079 eRet
= oslTranslateFileError(e
);
1081 SAL_INFO("sal.file", "close(" << fd
<< ")");
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");
1092 SAL_INFO("sal.file", "close(" << fd
<< ")");
1093 return osl_File_E_INVAL
;
1096 if (osl_file_queryLocking(uFlags
))
1099 if (flock(fd
, LOCK_EX
| LOCK_NB
) == -1)
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...
1107 if ((errno
!= ENOTSUP
) || ((flock(fd
, LOCK_SH
| LOCK_NB
) == 1) && (errno
!= ENOTSUP
)))
1109 eRet
= oslTranslateFileError(errno
);
1111 SAL_INFO("sal.file", "close(" << fd
<< ")");
1116 SAL_INFO("sal.file", "flock(" << fd
<< ",LOCK_EX|LOCK_NB): OK");
1118 struct flock aflock
;
1120 aflock
.l_type
= F_WRLCK
;
1121 aflock
.l_whence
= SEEK_SET
;
1125 if (fcntl(fd
, F_SETLK
, &aflock
) == -1)
1128 SAL_INFO("sal.file", "fcntl(" << fd
<< ",F_SETLK): " << UnixErrnoString(e
));
1129 eRet
= oslTranslateFileError(e
);
1131 SAL_INFO("sal.file", "close(" << fd
<< ")");
1134 #endif /* F_SETLK */
1137 /* allocate memory for impl structure */
1138 FileHandle_Impl
*pImpl
= new FileHandle_Impl(fd
, FileHandle_Impl::KIND_FD
, filePath
);
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
)
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
)
1168 if (macxp_resolveAlias(buffer
, sizeof(buffer
)) != 0)
1169 return oslTranslateFileError(errno
);
1172 return openFilePath(buffer
, pHandle
, uFlags
, mode
);
1175 oslFileError SAL_CALL
osl_closeFile(oslFileHandle Handle
)
1177 FileHandle_Impl
* pImpl
= static_cast< FileHandle_Impl
* >(Handle
);
1180 return osl_File_E_INVAL
;
1182 if (pImpl
->m_kind
== FileHandle_Impl::KIND_MEM
)
1185 rtl_string_release(pImpl
->m_memstreambuf
);
1186 pImpl
->m_memstreambuf
= nullptr;
1188 pImpl
->m_buffer
= NULL
;
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)
1210 SAL_INFO("sal.file", "close(" << pImpl
->m_fd
<< "): " << UnixErrnoString(e
));
1211 /* translate error code */
1212 result
= oslTranslateFileError(e
);
1215 SAL_INFO("sal.file", "close(" << pImpl
->m_fd
<< "): OK");
1217 (void) pthread_mutex_unlock(&(pImpl
->m_mutex
));
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
)
1239 static bool disabled
= getenv("SAL_DISABLE_FSYNC") != nullptr;
1242 SAL_INFO("sal.file", "fsync(" << pImpl
->m_fd
<< "): Disabled");
1243 else if (fsync(pImpl
->m_fd
) == -1)
1246 SAL_INFO("sal.file", "fsync(" << pImpl
->m_fd
<< "): " << UnixErrnoString(e
));
1247 return oslTranslateFileError(e
);
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();
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
,
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
;
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
);
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
)
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
1340 #if defined MACOSX || (defined(__sun) && (!defined(__XOPEN_OR_POSIX) || defined(_XPG6) || defined(__EXTENSIONS__)))
1341 int e
= posix_madvise(p
, nLength
, POSIX_MADV_WILLNEED
);
1343 SAL_INFO("sal.file", "posix_madvise(..., POSIX_MADV_WILLNEED) failed with " << e
);
1346 if (madvise(static_cast< caddr_t
>(p
), nLength
, MADV_WILLNEED
) != 0)
1347 SAL_INFO("sal.file", "madvise(..., MADV_WILLNEED) failed with " << UnixErrnoString(errno
));
1351 return osl_File_E_None
;
1354 static oslFileError
unmapFile(void* pAddr
, sal_uInt64 uLength
)
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
;
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
);
1384 oslFileError SAL_CALL
osl_unmapMappedFile(oslFileHandle Handle
, void* pAddr
, sal_uInt64 uLength
)
1386 FileHandle_Impl
*pImpl
= static_cast<FileHandle_Impl
*>(Handle
);
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
;
1420 oslFileError SAL_CALL
osl_readFile(
1421 oslFileHandle Handle
,
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
;
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
;
1476 oslFileError SAL_CALL
osl_readFileAt(
1477 oslFileHandle Handle
,
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
,
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
));
1584 case osl_Pos_Absolut
:
1586 return osl_File_E_INVAL
;
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
;
1595 if (nOffset
> MAX_OFF_T
- nPos
)
1596 return osl_File_E_OVERFLOW
;
1600 nPos
= sal::static_int_cast
< off_t
>(pImpl
->getSize());
1601 if ((nOffset
< 0) && (nPos
< -1*nOffset
))
1602 return osl_File_E_INVAL
;
1605 if (nOffset
> MAX_OFF_T
- nPos
)
1606 return osl_File_E_OVERFLOW
;
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
)
1647 pImpl
->m_bufptr
= -1;
1648 pImpl
->m_buflen
= 0;
1650 return pImpl
->setSize(uSize
);
1653 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */