Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 :
21 : #include "osl/file.hxx"
22 : #include "osl/detail/file.h"
23 :
24 : #include "osl/diagnose.h"
25 : #include "rtl/alloc.h"
26 :
27 : #include "system.h"
28 : #include "createfilehandlefromfd.hxx"
29 : #include "file_error_transl.h"
30 : #include "file_url.h"
31 :
32 : #include <algorithm>
33 : #include <limits>
34 :
35 : #include <string.h>
36 : #include <pthread.h>
37 : #include <sys/mman.h>
38 :
39 : #if defined(MACOSX)
40 :
41 : #include <sys/param.h>
42 : #include <sys/mount.h>
43 : #define HAVE_O_EXLOCK
44 :
45 : // add MACOSX Time Value
46 : #include <CoreFoundation/CoreFoundation.h>
47 :
48 : #endif /* MACOSX */
49 :
50 : #ifdef ANDROID
51 : #include <osl/detail/android-bootstrap.h>
52 : #endif
53 :
54 : #ifdef DEBUG_OSL_FILE
55 : # define OSL_FILE_TRACE osl_trace
56 : #else
57 : # define OSL_FILE_TRACE(fmt, ...)
58 : #endif
59 :
60 :
61 :
62 : /*******************************************************************
63 : *
64 : * FileHandle_Impl interface
65 : *
66 : ******************************************************************/
67 : struct FileHandle_Impl
68 : {
69 : pthread_mutex_t m_mutex;
70 : rtl_String * m_strFilePath; /* holds native file path */
71 : int m_fd;
72 :
73 : enum Kind
74 : {
75 : KIND_FD = 1,
76 : KIND_MEM = 2
77 : };
78 : int m_kind;
79 : /** State
80 : */
81 : enum StateBits
82 : {
83 : STATE_SEEKABLE = 1, /* default */
84 : STATE_READABLE = 2, /* default */
85 : STATE_WRITEABLE = 4, /* open() sets, write() requires, else osl_File_E_BADF */
86 : STATE_MODIFIED = 8 /* write() sets, flush() resets */
87 : };
88 : int m_state;
89 :
90 : sal_uInt64 m_size; /* file size */
91 : off_t m_offset; /* physical offset from begin of file */
92 : off_t m_fileptr; /* logical offset from begin of file */
93 :
94 : off_t m_bufptr; /* buffer offset from begin of file */
95 : size_t m_buflen; /* buffer filled [0, m_bufsiz - 1] */
96 :
97 : size_t m_bufsiz;
98 : sal_uInt8 * m_buffer;
99 :
100 : explicit FileHandle_Impl (int fd, Kind kind = KIND_FD, char const * path = "<anon>");
101 : ~FileHandle_Impl();
102 :
103 : static void* operator new (size_t n);
104 : static void operator delete (void * p);
105 :
106 : static size_t getpagesize();
107 :
108 : sal_uInt64 getPos() const;
109 : oslFileError setPos (sal_uInt64 uPos);
110 :
111 : sal_uInt64 getSize() const;
112 : oslFileError setSize (sal_uInt64 uSize);
113 :
114 : oslFileError readAt (
115 : off_t nOffset,
116 : void * pBuffer,
117 : size_t nBytesRequested,
118 : sal_uInt64 * pBytesRead);
119 :
120 : oslFileError writeAt (
121 : off_t nOffset,
122 : void const * pBuffer,
123 : size_t nBytesToWrite,
124 : sal_uInt64 * pBytesWritten);
125 :
126 : oslFileError readFileAt (
127 : off_t nOffset,
128 : void * pBuffer,
129 : size_t nBytesRequested,
130 : sal_uInt64 * pBytesRead);
131 :
132 : oslFileError writeFileAt (
133 : off_t nOffset,
134 : void const * pBuffer,
135 : size_t nBytesToWrite,
136 : sal_uInt64 * pBytesWritten);
137 :
138 : oslFileError readLineAt (
139 : off_t nOffset,
140 : sal_Sequence ** ppSequence,
141 : sal_uInt64 * pBytesRead);
142 :
143 : oslFileError writeSequence_Impl (
144 : sal_Sequence ** ppSequence,
145 : size_t * pnOffset,
146 : const void * pBuffer,
147 : size_t nBytes);
148 :
149 : oslFileError syncFile();
150 :
151 : /** Buffer cache / allocator.
152 : */
153 : class Allocator
154 : {
155 : rtl_cache_type * m_cache;
156 : size_t m_bufsiz;
157 :
158 : Allocator (Allocator const &);
159 : Allocator & operator= (Allocator const &);
160 :
161 : public:
162 : static Allocator & get();
163 :
164 : void allocate (sal_uInt8 ** ppBuffer, size_t * pnSize);
165 : void deallocate (sal_uInt8 * pBuffer);
166 :
167 : protected:
168 : Allocator();
169 : ~Allocator();
170 : };
171 :
172 : /** Guard.
173 : */
174 : class Guard
175 : {
176 : pthread_mutex_t * m_mutex;
177 :
178 : public:
179 : explicit Guard(pthread_mutex_t * pMutex);
180 : ~Guard();
181 : };
182 : };
183 :
184 : /*******************************************************************
185 : *
186 : * FileHandle_Impl implementation
187 : *
188 : ******************************************************************/
189 :
190 : FileHandle_Impl::Allocator &
191 186748 : FileHandle_Impl::Allocator::get()
192 : {
193 186748 : static Allocator g_aBufferAllocator;
194 186748 : return g_aBufferAllocator;
195 : }
196 :
197 1487 : FileHandle_Impl::Allocator::Allocator()
198 : : m_cache (0),
199 1487 : m_bufsiz (0)
200 : {
201 1487 : size_t const pagesize = FileHandle_Impl::getpagesize();
202 1487 : if (size_t(-1) != pagesize)
203 : {
204 : m_cache = rtl_cache_create (
205 1487 : "osl_file_buffer_cache", pagesize, 0, 0, 0, 0, 0, 0, 0);
206 1487 : if (0 != m_cache)
207 1487 : m_bufsiz = pagesize;
208 : }
209 1487 : }
210 1487 : FileHandle_Impl::Allocator::~Allocator()
211 : {
212 1487 : rtl_cache_destroy (m_cache), m_cache = 0;
213 1487 : }
214 :
215 93765 : void FileHandle_Impl::Allocator::allocate (sal_uInt8 ** ppBuffer, size_t * pnSize)
216 : {
217 : OSL_PRECOND((0 != ppBuffer) && (0 != pnSize), "FileHandle_Impl::Allocator::allocate(): contract violation");
218 93765 : if ((0 != ppBuffer) && (0 != pnSize))
219 93765 : *ppBuffer = static_cast< sal_uInt8* >(rtl_cache_alloc(m_cache)), *pnSize = m_bufsiz;
220 93765 : }
221 92983 : void FileHandle_Impl::Allocator::deallocate (sal_uInt8 * pBuffer)
222 : {
223 92983 : if (0 != pBuffer)
224 92983 : rtl_cache_free (m_cache, pBuffer);
225 92983 : }
226 :
227 8357615 : FileHandle_Impl::Guard::Guard(pthread_mutex_t * pMutex)
228 8357615 : : m_mutex (pMutex)
229 : {
230 : OSL_PRECOND (m_mutex != 0, "FileHandle_Impl::Guard::Guard(): null pointer.");
231 8357615 : (void) pthread_mutex_lock (m_mutex); // ignoring EINVAL ...
232 8357613 : }
233 8357615 : FileHandle_Impl::Guard::~Guard()
234 : {
235 : OSL_PRECOND (m_mutex != 0, "FileHandle_Impl::Guard::~Guard(): null pointer.");
236 8357615 : (void) pthread_mutex_unlock (m_mutex);
237 8357613 : }
238 :
239 93765 : FileHandle_Impl::FileHandle_Impl (int fd, enum Kind kind, char const * path)
240 : : m_strFilePath (0),
241 : m_fd (fd),
242 : m_kind (kind),
243 : m_state (STATE_SEEKABLE | STATE_READABLE),
244 : m_size (0),
245 : m_offset (0),
246 : m_fileptr (0),
247 : m_bufptr (-1),
248 : m_buflen (0),
249 : m_bufsiz (0),
250 93765 : m_buffer (0)
251 : {
252 93765 : (void) pthread_mutex_init(&m_mutex, 0);
253 93765 : rtl_string_newFromStr (&m_strFilePath, path);
254 93765 : if (m_kind == KIND_FD) {
255 93765 : Allocator::get().allocate (&m_buffer, &m_bufsiz);
256 93765 : if (0 != m_buffer)
257 93765 : memset (m_buffer, 0, m_bufsiz);
258 : }
259 93765 : }
260 92983 : FileHandle_Impl::~FileHandle_Impl()
261 : {
262 92983 : if (m_kind == KIND_FD)
263 92983 : Allocator::get().deallocate (m_buffer), m_buffer = 0;
264 92983 : rtl_string_release (m_strFilePath), m_strFilePath = 0;
265 92983 : (void) pthread_mutex_destroy(&m_mutex); // ignoring EBUSY ...
266 92983 : }
267 :
268 93765 : void* FileHandle_Impl::operator new (size_t n)
269 : {
270 93765 : return rtl_allocateMemory(n);
271 : }
272 92983 : void FileHandle_Impl::operator delete (void * p)
273 : {
274 92983 : rtl_freeMemory(p);
275 92983 : }
276 :
277 7483 : size_t FileHandle_Impl::getpagesize()
278 : {
279 : #if defined(FREEBSD) || defined(NETBSD) || defined(MACOSX) || \
280 : defined(OPENBSD) || defined(DRAGONFLY)
281 : return sal::static_int_cast< size_t >(::getpagesize());
282 : #else /* POSIX */
283 7483 : return sal::static_int_cast< size_t >(::sysconf(_SC_PAGESIZE));
284 : #endif /* xBSD || POSIX */
285 : }
286 :
287 252601 : sal_uInt64 FileHandle_Impl::getPos() const
288 : {
289 252601 : return sal::static_int_cast< sal_uInt64 >(m_fileptr);
290 : }
291 :
292 273110 : oslFileError FileHandle_Impl::setPos (sal_uInt64 uPos)
293 : {
294 : OSL_FILE_TRACE("FileHandle_Impl::setPos(%d, %lld) => %lld", m_fd, getPos(), uPos);
295 273110 : m_fileptr = sal::static_int_cast< off_t >(uPos);
296 273110 : return osl_File_E_None;
297 : }
298 :
299 72532 : sal_uInt64 FileHandle_Impl::getSize() const
300 : {
301 72532 : off_t const bufend = std::max((off_t)(0), m_bufptr) + m_buflen;
302 72532 : return std::max(m_size, sal::static_int_cast< sal_uInt64 >(bufend));
303 : }
304 :
305 6177 : oslFileError FileHandle_Impl::setSize (sal_uInt64 uSize)
306 : {
307 6177 : off_t const nSize = sal::static_int_cast< off_t >(uSize);
308 6177 : if (-1 == ftruncate (m_fd, nSize))
309 : {
310 : /* Failure. Save original result. Try fallback algorithm */
311 0 : oslFileError result = oslTranslateFileError (OSL_FET_ERROR, errno);
312 :
313 : /* Check against current size. Fail upon 'shrink' */
314 0 : if (uSize <= getSize())
315 : {
316 : /* Failure upon 'shrink'. Return original result */
317 0 : return (result);
318 : }
319 :
320 : /* Save current position */
321 0 : off_t const nCurPos = (off_t)lseek (m_fd, (off_t)0, SEEK_CUR);
322 0 : if (nCurPos == (off_t)(-1))
323 0 : return (result);
324 :
325 : /* Try 'expand' via 'lseek()' and 'write()' */
326 0 : if (-1 == lseek (m_fd, (off_t)(nSize - 1), SEEK_SET))
327 0 : return (result);
328 :
329 0 : if (-1 == write (m_fd, (char*)"", (size_t)1))
330 : {
331 : /* Failure. Restore saved position */
332 0 : (void) lseek (m_fd, (off_t)(nCurPos), SEEK_SET);
333 0 : return (result);
334 : }
335 :
336 : /* Success. Restore saved position */
337 0 : if (-1 == lseek (m_fd, (off_t)nCurPos, SEEK_SET))
338 0 : return (result);
339 : }
340 :
341 : OSL_FILE_TRACE("osl_setFileSize(%d, %lld) => %ld", m_fd, getSize(), nSize);
342 6177 : m_size = sal::static_int_cast< sal_uInt64 >(nSize);
343 6177 : return osl_File_E_None;
344 : }
345 :
346 258960 : oslFileError FileHandle_Impl::readAt (
347 : off_t nOffset,
348 : void * pBuffer,
349 : size_t nBytesRequested,
350 : sal_uInt64 * pBytesRead)
351 : {
352 : OSL_PRECOND((m_state & STATE_SEEKABLE), "FileHandle_Impl::readAt(): not seekable");
353 258960 : if (!(m_state & STATE_SEEKABLE))
354 0 : return osl_File_E_SPIPE;
355 :
356 : OSL_PRECOND((m_state & STATE_READABLE), "FileHandle_Impl::readAt(): not readable");
357 258960 : if (!(m_state & STATE_READABLE))
358 0 : return osl_File_E_BADF;
359 :
360 258960 : if (m_kind == KIND_MEM)
361 : {
362 : ssize_t nBytes;
363 :
364 0 : m_offset = nOffset;
365 :
366 0 : if ((sal_uInt64) m_offset >= m_size)
367 0 : nBytes = 0;
368 : else
369 : {
370 0 : nBytes = std::min(nBytesRequested, (size_t) (m_size - m_offset));
371 0 : memmove(pBuffer, m_buffer + m_offset, nBytes);
372 0 : m_offset += nBytes;
373 : }
374 0 : *pBytesRead = nBytes;
375 0 : return osl_File_E_None;
376 : }
377 :
378 258960 : ssize_t nBytes = ::pread (m_fd, pBuffer, nBytesRequested, nOffset);
379 258960 : if ((-1 == nBytes) && (EOVERFLOW == errno))
380 : {
381 : /* Some 'pread()'s fail with EOVERFLOW when reading at (or past)
382 : * end-of-file, different from 'lseek() + read()' behaviour.
383 : * Returning '0 bytes read' and 'osl_File_E_None' instead.
384 : */
385 0 : nBytes = 0;
386 : }
387 258960 : if (-1 == nBytes)
388 0 : return oslTranslateFileError (OSL_FET_ERROR, errno);
389 :
390 : OSL_FILE_TRACE("FileHandle_Impl::readAt(%d, %lld, %ld)", m_fd, nOffset, nBytes);
391 258960 : *pBytesRead = nBytes;
392 258960 : return osl_File_E_None;
393 : }
394 :
395 164380 : oslFileError FileHandle_Impl::writeAt (
396 : off_t nOffset,
397 : void const * pBuffer,
398 : size_t nBytesToWrite,
399 : sal_uInt64 * pBytesWritten)
400 : {
401 : OSL_PRECOND((m_state & STATE_SEEKABLE), "FileHandle_Impl::writeAt(): not seekable");
402 164380 : if (!(m_state & STATE_SEEKABLE))
403 0 : return osl_File_E_SPIPE;
404 :
405 : OSL_PRECOND((m_state & STATE_WRITEABLE), "FileHandle_Impl::writeAt(): not writeable");
406 164380 : if (!(m_state & STATE_WRITEABLE))
407 0 : return osl_File_E_BADF;
408 :
409 164380 : ssize_t nBytes = ::pwrite (m_fd, pBuffer, nBytesToWrite, nOffset);
410 164380 : if (-1 == nBytes)
411 0 : return oslTranslateFileError (OSL_FET_ERROR, errno);
412 :
413 : OSL_FILE_TRACE("FileHandle_Impl::writeAt(%d, %lld, %ld)", m_fd, nOffset, nBytes);
414 164380 : m_size = std::max (m_size, sal::static_int_cast< sal_uInt64 >(nOffset + nBytes));
415 :
416 164380 : *pBytesWritten = nBytes;
417 164380 : return osl_File_E_None;
418 : }
419 :
420 1322616 : oslFileError FileHandle_Impl::readFileAt (
421 : off_t nOffset,
422 : void * pBuffer,
423 : size_t nBytesRequested,
424 : sal_uInt64 * pBytesRead)
425 : {
426 1322616 : if (0 == (m_state & STATE_SEEKABLE))
427 : {
428 : // not seekable (pipe)
429 1036763 : ssize_t nBytes = ::read (m_fd, pBuffer, nBytesRequested);
430 1036763 : if (-1 == nBytes)
431 0 : return oslTranslateFileError (OSL_FET_ERROR, errno);
432 1036763 : *pBytesRead = nBytes;
433 1036763 : return osl_File_E_None;
434 : }
435 285853 : else if (m_kind == KIND_MEM || 0 == m_buffer)
436 : {
437 : // not buffered
438 0 : return readAt (nOffset, pBuffer, nBytesRequested, pBytesRead);
439 : }
440 : else
441 : {
442 285853 : sal_uInt8 * buffer = static_cast<sal_uInt8*>(pBuffer);
443 747233 : for (*pBytesRead = 0; nBytesRequested > 0; )
444 : {
445 316765 : off_t const bufptr = (nOffset / m_bufsiz) * m_bufsiz;
446 316765 : size_t const bufpos = (nOffset % m_bufsiz);
447 :
448 316765 : if (bufptr != m_bufptr)
449 : {
450 : // flush current buffer
451 95529 : oslFileError result = syncFile();
452 95529 : if (result != osl_File_E_None)
453 53961 : return (result);
454 95529 : m_bufptr = -1, m_buflen = 0;
455 :
456 95529 : if (nBytesRequested >= m_bufsiz)
457 : {
458 : // buffer too small, read through from file
459 53961 : sal_uInt64 uDone = 0;
460 53961 : result = readAt (nOffset, &(buffer[*pBytesRead]), nBytesRequested, &uDone);
461 53961 : if (result != osl_File_E_None)
462 0 : return (result);
463 :
464 53961 : *pBytesRead += uDone;
465 53961 : return osl_File_E_None;
466 : }
467 :
468 : // update buffer (pointer)
469 41568 : sal_uInt64 uDone = 0;
470 41568 : result = readAt (bufptr, m_buffer, m_bufsiz, &uDone);
471 41568 : if (result != osl_File_E_None)
472 0 : return (result);
473 41568 : m_bufptr = bufptr, m_buflen = uDone;
474 : }
475 262804 : if (bufpos >= m_buflen)
476 : {
477 : // end of file
478 87277 : return osl_File_E_None;
479 : }
480 :
481 175527 : size_t const bytes = std::min (m_buflen - bufpos, nBytesRequested);
482 : OSL_FILE_TRACE("FileHandle_Impl::readFileAt(%d, %lld, %ld)", m_fd, nOffset, bytes);
483 :
484 175527 : memcpy (&(buffer[*pBytesRead]), &(m_buffer[bufpos]), bytes);
485 175527 : nBytesRequested -= bytes, *pBytesRead += bytes, nOffset += bytes;
486 : }
487 144615 : return osl_File_E_None;
488 : }
489 : }
490 :
491 6388532 : oslFileError FileHandle_Impl::writeFileAt (
492 : off_t nOffset,
493 : void const * pBuffer,
494 : size_t nBytesToWrite,
495 : sal_uInt64 * pBytesWritten)
496 : {
497 6388532 : if (0 == (m_state & STATE_SEEKABLE))
498 : {
499 : // not seekable (pipe)
500 3 : ssize_t nBytes = ::write (m_fd, pBuffer, nBytesToWrite);
501 3 : if (-1 == nBytes)
502 0 : return oslTranslateFileError (OSL_FET_ERROR, errno);
503 3 : *pBytesWritten = nBytes;
504 3 : return osl_File_E_None;
505 : }
506 6388529 : else if (0 == m_buffer)
507 : {
508 : // not buffered
509 0 : return writeAt (nOffset, pBuffer, nBytesToWrite, pBytesWritten);
510 : }
511 : else
512 : {
513 6388529 : sal_uInt8 const * buffer = static_cast<sal_uInt8 const *>(pBuffer);
514 19124721 : for (*pBytesWritten = 0; nBytesToWrite > 0; )
515 : {
516 6353294 : off_t const bufptr = (nOffset / m_bufsiz) * m_bufsiz;
517 6353294 : size_t const bufpos = (nOffset % m_bufsiz);
518 6353294 : if (bufptr != m_bufptr)
519 : {
520 : // flush current buffer
521 164359 : oslFileError result = syncFile();
522 164359 : if (result != osl_File_E_None)
523 5631 : return (result);
524 164359 : m_bufptr = -1, m_buflen = 0;
525 :
526 164359 : if (nBytesToWrite >= m_bufsiz)
527 : {
528 : // buffer to small, write through to file
529 5631 : sal_uInt64 uDone = 0;
530 5631 : result = writeAt (nOffset, &(buffer[*pBytesWritten]), nBytesToWrite, &uDone);
531 5631 : if (result != osl_File_E_None)
532 0 : return (result);
533 5631 : if (uDone != nBytesToWrite)
534 0 : return osl_File_E_IO;
535 :
536 5631 : *pBytesWritten += uDone;
537 5631 : return osl_File_E_None;
538 : }
539 :
540 : // update buffer (pointer)
541 158728 : sal_uInt64 uDone = 0;
542 158728 : result = readAt (bufptr, m_buffer, m_bufsiz, &uDone);
543 158728 : if (result != osl_File_E_None)
544 0 : return (result);
545 158728 : m_bufptr = bufptr, m_buflen = uDone;
546 : }
547 :
548 6347663 : size_t const bytes = std::min (m_bufsiz - bufpos, nBytesToWrite);
549 : OSL_FILE_TRACE("FileHandle_Impl::writeFileAt(%d, %lld, %ld)", m_fd, nOffset, bytes);
550 :
551 6347663 : memcpy (&(m_buffer[bufpos]), &(buffer[*pBytesWritten]), bytes);
552 6347663 : nBytesToWrite -= bytes, *pBytesWritten += bytes, nOffset += bytes;
553 :
554 6347663 : m_buflen = std::max(m_buflen, bufpos + bytes);
555 6347663 : m_state |= STATE_MODIFIED;
556 : }
557 6382898 : return osl_File_E_None;
558 : }
559 : }
560 :
561 49800 : oslFileError FileHandle_Impl::readLineAt (
562 : off_t nOffset,
563 : sal_Sequence ** ppSequence,
564 : sal_uInt64 * pBytesRead)
565 : {
566 49800 : oslFileError result = osl_File_E_None;
567 :
568 49800 : off_t bufptr = nOffset / m_bufsiz * m_bufsiz;
569 49800 : if (bufptr != m_bufptr)
570 : {
571 : /* flush current buffer */
572 4703 : result = syncFile();
573 4703 : if (result != osl_File_E_None)
574 0 : return (result);
575 :
576 : /* update buffer (pointer) */
577 4703 : sal_uInt64 uDone = 0;
578 4703 : result = readAt (bufptr, m_buffer, m_bufsiz, &uDone);
579 4703 : if (result != osl_File_E_None)
580 0 : return (result);
581 :
582 4703 : m_bufptr = bufptr, m_buflen = uDone;
583 : }
584 :
585 : static int const LINE_STATE_BEGIN = 0;
586 : static int const LINE_STATE_CR = 1;
587 : static int const LINE_STATE_LF = 2;
588 :
589 49800 : size_t bufpos = nOffset - m_bufptr, curpos = bufpos, dstpos = 0;
590 49800 : int state = (bufpos >= m_buflen) ? LINE_STATE_LF : LINE_STATE_BEGIN;
591 :
592 2051133 : for ( ; state != LINE_STATE_LF; )
593 : {
594 1951584 : if (curpos >= m_buflen)
595 : {
596 : /* buffer examined */
597 51 : if (0 < (curpos - bufpos))
598 : {
599 : /* flush buffer to sequence */
600 : result = writeSequence_Impl (
601 51 : ppSequence, &dstpos, &(m_buffer[bufpos]), curpos - bufpos);
602 51 : if (result != osl_File_E_None)
603 0 : return (result);
604 51 : *pBytesRead += curpos - bufpos, nOffset += curpos - bufpos;
605 : }
606 :
607 51 : bufptr = nOffset / m_bufsiz * m_bufsiz;
608 51 : if (bufptr != m_bufptr)
609 : {
610 : /* update buffer (pointer) */
611 0 : sal_uInt64 uDone = 0;
612 0 : result = readAt (bufptr, m_buffer, m_bufsiz, &uDone);
613 0 : if (result != osl_File_E_None)
614 0 : return (result);
615 0 : m_bufptr = bufptr, m_buflen = uDone;
616 : }
617 :
618 51 : bufpos = nOffset - m_bufptr, curpos = bufpos;
619 51 : if (bufpos >= m_buflen)
620 51 : break;
621 : }
622 1951533 : switch (state)
623 : {
624 : case LINE_STATE_CR:
625 0 : state = LINE_STATE_LF;
626 0 : switch (m_buffer[curpos])
627 : {
628 : case 0x0A: /* CRLF */
629 : /* eat current char */
630 0 : curpos++;
631 0 : break;
632 : default: /* single CR */
633 : /* keep current char */
634 0 : break;
635 : }
636 0 : break;
637 : default:
638 : /* determine next state */
639 1951533 : switch (m_buffer[curpos])
640 : {
641 : case 0x0A: /* single LF */
642 45097 : state = LINE_STATE_LF;
643 45097 : break;
644 : case 0x0D: /* CR */
645 0 : state = LINE_STATE_CR;
646 0 : break;
647 : default: /* advance to next char */
648 1906436 : curpos++;
649 1906436 : break;
650 : }
651 1951533 : if (state != LINE_STATE_BEGIN)
652 : {
653 : /* skip the newline char */
654 45097 : curpos++;
655 :
656 : /* flush buffer to sequence */
657 : result = writeSequence_Impl (
658 45097 : ppSequence, &dstpos, &(m_buffer[bufpos]), curpos - bufpos - 1);
659 45097 : if (result != osl_File_E_None)
660 0 : return (result);
661 45097 : *pBytesRead += curpos - bufpos, nOffset += curpos - bufpos;
662 : }
663 1951533 : break;
664 : }
665 : }
666 :
667 49800 : result = writeSequence_Impl (ppSequence, &dstpos, 0, 0);
668 49800 : if (result != osl_File_E_None)
669 0 : return (result);
670 49800 : if (0 < dstpos)
671 44818 : return osl_File_E_None;
672 4982 : if (bufpos >= m_buflen)
673 4652 : return osl_File_E_AGAIN;
674 330 : return osl_File_E_None;
675 : }
676 :
677 94948 : oslFileError FileHandle_Impl::writeSequence_Impl (
678 : sal_Sequence ** ppSequence,
679 : size_t * pnOffset,
680 : const void * pBuffer,
681 : size_t nBytes)
682 : {
683 94948 : sal_Int32 nElements = *pnOffset + nBytes;
684 94948 : if (!*ppSequence)
685 : {
686 : /* construct sequence */
687 0 : rtl_byte_sequence_constructNoDefault(ppSequence, nElements);
688 : }
689 94948 : else if (nElements != (*ppSequence)->nElements)
690 : {
691 : /* resize sequence */
692 48024 : rtl_byte_sequence_realloc(ppSequence, nElements);
693 : }
694 94948 : if (*ppSequence != 0)
695 : {
696 : /* fill sequence */
697 94948 : memcpy(&((*ppSequence)->elements[*pnOffset]), pBuffer, nBytes), *pnOffset += nBytes;
698 : }
699 94948 : return (*ppSequence != 0) ? osl_File_E_None : osl_File_E_NOMEM;
700 : }
701 :
702 364076 : oslFileError FileHandle_Impl::syncFile()
703 : {
704 364076 : oslFileError result = osl_File_E_None;
705 364076 : if (m_state & STATE_MODIFIED)
706 : {
707 158749 : sal_uInt64 uDone = 0;
708 158749 : result = writeAt (m_bufptr, m_buffer, m_buflen, &uDone);
709 158749 : if (result != osl_File_E_None)
710 0 : return (result);
711 158749 : if (uDone != m_buflen)
712 0 : return osl_File_E_IO;
713 158749 : m_state &= ~STATE_MODIFIED;
714 : }
715 364076 : return (result);
716 : }
717 :
718 474 : oslFileHandle osl::detail::createFileHandleFromFD( int fd )
719 : {
720 474 : if (-1 == fd)
721 0 : return 0; // EINVAL
722 :
723 : struct stat aFileStat;
724 474 : if (-1 == fstat (fd, &aFileStat))
725 0 : return 0; // EBADF
726 :
727 474 : FileHandle_Impl * pImpl = new FileHandle_Impl (fd);
728 474 : if (0 == pImpl)
729 0 : return 0; // ENOMEM
730 :
731 : // assume writeable
732 474 : pImpl->m_state |= FileHandle_Impl::STATE_WRITEABLE;
733 474 : if (!S_ISREG(aFileStat.st_mode))
734 : {
735 : /* not a regular file, mark not seekable */
736 474 : pImpl->m_state &= ~FileHandle_Impl::STATE_SEEKABLE;
737 : }
738 : else
739 : {
740 : /* regular file, init current size */
741 0 : pImpl->m_size = sal::static_int_cast< sal_uInt64 >(aFileStat.st_size);
742 : }
743 :
744 : OSL_FILE_TRACE("osl::detail::createFileHandleFromFD(%d, writeable) => %s",
745 : pImpl->m_fd, rtl_string_getStr(pImpl->m_strFilePath));
746 474 : return (oslFileHandle)(pImpl);
747 : }
748 :
749 : /*******************************************************************
750 : * osl_file_adjustLockFlags
751 : ******************************************************************/
752 81982 : static int osl_file_adjustLockFlags (const char * path, int flags)
753 : {
754 : #ifdef MACOSX
755 : /*
756 : * The AFP implementation of MacOS X 10.4 treats O_EXLOCK in a way
757 : * that makes it impossible for OOo to create a backup copy of the
758 : * file it keeps opened. OTOH O_SHLOCK for AFP behaves as desired by
759 : * the OOo file handling, so we need to check the path of the file
760 : * for the filesystem name.
761 : */
762 : struct statfs s;
763 : if( 0 <= statfs( path, &s ) )
764 : {
765 : if( 0 == strncmp("afpfs", s.f_fstypename, 5) )
766 : {
767 : flags &= ~O_EXLOCK;
768 : flags |= O_SHLOCK;
769 : }
770 : else
771 : {
772 : /* Needed flags to allow opening a webdav file */
773 : flags &= ~(O_EXLOCK | O_SHLOCK | O_NONBLOCK);
774 : }
775 : }
776 : #endif /* MACOSX */
777 :
778 : (void) path;
779 81982 : return flags;
780 : }
781 :
782 : /****************************************************************************
783 : * osl_file_queryLocking
784 : ***************************************************************************/
785 93291 : static bool osl_file_queryLocking (sal_uInt32 uFlags)
786 : {
787 : #if !defined HAVE_O_EXLOCK
788 93291 : if (!(uFlags & osl_File_OpenFlag_NoLock)
789 80155 : && ((uFlags & osl_File_OpenFlag_Write)
790 36346 : || (uFlags & osl_File_OpenFlag_Create)))
791 : {
792 44014 : static bool enabled = getenv("SAL_ENABLE_FILE_LOCKING") != 0;
793 : // getenv is not thread safe, so minimize use of result
794 44014 : return enabled;
795 : }
796 : #endif
797 : (void) uFlags;
798 49277 : return false;
799 : }
800 :
801 : #ifdef UNX
802 :
803 : static oslFileError
804 0 : osl_openMemoryAsFile( void *address, size_t size, oslFileHandle *pHandle, const char *path )
805 : {
806 : oslFileError eRet;
807 0 : FileHandle_Impl * pImpl = new FileHandle_Impl (-1, FileHandle_Impl::KIND_MEM, path);
808 0 : if (!pImpl)
809 : {
810 0 : eRet = oslTranslateFileError (OSL_FET_ERROR, ENOMEM);
811 0 : return eRet;
812 : }
813 0 : pImpl->m_size = sal::static_int_cast< sal_uInt64 >(size);
814 :
815 0 : *pHandle = (oslFileHandle)(pImpl);
816 :
817 0 : pImpl->m_bufptr = 0;
818 0 : pImpl->m_buflen = size;
819 :
820 0 : pImpl->m_bufsiz = size;
821 0 : pImpl->m_buffer = (sal_uInt8*) address;
822 :
823 0 : return osl_File_E_None;
824 : }
825 :
826 : oslFileError
827 0 : SAL_CALL osl_openMemoryAsFile( void *address, size_t size, oslFileHandle *pHandle )
828 : {
829 0 : return osl_openMemoryAsFile( address, size, pHandle, "<anon>" );
830 : }
831 :
832 : #endif
833 :
834 : /****************************************************************************
835 : * osl_openFile
836 : ***************************************************************************/
837 : #ifdef HAVE_O_EXLOCK
838 : #define OPEN_WRITE_FLAGS ( O_RDWR | O_EXLOCK | O_NONBLOCK )
839 : #define OPEN_CREATE_FLAGS ( O_CREAT | O_RDWR | O_EXLOCK | O_NONBLOCK )
840 : #else
841 : #define OPEN_WRITE_FLAGS ( O_RDWR )
842 : #define OPEN_CREATE_FLAGS ( O_CREAT | O_RDWR )
843 : #endif
844 :
845 : oslFileError
846 96127 : SAL_CALL osl_openFilePath( const char *cpFilePath, oslFileHandle* pHandle, sal_uInt32 uFlags )
847 : {
848 : oslFileError eRet;
849 :
850 : #ifdef ANDROID
851 : /* Opening a file from /assets read-only means
852 : * we should mmap it from the .apk file
853 : */
854 : if (strncmp (cpFilePath, "/assets/", sizeof ("/assets/") - 1) == 0)
855 : {
856 : if (uFlags & osl_File_OpenFlag_Write)
857 : {
858 : // It seems to work better to silently "open" it read-only
859 : // and let write attempts, if any, fail later. Otherwise
860 : // loading a document from /assets fails with that idiotic
861 : // "General Error" dialog...
862 : }
863 : void *address;
864 : size_t size;
865 : address = lo_apkentry(cpFilePath, &size);
866 : OSL_TRACE("osl_openFile(%s) => %p",
867 : cpFilePath, address);
868 : if (address == NULL)
869 : {
870 : errno = ENOENT;
871 : return osl_File_E_NOENT;
872 : }
873 : return osl_openMemoryAsFile(address, size, pHandle, cpFilePath);
874 : }
875 : #endif
876 :
877 : /* set mode and flags */
878 96127 : int mode = S_IRUSR | S_IRGRP | S_IROTH;
879 96127 : int flags = O_RDONLY;
880 96127 : if (uFlags & osl_File_OpenFlag_Write)
881 : {
882 45181 : mode |= S_IWUSR | S_IWGRP | S_IWOTH;
883 45181 : flags = OPEN_WRITE_FLAGS;
884 : }
885 96127 : if (uFlags & osl_File_OpenFlag_Create)
886 : {
887 41032 : mode |= S_IWUSR | S_IWGRP | S_IWOTH;
888 41032 : flags = OPEN_CREATE_FLAGS;
889 : }
890 :
891 : /* Check for flags passed in from SvFileStream::Open() */
892 96127 : if (uFlags & osl_File_OpenFlag_Trunc)
893 232 : flags |= O_TRUNC;
894 96127 : if (!(uFlags & osl_File_OpenFlag_NoExcl))
895 90421 : flags |= O_EXCL;
896 :
897 96127 : if (uFlags & osl_File_OpenFlag_NoLock)
898 : {
899 : #ifdef HAVE_O_EXLOCK
900 : flags &= ~(O_EXLOCK | O_SHLOCK | O_NONBLOCK);
901 : #endif /* HAVE_O_EXLOCK */
902 : }
903 : else
904 : {
905 81982 : flags = osl_file_adjustLockFlags (cpFilePath, flags);
906 : }
907 :
908 : /* open the file */
909 96127 : int fd = open( cpFilePath, flags, mode );
910 : #ifdef IOS
911 : /* Horrible hack: If opening for RDWR and getting EPERM, just try
912 : * again for RDONLY. Quicker this way than to figure out why
913 : * we get that oh so useful General Error when trying to open a
914 : * read-only document.
915 : */
916 : if (-1 == fd && (flags & O_RDWR) && EPERM == errno)
917 : {
918 : int rdonly_flags = (flags & ~O_ACCMODE) | O_RDONLY;
919 : fd = open( cpFilePath, rdonly_flags, mode );
920 : }
921 : #endif
922 96127 : if (-1 == fd)
923 : {
924 2836 : int saved_errno = errno;
925 : OSL_TRACE("osl_openFile(%s, %s) failed: %s",
926 : cpFilePath,
927 : flags & O_RDWR ? "writeable":"readonly",
928 : strerror(saved_errno));
929 2836 : return oslTranslateFileError (OSL_FET_ERROR, saved_errno);
930 : }
931 :
932 : /* reset O_NONBLOCK flag */
933 93291 : if (flags & O_NONBLOCK)
934 : {
935 0 : int f = fcntl (fd, F_GETFL, 0);
936 0 : if (-1 == f)
937 : {
938 0 : int saved_errno = errno;
939 : OSL_TRACE("osl_openFile(%s, %s): fcntl(%d, F_GETFL) failed: %s",
940 : cpFilePath,
941 : flags & O_RDWR ? "writeable":"readonly",
942 : fd,
943 : strerror(saved_errno));
944 0 : eRet = oslTranslateFileError (OSL_FET_ERROR, saved_errno);
945 0 : (void) close(fd);
946 0 : return eRet;
947 : }
948 0 : if (-1 == fcntl (fd, F_SETFL, (f & ~O_NONBLOCK)))
949 : {
950 0 : int saved_errno = errno;
951 : OSL_TRACE("osl_openFile(%s, %s): fcntl(%d, F_SETFL) failed: %s",
952 : cpFilePath,
953 : flags & O_RDWR ? "writeable":"readonly",
954 : fd,
955 : strerror(saved_errno));
956 0 : eRet = oslTranslateFileError (OSL_FET_ERROR, saved_errno);
957 0 : (void) close(fd);
958 0 : return eRet;
959 : }
960 : }
961 :
962 : /* get file status (mode, size) */
963 : struct stat aFileStat;
964 93291 : if (-1 == fstat (fd, &aFileStat))
965 : {
966 0 : int saved_errno = errno;
967 : OSL_TRACE("osl_openFile(%s, %s): fstat(%d) failed: %s",
968 : cpFilePath,
969 : flags & O_RDWR ? "writeable":"readonly",
970 : fd,
971 : strerror(saved_errno));
972 0 : eRet = oslTranslateFileError (OSL_FET_ERROR, saved_errno);
973 0 : (void) close(fd);
974 0 : return eRet;
975 : }
976 93291 : if (!S_ISREG(aFileStat.st_mode))
977 : {
978 : /* we only open regular files here */
979 : OSL_TRACE("osl_openFile(%s): not a regular file",
980 : cpFilePath);
981 0 : (void) close(fd);
982 0 : return osl_File_E_INVAL;
983 : }
984 :
985 93291 : if (osl_file_queryLocking (uFlags))
986 : {
987 : #ifdef MACOSX
988 : if (-1 == flock (fd, LOCK_EX | LOCK_NB))
989 : {
990 : /* Mac OSX returns ENOTSUP for webdav drives. We should try read lock */
991 : if ((errno != ENOTSUP) || ((-1 == flock (fd, LOCK_SH | LOCK_NB)) && (errno != ENOTSUP)))
992 : {
993 : eRet = oslTranslateFileError (OSL_FET_ERROR, errno);
994 : (void) close(fd);
995 : return eRet;
996 : }
997 : }
998 : #else /* F_SETLK */
999 : {
1000 : struct flock aflock;
1001 :
1002 44014 : aflock.l_type = F_WRLCK;
1003 44014 : aflock.l_whence = SEEK_SET;
1004 44014 : aflock.l_start = 0;
1005 44014 : aflock.l_len = 0;
1006 :
1007 44014 : if (-1 == fcntl (fd, F_SETLK, &aflock))
1008 : {
1009 0 : int saved_errno = errno;
1010 : OSL_TRACE("osl_openFile(%s, %s): fcntl(%d, F_SETLK) failed: %s",
1011 : cpFilePath,
1012 : flags & O_RDWR ? "writeable":"readonly",
1013 : fd,
1014 : strerror(saved_errno));
1015 0 : eRet = oslTranslateFileError (OSL_FET_ERROR, saved_errno);
1016 0 : (void) close(fd);
1017 0 : return eRet;
1018 : }
1019 : }
1020 : #endif /* F_SETLK */
1021 : }
1022 :
1023 : /* allocate memory for impl structure */
1024 93291 : FileHandle_Impl * pImpl = new FileHandle_Impl (fd, FileHandle_Impl::KIND_FD, cpFilePath);
1025 93291 : if (!pImpl)
1026 : {
1027 0 : eRet = oslTranslateFileError (OSL_FET_ERROR, ENOMEM);
1028 0 : (void) close(fd);
1029 0 : return eRet;
1030 : }
1031 93291 : if (flags & O_RDWR)
1032 50724 : pImpl->m_state |= FileHandle_Impl::STATE_WRITEABLE;
1033 93291 : pImpl->m_size = sal::static_int_cast< sal_uInt64 >(aFileStat.st_size);
1034 :
1035 : OSL_TRACE("osl_openFile(%s, %s) => %d",
1036 : rtl_string_getStr(pImpl->m_strFilePath),
1037 : flags & O_RDWR ? "writeable":"readonly",
1038 : pImpl->m_fd);
1039 :
1040 93291 : *pHandle = (oslFileHandle)(pImpl);
1041 93291 : return osl_File_E_None;
1042 : }
1043 :
1044 : oslFileError
1045 93863 : SAL_CALL osl_openFile( rtl_uString* ustrFileURL, oslFileHandle* pHandle, sal_uInt32 uFlags )
1046 : {
1047 : oslFileError eRet;
1048 :
1049 93863 : if ((ustrFileURL == 0) || (ustrFileURL->length == 0) || (pHandle == 0))
1050 0 : return osl_File_E_INVAL;
1051 :
1052 : /* convert file URL to system path */
1053 : char buffer[PATH_MAX];
1054 93863 : eRet = FileURLToPath (buffer, sizeof(buffer), ustrFileURL);
1055 93863 : if (eRet != osl_File_E_None)
1056 0 : return eRet;
1057 :
1058 : #ifdef MACOSX
1059 : if (macxp_resolveAlias (buffer, sizeof(buffer)) != 0)
1060 : return oslTranslateFileError (OSL_FET_ERROR, errno);
1061 : #endif /* MACOSX */
1062 :
1063 93863 : return osl_openFilePath (buffer, pHandle, uFlags);
1064 : }
1065 :
1066 : /****************************************************************************/
1067 : /* osl_closeFile */
1068 : /****************************************************************************/
1069 : oslFileError
1070 92983 : SAL_CALL osl_closeFile( oslFileHandle Handle )
1071 : {
1072 92983 : FileHandle_Impl* pImpl = static_cast<FileHandle_Impl*>(Handle);
1073 :
1074 92983 : if (pImpl == 0)
1075 0 : return osl_File_E_INVAL;
1076 :
1077 : OSL_TRACE("osl_closeFile(%s:%d)", rtl_string_getStr(pImpl->m_strFilePath), pImpl->m_fd);
1078 :
1079 92983 : if (pImpl->m_kind == FileHandle_Impl::KIND_MEM)
1080 : {
1081 0 : delete pImpl;
1082 0 : return osl_File_E_None;
1083 : }
1084 :
1085 92983 : if (pImpl->m_fd < 0)
1086 0 : return osl_File_E_INVAL;
1087 :
1088 92983 : (void) pthread_mutex_lock (&(pImpl->m_mutex));
1089 :
1090 : /* close(2) implicitly (and unconditionally) unlocks */
1091 92983 : oslFileError result = pImpl->syncFile();
1092 92983 : if (result != osl_File_E_None)
1093 : {
1094 : /* close, ignoring double failure */
1095 0 : (void) close (pImpl->m_fd);
1096 : }
1097 92983 : else if (-1 == close (pImpl->m_fd))
1098 : {
1099 : /* translate error code */
1100 0 : result = oslTranslateFileError (OSL_FET_ERROR, errno);
1101 : }
1102 :
1103 92983 : (void) pthread_mutex_unlock (&(pImpl->m_mutex));
1104 92983 : delete pImpl;
1105 92983 : return (result);
1106 : }
1107 :
1108 : /************************************************
1109 : * osl_syncFile
1110 : ***********************************************/
1111 : oslFileError
1112 326 : SAL_CALL osl_syncFile(oslFileHandle Handle)
1113 : {
1114 326 : FileHandle_Impl* pImpl = static_cast<FileHandle_Impl*>(Handle);
1115 :
1116 326 : if ((0 == pImpl) || ((pImpl->m_kind == FileHandle_Impl::KIND_FD) && (-1 == pImpl->m_fd)))
1117 1 : return osl_File_E_INVAL;
1118 :
1119 325 : if (pImpl->m_kind == FileHandle_Impl::KIND_MEM)
1120 0 : return osl_File_E_None;
1121 :
1122 325 : FileHandle_Impl::Guard lock (&(pImpl->m_mutex));
1123 :
1124 : OSL_TRACE("osl_syncFile(%d)", pImpl->m_fd);
1125 325 : oslFileError result = pImpl->syncFile();
1126 325 : if (result != osl_File_E_None)
1127 0 : return (result);
1128 325 : if (-1 == fsync (pImpl->m_fd))
1129 0 : return oslTranslateFileError (OSL_FET_ERROR, errno);
1130 :
1131 325 : return osl_File_E_None;
1132 : }
1133 :
1134 : /************************************************
1135 : * osl_fileGetOSHandle
1136 : ***********************************************/
1137 : oslFileError
1138 0 : SAL_CALL osl_getFileOSHandle(
1139 : oslFileHandle Handle,
1140 : sal_IntPtr *piFileHandle )
1141 : {
1142 0 : FileHandle_Impl* pImpl = static_cast<FileHandle_Impl*>(Handle);
1143 :
1144 0 : if (0 == pImpl || pImpl->m_kind != FileHandle_Impl::KIND_FD || -1 == pImpl->m_fd)
1145 0 : return osl_File_E_INVAL;
1146 :
1147 0 : *piFileHandle = pImpl->m_fd;
1148 :
1149 0 : return osl_File_E_None;
1150 : }
1151 :
1152 : /*******************************************
1153 : osl_mapFile
1154 : ********************************************/
1155 : oslFileError
1156 27931 : SAL_CALL osl_mapFile (
1157 : oslFileHandle Handle,
1158 : void** ppAddr,
1159 : sal_uInt64 uLength,
1160 : sal_uInt64 uOffset,
1161 : sal_uInt32 uFlags
1162 : )
1163 : {
1164 27931 : FileHandle_Impl* pImpl = static_cast<FileHandle_Impl*>(Handle);
1165 :
1166 27931 : if ((0 == pImpl) || ((pImpl->m_kind == FileHandle_Impl::KIND_FD) && (-1 == pImpl->m_fd)) || (0 == ppAddr))
1167 0 : return osl_File_E_INVAL;
1168 27931 : *ppAddr = 0;
1169 :
1170 : static sal_uInt64 const g_limit_size_t = std::numeric_limits< size_t >::max();
1171 27931 : if (g_limit_size_t < uLength)
1172 0 : return osl_File_E_OVERFLOW;
1173 27931 : size_t const nLength = sal::static_int_cast< size_t >(uLength);
1174 :
1175 : static sal_uInt64 const g_limit_off_t = std::numeric_limits< off_t >::max();
1176 27931 : if (g_limit_off_t < uOffset)
1177 0 : return osl_File_E_OVERFLOW;
1178 :
1179 27931 : if (pImpl->m_kind == FileHandle_Impl::KIND_MEM)
1180 : {
1181 0 : *ppAddr = pImpl->m_buffer + uOffset;
1182 0 : return osl_File_E_None;
1183 : }
1184 :
1185 27931 : off_t const nOffset = sal::static_int_cast< off_t >(uOffset);
1186 :
1187 27931 : void* p = mmap(NULL, nLength, PROT_READ, MAP_SHARED, pImpl->m_fd, nOffset);
1188 27931 : if (MAP_FAILED == p)
1189 4 : return oslTranslateFileError(OSL_FET_ERROR, errno);
1190 27927 : *ppAddr = p;
1191 :
1192 27927 : if (uFlags & osl_File_MapFlag_RandomAccess)
1193 : {
1194 : // Determine memory pagesize.
1195 5996 : size_t const nPageSize = FileHandle_Impl::getpagesize();
1196 5996 : if (size_t(-1) != nPageSize)
1197 : {
1198 : /*
1199 : * Pagein, touching first byte of every memory page.
1200 : * Note: volatile disables optimizing the loop away.
1201 : */
1202 5996 : sal_uInt8 * pData (reinterpret_cast<sal_uInt8*>(*ppAddr));
1203 5996 : size_t nSize (nLength);
1204 :
1205 5996 : volatile sal_uInt8 c = 0;
1206 67770 : while (nSize > nPageSize)
1207 : {
1208 55778 : c ^= pData[0];
1209 55778 : pData += nPageSize;
1210 55778 : nSize -= nPageSize;
1211 : }
1212 5996 : if (nSize > 0)
1213 : {
1214 5996 : c^= pData[0];
1215 : }
1216 : }
1217 : }
1218 27927 : if (uFlags & osl_File_MapFlag_WillNeed)
1219 : {
1220 : // On Linux, madvise(..., MADV_WILLNEED) appears to have the undesirable
1221 : // effect of not returning until the data has actually been paged in, so
1222 : // that its net effect would typically be to slow down the process
1223 : // (which could start processing at the beginning of the data while the
1224 : // OS simultaneously pages in the rest); on other platforms, it remains
1225 : // to be evaluated whether madvise or equivalent is available and
1226 : // actually useful:
1227 : #if defined MACOSX
1228 : int e = posix_madvise(p, nLength, POSIX_MADV_WILLNEED);
1229 : if (e != 0)
1230 : {
1231 : OSL_TRACE(
1232 : "posix_madvise(..., POSIX_MADV_WILLNEED) failed with %d", e);
1233 : }
1234 : #elif defined SOLARIS
1235 : if (madvise(static_cast< caddr_t >(p), nLength, MADV_WILLNEED) != 0)
1236 : {
1237 : OSL_TRACE("madvise(..., MADV_WILLNEED) failed with %d", errno);
1238 : }
1239 : #endif
1240 : }
1241 27927 : return osl_File_E_None;
1242 : }
1243 :
1244 : static
1245 : oslFileError
1246 27531 : unmapFile (void* pAddr, sal_uInt64 uLength)
1247 : {
1248 27531 : if (0 == pAddr)
1249 0 : return osl_File_E_INVAL;
1250 :
1251 : static sal_uInt64 const g_limit_size_t = std::numeric_limits< size_t >::max();
1252 27531 : if (g_limit_size_t < uLength)
1253 0 : return osl_File_E_OVERFLOW;
1254 27531 : size_t const nLength = sal::static_int_cast< size_t >(uLength);
1255 :
1256 27531 : if (-1 == munmap(static_cast<char*>(pAddr), nLength))
1257 0 : return oslTranslateFileError(OSL_FET_ERROR, errno);
1258 :
1259 27531 : return osl_File_E_None;
1260 : }
1261 :
1262 : #ifndef ANDROID
1263 :
1264 : // Note that osl_unmapFile() just won't work on Android in general
1265 : // where for (uncompressed) files inside the .apk, in the /assets
1266 : // folder osl_mapFile just returns a pointer to the file inside the
1267 : // already mmapped .apk archive.
1268 :
1269 : /*******************************************
1270 : osl_unmapFile
1271 : ********************************************/
1272 : oslFileError
1273 0 : SAL_CALL osl_unmapFile (void* pAddr, sal_uInt64 uLength)
1274 : {
1275 0 : return unmapFile (pAddr, uLength);
1276 : }
1277 :
1278 : #endif
1279 :
1280 : /*******************************************
1281 : osl_unmapMappedFile
1282 : ********************************************/
1283 : oslFileError
1284 27531 : SAL_CALL osl_unmapMappedFile (oslFileHandle Handle, void* pAddr, sal_uInt64 uLength)
1285 : {
1286 27531 : FileHandle_Impl * pImpl = static_cast<FileHandle_Impl*>(Handle);
1287 :
1288 27531 : if (pImpl == 0)
1289 0 : return osl_File_E_INVAL;
1290 :
1291 27531 : if (pImpl->m_kind == FileHandle_Impl::KIND_FD)
1292 27531 : return unmapFile (pAddr, uLength);
1293 :
1294 : // For parts of already mmapped "parent" files, whose mapping we
1295 : // can't change, not much we can or should do...
1296 0 : return osl_File_E_None;
1297 : }
1298 :
1299 : /*******************************************
1300 : osl_readLine
1301 : ********************************************/
1302 : oslFileError
1303 49800 : SAL_CALL osl_readLine (
1304 : oslFileHandle Handle,
1305 : sal_Sequence ** ppSequence)
1306 : {
1307 49800 : FileHandle_Impl * pImpl = static_cast<FileHandle_Impl*>(Handle);
1308 :
1309 49800 : if ((0 == pImpl) || ((pImpl->m_kind == FileHandle_Impl::KIND_FD) && (-1 == pImpl->m_fd)) || (0 == ppSequence))
1310 0 : return osl_File_E_INVAL;
1311 49800 : sal_uInt64 uBytesRead = 0;
1312 :
1313 : // read at current fileptr; fileptr += uBytesRead;
1314 49800 : FileHandle_Impl::Guard lock (&(pImpl->m_mutex));
1315 : oslFileError result = pImpl->readLineAt (
1316 49800 : pImpl->m_fileptr, ppSequence, &uBytesRead);
1317 49800 : if (result == osl_File_E_None)
1318 45148 : pImpl->m_fileptr += uBytesRead;
1319 49800 : return (result);
1320 : }
1321 :
1322 : /*******************************************
1323 : osl_readFile
1324 : ********************************************/
1325 : oslFileError
1326 1317166 : SAL_CALL osl_readFile (
1327 : oslFileHandle Handle,
1328 : void * pBuffer,
1329 : sal_uInt64 uBytesRequested,
1330 : sal_uInt64 * pBytesRead)
1331 : {
1332 1317166 : FileHandle_Impl* pImpl = static_cast<FileHandle_Impl*>(Handle);
1333 :
1334 1317166 : if ((0 == pImpl) || ((pImpl->m_kind == FileHandle_Impl::KIND_FD) && (-1 == pImpl->m_fd)) || (0 == pBuffer) || (0 == pBytesRead))
1335 0 : return osl_File_E_INVAL;
1336 :
1337 : static sal_uInt64 const g_limit_ssize_t = std::numeric_limits< ssize_t >::max();
1338 1317166 : if (g_limit_ssize_t < uBytesRequested)
1339 0 : return osl_File_E_OVERFLOW;
1340 1317166 : size_t const nBytesRequested = sal::static_int_cast< size_t >(uBytesRequested);
1341 :
1342 : // read at current fileptr; fileptr += *pBytesRead;
1343 1317166 : FileHandle_Impl::Guard lock (&(pImpl->m_mutex));
1344 : oslFileError result = pImpl->readFileAt (
1345 1317166 : pImpl->m_fileptr, pBuffer, nBytesRequested, pBytesRead);
1346 1317166 : if (result == osl_File_E_None)
1347 1317166 : pImpl->m_fileptr += *pBytesRead;
1348 1317166 : return (result);
1349 : }
1350 :
1351 : /*******************************************
1352 : osl_writeFile
1353 : ********************************************/
1354 : oslFileError
1355 6136415 : SAL_CALL osl_writeFile (
1356 : oslFileHandle Handle,
1357 : const void * pBuffer,
1358 : sal_uInt64 uBytesToWrite,
1359 : sal_uInt64 * pBytesWritten)
1360 : {
1361 6136415 : FileHandle_Impl* pImpl = static_cast<FileHandle_Impl*>(Handle);
1362 :
1363 6136415 : if ((0 == pImpl) || (-1 == pImpl->m_fd) || (0 == pBuffer) || (0 == pBytesWritten))
1364 1 : return osl_File_E_INVAL;
1365 6136414 : if (0 == (pImpl->m_state & FileHandle_Impl::STATE_WRITEABLE))
1366 0 : return osl_File_E_BADF;
1367 :
1368 : static sal_uInt64 const g_limit_ssize_t = std::numeric_limits< ssize_t >::max();
1369 6136414 : if (g_limit_ssize_t < uBytesToWrite)
1370 0 : return osl_File_E_OVERFLOW;
1371 6136414 : size_t const nBytesToWrite = sal::static_int_cast< size_t >(uBytesToWrite);
1372 :
1373 : // write at current fileptr; fileptr += *pBytesWritten;
1374 6136414 : FileHandle_Impl::Guard lock (&(pImpl->m_mutex));
1375 : oslFileError result = pImpl->writeFileAt (
1376 6136414 : pImpl->m_fileptr, pBuffer, nBytesToWrite, pBytesWritten);
1377 6136414 : if (result == osl_File_E_None)
1378 6136414 : pImpl->m_fileptr += *pBytesWritten;
1379 6136414 : return (result);
1380 : }
1381 :
1382 : /*******************************************
1383 : osl_readFileAt
1384 : ********************************************/
1385 : oslFileError
1386 5450 : SAL_CALL osl_readFileAt (
1387 : oslFileHandle Handle,
1388 : sal_uInt64 uOffset,
1389 : void* pBuffer,
1390 : sal_uInt64 uBytesRequested,
1391 : sal_uInt64* pBytesRead)
1392 : {
1393 5450 : FileHandle_Impl* pImpl = static_cast<FileHandle_Impl*>(Handle);
1394 :
1395 5450 : if ((0 == pImpl) || ((pImpl->m_kind == FileHandle_Impl::KIND_FD) && (-1 == pImpl->m_fd)) || (0 == pBuffer) || (0 == pBytesRead))
1396 0 : return osl_File_E_INVAL;
1397 5450 : if (0 == (pImpl->m_state & FileHandle_Impl::STATE_SEEKABLE))
1398 0 : return osl_File_E_SPIPE;
1399 :
1400 : static sal_uInt64 const g_limit_off_t = std::numeric_limits< off_t >::max();
1401 5450 : if (g_limit_off_t < uOffset)
1402 0 : return osl_File_E_OVERFLOW;
1403 5450 : off_t const nOffset = sal::static_int_cast< off_t >(uOffset);
1404 :
1405 : static sal_uInt64 const g_limit_ssize_t = std::numeric_limits< ssize_t >::max();
1406 5450 : if (g_limit_ssize_t < uBytesRequested)
1407 0 : return osl_File_E_OVERFLOW;
1408 5450 : size_t const nBytesRequested = sal::static_int_cast< size_t >(uBytesRequested);
1409 :
1410 : // read at specified fileptr
1411 5450 : FileHandle_Impl::Guard lock (&(pImpl->m_mutex));
1412 5450 : return pImpl->readFileAt (nOffset, pBuffer, nBytesRequested, pBytesRead);
1413 : }
1414 :
1415 : /*******************************************
1416 : osl_writeFileAt
1417 : ********************************************/
1418 : oslFileError
1419 252118 : SAL_CALL osl_writeFileAt (
1420 : oslFileHandle Handle,
1421 : sal_uInt64 uOffset,
1422 : const void* pBuffer,
1423 : sal_uInt64 uBytesToWrite,
1424 : sal_uInt64* pBytesWritten)
1425 : {
1426 252118 : FileHandle_Impl* pImpl = static_cast<FileHandle_Impl*>(Handle);
1427 :
1428 252118 : if ((0 == pImpl) || (-1 == pImpl->m_fd) || (0 == pBuffer) || (0 == pBytesWritten))
1429 0 : return osl_File_E_INVAL;
1430 252118 : if (0 == (pImpl->m_state & FileHandle_Impl::STATE_SEEKABLE))
1431 0 : return osl_File_E_SPIPE;
1432 252118 : if (0 == (pImpl->m_state & FileHandle_Impl::STATE_WRITEABLE))
1433 0 : return osl_File_E_BADF;
1434 :
1435 : static sal_uInt64 const g_limit_off_t = std::numeric_limits< off_t >::max();
1436 252118 : if (g_limit_off_t < uOffset)
1437 0 : return osl_File_E_OVERFLOW;
1438 252118 : off_t const nOffset = sal::static_int_cast< off_t >(uOffset);
1439 :
1440 : static sal_uInt64 const g_limit_ssize_t = std::numeric_limits< ssize_t >::max();
1441 252118 : if (g_limit_ssize_t < uBytesToWrite)
1442 0 : return osl_File_E_OVERFLOW;
1443 252118 : size_t const nBytesToWrite = sal::static_int_cast< size_t >(uBytesToWrite);
1444 :
1445 : // write at specified fileptr
1446 252118 : FileHandle_Impl::Guard lock (&(pImpl->m_mutex));
1447 252118 : return pImpl->writeFileAt (nOffset, pBuffer, nBytesToWrite, pBytesWritten);
1448 : }
1449 :
1450 : /****************************************************************************/
1451 : /* osl_isEndOfFile */
1452 : /****************************************************************************/
1453 : oslFileError
1454 31 : SAL_CALL osl_isEndOfFile( oslFileHandle Handle, sal_Bool *pIsEOF )
1455 : {
1456 31 : FileHandle_Impl* pImpl = static_cast<FileHandle_Impl*>(Handle);
1457 :
1458 31 : if ((0 == pImpl) || ((pImpl->m_kind == FileHandle_Impl::KIND_FD) && (-1 == pImpl->m_fd)) || (0 == pIsEOF))
1459 0 : return osl_File_E_INVAL;
1460 :
1461 31 : FileHandle_Impl::Guard lock (&(pImpl->m_mutex));
1462 31 : *pIsEOF = (pImpl->getPos() == pImpl->getSize());
1463 31 : return osl_File_E_None;
1464 : }
1465 :
1466 : /************************************************
1467 : * osl_getFilePos
1468 : ***********************************************/
1469 : oslFileError
1470 252545 : SAL_CALL osl_getFilePos( oslFileHandle Handle, sal_uInt64* pPos )
1471 : {
1472 252545 : FileHandle_Impl* pImpl = static_cast<FileHandle_Impl*>(Handle);
1473 :
1474 252545 : if ((0 == pImpl) || ((pImpl->m_kind == FileHandle_Impl::KIND_FD) && (-1 == pImpl->m_fd)) || (0 == pPos))
1475 0 : return osl_File_E_INVAL;
1476 :
1477 252545 : FileHandle_Impl::Guard lock (&(pImpl->m_mutex));
1478 252545 : *pPos = pImpl->getPos();
1479 252545 : return osl_File_E_None;
1480 : }
1481 :
1482 : /*******************************************
1483 : osl_setFilePos
1484 : ********************************************/
1485 : oslFileError
1486 273110 : SAL_CALL osl_setFilePos (oslFileHandle Handle, sal_uInt32 uHow, sal_Int64 uOffset)
1487 : {
1488 273110 : FileHandle_Impl* pImpl = static_cast<FileHandle_Impl*>(Handle);
1489 :
1490 273110 : if ((0 == pImpl) || ((pImpl->m_kind == FileHandle_Impl::KIND_FD) && (-1 == pImpl->m_fd)))
1491 0 : return osl_File_E_INVAL;
1492 :
1493 : static sal_Int64 const g_limit_off_t = std::numeric_limits< off_t >::max();
1494 : if (g_limit_off_t < uOffset)
1495 : return osl_File_E_OVERFLOW;
1496 273110 : off_t nPos = 0, nOffset = sal::static_int_cast< off_t >(uOffset);
1497 :
1498 273110 : FileHandle_Impl::Guard lock (&(pImpl->m_mutex));
1499 273110 : switch(uHow)
1500 : {
1501 : case osl_Pos_Absolut:
1502 271241 : if (0 > nOffset)
1503 0 : return osl_File_E_INVAL;
1504 271241 : break;
1505 :
1506 : case osl_Pos_Current:
1507 25 : nPos = sal::static_int_cast< off_t >(pImpl->getPos());
1508 25 : if ((0 > nOffset) && (-1*nOffset > nPos))
1509 0 : return osl_File_E_INVAL;
1510 : if (g_limit_off_t < (sal_Int64) nPos + nOffset)
1511 : return osl_File_E_OVERFLOW;
1512 25 : break;
1513 :
1514 : case osl_Pos_End:
1515 1844 : nPos = sal::static_int_cast< off_t >(pImpl->getSize());
1516 1844 : if ((0 > nOffset) && (-1*nOffset > nPos))
1517 0 : return osl_File_E_INVAL;
1518 : if (g_limit_off_t < (sal_Int64) nPos + nOffset)
1519 : return osl_File_E_OVERFLOW;
1520 1844 : break;
1521 :
1522 : default:
1523 0 : return osl_File_E_INVAL;
1524 : }
1525 :
1526 273110 : return pImpl->setPos (nPos + nOffset);
1527 : }
1528 :
1529 : /****************************************************************************
1530 : * osl_getFileSize
1531 : ****************************************************************************/
1532 : oslFileError
1533 70657 : SAL_CALL osl_getFileSize( oslFileHandle Handle, sal_uInt64* pSize )
1534 : {
1535 70657 : FileHandle_Impl* pImpl = static_cast<FileHandle_Impl*>(Handle);
1536 :
1537 70657 : if ((0 == pImpl) || ((pImpl->m_kind == FileHandle_Impl::KIND_FD) && (-1 == pImpl->m_fd)) || (0 == pSize))
1538 0 : return osl_File_E_INVAL;
1539 :
1540 70657 : FileHandle_Impl::Guard lock (&(pImpl->m_mutex));
1541 70657 : *pSize = pImpl->getSize();
1542 70657 : return osl_File_E_None;
1543 : }
1544 :
1545 : /************************************************
1546 : * osl_setFileSize
1547 : ***********************************************/
1548 : oslFileError
1549 6177 : SAL_CALL osl_setFileSize( oslFileHandle Handle, sal_uInt64 uSize )
1550 : {
1551 6177 : FileHandle_Impl* pImpl = static_cast<FileHandle_Impl*>(Handle);
1552 :
1553 6177 : if ((0 == pImpl) || (-1 == pImpl->m_fd))
1554 0 : return osl_File_E_INVAL;
1555 6177 : if (0 == (pImpl->m_state & FileHandle_Impl::STATE_WRITEABLE))
1556 0 : return osl_File_E_BADF;
1557 :
1558 : static sal_uInt64 const g_limit_off_t = std::numeric_limits< off_t >::max();
1559 6177 : if (g_limit_off_t < uSize)
1560 0 : return osl_File_E_OVERFLOW;
1561 :
1562 6177 : oslFileError result = pImpl->syncFile();
1563 6177 : if (result != osl_File_E_None)
1564 0 : return (result);
1565 6177 : pImpl->m_bufptr = -1, pImpl->m_buflen = 0;
1566 :
1567 6177 : return pImpl->setSize (uSize);
1568 : }
1569 :
1570 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|