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 ******************************************************************/
64struct 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
181FileHandle_Impl::Allocator &
182FileHandle_Impl::Allocator::get()
183{
184 static Allocator g_aBufferAllocator;
185 return g_aBufferAllocator;
186}
187
188FileHandle_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}
201FileHandle_Impl::Allocator::~Allocator()
202{
203 rtl_cache_destroy (m_cache), m_cache = 0;
204}
205
206void 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}
212void FileHandle_Impl::Allocator::deallocate (sal_uInt8 * pBuffer)
213{
214 if (0 != pBuffer)
215 rtl_cache_free (m_cache, pBuffer);
216}
217
218FileHandle_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}
224FileHandle_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
230FileHandle_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}
251FileHandle_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
259void* FileHandle_Impl::operator new (size_t n)
260{
261 return rtl_allocateMemory(n);
262}
263void FileHandle_Impl::operator delete (void * p)
264{
265 rtl_freeMemory(p);
266}
267
268size_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
278sal_uInt64 FileHandle_Impl::getPos() const
279{
280 return sal::static_int_cast< sal_uInt64 >(m_fileptr);
281}
282
283oslFileError 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
290sal_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
296oslFileError 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
337oslFileError 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
386oslFileError 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
411oslFileError 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
482oslFileError 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
552oslFileError 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
668oslFileError 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
693oslFileError 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
709oslFileHandle 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
739static 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
769static 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
787static oslFileError
788osl_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
810oslFileError
811SAL_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
826oslFileError
827SAL_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
1003oslFileError
1004SAL_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
1025oslFileError
1026SAL_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
1064oslFileError
1065SAL_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
1087oslFileError
1088SAL_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
1102oslFileError
1103SAL_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
1190static
1191oslFileError
1192unmapFile (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
1215oslFileError
1216SAL_CALL osl_unmapFile (void* pAddr, sal_uInt64 uLength)
1217{
1218 return unmapFile (pAddr, uLength);
1219}
1220
1221#endif
1222
1223oslFileError
1224SAL_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
1239oslFileError
1240SAL_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
1259oslFileError
1260SAL_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
1285oslFileError
1286SAL_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
1313oslFileError
1314SAL_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
1343oslFileError
1344SAL_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
1375oslFileError
1376SAL_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
1388oslFileError
1389SAL_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
1401oslFileError
1402SAL_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
1445oslFileError
1446SAL_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
1458oslFileError
1459SAL_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