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