1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19
20 #include <systools/win32/uwinapi.h>
21
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>
28
29 #include "file-impl.hxx"
30 #include "file_url.hxx"
31 #include "file_error.hxx"
32
33 #include <atomic>
34 #include <cassert>
35 #include <algorithm>
36 #include <limits>
37
38 #ifdef max /* conflict w/ std::numeric_limits<T>::max() */
39 #undef max
40 #endif
41 #ifdef min
42 #undef min
43 #endif
44
45 namespace {
46
47 /** State
48 */
49 enum class StateBits
50 {
51 Seekable = 1, /*< open() sets, iff regular file */
52 Readable = 2, /*< open() sets, read() requires */
53 Writeable = 4, /*< open() sets, write() requires */
54 Modified = 8 /* write() sets, flush() resets */
55 };
56
57 }
58
59 template<> struct o3tl::typed_flags<StateBits>: o3tl::is_typed_flags<StateBits, 0xF> {};
60
61 namespace {
62
63 /** File handle implementation.
64 */
65 struct FileHandle_Impl
66 {
67 CRITICAL_SECTION m_mutex;
68 HANDLE m_hFile;
69
70 StateBits m_state;
71
72 sal_uInt64 m_size; /*< file size */
73 LONGLONG m_offset; /*< physical offset from begin of file */
74 // m_filepos is hit hard in some situations, where the overhead of a mutex starts to show up, so use an atomic
75 std::atomic<LONGLONG> m_filepos; /*< logical offset from begin of file */
76
77 LONGLONG m_bufptr; /*< buffer offset from begin of file */
78 SIZE_T m_buflen; /*< buffer filled [0, m_bufsiz - 1] */
79
80 SIZE_T m_bufsiz;
81 sal_uInt8 * m_buffer;
82
83 explicit FileHandle_Impl (HANDLE hFile);
84 ~FileHandle_Impl();
85
86 static void* operator new(size_t n);
87 static void operator delete(void * p, size_t);
88 static SIZE_T getpagesize();
89
90 sal_uInt64 getPos() const;
91 oslFileError setPos (sal_uInt64 uPos);
92
93 sal_uInt64 getSize() const;
94 oslFileError setSize (sal_uInt64 uPos);
95
96 oslFileError readAt(
97 LONGLONG nOffset,
98 void * pBuffer,
99 DWORD nBytesRequested,
100 sal_uInt64 * pBytesRead);
101
102 oslFileError writeAt(
103 LONGLONG nOffset,
104 void const * pBuffer,
105 DWORD nBytesToWrite,
106 sal_uInt64 * pBytesWritten);
107
108 oslFileError readFileAt(
109 LONGLONG nOffset,
110 void * pBuffer,
111 sal_uInt64 uBytesRequested,
112 sal_uInt64 * pBytesRead);
113
114 oslFileError writeFileAt(
115 LONGLONG nOffset,
116 void const * pBuffer,
117 sal_uInt64 uBytesToWrite,
118 sal_uInt64 * pBytesWritten);
119
120 oslFileError readLineAt(
121 LONGLONG nOffset,
122 sal_Sequence ** ppSequence,
123 sal_uInt64 * pBytesRead);
124
125 static oslFileError writeSequence_Impl (
126 sal_Sequence ** ppSequence,
127 SIZE_T * pnOffset,
128 const void * pBuffer,
129 SIZE_T nBytes);
130
131 oslFileError syncFile();
132
133 /** Guard.
134 */
135 class Guard
136 {
137 LPCRITICAL_SECTION m_mutex;
138
139 public:
140 explicit Guard(LPCRITICAL_SECTION pMutex);
141 ~Guard();
142 };
143 };
144
145 }
146
Guard(LPCRITICAL_SECTION pMutex)147 FileHandle_Impl::Guard::Guard(LPCRITICAL_SECTION pMutex)
148 : m_mutex (pMutex)
149 {
150 assert(pMutex);
151 ::EnterCriticalSection (m_mutex);
152 }
153
~Guard()154 FileHandle_Impl::Guard::~Guard()
155 {
156 ::LeaveCriticalSection (m_mutex);
157 }
158
FileHandle_Impl(HANDLE hFile)159 FileHandle_Impl::FileHandle_Impl(HANDLE hFile)
160 : m_hFile (hFile),
161 m_state (StateBits::Readable | StateBits::Writeable),
162 m_size (0),
163 m_offset (0),
164 m_filepos (0),
165 m_bufptr (-1),
166 m_buflen (0),
167 m_bufsiz (getpagesize()),
168 m_buffer (nullptr)
169 {
170 ::InitializeCriticalSection (&m_mutex);
171 m_buffer = static_cast<sal_uInt8 *>(calloc(m_bufsiz, 1));
172 }
173
~FileHandle_Impl()174 FileHandle_Impl::~FileHandle_Impl()
175 {
176 free(m_buffer);
177 m_buffer = nullptr;
178 ::DeleteCriticalSection (&m_mutex);
179 }
180
operator new(size_t n)181 void * FileHandle_Impl::operator new(size_t n)
182 {
183 return malloc(n);
184 }
185
operator delete(void * p,size_t)186 void FileHandle_Impl::operator delete(void * p, size_t)
187 {
188 free(p);
189 }
190
getpagesize()191 SIZE_T FileHandle_Impl::getpagesize()
192 {
193 SYSTEM_INFO info;
194 ::GetSystemInfo(&info);
195 return sal::static_int_cast< SIZE_T >(info.dwPageSize);
196 }
197
getPos() const198 sal_uInt64 FileHandle_Impl::getPos() const
199 {
200 return sal::static_int_cast< sal_uInt64 >(m_filepos.load());
201 }
202
setPos(sal_uInt64 uPos)203 oslFileError FileHandle_Impl::setPos(sal_uInt64 uPos)
204 {
205 m_filepos = sal::static_int_cast< LONGLONG >(uPos);
206 return osl_File_E_None;
207 }
208
getSize() const209 sal_uInt64 FileHandle_Impl::getSize() const
210 {
211 LONGLONG bufend = std::max(LONGLONG(0), m_bufptr) + m_buflen;
212 return std::max(m_size, sal::static_int_cast< sal_uInt64 >(bufend));
213 }
214
setSize(sal_uInt64 uSize)215 oslFileError FileHandle_Impl::setSize(sal_uInt64 uSize)
216 {
217 LARGE_INTEGER nDstPos; nDstPos.QuadPart = sal::static_int_cast< LONGLONG >(uSize);
218 if (!::SetFilePointerEx(m_hFile, nDstPos, nullptr, FILE_BEGIN))
219 return oslTranslateFileError(GetLastError());
220
221 if (!::SetEndOfFile(m_hFile))
222 return oslTranslateFileError(GetLastError());
223 m_size = uSize;
224
225 nDstPos.QuadPart = m_offset;
226 if (!::SetFilePointerEx(m_hFile, nDstPos, nullptr, FILE_BEGIN))
227 return oslTranslateFileError(GetLastError());
228
229 return osl_File_E_None;
230 }
231
readAt(LONGLONG nOffset,void * pBuffer,DWORD nBytesRequested,sal_uInt64 * pBytesRead)232 oslFileError FileHandle_Impl::readAt(
233 LONGLONG nOffset,
234 void * pBuffer,
235 DWORD nBytesRequested,
236 sal_uInt64 * pBytesRead)
237 {
238 SAL_WARN_IF(!(m_state & StateBits::Seekable), "sal.osl", "FileHandle_Impl::readAt(): not seekable");
239 if (!(m_state & StateBits::Seekable))
240 return osl_File_E_SPIPE;
241
242 SAL_WARN_IF(!(m_state & StateBits::Readable), "sal.osl", "FileHandle_Impl::readAt(): not readable");
243 if (!(m_state & StateBits::Readable))
244 return osl_File_E_BADF;
245
246 if (nOffset != m_offset)
247 {
248 LARGE_INTEGER liOffset; liOffset.QuadPart = nOffset;
249 if (!::SetFilePointerEx(m_hFile, liOffset, nullptr, FILE_BEGIN))
250 return oslTranslateFileError(GetLastError());
251 m_offset = nOffset;
252 }
253
254 DWORD dwDone = 0;
255 if (!::ReadFile(m_hFile, pBuffer, nBytesRequested, &dwDone, nullptr))
256 return oslTranslateFileError(GetLastError());
257 m_offset += dwDone;
258
259 *pBytesRead = dwDone;
260 return osl_File_E_None;
261 }
262
writeAt(LONGLONG nOffset,void const * pBuffer,DWORD nBytesToWrite,sal_uInt64 * pBytesWritten)263 oslFileError FileHandle_Impl::writeAt(
264 LONGLONG nOffset,
265 void const * pBuffer,
266 DWORD nBytesToWrite,
267 sal_uInt64 * pBytesWritten)
268 {
269 SAL_WARN_IF(!(m_state & StateBits::Seekable), "sal.osl", "FileHandle_Impl::writeAt(): not seekable");
270 if (!(m_state & StateBits::Seekable))
271 return osl_File_E_SPIPE;
272
273 SAL_WARN_IF(!(m_state & StateBits::Writeable), "sal.osl", "FileHandle_Impl::writeAt(): not writeable");
274 if (!(m_state & StateBits::Writeable))
275 return osl_File_E_BADF;
276
277 if (nOffset != m_offset)
278 {
279 LARGE_INTEGER liOffset; liOffset.QuadPart = nOffset;
280 if (!::SetFilePointerEx (m_hFile, liOffset, nullptr, FILE_BEGIN))
281 return oslTranslateFileError(GetLastError());
282 m_offset = nOffset;
283 }
284
285 DWORD dwDone = 0;
286 if (!::WriteFile(m_hFile, pBuffer, nBytesToWrite, &dwDone, nullptr))
287 return oslTranslateFileError(GetLastError());
288 m_offset += dwDone;
289
290 m_size = std::max(m_size, sal::static_int_cast< sal_uInt64 >(m_offset));
291
292 *pBytesWritten = dwDone;
293 return osl_File_E_None;
294 }
295
readFileAt(LONGLONG nOffset,void * pBuffer,sal_uInt64 uBytesRequested,sal_uInt64 * pBytesRead)296 oslFileError FileHandle_Impl::readFileAt(
297 LONGLONG nOffset,
298 void * pBuffer,
299 sal_uInt64 uBytesRequested,
300 sal_uInt64 * pBytesRead)
301 {
302 static sal_uInt64 const g_limit_dword = std::numeric_limits< DWORD >::max();
303 if (g_limit_dword < uBytesRequested)
304 return osl_File_E_OVERFLOW;
305 DWORD nBytesRequested = sal::static_int_cast< DWORD >(uBytesRequested);
306
307 if (!(m_state & StateBits::Seekable))
308 {
309 // not seekable (pipe)
310 DWORD dwDone = 0;
311 if (!::ReadFile(m_hFile, pBuffer, nBytesRequested, &dwDone, nullptr))
312 return oslTranslateFileError(GetLastError());
313 *pBytesRead = dwDone;
314 return osl_File_E_None;
315 }
316 else if (!m_buffer)
317 {
318 // not buffered
319 return readAt (nOffset, pBuffer, nBytesRequested, pBytesRead);
320 }
321 else
322 {
323 sal_uInt8 * buffer = static_cast< sal_uInt8* >(pBuffer);
324 for (*pBytesRead = 0; nBytesRequested > 0;)
325 {
326 LONGLONG const bufptr = (nOffset / m_bufsiz) * m_bufsiz;
327 SIZE_T const bufpos = nOffset % m_bufsiz;
328
329 if (bufptr != m_bufptr)
330 {
331 // flush current buffer
332 oslFileError result = syncFile();
333 if (result != osl_File_E_None)
334 return result;
335 m_bufptr = -1;
336 m_buflen = 0;
337
338 if (nBytesRequested >= m_bufsiz)
339 {
340 // buffer too small, read through from file
341 sal_uInt64 uDone = 0;
342 result = readAt (nOffset, &(buffer[*pBytesRead]), nBytesRequested, &uDone);
343 if (result != osl_File_E_None)
344 return result;
345
346 nBytesRequested -= sal::static_int_cast< DWORD >(uDone);
347 *pBytesRead += uDone;
348 return osl_File_E_None;
349 }
350
351 // update buffer (pointer)
352 sal_uInt64 uDone = 0;
353 result = readAt(bufptr, m_buffer, m_bufsiz, &uDone);
354 if (result != osl_File_E_None)
355 return result;
356 m_bufptr = bufptr;
357 m_buflen = sal::static_int_cast< SIZE_T >(uDone);
358 }
359 if (bufpos >= m_buflen)
360 {
361 // end of file
362 return osl_File_E_None;
363 }
364
365 SIZE_T const bytes = std::min(m_buflen - bufpos, static_cast<SIZE_T>(nBytesRequested));
366 memcpy(&(buffer[*pBytesRead]), &(m_buffer[bufpos]), bytes);
367 nBytesRequested -= bytes;
368 *pBytesRead += bytes;
369 nOffset += bytes;
370 }
371 return osl_File_E_None;
372 }
373 }
374
writeFileAt(LONGLONG nOffset,void const * pBuffer,sal_uInt64 uBytesToWrite,sal_uInt64 * pBytesWritten)375 oslFileError FileHandle_Impl::writeFileAt(
376 LONGLONG nOffset,
377 void const * pBuffer,
378 sal_uInt64 uBytesToWrite,
379 sal_uInt64 * pBytesWritten)
380 {
381 static sal_uInt64 const g_limit_dword = std::numeric_limits< DWORD >::max();
382 if (g_limit_dword < uBytesToWrite)
383 return osl_File_E_OVERFLOW;
384 DWORD nBytesToWrite = sal::static_int_cast< DWORD >(uBytesToWrite);
385
386 if (!(m_state & StateBits::Seekable))
387 {
388 // not seekable (pipe)
389 DWORD dwDone = 0;
390 if (!::WriteFile(m_hFile, pBuffer, nBytesToWrite, &dwDone, nullptr))
391 return oslTranslateFileError(GetLastError());
392 *pBytesWritten = dwDone;
393 return osl_File_E_None;
394 }
395 else if (!m_buffer)
396 {
397 // not buffered
398 return writeAt(nOffset, pBuffer, nBytesToWrite, pBytesWritten);
399 }
400 else
401 {
402 sal_uInt8 const * buffer = static_cast< sal_uInt8 const* >(pBuffer);
403 for (*pBytesWritten = 0; nBytesToWrite > 0;)
404 {
405 LONGLONG const bufptr = (nOffset / m_bufsiz) * m_bufsiz;
406 SIZE_T const bufpos = nOffset % m_bufsiz;
407 if (bufptr != m_bufptr)
408 {
409 // flush current buffer
410 oslFileError result = syncFile();
411 if (result != osl_File_E_None)
412 return result;
413 m_bufptr = -1;
414 m_buflen = 0;
415
416 if (nBytesToWrite >= m_bufsiz)
417 {
418 // buffer too small, write through to file
419 sal_uInt64 uDone = 0;
420 result = writeAt(nOffset, &(buffer[*pBytesWritten]), nBytesToWrite, &uDone);
421 if (result != osl_File_E_None)
422 return result;
423 if (uDone != nBytesToWrite)
424 return osl_File_E_IO;
425
426 nBytesToWrite -= sal::static_int_cast< DWORD >(uDone);
427 *pBytesWritten += uDone;
428 return osl_File_E_None;
429 }
430
431 // update buffer (pointer)
432 sal_uInt64 uDone = 0;
433 result = readAt(bufptr, m_buffer, m_bufsiz, &uDone);
434 if (result != osl_File_E_None)
435 return result;
436 m_bufptr = bufptr;
437 m_buflen = sal::static_int_cast< SIZE_T >(uDone);
438 }
439
440 SIZE_T const bytes = std::min(m_bufsiz - bufpos, static_cast<SIZE_T>(nBytesToWrite));
441 memcpy(&(m_buffer[bufpos]), &(buffer[*pBytesWritten]), bytes);
442 nBytesToWrite -= bytes;
443 *pBytesWritten += bytes;
444 nOffset += bytes;
445
446 m_buflen = std::max(m_buflen, bufpos + bytes);
447 m_state |= StateBits::Modified;
448 }
449 return osl_File_E_None;
450 }
451 }
452
readLineAt(LONGLONG nOffset,sal_Sequence ** ppSequence,sal_uInt64 * pBytesRead)453 oslFileError FileHandle_Impl::readLineAt(
454 LONGLONG nOffset,
455 sal_Sequence ** ppSequence,
456 sal_uInt64 * pBytesRead)
457 {
458 oslFileError result = osl_File_E_None;
459
460 LONGLONG bufptr = (nOffset / m_bufsiz) * m_bufsiz;
461 if (bufptr != m_bufptr)
462 {
463 /* flush current buffer */
464 result = syncFile();
465 if (result != osl_File_E_None)
466 return result;
467
468 /* update buffer (pointer) */
469 sal_uInt64 uDone = 0;
470 result = readAt(bufptr, m_buffer, m_bufsiz, &uDone);
471 if (result != osl_File_E_None)
472 return result;
473
474 m_bufptr = bufptr;
475 m_buflen = sal::static_int_cast< SIZE_T >(uDone);
476 }
477
478 static int const LINE_STATE_BEGIN = 0;
479 static int const LINE_STATE_CR = 1;
480 static int const LINE_STATE_LF = 2;
481
482 SIZE_T bufpos = sal::static_int_cast< SIZE_T >(nOffset - m_bufptr), curpos = bufpos, dstpos = 0;
483 int state = (bufpos >= m_buflen) ? LINE_STATE_LF : LINE_STATE_BEGIN;
484
485 for (; state != LINE_STATE_LF;)
486 {
487 if (curpos >= m_buflen)
488 {
489 /* buffer examined */
490 if (curpos > bufpos) // actually, curpos can't become less than bufpos, so != could do
491 {
492 /* flush buffer to sequence */
493 result = writeSequence_Impl(
494 ppSequence, &dstpos, &(m_buffer[bufpos]), curpos - bufpos);
495 if (result != osl_File_E_None)
496 return result;
497 *pBytesRead += curpos - bufpos;
498 nOffset += curpos - bufpos;
499 }
500
501 bufptr = nOffset / m_bufsiz * m_bufsiz;
502 if (bufptr != m_bufptr)
503 {
504 /* update buffer (pointer) */
505 sal_uInt64 uDone = 0;
506 result = readAt(bufptr, m_buffer, m_bufsiz, &uDone);
507 if (result != osl_File_E_None)
508 return result;
509 m_bufptr = bufptr;
510 m_buflen = sal::static_int_cast< SIZE_T >(uDone);
511 }
512
513 bufpos = sal::static_int_cast< SIZE_T >(nOffset - m_bufptr);
514 curpos = bufpos;
515 if (bufpos >= m_buflen)
516 break;
517 }
518 switch (state)
519 {
520 case LINE_STATE_CR:
521 state = LINE_STATE_LF;
522 switch (m_buffer[curpos])
523 {
524 case 0x0A: /* CRLF */
525 /* eat current char */
526 curpos++;
527 break;
528 default: /* single CR */
529 /* keep current char */
530 break;
531 }
532 break;
533 default:
534 /* determine next state */
535 switch (m_buffer[curpos])
536 {
537 case 0x0A: /* single LF */
538 state = LINE_STATE_LF;
539 break;
540 case 0x0D: /* CR */
541 state = LINE_STATE_CR;
542 break;
543 default: /* advance to next char */
544 curpos++;
545 break;
546 }
547 if (state != LINE_STATE_BEGIN)
548 {
549 /* store (and eat) the newline char */
550 m_buffer[curpos] = 0x0A;
551 curpos++;
552
553 /* flush buffer to sequence */
554 result = writeSequence_Impl(
555 ppSequence, &dstpos, &(m_buffer[bufpos]), curpos - bufpos - 1);
556 if (result != osl_File_E_None)
557 return result;
558 *pBytesRead += curpos - bufpos;
559 nOffset += curpos - bufpos;
560 }
561 break;
562 }
563 }
564
565 result = writeSequence_Impl(ppSequence, &dstpos, nullptr, 0);
566 if (result != osl_File_E_None)
567 return result;
568 if (dstpos > 0)
569 return osl_File_E_None;
570 if (bufpos >= m_buflen)
571 return osl_File_E_AGAIN;
572 return osl_File_E_None;
573 }
574
writeSequence_Impl(sal_Sequence ** ppSequence,SIZE_T * pnOffset,const void * pBuffer,SIZE_T nBytes)575 oslFileError FileHandle_Impl::writeSequence_Impl(
576 sal_Sequence ** ppSequence,
577 SIZE_T * pnOffset,
578 const void * pBuffer,
579 SIZE_T nBytes)
580 {
581 sal_Int32 nElements = *pnOffset + nBytes;
582 if (!*ppSequence)
583 {
584 /* construct sequence */
585 rtl_byte_sequence_constructNoDefault(ppSequence, nElements);
586 }
587 else if (nElements != (*ppSequence)->nElements)
588 {
589 /* resize sequence */
590 rtl_byte_sequence_realloc(ppSequence, nElements);
591 }
592 if (*ppSequence)
593 {
594 /* fill sequence */
595 memcpy(&((*ppSequence)->elements[*pnOffset]), pBuffer, nBytes);
596 *pnOffset += nBytes;
597 }
598 return (*ppSequence) ? osl_File_E_None : osl_File_E_NOMEM;
599 }
600
syncFile()601 oslFileError FileHandle_Impl::syncFile()
602 {
603 oslFileError result = osl_File_E_None;
604 if (m_state & StateBits::Modified)
605 {
606 sal_uInt64 uDone = 0;
607 result = writeAt(m_bufptr, m_buffer, m_buflen, &uDone);
608 if (result != osl_File_E_None)
609 return result;
610 if (uDone != m_buflen)
611 return osl_File_E_IO;
612 m_state &= ~StateBits::Modified;
613 }
614 return result;
615 }
616
osl_createFileHandleFromOSHandle(HANDLE hFile,sal_uInt32 uFlags)617 extern "C" oslFileHandle osl_createFileHandleFromOSHandle(
618 HANDLE hFile,
619 sal_uInt32 uFlags)
620 {
621 if (!IsValidHandle(hFile))
622 return nullptr; // EINVAL
623
624 FileHandle_Impl * pImpl = new FileHandle_Impl(hFile);
625
626 /* check for regular file */
627 if (GetFileType(hFile) == FILE_TYPE_DISK)
628 {
629 /* mark seekable */
630 pImpl->m_state |= StateBits::Seekable;
631
632 /* init current size */
633 LARGE_INTEGER uSize = { { 0, 0 } };
634 (void) ::GetFileSizeEx(hFile, &uSize);
635 pImpl->m_size = (sal::static_int_cast<sal_uInt64>(uSize.HighPart) << 32) + uSize.LowPart;
636 }
637
638 if (!(uFlags & osl_File_OpenFlag_Read))
639 pImpl->m_state &= ~StateBits::Readable;
640 if (!(uFlags & osl_File_OpenFlag_Write))
641 pImpl->m_state &= ~StateBits::Writeable;
642
643 SAL_WARN_IF(
644 !((uFlags & osl_File_OpenFlag_Read) || (uFlags & osl_File_OpenFlag_Write)),
645 "sal.osl",
646 "osl_createFileHandleFromOSHandle(): missing read/write access flags");
647 return static_cast<oslFileHandle>(pImpl);
648 }
649
osl_openFile(rtl_uString * strPath,oslFileHandle * pHandle,sal_uInt32 uFlags)650 oslFileError SAL_CALL osl_openFile(
651 rtl_uString * strPath,
652 oslFileHandle * pHandle,
653 sal_uInt32 uFlags)
654 {
655 rtl_uString * strSysPath = nullptr;
656 oslFileError result = osl_getSystemPathFromFileURL_(strPath, &strSysPath, false);
657 if (result != osl_File_E_None)
658 return result;
659
660 // tdf126742 use FILE_SHARE_WRITE to get closer to non-Windows platform behaviour,
661 // for details and discussion see task please
662 DWORD dwAccess = GENERIC_READ, dwShare = FILE_SHARE_READ | FILE_SHARE_WRITE, dwCreation = 0;
663
664 if (uFlags & osl_File_OpenFlag_Write)
665 dwAccess |= GENERIC_WRITE;
666
667 if (uFlags & osl_File_OpenFlag_NoLock)
668 dwShare |= FILE_SHARE_DELETE;
669
670 if (uFlags & osl_File_OpenFlag_Create)
671 dwCreation |= CREATE_NEW;
672 else
673 dwCreation |= OPEN_EXISTING;
674
675 HANDLE hFile = CreateFileW(
676 o3tl::toW(rtl_uString_getStr(strSysPath)),
677 dwAccess, dwShare, nullptr, dwCreation, 0, nullptr);
678
679 // @@@ ERROR HANDLING @@@
680 if (!IsValidHandle(hFile))
681 result = oslTranslateFileError(GetLastError());
682
683 *pHandle = osl_createFileHandleFromOSHandle(hFile, uFlags | osl_File_OpenFlag_Read);
684
685 rtl_uString_release(strSysPath);
686 return result;
687 }
688
osl_syncFile(oslFileHandle Handle)689 oslFileError SAL_CALL osl_syncFile(oslFileHandle Handle)
690 {
691 FileHandle_Impl * pImpl = static_cast<FileHandle_Impl*>(Handle);
692 if ((!pImpl) || !IsValidHandle(pImpl->m_hFile))
693 return osl_File_E_INVAL;
694
695 FileHandle_Impl::Guard lock(&(pImpl->m_mutex));
696
697 oslFileError result = pImpl->syncFile();
698 if (result != osl_File_E_None)
699 return result;
700
701 if (!FlushFileBuffers(pImpl->m_hFile))
702 return oslTranslateFileError(GetLastError());
703
704 return osl_File_E_None;
705 }
706
osl_closeFile(oslFileHandle Handle)707 oslFileError SAL_CALL osl_closeFile(oslFileHandle Handle)
708 {
709 FileHandle_Impl * pImpl = static_cast<FileHandle_Impl*>(Handle);
710 if ((!pImpl) || !IsValidHandle(pImpl->m_hFile))
711 return osl_File_E_INVAL;
712
713 ::EnterCriticalSection(&(pImpl->m_mutex));
714
715 oslFileError result = pImpl->syncFile();
716 if (result != osl_File_E_None)
717 {
718 /* ignore double failure */
719 (void)::CloseHandle(pImpl->m_hFile);
720 }
721 else if (!::CloseHandle(pImpl->m_hFile))
722 {
723 /* translate error code */
724 result = oslTranslateFileError(GetLastError());
725 }
726
727 ::LeaveCriticalSection(&(pImpl->m_mutex));
728 delete pImpl;
729 return result;
730 }
731
732 namespace {
733
734 // coverity[result_independent_of_operands] - crossplatform requirement
exceedsMaxSIZE_T(T n)735 template<typename T> bool exceedsMaxSIZE_T(T n)
736 { return n > std::numeric_limits< SIZE_T >::max(); }
737
738 }
739
osl_mapFile(oslFileHandle Handle,void ** ppAddr,sal_uInt64 uLength,sal_uInt64 uOffset,sal_uInt32 uFlags)740 oslFileError SAL_CALL osl_mapFile(
741 oslFileHandle Handle,
742 void** ppAddr,
743 sal_uInt64 uLength,
744 sal_uInt64 uOffset,
745 sal_uInt32 uFlags)
746 {
747 struct FileMapping
748 {
749 HANDLE m_handle;
750
751 explicit FileMapping(HANDLE hMap)
752 : m_handle(hMap)
753 {}
754
755 ~FileMapping()
756 {
757 (void)::CloseHandle(m_handle);
758 }
759 };
760
761 FileHandle_Impl * pImpl = static_cast<FileHandle_Impl*>(Handle);
762 if ((!pImpl) || !IsValidHandle(pImpl->m_hFile) || (!ppAddr))
763 return osl_File_E_INVAL;
764 *ppAddr = nullptr;
765
766 if (exceedsMaxSIZE_T(uLength))
767 return osl_File_E_OVERFLOW;
768 SIZE_T const nLength = sal::static_int_cast< SIZE_T >(uLength);
769
770 FileMapping aMap(::CreateFileMappingW(pImpl->m_hFile, nullptr, SEC_COMMIT | PAGE_READONLY, 0, 0, nullptr));
771 if (!IsValidHandle(aMap.m_handle))
772 return oslTranslateFileError(GetLastError());
773
774 DWORD const dwOffsetHi = sal::static_int_cast<DWORD>(uOffset >> 32);
775 DWORD const dwOffsetLo = sal::static_int_cast<DWORD>(uOffset & 0xFFFFFFFF);
776
777 *ppAddr = ::MapViewOfFile(aMap.m_handle, FILE_MAP_READ, dwOffsetHi, dwOffsetLo, nLength);
778 if (!*ppAddr)
779 return oslTranslateFileError(GetLastError());
780
781 if (uFlags & osl_File_MapFlag_RandomAccess)
782 {
783 // Determine memory pagesize.
784 SYSTEM_INFO info;
785 ::GetSystemInfo(&info);
786 DWORD const dwPageSize = info.dwPageSize;
787
788 /*
789 * Pagein, touching first byte of each memory page.
790 * Note: volatile disables optimizing the loop away.
791 */
792 BYTE volatile * pData(static_cast<BYTE*>(*ppAddr));
793 SIZE_T nSize(nLength);
794
795 while (nSize > dwPageSize)
796 {
797 pData[0];
798 pData += dwPageSize;
799 nSize -= dwPageSize;
800 }
801 if (nSize > 0)
802 {
803 pData[0];
804 }
805 }
806 return osl_File_E_None;
807 }
808
osl_unmapFile(void * pAddr,sal_uInt64)809 oslFileError SAL_CALL osl_unmapFile(void* pAddr, sal_uInt64 /* uLength */)
810 {
811 if (!pAddr)
812 return osl_File_E_INVAL;
813
814 if (!::UnmapViewOfFile(pAddr))
815 return oslTranslateFileError(GetLastError());
816
817 return osl_File_E_None;
818 }
819
osl_unmapMappedFile(oslFileHandle,void * pAddr,sal_uInt64 uLength)820 oslFileError SAL_CALL osl_unmapMappedFile(oslFileHandle /* Handle */, void* pAddr, sal_uInt64 uLength)
821 {
822 return osl_unmapFile(pAddr, uLength);
823 }
824
825 oslFileError
osl_readLine(oslFileHandle Handle,sal_Sequence ** ppSequence)826 SAL_CALL osl_readLine(
827 oslFileHandle Handle,
828 sal_Sequence ** ppSequence)
829 {
830 FileHandle_Impl * pImpl = static_cast<FileHandle_Impl*>(Handle);
831 if ((!pImpl) || !IsValidHandle(pImpl->m_hFile) || (!ppSequence))
832 return osl_File_E_INVAL;
833 sal_uInt64 uBytesRead = 0;
834
835 // read at current filepos; filepos += uBytesRead;
836 FileHandle_Impl::Guard lock(&(pImpl->m_mutex));
837 oslFileError result = pImpl->readLineAt(
838 pImpl->m_filepos, ppSequence, &uBytesRead);
839 if (result == osl_File_E_None)
840 pImpl->m_filepos += uBytesRead;
841 return result;
842 }
843
osl_readFile(oslFileHandle Handle,void * pBuffer,sal_uInt64 uBytesRequested,sal_uInt64 * pBytesRead)844 oslFileError SAL_CALL osl_readFile(
845 oslFileHandle Handle,
846 void * pBuffer,
847 sal_uInt64 uBytesRequested,
848 sal_uInt64 * pBytesRead)
849 {
850 FileHandle_Impl * pImpl = static_cast<FileHandle_Impl*>(Handle);
851 if ((!pImpl) || !IsValidHandle(pImpl->m_hFile) || (!pBuffer) || (!pBytesRead))
852 return osl_File_E_INVAL;
853
854 // read at current filepos; filepos += *pBytesRead;
855 FileHandle_Impl::Guard lock(&(pImpl->m_mutex));
856 oslFileError result = pImpl->readFileAt(
857 pImpl->m_filepos, pBuffer, uBytesRequested, pBytesRead);
858 if (result == osl_File_E_None)
859 pImpl->m_filepos += *pBytesRead;
860 return result;
861 }
862
osl_writeFile(oslFileHandle Handle,const void * pBuffer,sal_uInt64 uBytesToWrite,sal_uInt64 * pBytesWritten)863 oslFileError SAL_CALL osl_writeFile(
864 oslFileHandle Handle,
865 const void * pBuffer,
866 sal_uInt64 uBytesToWrite,
867 sal_uInt64 * pBytesWritten)
868 {
869 FileHandle_Impl * pImpl = static_cast<FileHandle_Impl*>(Handle);
870
871 if ((!pImpl) || !IsValidHandle(pImpl->m_hFile) || (!pBuffer) || (!pBytesWritten))
872 return osl_File_E_INVAL;
873
874 // write at current filepos; filepos += *pBytesWritten;
875 FileHandle_Impl::Guard lock(&(pImpl->m_mutex));
876 oslFileError result = pImpl->writeFileAt(
877 pImpl->m_filepos, pBuffer, uBytesToWrite, pBytesWritten);
878 if (result == osl_File_E_None)
879 pImpl->m_filepos += *pBytesWritten;
880 return result;
881 }
882
883 LONGLONG const g_limit_longlong = std::numeric_limits< LONGLONG >::max();
884
885 namespace {
886
887 // coverity[result_independent_of_operands] - crossplatform requirement
exceedsMaxLONGLONG(T n)888 template<typename T> bool exceedsMaxLONGLONG(T n)
889 { return n > g_limit_longlong; }
890
exceedsMinLONGLONG(T n)891 template<typename T> bool exceedsMinLONGLONG(T n)
892 { return n < std::numeric_limits<LONGLONG>::min(); }
893
894 }
895
osl_readFileAt(oslFileHandle Handle,sal_uInt64 uOffset,void * pBuffer,sal_uInt64 uBytesRequested,sal_uInt64 * pBytesRead)896 oslFileError SAL_CALL osl_readFileAt(
897 oslFileHandle Handle,
898 sal_uInt64 uOffset,
899 void* pBuffer,
900 sal_uInt64 uBytesRequested,
901 sal_uInt64* pBytesRead)
902 {
903 FileHandle_Impl * pImpl = static_cast<FileHandle_Impl*>(Handle);
904
905 if ((!pImpl) || !IsValidHandle(pImpl->m_hFile) || (!pBuffer) || (!pBytesRead))
906 return osl_File_E_INVAL;
907 if (!(pImpl->m_state & StateBits::Seekable))
908 return osl_File_E_SPIPE;
909
910 if (exceedsMaxLONGLONG(uOffset))
911 return osl_File_E_OVERFLOW;
912 LONGLONG const nOffset = sal::static_int_cast< LONGLONG >(uOffset);
913
914 // read at specified fileptr
915 FileHandle_Impl::Guard lock (&(pImpl->m_mutex));
916 return pImpl->readFileAt(nOffset, pBuffer, uBytesRequested, pBytesRead);
917 }
918
osl_writeFileAt(oslFileHandle Handle,sal_uInt64 uOffset,const void * pBuffer,sal_uInt64 uBytesToWrite,sal_uInt64 * pBytesWritten)919 oslFileError SAL_CALL osl_writeFileAt(
920 oslFileHandle Handle,
921 sal_uInt64 uOffset,
922 const void* pBuffer,
923 sal_uInt64 uBytesToWrite,
924 sal_uInt64* pBytesWritten)
925 {
926 FileHandle_Impl * pImpl = static_cast<FileHandle_Impl*>(Handle);
927
928 if ((!pImpl) || !IsValidHandle(pImpl->m_hFile) || (!pBuffer) || (!pBytesWritten))
929 return osl_File_E_INVAL;
930 if (!(pImpl->m_state & StateBits::Seekable))
931 return osl_File_E_SPIPE;
932
933 if (exceedsMaxLONGLONG(uOffset))
934 return osl_File_E_OVERFLOW;
935 LONGLONG const nOffset = sal::static_int_cast< LONGLONG >(uOffset);
936
937 // write at specified fileptr
938 FileHandle_Impl::Guard lock(&(pImpl->m_mutex));
939 return pImpl->writeFileAt(nOffset, pBuffer, uBytesToWrite, pBytesWritten);
940 }
941
osl_isEndOfFile(oslFileHandle Handle,sal_Bool * pIsEOF)942 oslFileError SAL_CALL osl_isEndOfFile(oslFileHandle Handle, sal_Bool *pIsEOF)
943 {
944 FileHandle_Impl * pImpl = static_cast<FileHandle_Impl*>(Handle);
945
946 if ((!pImpl) || !IsValidHandle(pImpl->m_hFile) || (!pIsEOF))
947 return osl_File_E_INVAL;
948
949 FileHandle_Impl::Guard lock(&(pImpl->m_mutex));
950 *pIsEOF = (pImpl->getPos() == pImpl->getSize());
951 return osl_File_E_None;
952 }
953
osl_getFilePos(oslFileHandle Handle,sal_uInt64 * pPos)954 oslFileError SAL_CALL osl_getFilePos(oslFileHandle Handle, sal_uInt64 *pPos)
955 {
956 FileHandle_Impl * pImpl = static_cast<FileHandle_Impl*>(Handle);
957 if ((!pImpl) || !IsValidHandle(pImpl->m_hFile) || (!pPos))
958 return osl_File_E_INVAL;
959
960 // no need to lock because pos is atomic
961 *pPos = pImpl->getPos();
962
963 return osl_File_E_None;
964 }
965
osl_setFilePos(oslFileHandle Handle,sal_uInt32 uHow,sal_Int64 uOffset)966 oslFileError SAL_CALL osl_setFilePos(oslFileHandle Handle, sal_uInt32 uHow, sal_Int64 uOffset)
967 {
968 FileHandle_Impl * pImpl = static_cast<FileHandle_Impl*>(Handle);
969 if ((!pImpl) || !IsValidHandle(pImpl->m_hFile))
970 return osl_File_E_INVAL;
971
972 if (exceedsMaxLONGLONG(uOffset) || exceedsMinLONGLONG(uOffset))
973 return osl_File_E_OVERFLOW;
974 LONGLONG nPos = 0, nOffset = sal::static_int_cast< LONGLONG >(uOffset);
975
976 FileHandle_Impl::Guard lock(&(pImpl->m_mutex));
977 switch (uHow)
978 {
979 case osl_Pos_Absolut:
980 if (nOffset < 0)
981 return osl_File_E_INVAL;
982 break;
983
984 case osl_Pos_Current:
985 nPos = sal::static_int_cast< LONGLONG >(pImpl->getPos());
986 if ((nOffset < 0) && (nPos < -1*nOffset))
987 return osl_File_E_INVAL;
988 assert(nPos >= 0);
989 if (nOffset > g_limit_longlong - nPos)
990 return osl_File_E_OVERFLOW;
991 break;
992
993 case osl_Pos_End:
994 nPos = sal::static_int_cast< LONGLONG >(pImpl->getSize());
995 if ((nOffset < 0) && (nPos < -1*nOffset))
996 return osl_File_E_INVAL;
997 assert(nPos >= 0);
998 if (nOffset > g_limit_longlong - nPos)
999 return osl_File_E_OVERFLOW;
1000 break;
1001
1002 default:
1003 return osl_File_E_INVAL;
1004 }
1005
1006 return pImpl->setPos(nPos + nOffset);
1007 }
1008
osl_getFileSize(oslFileHandle Handle,sal_uInt64 * pSize)1009 oslFileError SAL_CALL osl_getFileSize(oslFileHandle Handle, sal_uInt64 *pSize)
1010 {
1011 FileHandle_Impl * pImpl = static_cast<FileHandle_Impl*>(Handle);
1012
1013 if ((!pImpl) || !IsValidHandle(pImpl->m_hFile) || (!pSize))
1014 return osl_File_E_INVAL;
1015
1016 FileHandle_Impl::Guard lock(&(pImpl->m_mutex));
1017 *pSize = pImpl->getSize();
1018 return osl_File_E_None;
1019 }
1020
osl_setFileSize(oslFileHandle Handle,sal_uInt64 uSize)1021 oslFileError SAL_CALL osl_setFileSize(oslFileHandle Handle, sal_uInt64 uSize)
1022 {
1023 FileHandle_Impl * pImpl = static_cast<FileHandle_Impl*>(Handle);
1024
1025 if ((!pImpl) || !IsValidHandle(pImpl->m_hFile))
1026 return osl_File_E_INVAL;
1027 if (!(pImpl->m_state & StateBits::Writeable))
1028 return osl_File_E_BADF;
1029
1030 if (exceedsMaxLONGLONG(uSize))
1031 return osl_File_E_OVERFLOW;
1032
1033 FileHandle_Impl::Guard lock(&(pImpl->m_mutex));
1034 oslFileError result = pImpl->syncFile();
1035 if (result != osl_File_E_None)
1036 return result;
1037 pImpl->m_bufptr = -1;
1038 pImpl->m_buflen = 0;
1039
1040 return pImpl->setSize(uSize);
1041 }
1042
osl_removeFile(rtl_uString * strPath)1043 oslFileError SAL_CALL osl_removeFile(rtl_uString* strPath)
1044 {
1045 rtl_uString *strSysPath = nullptr;
1046 oslFileError error = osl_getSystemPathFromFileURL_(strPath, &strSysPath, false);
1047
1048 if (error == osl_File_E_None)
1049 {
1050 if (DeleteFileW(o3tl::toW(rtl_uString_getStr(strSysPath))))
1051 error = osl_File_E_None;
1052 else
1053 error = oslTranslateFileError(GetLastError());
1054
1055 rtl_uString_release(strSysPath);
1056 }
1057 return error;
1058 }
1059
osl_copyFile(rtl_uString * strPath,rtl_uString * strDestPath)1060 oslFileError SAL_CALL osl_copyFile(rtl_uString* strPath, rtl_uString *strDestPath)
1061 {
1062 rtl_uString *strSysPath = nullptr, *strSysDestPath = nullptr;
1063 oslFileError error = osl_getSystemPathFromFileURL_(strPath, &strSysPath, false);
1064
1065 if (error == osl_File_E_None)
1066 error = osl_getSystemPathFromFileURL_(strDestPath, &strSysDestPath, false);
1067
1068 if (error == osl_File_E_None)
1069 {
1070 LPCWSTR src = o3tl::toW(rtl_uString_getStr(strSysPath));
1071 LPCWSTR dst = o3tl::toW(rtl_uString_getStr(strSysDestPath));
1072
1073 if (CopyFileW(src, dst, FALSE))
1074 error = osl_File_E_None;
1075 else
1076 error = oslTranslateFileError(GetLastError());
1077 }
1078
1079 if (strSysPath)
1080 rtl_uString_release(strSysPath);
1081 if (strSysDestPath)
1082 rtl_uString_release(strSysDestPath);
1083
1084 return error;
1085 }
1086
osl_moveFile(rtl_uString * strPath,rtl_uString * strDestPath)1087 oslFileError SAL_CALL osl_moveFile(rtl_uString* strPath, rtl_uString *strDestPath)
1088 {
1089 rtl_uString *strSysPath = nullptr, *strSysDestPath = nullptr;
1090 oslFileError error = osl_getSystemPathFromFileURL_(strPath, &strSysPath, false);
1091
1092 if (error == osl_File_E_None)
1093 error = osl_getSystemPathFromFileURL_(strDestPath, &strSysDestPath, false);
1094
1095 if (error == osl_File_E_None)
1096 {
1097 LPCWSTR src = o3tl::toW(rtl_uString_getStr(strSysPath));
1098 LPCWSTR dst = o3tl::toW(rtl_uString_getStr(strSysDestPath));
1099
1100 if (MoveFileExW(src, dst, MOVEFILE_COPY_ALLOWED | MOVEFILE_WRITE_THROUGH | MOVEFILE_REPLACE_EXISTING))
1101 error = osl_File_E_None;
1102 else
1103 error = oslTranslateFileError(GetLastError());
1104 }
1105
1106 if (strSysPath)
1107 rtl_uString_release(strSysPath);
1108 if (strSysDestPath)
1109 rtl_uString_release(strSysDestPath);
1110
1111 return error;
1112 }
1113
osl_replaceFile(rtl_uString * strPath,rtl_uString * strDestPath)1114 oslFileError SAL_CALL osl_replaceFile(rtl_uString* strPath, rtl_uString* strDestPath)
1115 {
1116 rtl_uString *strSysPath = nullptr, *strSysDestPath = nullptr;
1117 oslFileError error = osl_getSystemPathFromFileURL_(strPath, &strSysPath, false);
1118
1119 if (error == osl_File_E_None)
1120 error = osl_getSystemPathFromFileURL_(strDestPath, &strSysDestPath, false);
1121
1122 if (error == osl_File_E_None)
1123 {
1124 LPCWSTR src = o3tl::toW(rtl_uString_getStr(strSysPath));
1125 LPCWSTR dst = o3tl::toW(rtl_uString_getStr(strSysDestPath));
1126
1127 if (!ReplaceFileW(dst, src, nullptr,
1128 REPLACEFILE_WRITE_THROUGH | REPLACEFILE_IGNORE_MERGE_ERRORS
1129 | REPLACEFILE_IGNORE_ACL_ERRORS,
1130 nullptr, nullptr))
1131 {
1132 DWORD dwError = GetLastError();
1133 if (dwError == ERROR_FILE_NOT_FOUND) // no strDestPath file?
1134 error = osl_moveFile(strPath, strDestPath);
1135 else
1136 error = oslTranslateFileError(dwError);
1137 }
1138 }
1139
1140 if (strSysPath)
1141 rtl_uString_release(strSysPath);
1142 if (strSysDestPath)
1143 rtl_uString_release(strSysDestPath);
1144
1145 return error;
1146 }
1147
1148 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
1149