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