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