xref: /aoo42x/main/sal/osl/w32/file.cxx (revision 87d2adbc)
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 &
173 FileHandle_Impl::Allocator::get()
174 {
175 	static Allocator g_aBufferAllocator;
176 	return g_aBufferAllocator;
177 }
178 
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 
190 FileHandle_Impl::Allocator::~Allocator()
191 {
192 	rtl_cache_destroy(m_cache), m_cache = 0;
193 }
194 
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 
201 void FileHandle_Impl::Allocator::deallocate (sal_uInt8 * pBuffer)
202 {
203 	if (0 != pBuffer)
204 		rtl_cache_free (m_cache, pBuffer);
205 }
206 
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 }
213 FileHandle_Impl::Guard::~Guard()
214 {
215     OSL_PRECOND (m_mutex != 0, "FileHandle_Impl::Guard::~Guard(): null pointer.");
216     ::LeaveCriticalSection (m_mutex);
217 }
218 
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 
236 FileHandle_Impl::~FileHandle_Impl()
237 {
238 	Allocator::get().deallocate (m_buffer), m_buffer = 0;
239     ::DeleteCriticalSection (&m_mutex);
240 }
241 
242 void * FileHandle_Impl::operator new(size_t n)
243 {
244 	return rtl_allocateMemory(n);
245 }
246 
247 void FileHandle_Impl::operator delete(void * p, size_t)
248 {
249 	rtl_freeMemory(p);
250 }
251 
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 
259 sal_uInt64 FileHandle_Impl::getPos() const
260 {
261 	return sal::static_int_cast< sal_uInt64 >(m_filepos);
262 }
263 
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 
270 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 
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 
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 
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 
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 
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 
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 
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 
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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 //#############################################
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 
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 //#############################################
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