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