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