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 <systools/win32/uwinapi.h>
22 #include <osl/file.hxx>
23 #include <rtl/alloc.h>
24 #include <rtl/byteseq.h>
25 #include <sal/log.hxx>
26 #include <o3tl/char16_t2wchar_t.hxx>
27 #include <o3tl/typed_flags_set.hxx>
29 #include "file-impl.hxx"
30 #include "file_url.hxx"
31 #include "file_error.hxx"
39 #ifdef max /* conflict w/ std::numeric_limits<T>::max() */
52 Seekable
= 1, /*< open() sets, iff regular file */
53 Readable
= 2, /*< open() sets, read() requires */
54 Writeable
= 4, /*< open() sets, write() requires */
55 Modified
= 8 /* write() sets, flush() resets */
60 template<> struct o3tl::typed_flags
<StateBits
>: o3tl::is_typed_flags
<StateBits
, 0xF> {};
64 /** File handle implementation.
66 struct FileHandle_Impl
73 sal_uInt64 m_size
; /*< file size */
74 LONGLONG m_offset
; /*< physical offset from begin of file */
75 // m_filepos is hit hard in some situations, where the overhead of a mutex starts to show up, so use an atomic
76 std::atomic
<LONGLONG
> m_filepos
; /*< logical offset from begin of file */
78 LONGLONG m_bufptr
; /*< buffer offset from begin of file */
79 SIZE_T m_buflen
; /*< buffer filled [0, m_bufsiz - 1] */
84 explicit FileHandle_Impl (HANDLE hFile
);
87 static SIZE_T
getpagesize();
89 sal_uInt64
getPos() const;
90 oslFileError
setPos (sal_uInt64 uPos
);
92 sal_uInt64
getSize() const;
93 oslFileError
setSize (sal_uInt64 uPos
);
98 DWORD nBytesRequested
,
99 sal_uInt64
* pBytesRead
);
101 oslFileError
writeAt(
103 void const * pBuffer
,
105 sal_uInt64
* pBytesWritten
);
107 oslFileError
readFileAt(
110 sal_uInt64 uBytesRequested
,
111 sal_uInt64
* pBytesRead
);
113 oslFileError
writeFileAt(
115 void const * pBuffer
,
116 sal_uInt64 uBytesToWrite
,
117 sal_uInt64
* pBytesWritten
);
119 oslFileError
readLineAt(
121 sal_Sequence
** ppSequence
,
122 sal_uInt64
* pBytesRead
);
124 static oslFileError
writeSequence_Impl (
125 sal_Sequence
** ppSequence
,
127 const void * pBuffer
,
130 oslFileError
syncFile();
136 FileHandle_Impl::FileHandle_Impl(HANDLE hFile
)
138 m_state (StateBits::Readable
| StateBits::Writeable
),
144 m_bufsiz (getpagesize()),
147 m_buffer
= static_cast<sal_uInt8
*>(calloc(m_bufsiz
, 1));
150 FileHandle_Impl::~FileHandle_Impl()
156 SIZE_T
FileHandle_Impl::getpagesize()
159 ::GetSystemInfo(&info
);
160 return sal::static_int_cast
< SIZE_T
>(info
.dwPageSize
);
163 sal_uInt64
FileHandle_Impl::getPos() const
165 return sal::static_int_cast
< sal_uInt64
>(m_filepos
.load());
168 oslFileError
FileHandle_Impl::setPos(sal_uInt64 uPos
)
170 m_filepos
= sal::static_int_cast
< LONGLONG
>(uPos
);
171 return osl_File_E_None
;
174 sal_uInt64
FileHandle_Impl::getSize() const
176 LONGLONG bufend
= std::max(LONGLONG(0), m_bufptr
) + m_buflen
;
177 return std::max(m_size
, sal::static_int_cast
< sal_uInt64
>(bufend
));
180 oslFileError
FileHandle_Impl::setSize(sal_uInt64 uSize
)
182 LARGE_INTEGER nDstPos
; nDstPos
.QuadPart
= sal::static_int_cast
< LONGLONG
>(uSize
);
183 if (!::SetFilePointerEx(m_hFile
, nDstPos
, nullptr, FILE_BEGIN
))
184 return oslTranslateFileError(GetLastError());
186 if (!::SetEndOfFile(m_hFile
))
187 return oslTranslateFileError(GetLastError());
190 nDstPos
.QuadPart
= m_offset
;
191 if (!::SetFilePointerEx(m_hFile
, nDstPos
, nullptr, FILE_BEGIN
))
192 return oslTranslateFileError(GetLastError());
194 return osl_File_E_None
;
197 oslFileError
FileHandle_Impl::readAt(
200 DWORD nBytesRequested
,
201 sal_uInt64
* pBytesRead
)
203 SAL_WARN_IF(!(m_state
& StateBits::Seekable
), "sal.osl", "FileHandle_Impl::readAt(): not seekable");
204 if (!(m_state
& StateBits::Seekable
))
205 return osl_File_E_SPIPE
;
207 SAL_WARN_IF(!(m_state
& StateBits::Readable
), "sal.osl", "FileHandle_Impl::readAt(): not readable");
208 if (!(m_state
& StateBits::Readable
))
209 return osl_File_E_BADF
;
211 if (nOffset
!= m_offset
)
213 LARGE_INTEGER liOffset
; liOffset
.QuadPart
= nOffset
;
214 if (!::SetFilePointerEx(m_hFile
, liOffset
, nullptr, FILE_BEGIN
))
215 return oslTranslateFileError(GetLastError());
220 if (!::ReadFile(m_hFile
, pBuffer
, nBytesRequested
, &dwDone
, nullptr))
221 return oslTranslateFileError(GetLastError());
224 *pBytesRead
= dwDone
;
225 return osl_File_E_None
;
228 oslFileError
FileHandle_Impl::writeAt(
230 void const * pBuffer
,
232 sal_uInt64
* pBytesWritten
)
234 SAL_WARN_IF(!(m_state
& StateBits::Seekable
), "sal.osl", "FileHandle_Impl::writeAt(): not seekable");
235 if (!(m_state
& StateBits::Seekable
))
236 return osl_File_E_SPIPE
;
238 SAL_WARN_IF(!(m_state
& StateBits::Writeable
), "sal.osl", "FileHandle_Impl::writeAt(): not writeable");
239 if (!(m_state
& StateBits::Writeable
))
240 return osl_File_E_BADF
;
242 if (nOffset
!= m_offset
)
244 LARGE_INTEGER liOffset
; liOffset
.QuadPart
= nOffset
;
245 if (!::SetFilePointerEx (m_hFile
, liOffset
, nullptr, FILE_BEGIN
))
246 return oslTranslateFileError(GetLastError());
251 if (!::WriteFile(m_hFile
, pBuffer
, nBytesToWrite
, &dwDone
, nullptr))
252 return oslTranslateFileError(GetLastError());
255 m_size
= std::max(m_size
, sal::static_int_cast
< sal_uInt64
>(m_offset
));
257 *pBytesWritten
= dwDone
;
258 return osl_File_E_None
;
261 oslFileError
FileHandle_Impl::readFileAt(
264 sal_uInt64 uBytesRequested
,
265 sal_uInt64
* pBytesRead
)
267 static sal_uInt64
const g_limit_dword
= std::numeric_limits
< DWORD
>::max();
268 if (g_limit_dword
< uBytesRequested
)
269 return osl_File_E_OVERFLOW
;
270 DWORD nBytesRequested
= sal::static_int_cast
< DWORD
>(uBytesRequested
);
272 if (!(m_state
& StateBits::Seekable
))
274 // not seekable (pipe)
276 if (!::ReadFile(m_hFile
, pBuffer
, nBytesRequested
, &dwDone
, nullptr))
277 return oslTranslateFileError(GetLastError());
278 *pBytesRead
= dwDone
;
279 return osl_File_E_None
;
284 return readAt (nOffset
, pBuffer
, nBytesRequested
, pBytesRead
);
288 sal_uInt8
* buffer
= static_cast< sal_uInt8
* >(pBuffer
);
289 for (*pBytesRead
= 0; nBytesRequested
> 0;)
291 LONGLONG
const bufptr
= (nOffset
/ m_bufsiz
) * m_bufsiz
;
292 SIZE_T
const bufpos
= nOffset
% m_bufsiz
;
294 if (bufptr
!= m_bufptr
)
296 // flush current buffer
297 oslFileError result
= syncFile();
298 if (result
!= osl_File_E_None
)
303 if (nBytesRequested
>= m_bufsiz
)
305 // buffer too small, read through from file
306 sal_uInt64 uDone
= 0;
307 result
= readAt (nOffset
, &(buffer
[*pBytesRead
]), nBytesRequested
, &uDone
);
308 if (result
!= osl_File_E_None
)
311 nBytesRequested
-= sal::static_int_cast
< DWORD
>(uDone
);
312 *pBytesRead
+= uDone
;
313 return osl_File_E_None
;
316 // update buffer (pointer)
317 sal_uInt64 uDone
= 0;
318 result
= readAt(bufptr
, m_buffer
, m_bufsiz
, &uDone
);
319 if (result
!= osl_File_E_None
)
322 m_buflen
= sal::static_int_cast
< SIZE_T
>(uDone
);
324 if (bufpos
>= m_buflen
)
327 return osl_File_E_None
;
330 SIZE_T
const bytes
= std::min(m_buflen
- bufpos
, static_cast<SIZE_T
>(nBytesRequested
));
331 memcpy(&(buffer
[*pBytesRead
]), &(m_buffer
[bufpos
]), bytes
);
332 nBytesRequested
-= bytes
;
333 *pBytesRead
+= bytes
;
336 return osl_File_E_None
;
340 oslFileError
FileHandle_Impl::writeFileAt(
342 void const * pBuffer
,
343 sal_uInt64 uBytesToWrite
,
344 sal_uInt64
* pBytesWritten
)
346 static sal_uInt64
const g_limit_dword
= std::numeric_limits
< DWORD
>::max();
347 if (g_limit_dword
< uBytesToWrite
)
348 return osl_File_E_OVERFLOW
;
349 DWORD nBytesToWrite
= sal::static_int_cast
< DWORD
>(uBytesToWrite
);
351 if (!(m_state
& StateBits::Seekable
))
353 // not seekable (pipe)
355 if (!::WriteFile(m_hFile
, pBuffer
, nBytesToWrite
, &dwDone
, nullptr))
356 return oslTranslateFileError(GetLastError());
357 *pBytesWritten
= dwDone
;
358 return osl_File_E_None
;
363 return writeAt(nOffset
, pBuffer
, nBytesToWrite
, pBytesWritten
);
367 sal_uInt8
const * buffer
= static_cast< sal_uInt8
const* >(pBuffer
);
368 for (*pBytesWritten
= 0; nBytesToWrite
> 0;)
370 LONGLONG
const bufptr
= (nOffset
/ m_bufsiz
) * m_bufsiz
;
371 SIZE_T
const bufpos
= nOffset
% m_bufsiz
;
372 if (bufptr
!= m_bufptr
)
374 // flush current buffer
375 oslFileError result
= syncFile();
376 if (result
!= osl_File_E_None
)
381 if (nBytesToWrite
>= m_bufsiz
)
383 // buffer too small, write through to file
384 sal_uInt64 uDone
= 0;
385 result
= writeAt(nOffset
, &(buffer
[*pBytesWritten
]), nBytesToWrite
, &uDone
);
386 if (result
!= osl_File_E_None
)
388 if (uDone
!= nBytesToWrite
)
389 return osl_File_E_IO
;
391 nBytesToWrite
-= sal::static_int_cast
< DWORD
>(uDone
);
392 *pBytesWritten
+= uDone
;
393 return osl_File_E_None
;
396 // update buffer (pointer)
397 sal_uInt64 uDone
= 0;
398 result
= readAt(bufptr
, m_buffer
, m_bufsiz
, &uDone
);
399 if (result
!= osl_File_E_None
)
402 m_buflen
= sal::static_int_cast
< SIZE_T
>(uDone
);
405 SIZE_T
const bytes
= std::min(m_bufsiz
- bufpos
, static_cast<SIZE_T
>(nBytesToWrite
));
406 memcpy(&(m_buffer
[bufpos
]), &(buffer
[*pBytesWritten
]), bytes
);
407 nBytesToWrite
-= bytes
;
408 *pBytesWritten
+= bytes
;
411 m_buflen
= std::max(m_buflen
, bufpos
+ bytes
);
412 m_state
|= StateBits::Modified
;
414 return osl_File_E_None
;
418 oslFileError
FileHandle_Impl::readLineAt(
420 sal_Sequence
** ppSequence
,
421 sal_uInt64
* pBytesRead
)
423 oslFileError result
= osl_File_E_None
;
425 LONGLONG bufptr
= (nOffset
/ m_bufsiz
) * m_bufsiz
;
426 if (bufptr
!= m_bufptr
)
428 /* flush current buffer */
430 if (result
!= osl_File_E_None
)
433 /* update buffer (pointer) */
434 sal_uInt64 uDone
= 0;
435 result
= readAt(bufptr
, m_buffer
, m_bufsiz
, &uDone
);
436 if (result
!= osl_File_E_None
)
440 m_buflen
= sal::static_int_cast
< SIZE_T
>(uDone
);
443 static int const LINE_STATE_BEGIN
= 0;
444 static int const LINE_STATE_CR
= 1;
445 static int const LINE_STATE_LF
= 2;
447 SIZE_T bufpos
= sal::static_int_cast
< SIZE_T
>(nOffset
- m_bufptr
), curpos
= bufpos
, dstpos
= 0;
448 int state
= (bufpos
>= m_buflen
) ? LINE_STATE_LF
: LINE_STATE_BEGIN
;
450 for (; state
!= LINE_STATE_LF
;)
452 if (curpos
>= m_buflen
)
454 /* buffer examined */
455 if (curpos
> bufpos
) // actually, curpos can't become less than bufpos, so != could do
457 /* flush buffer to sequence */
458 result
= writeSequence_Impl(
459 ppSequence
, &dstpos
, &(m_buffer
[bufpos
]), curpos
- bufpos
);
460 if (result
!= osl_File_E_None
)
462 *pBytesRead
+= curpos
- bufpos
;
463 nOffset
+= curpos
- bufpos
;
466 bufptr
= nOffset
/ m_bufsiz
* m_bufsiz
;
467 if (bufptr
!= m_bufptr
)
469 /* update buffer (pointer) */
470 sal_uInt64 uDone
= 0;
471 result
= readAt(bufptr
, m_buffer
, m_bufsiz
, &uDone
);
472 if (result
!= osl_File_E_None
)
475 m_buflen
= sal::static_int_cast
< SIZE_T
>(uDone
);
478 bufpos
= sal::static_int_cast
< SIZE_T
>(nOffset
- m_bufptr
);
480 if (bufpos
>= m_buflen
)
486 state
= LINE_STATE_LF
;
487 switch (m_buffer
[curpos
])
489 case 0x0A: /* CRLF */
490 /* eat current char */
493 default: /* single CR */
494 /* keep current char */
499 /* determine next state */
500 switch (m_buffer
[curpos
])
502 case 0x0A: /* single LF */
503 state
= LINE_STATE_LF
;
506 state
= LINE_STATE_CR
;
508 default: /* advance to next char */
512 if (state
!= LINE_STATE_BEGIN
)
514 /* store (and eat) the newline char */
515 m_buffer
[curpos
] = 0x0A;
518 /* flush buffer to sequence */
519 result
= writeSequence_Impl(
520 ppSequence
, &dstpos
, &(m_buffer
[bufpos
]), curpos
- bufpos
- 1);
521 if (result
!= osl_File_E_None
)
523 *pBytesRead
+= curpos
- bufpos
;
524 nOffset
+= curpos
- bufpos
;
530 result
= writeSequence_Impl(ppSequence
, &dstpos
, nullptr, 0);
531 if (result
!= osl_File_E_None
)
534 return osl_File_E_None
;
535 if (bufpos
>= m_buflen
)
536 return osl_File_E_AGAIN
;
537 return osl_File_E_None
;
540 oslFileError
FileHandle_Impl::writeSequence_Impl(
541 sal_Sequence
** ppSequence
,
543 const void * pBuffer
,
546 sal_Int32 nElements
= *pnOffset
+ nBytes
;
549 /* construct sequence */
550 rtl_byte_sequence_constructNoDefault(ppSequence
, nElements
);
552 else if (nElements
!= (*ppSequence
)->nElements
)
554 /* resize sequence */
555 rtl_byte_sequence_realloc(ppSequence
, nElements
);
560 memcpy(&((*ppSequence
)->elements
[*pnOffset
]), pBuffer
, nBytes
);
563 return (*ppSequence
) ? osl_File_E_None
: osl_File_E_NOMEM
;
566 oslFileError
FileHandle_Impl::syncFile()
568 oslFileError result
= osl_File_E_None
;
569 if (m_state
& StateBits::Modified
)
571 sal_uInt64 uDone
= 0;
572 result
= writeAt(m_bufptr
, m_buffer
, m_buflen
, &uDone
);
573 if (result
!= osl_File_E_None
)
575 if (uDone
!= m_buflen
)
576 return osl_File_E_IO
;
577 m_state
&= ~StateBits::Modified
;
582 extern "C" oslFileHandle
osl_createFileHandleFromOSHandle(
586 if (!IsValidHandle(hFile
))
587 return nullptr; // EINVAL
589 FileHandle_Impl
* pImpl
= new FileHandle_Impl(hFile
);
591 /* check for regular file */
592 if (GetFileType(hFile
) == FILE_TYPE_DISK
)
595 pImpl
->m_state
|= StateBits::Seekable
;
597 /* init current size */
598 LARGE_INTEGER uSize
= { { 0, 0 } };
599 (void) ::GetFileSizeEx(hFile
, &uSize
);
600 pImpl
->m_size
= (sal::static_int_cast
<sal_uInt64
>(uSize
.HighPart
) << 32) + uSize
.LowPart
;
603 if (!(uFlags
& osl_File_OpenFlag_Read
))
604 pImpl
->m_state
&= ~StateBits::Readable
;
605 if (!(uFlags
& osl_File_OpenFlag_Write
))
606 pImpl
->m_state
&= ~StateBits::Writeable
;
609 !((uFlags
& osl_File_OpenFlag_Read
) || (uFlags
& osl_File_OpenFlag_Write
)),
611 "osl_createFileHandleFromOSHandle(): missing read/write access flags");
612 return static_cast<oslFileHandle
>(pImpl
);
615 oslFileError SAL_CALL
osl_openFile(
616 rtl_uString
* strPath
,
617 oslFileHandle
* pHandle
,
621 oslFileError result
= osl_getSystemPathFromFileURL_(OUString::unacquired(&strPath
), &strSysPath
.pData
, false);
622 if (result
!= osl_File_E_None
)
625 // tdf126742 use FILE_SHARE_WRITE to get closer to non-Windows platform behaviour,
626 // for details and discussion see task please
627 DWORD dwAccess
= GENERIC_READ
, dwShare
= FILE_SHARE_READ
| FILE_SHARE_WRITE
, dwCreation
= 0;
629 if (uFlags
& osl_File_OpenFlag_Write
)
630 dwAccess
|= GENERIC_WRITE
;
632 if (uFlags
& osl_File_OpenFlag_NoLock
)
633 dwShare
|= FILE_SHARE_DELETE
;
635 if (uFlags
& osl_File_OpenFlag_Create
)
636 dwCreation
|= CREATE_NEW
;
638 dwCreation
|= OPEN_EXISTING
;
640 HANDLE hFile
= CreateFileW(
641 o3tl::toW(strSysPath
.getStr()),
642 dwAccess
, dwShare
, nullptr, dwCreation
, 0, nullptr);
644 // @@@ ERROR HANDLING @@@
645 if (!IsValidHandle(hFile
))
646 result
= oslTranslateFileError(GetLastError());
648 *pHandle
= osl_createFileHandleFromOSHandle(hFile
, uFlags
| osl_File_OpenFlag_Read
);
653 oslFileError SAL_CALL
osl_syncFile(oslFileHandle Handle
)
655 FileHandle_Impl
* pImpl
= static_cast<FileHandle_Impl
*>(Handle
);
656 if ((!pImpl
) || !IsValidHandle(pImpl
->m_hFile
))
657 return osl_File_E_INVAL
;
659 std::lock_guard
lock(pImpl
->m_mutex
);
661 oslFileError result
= pImpl
->syncFile();
662 if (result
!= osl_File_E_None
)
665 if (!FlushFileBuffers(pImpl
->m_hFile
))
666 return oslTranslateFileError(GetLastError());
668 return osl_File_E_None
;
671 oslFileError SAL_CALL
osl_closeFile(oslFileHandle Handle
)
673 FileHandle_Impl
* pImpl
= static_cast<FileHandle_Impl
*>(Handle
);
674 if ((!pImpl
) || !IsValidHandle(pImpl
->m_hFile
))
675 return osl_File_E_INVAL
;
679 std::lock_guard
lock(pImpl
->m_mutex
);
681 result
= pImpl
->syncFile();
682 if (result
!= osl_File_E_None
)
684 /* ignore double failure */
685 (void)::CloseHandle(pImpl
->m_hFile
);
687 else if (!::CloseHandle(pImpl
->m_hFile
))
689 /* translate error code */
690 result
= oslTranslateFileError(GetLastError());
700 // coverity[result_independent_of_operands] - crossplatform requirement
701 template<typename T
> bool exceedsMaxSIZE_T(T n
)
702 { return n
> std::numeric_limits
< SIZE_T
>::max(); }
706 oslFileError SAL_CALL
osl_mapFile(
707 oslFileHandle Handle
,
717 explicit FileMapping(HANDLE hMap
)
723 (void)::CloseHandle(m_handle
);
727 FileHandle_Impl
* pImpl
= static_cast<FileHandle_Impl
*>(Handle
);
728 if ((!pImpl
) || !IsValidHandle(pImpl
->m_hFile
) || (!ppAddr
))
729 return osl_File_E_INVAL
;
732 if (exceedsMaxSIZE_T(uLength
))
733 return osl_File_E_OVERFLOW
;
734 SIZE_T
const nLength
= sal::static_int_cast
< SIZE_T
>(uLength
);
736 FileMapping
aMap(::CreateFileMappingW(pImpl
->m_hFile
, nullptr, SEC_COMMIT
| PAGE_READONLY
, 0, 0, nullptr));
737 if (!IsValidHandle(aMap
.m_handle
))
738 return oslTranslateFileError(GetLastError());
740 DWORD
const dwOffsetHi
= sal::static_int_cast
<DWORD
>(uOffset
>> 32);
741 DWORD
const dwOffsetLo
= sal::static_int_cast
<DWORD
>(uOffset
& 0xFFFFFFFF);
743 *ppAddr
= ::MapViewOfFile(aMap
.m_handle
, FILE_MAP_READ
, dwOffsetHi
, dwOffsetLo
, nLength
);
745 return oslTranslateFileError(GetLastError());
747 if (uFlags
& osl_File_MapFlag_RandomAccess
)
749 // Determine memory pagesize.
751 ::GetSystemInfo(&info
);
752 DWORD
const dwPageSize
= info
.dwPageSize
;
755 * Pagein, touching first byte of each memory page.
756 * Note: volatile disables optimizing the loop away.
758 BYTE
volatile * pData(static_cast<BYTE
*>(*ppAddr
));
759 SIZE_T
nSize(nLength
);
761 while (nSize
> dwPageSize
)
772 return osl_File_E_None
;
775 oslFileError SAL_CALL
osl_unmapFile(void* pAddr
, sal_uInt64
/* uLength */)
778 return osl_File_E_INVAL
;
780 if (!::UnmapViewOfFile(pAddr
))
781 return oslTranslateFileError(GetLastError());
783 return osl_File_E_None
;
786 oslFileError SAL_CALL
osl_unmapMappedFile(oslFileHandle
/* Handle */, void* pAddr
, sal_uInt64 uLength
)
788 return osl_unmapFile(pAddr
, uLength
);
792 SAL_CALL
osl_readLine(
793 oslFileHandle Handle
,
794 sal_Sequence
** ppSequence
)
796 FileHandle_Impl
* pImpl
= static_cast<FileHandle_Impl
*>(Handle
);
797 if ((!pImpl
) || !IsValidHandle(pImpl
->m_hFile
) || (!ppSequence
))
798 return osl_File_E_INVAL
;
799 sal_uInt64 uBytesRead
= 0;
801 // read at current filepos; filepos += uBytesRead;
802 std::lock_guard
lock(pImpl
->m_mutex
);
803 oslFileError result
= pImpl
->readLineAt(
804 pImpl
->m_filepos
, ppSequence
, &uBytesRead
);
805 if (result
== osl_File_E_None
)
806 pImpl
->m_filepos
+= uBytesRead
;
810 oslFileError SAL_CALL
osl_readFile(
811 oslFileHandle Handle
,
813 sal_uInt64 uBytesRequested
,
814 sal_uInt64
* pBytesRead
)
816 FileHandle_Impl
* pImpl
= static_cast<FileHandle_Impl
*>(Handle
);
817 if ((!pImpl
) || !IsValidHandle(pImpl
->m_hFile
) || (!pBuffer
) || (!pBytesRead
))
818 return osl_File_E_INVAL
;
820 // read at current filepos; filepos += *pBytesRead;
821 std::lock_guard
lock(pImpl
->m_mutex
);
822 oslFileError result
= pImpl
->readFileAt(
823 pImpl
->m_filepos
, pBuffer
, uBytesRequested
, pBytesRead
);
824 if (result
== osl_File_E_None
)
825 pImpl
->m_filepos
+= *pBytesRead
;
829 oslFileError SAL_CALL
osl_writeFile(
830 oslFileHandle Handle
,
831 const void * pBuffer
,
832 sal_uInt64 uBytesToWrite
,
833 sal_uInt64
* pBytesWritten
)
835 FileHandle_Impl
* pImpl
= static_cast<FileHandle_Impl
*>(Handle
);
837 if ((!pImpl
) || !IsValidHandle(pImpl
->m_hFile
) || (!pBuffer
) || (!pBytesWritten
))
838 return osl_File_E_INVAL
;
840 // write at current filepos; filepos += *pBytesWritten;
841 std::lock_guard
lock(pImpl
->m_mutex
);
842 oslFileError result
= pImpl
->writeFileAt(
843 pImpl
->m_filepos
, pBuffer
, uBytesToWrite
, pBytesWritten
);
844 if (result
== osl_File_E_None
)
845 pImpl
->m_filepos
+= *pBytesWritten
;
849 LONGLONG
const g_limit_longlong
= std::numeric_limits
< LONGLONG
>::max();
853 // coverity[result_independent_of_operands] - crossplatform requirement
854 template<typename T
> bool exceedsMaxLONGLONG(T n
)
855 { return n
> g_limit_longlong
; }
857 template<typename T
> bool exceedsMinLONGLONG(T n
)
858 { return n
< std::numeric_limits
<LONGLONG
>::min(); }
862 oslFileError SAL_CALL
osl_readFileAt(
863 oslFileHandle Handle
,
866 sal_uInt64 uBytesRequested
,
867 sal_uInt64
* pBytesRead
)
869 FileHandle_Impl
* pImpl
= static_cast<FileHandle_Impl
*>(Handle
);
871 if ((!pImpl
) || !IsValidHandle(pImpl
->m_hFile
) || (!pBuffer
) || (!pBytesRead
))
872 return osl_File_E_INVAL
;
873 if (!(pImpl
->m_state
& StateBits::Seekable
))
874 return osl_File_E_SPIPE
;
876 if (exceedsMaxLONGLONG(uOffset
))
877 return osl_File_E_OVERFLOW
;
878 LONGLONG
const nOffset
= sal::static_int_cast
< LONGLONG
>(uOffset
);
880 // read at specified fileptr
881 std::lock_guard
lock (pImpl
->m_mutex
);
882 return pImpl
->readFileAt(nOffset
, pBuffer
, uBytesRequested
, pBytesRead
);
885 oslFileError SAL_CALL
osl_writeFileAt(
886 oslFileHandle Handle
,
889 sal_uInt64 uBytesToWrite
,
890 sal_uInt64
* pBytesWritten
)
892 FileHandle_Impl
* pImpl
= static_cast<FileHandle_Impl
*>(Handle
);
894 if ((!pImpl
) || !IsValidHandle(pImpl
->m_hFile
) || (!pBuffer
) || (!pBytesWritten
))
895 return osl_File_E_INVAL
;
896 if (!(pImpl
->m_state
& StateBits::Seekable
))
897 return osl_File_E_SPIPE
;
899 if (exceedsMaxLONGLONG(uOffset
))
900 return osl_File_E_OVERFLOW
;
901 LONGLONG
const nOffset
= sal::static_int_cast
< LONGLONG
>(uOffset
);
903 // write at specified fileptr
904 std::lock_guard
lock(pImpl
->m_mutex
);
905 return pImpl
->writeFileAt(nOffset
, pBuffer
, uBytesToWrite
, pBytesWritten
);
908 oslFileError SAL_CALL
osl_isEndOfFile(oslFileHandle Handle
, sal_Bool
*pIsEOF
)
910 FileHandle_Impl
* pImpl
= static_cast<FileHandle_Impl
*>(Handle
);
912 if ((!pImpl
) || !IsValidHandle(pImpl
->m_hFile
) || (!pIsEOF
))
913 return osl_File_E_INVAL
;
915 std::lock_guard
lock(pImpl
->m_mutex
);
916 *pIsEOF
= (pImpl
->getPos() == pImpl
->getSize());
917 return osl_File_E_None
;
920 oslFileError SAL_CALL
osl_getFilePos(oslFileHandle Handle
, sal_uInt64
*pPos
)
922 FileHandle_Impl
* pImpl
= static_cast<FileHandle_Impl
*>(Handle
);
923 if ((!pImpl
) || !IsValidHandle(pImpl
->m_hFile
) || (!pPos
))
924 return osl_File_E_INVAL
;
926 // no need to lock because pos is atomic
927 *pPos
= pImpl
->getPos();
929 return osl_File_E_None
;
932 oslFileError SAL_CALL
osl_setFilePos(oslFileHandle Handle
, sal_uInt32 uHow
, sal_Int64 uOffset
)
934 FileHandle_Impl
* pImpl
= static_cast<FileHandle_Impl
*>(Handle
);
935 if ((!pImpl
) || !IsValidHandle(pImpl
->m_hFile
))
936 return osl_File_E_INVAL
;
938 if (exceedsMaxLONGLONG(uOffset
) || exceedsMinLONGLONG(uOffset
))
939 return osl_File_E_OVERFLOW
;
940 LONGLONG nPos
= 0, nOffset
= sal::static_int_cast
< LONGLONG
>(uOffset
);
942 std::lock_guard
lock(pImpl
->m_mutex
);
945 case osl_Pos_Absolut
:
947 return osl_File_E_INVAL
;
950 case osl_Pos_Current
:
951 nPos
= sal::static_int_cast
< LONGLONG
>(pImpl
->getPos());
952 if ((nOffset
< 0) && (nPos
< -1*nOffset
))
953 return osl_File_E_INVAL
;
955 if (nOffset
> g_limit_longlong
- nPos
)
956 return osl_File_E_OVERFLOW
;
960 nPos
= sal::static_int_cast
< LONGLONG
>(pImpl
->getSize());
961 if ((nOffset
< 0) && (nPos
< -1*nOffset
))
962 return osl_File_E_INVAL
;
964 if (nOffset
> g_limit_longlong
- nPos
)
965 return osl_File_E_OVERFLOW
;
969 return osl_File_E_INVAL
;
972 return pImpl
->setPos(nPos
+ nOffset
);
975 oslFileError SAL_CALL
osl_getFileSize(oslFileHandle Handle
, sal_uInt64
*pSize
)
977 FileHandle_Impl
* pImpl
= static_cast<FileHandle_Impl
*>(Handle
);
979 if ((!pImpl
) || !IsValidHandle(pImpl
->m_hFile
) || (!pSize
))
980 return osl_File_E_INVAL
;
982 std::lock_guard
lock(pImpl
->m_mutex
);
983 *pSize
= pImpl
->getSize();
984 return osl_File_E_None
;
987 oslFileError SAL_CALL
osl_setFileSize(oslFileHandle Handle
, sal_uInt64 uSize
)
989 FileHandle_Impl
* pImpl
= static_cast<FileHandle_Impl
*>(Handle
);
991 if ((!pImpl
) || !IsValidHandle(pImpl
->m_hFile
))
992 return osl_File_E_INVAL
;
993 if (!(pImpl
->m_state
& StateBits::Writeable
))
994 return osl_File_E_BADF
;
996 if (exceedsMaxLONGLONG(uSize
))
997 return osl_File_E_OVERFLOW
;
999 std::lock_guard
lock(pImpl
->m_mutex
);
1000 oslFileError result
= pImpl
->syncFile();
1001 if (result
!= osl_File_E_None
)
1003 pImpl
->m_bufptr
= -1;
1004 pImpl
->m_buflen
= 0;
1006 return pImpl
->setSize(uSize
);
1009 oslFileError SAL_CALL
osl_removeFile(rtl_uString
* strPath
)
1011 OUString strSysPath
;
1012 oslFileError error
= osl_getSystemPathFromFileURL_(OUString::unacquired(&strPath
), &strSysPath
.pData
, false);
1014 if (error
== osl_File_E_None
)
1016 if (DeleteFileW(o3tl::toW(strSysPath
.getStr())))
1017 error
= osl_File_E_None
;
1019 error
= oslTranslateFileError(GetLastError());
1024 oslFileError SAL_CALL
osl_copyFile(rtl_uString
* strPath
, rtl_uString
*strDestPath
)
1026 OUString strSysPath
, strSysDestPath
;
1027 oslFileError error
= osl_getSystemPathFromFileURL_(OUString::unacquired(&strPath
), &strSysPath
.pData
, false);
1029 if (error
== osl_File_E_None
)
1030 error
= osl_getSystemPathFromFileURL_(OUString::unacquired(&strDestPath
), &strSysDestPath
.pData
, false);
1032 if (error
== osl_File_E_None
)
1034 LPCWSTR src
= o3tl::toW(strSysPath
.getStr());
1035 LPCWSTR dst
= o3tl::toW(strSysDestPath
.getStr());
1037 if (CopyFileW(src
, dst
, FALSE
))
1038 error
= osl_File_E_None
;
1040 error
= oslTranslateFileError(GetLastError());
1046 oslFileError SAL_CALL
osl_moveFile(rtl_uString
* strPath
, rtl_uString
*strDestPath
)
1048 OUString strSysPath
, strSysDestPath
;
1049 oslFileError error
= osl_getSystemPathFromFileURL_(OUString::unacquired(&strPath
), &strSysPath
.pData
, false);
1051 if (error
== osl_File_E_None
)
1052 error
= osl_getSystemPathFromFileURL_(OUString::unacquired(&strDestPath
), &strSysDestPath
.pData
, false);
1054 if (error
== osl_File_E_None
)
1056 LPCWSTR src
= o3tl::toW(strSysPath
.getStr());
1057 LPCWSTR dst
= o3tl::toW(strSysDestPath
.getStr());
1059 if (MoveFileExW(src
, dst
, MOVEFILE_COPY_ALLOWED
| MOVEFILE_WRITE_THROUGH
| MOVEFILE_REPLACE_EXISTING
))
1060 error
= osl_File_E_None
;
1062 error
= oslTranslateFileError(GetLastError());
1068 oslFileError SAL_CALL
osl_replaceFile(rtl_uString
* strPath
, rtl_uString
* strDestPath
)
1070 OUString strSysPath
, strSysDestPath
;
1071 oslFileError error
= osl_getSystemPathFromFileURL_(OUString::unacquired(&strPath
), &strSysPath
.pData
, false);
1073 if (error
== osl_File_E_None
)
1074 error
= osl_getSystemPathFromFileURL_(OUString::unacquired(&strDestPath
), &strSysDestPath
.pData
, false);
1076 if (error
== osl_File_E_None
)
1078 LPCWSTR src
= o3tl::toW(strSysPath
.getStr());
1079 LPCWSTR dst
= o3tl::toW(strSysDestPath
.getStr());
1081 if (!ReplaceFileW(dst
, src
, nullptr,
1082 REPLACEFILE_WRITE_THROUGH
| REPLACEFILE_IGNORE_MERGE_ERRORS
1083 | REPLACEFILE_IGNORE_ACL_ERRORS
,
1086 DWORD dwError
= GetLastError();
1087 if (dwError
== ERROR_FILE_NOT_FOUND
// no strDestPath file?
1088 || dwError
== ERROR_UNABLE_TO_MOVE_REPLACEMENT
// e.g., files on different volumes
1089 || dwError
== ERROR_UNABLE_TO_MOVE_REPLACEMENT_2
1090 || dwError
== ERROR_UNABLE_TO_REMOVE_REPLACED
)
1091 error
= osl_moveFile(strPath
, strDestPath
);
1093 error
= oslTranslateFileError(dwError
);
1100 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */