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