tdf#154285 Check upper bound of arguments in SbRtl_Minute function
[LibreOffice.git] / sal / osl / w32 / file.cxx
blob4c4c06f462fa4eb48cbe73976ac1dc8fc3d0b325
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <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"
33 #include <atomic>
34 #include <cassert>
35 #include <algorithm>
36 #include <limits>
37 #include <mutex>
39 #ifdef max /* conflict w/ std::numeric_limits<T>::max() */
40 #undef max
41 #endif
42 #ifdef min
43 #undef min
44 #endif
46 namespace {
48 /** State
50 enum class StateBits
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> {};
62 namespace {
64 /** File handle implementation.
66 struct FileHandle_Impl
68 std::mutex m_mutex;
69 HANDLE m_hFile;
71 StateBits m_state;
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] */
81 SIZE_T m_bufsiz;
82 sal_uInt8 * m_buffer;
84 explicit FileHandle_Impl (HANDLE hFile);
85 ~FileHandle_Impl();
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);
95 oslFileError readAt(
96 LONGLONG nOffset,
97 void * pBuffer,
98 DWORD nBytesRequested,
99 sal_uInt64 * pBytesRead);
101 oslFileError writeAt(
102 LONGLONG nOffset,
103 void const * pBuffer,
104 DWORD nBytesToWrite,
105 sal_uInt64 * pBytesWritten);
107 oslFileError readFileAt(
108 LONGLONG nOffset,
109 void * pBuffer,
110 sal_uInt64 uBytesRequested,
111 sal_uInt64 * pBytesRead);
113 oslFileError writeFileAt(
114 LONGLONG nOffset,
115 void const * pBuffer,
116 sal_uInt64 uBytesToWrite,
117 sal_uInt64 * pBytesWritten);
119 oslFileError readLineAt(
120 LONGLONG nOffset,
121 sal_Sequence ** ppSequence,
122 sal_uInt64 * pBytesRead);
124 static oslFileError writeSequence_Impl (
125 sal_Sequence ** ppSequence,
126 SIZE_T * pnOffset,
127 const void * pBuffer,
128 SIZE_T nBytes);
130 oslFileError syncFile();
136 FileHandle_Impl::FileHandle_Impl(HANDLE hFile)
137 : m_hFile (hFile),
138 m_state (StateBits::Readable | StateBits::Writeable),
139 m_size (0),
140 m_offset (0),
141 m_filepos (0),
142 m_bufptr (-1),
143 m_buflen (0),
144 m_bufsiz (getpagesize()),
145 m_buffer (nullptr)
147 m_buffer = static_cast<sal_uInt8 *>(calloc(m_bufsiz, 1));
150 FileHandle_Impl::~FileHandle_Impl()
152 free(m_buffer);
153 m_buffer = nullptr;
156 SIZE_T FileHandle_Impl::getpagesize()
158 SYSTEM_INFO info;
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());
188 m_size = uSize;
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(
198 LONGLONG nOffset,
199 void * pBuffer,
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());
216 m_offset = nOffset;
219 DWORD dwDone = 0;
220 if (!::ReadFile(m_hFile, pBuffer, nBytesRequested, &dwDone, nullptr))
221 return oslTranslateFileError(GetLastError());
222 m_offset += dwDone;
224 *pBytesRead = dwDone;
225 return osl_File_E_None;
228 oslFileError FileHandle_Impl::writeAt(
229 LONGLONG nOffset,
230 void const * pBuffer,
231 DWORD nBytesToWrite,
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());
247 m_offset = nOffset;
250 DWORD dwDone = 0;
251 if (!::WriteFile(m_hFile, pBuffer, nBytesToWrite, &dwDone, nullptr))
252 return oslTranslateFileError(GetLastError());
253 m_offset += dwDone;
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(
262 LONGLONG nOffset,
263 void * pBuffer,
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)
275 DWORD dwDone = 0;
276 if (!::ReadFile(m_hFile, pBuffer, nBytesRequested, &dwDone, nullptr))
277 return oslTranslateFileError(GetLastError());
278 *pBytesRead = dwDone;
279 return osl_File_E_None;
281 else if (!m_buffer)
283 // not buffered
284 return readAt (nOffset, pBuffer, nBytesRequested, pBytesRead);
286 else
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)
299 return result;
300 m_bufptr = -1;
301 m_buflen = 0;
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)
309 return result;
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)
320 return result;
321 m_bufptr = bufptr;
322 m_buflen = sal::static_int_cast< SIZE_T >(uDone);
324 if (bufpos >= m_buflen)
326 // end of file
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;
334 nOffset += bytes;
336 return osl_File_E_None;
340 oslFileError FileHandle_Impl::writeFileAt(
341 LONGLONG nOffset,
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)
354 DWORD dwDone = 0;
355 if (!::WriteFile(m_hFile, pBuffer, nBytesToWrite, &dwDone, nullptr))
356 return oslTranslateFileError(GetLastError());
357 *pBytesWritten = dwDone;
358 return osl_File_E_None;
360 else if (!m_buffer)
362 // not buffered
363 return writeAt(nOffset, pBuffer, nBytesToWrite, pBytesWritten);
365 else
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)
377 return result;
378 m_bufptr = -1;
379 m_buflen = 0;
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)
387 return result;
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)
400 return result;
401 m_bufptr = bufptr;
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;
409 nOffset += 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(
419 LONGLONG nOffset,
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 */
429 result = syncFile();
430 if (result != osl_File_E_None)
431 return result;
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)
437 return result;
439 m_bufptr = bufptr;
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)
461 return result;
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)
473 return result;
474 m_bufptr = bufptr;
475 m_buflen = sal::static_int_cast< SIZE_T >(uDone);
478 bufpos = sal::static_int_cast< SIZE_T >(nOffset - m_bufptr);
479 curpos = bufpos;
480 if (bufpos >= m_buflen)
481 break;
483 switch (state)
485 case LINE_STATE_CR:
486 state = LINE_STATE_LF;
487 switch (m_buffer[curpos])
489 case 0x0A: /* CRLF */
490 /* eat current char */
491 curpos++;
492 break;
493 default: /* single CR */
494 /* keep current char */
495 break;
497 break;
498 default:
499 /* determine next state */
500 switch (m_buffer[curpos])
502 case 0x0A: /* single LF */
503 state = LINE_STATE_LF;
504 break;
505 case 0x0D: /* CR */
506 state = LINE_STATE_CR;
507 break;
508 default: /* advance to next char */
509 curpos++;
510 break;
512 if (state != LINE_STATE_BEGIN)
514 /* store (and eat) the newline char */
515 m_buffer[curpos] = 0x0A;
516 curpos++;
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)
522 return result;
523 *pBytesRead += curpos - bufpos;
524 nOffset += curpos - bufpos;
526 break;
530 result = writeSequence_Impl(ppSequence, &dstpos, nullptr, 0);
531 if (result != osl_File_E_None)
532 return result;
533 if (dstpos > 0)
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,
542 SIZE_T * pnOffset,
543 const void * pBuffer,
544 SIZE_T nBytes)
546 sal_Int32 nElements = *pnOffset + nBytes;
547 if (!*ppSequence)
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);
557 if (*ppSequence)
559 /* fill sequence */
560 memcpy(&((*ppSequence)->elements[*pnOffset]), pBuffer, nBytes);
561 *pnOffset += 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)
574 return result;
575 if (uDone != m_buflen)
576 return osl_File_E_IO;
577 m_state &= ~StateBits::Modified;
579 return result;
582 extern "C" oslFileHandle osl_createFileHandleFromOSHandle(
583 HANDLE hFile,
584 sal_uInt32 uFlags)
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)
594 /* mark seekable */
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;
608 SAL_WARN_IF(
609 !((uFlags & osl_File_OpenFlag_Read) || (uFlags & osl_File_OpenFlag_Write)),
610 "sal.osl",
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,
618 sal_uInt32 uFlags)
620 OUString strSysPath;
621 oslFileError result = osl_getSystemPathFromFileURL_(OUString::unacquired(&strPath), &strSysPath.pData, false);
622 if (result != osl_File_E_None)
623 return result;
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;
637 else
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);
650 return result;
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)
663 return result;
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;
677 oslFileError result;
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());
694 delete pImpl;
695 return result;
698 namespace {
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,
708 void** ppAddr,
709 sal_uInt64 uLength,
710 sal_uInt64 uOffset,
711 sal_uInt32 uFlags)
713 struct FileMapping
715 HANDLE m_handle;
717 explicit FileMapping(HANDLE hMap)
718 : m_handle(hMap)
721 ~FileMapping()
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;
730 *ppAddr = nullptr;
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);
744 if (!*ppAddr)
745 return oslTranslateFileError(GetLastError());
747 if (uFlags & osl_File_MapFlag_RandomAccess)
749 // Determine memory pagesize.
750 SYSTEM_INFO info;
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)
763 pData[0];
764 pData += dwPageSize;
765 nSize -= dwPageSize;
767 if (nSize > 0)
769 pData[0];
772 return osl_File_E_None;
775 oslFileError SAL_CALL osl_unmapFile(void* pAddr, sal_uInt64 /* uLength */)
777 if (!pAddr)
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);
791 oslFileError
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;
807 return result;
810 oslFileError SAL_CALL osl_readFile(
811 oslFileHandle Handle,
812 void * pBuffer,
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;
826 return result;
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;
846 return result;
849 LONGLONG const g_limit_longlong = std::numeric_limits< LONGLONG >::max();
851 namespace {
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,
864 sal_uInt64 uOffset,
865 void* pBuffer,
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,
887 sal_uInt64 uOffset,
888 const void* pBuffer,
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);
943 switch (uHow)
945 case osl_Pos_Absolut:
946 if (nOffset < 0)
947 return osl_File_E_INVAL;
948 break;
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;
954 assert(nPos >= 0);
955 if (nOffset > g_limit_longlong - nPos)
956 return osl_File_E_OVERFLOW;
957 break;
959 case osl_Pos_End:
960 nPos = sal::static_int_cast< LONGLONG >(pImpl->getSize());
961 if ((nOffset < 0) && (nPos < -1*nOffset))
962 return osl_File_E_INVAL;
963 assert(nPos >= 0);
964 if (nOffset > g_limit_longlong - nPos)
965 return osl_File_E_OVERFLOW;
966 break;
968 default:
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)
1002 return result;
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;
1018 else
1019 error = oslTranslateFileError(GetLastError());
1021 return error;
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;
1039 else
1040 error = oslTranslateFileError(GetLastError());
1043 return error;
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;
1061 else
1062 error = oslTranslateFileError(GetLastError());
1065 return error;
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,
1084 nullptr, nullptr))
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);
1092 else
1093 error = oslTranslateFileError(dwError);
1097 return error;
1100 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */