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