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