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