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