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 * FileHandle_Impl implementation
182 ******************************************************************/
183
184 FileHandle_Impl::Allocator &
get()185 FileHandle_Impl::Allocator::get()
186 {
187 static Allocator g_aBufferAllocator;
188 return g_aBufferAllocator;
189 }
190
Allocator()191 FileHandle_Impl::Allocator::Allocator()
192 : m_cache (0),
193 m_bufsiz (0)
194 {
195 size_t const pagesize = FileHandle_Impl::getpagesize();
196 if (size_t(-1) != pagesize)
197 {
198 m_cache = rtl_cache_create (
199 "osl_file_buffer_cache", pagesize, 0, 0, 0, 0, 0, 0, 0);
200 if (0 != m_cache)
201 m_bufsiz = pagesize;
202 }
203 }
~Allocator()204 FileHandle_Impl::Allocator::~Allocator()
205 {
206 rtl_cache_destroy (m_cache), m_cache = 0;
207 }
208
allocate(sal_uInt8 ** ppBuffer,size_t * pnSize)209 void FileHandle_Impl::Allocator::allocate (sal_uInt8 ** ppBuffer, size_t * pnSize)
210 {
211 OSL_PRECOND((0 != ppBuffer) && (0 != pnSize), "FileHandle_Impl::Allocator::allocate(): contract violation");
212 if ((0 != ppBuffer) && (0 != pnSize))
213 *ppBuffer = static_cast< sal_uInt8* >(rtl_cache_alloc(m_cache)), *pnSize = m_bufsiz;
214 }
deallocate(sal_uInt8 * pBuffer)215 void FileHandle_Impl::Allocator::deallocate (sal_uInt8 * pBuffer)
216 {
217 if (0 != pBuffer)
218 rtl_cache_free (m_cache, pBuffer);
219 }
220
Guard(pthread_mutex_t * pMutex)221 FileHandle_Impl::Guard::Guard(pthread_mutex_t * pMutex)
222 : m_mutex (pMutex)
223 {
224 OSL_PRECOND (m_mutex != 0, "FileHandle_Impl::Guard::Guard(): null pointer.");
225 (void) pthread_mutex_lock (m_mutex); // ignoring EINVAL ...
226 }
~Guard()227 FileHandle_Impl::Guard::~Guard()
228 {
229 OSL_PRECOND (m_mutex != 0, "FileHandle_Impl::Guard::~Guard(): null pointer.");
230 (void) pthread_mutex_unlock (m_mutex);
231 }
232
FileHandle_Impl(int fd,char const * path)233 FileHandle_Impl::FileHandle_Impl (int fd, char const * path)
234 : m_strFilePath (0),
235 m_fd (fd),
236 m_state (STATE_SEEKABLE | STATE_READABLE),
237 m_size (0),
238 m_offset (0),
239 m_fileptr (0),
240 m_bufptr (-1),
241 m_buflen (0),
242 m_bufsiz (0),
243 m_buffer (0)
244 {
245 (void) pthread_mutex_init(&m_mutex, 0);
246 rtl_string_newFromStr (&m_strFilePath, path);
247 Allocator::get().allocate (&m_buffer, &m_bufsiz);
248 if (0 != m_buffer)
249 memset (m_buffer, 0, m_bufsiz);
250 }
~FileHandle_Impl()251 FileHandle_Impl::~FileHandle_Impl()
252 {
253 Allocator::get().deallocate (m_buffer), m_buffer = 0;
254 rtl_string_release (m_strFilePath), m_strFilePath = 0;
255 (void) pthread_mutex_destroy(&m_mutex); // ignoring EBUSY ...
256 }
257
operator new(size_t n)258 void* FileHandle_Impl::operator new (size_t n)
259 {
260 return rtl_allocateMemory(n);
261 }
operator delete(void * p,size_t)262 void FileHandle_Impl::operator delete (void * p, size_t)
263 {
264 rtl_freeMemory(p);
265 }
266
getpagesize()267 size_t FileHandle_Impl::getpagesize()
268 {
269 #if defined(FREEBSD) || defined(NETBSD) || defined(MACOSX)
270 return sal::static_int_cast< size_t >(::getpagesize());
271 #else /* POSIX */
272 return sal::static_int_cast< size_t >(::sysconf(_SC_PAGESIZE));
273 #endif /* xBSD || POSIX */
274 }
275
getPos() const276 sal_uInt64 FileHandle_Impl::getPos() const
277 {
278 return sal::static_int_cast< sal_uInt64 >(m_fileptr);
279 }
280
setPos(sal_uInt64 uPos)281 oslFileError FileHandle_Impl::setPos (sal_uInt64 uPos)
282 {
283 OSL_FILE_TRACE("FileHandle_Impl::setPos(%d, %lld) => %lld", m_fd, getPos(), uPos);
284 m_fileptr = sal::static_int_cast< off_t >(uPos);
285 return osl_File_E_None;
286 }
287
getSize() const288 sal_uInt64 FileHandle_Impl::getSize() const
289 {
290 off_t const bufend = std::max((off_t)(0), m_bufptr) + m_buflen;
291 return std::max(m_size, sal::static_int_cast< sal_uInt64 >(bufend));
292 }
293
setSize(sal_uInt64 uSize)294 oslFileError FileHandle_Impl::setSize (sal_uInt64 uSize)
295 {
296 off_t const nSize = sal::static_int_cast< off_t >(uSize);
297 if (-1 == ftruncate (m_fd, nSize))
298 {
299 /* Failure. Save original result. Try fallback algorithm */
300 oslFileError result = oslTranslateFileError (OSL_FET_ERROR, errno);
301
302 /* Check against current size. Fail upon 'shrink' */
303 if (uSize <= getSize())
304 {
305 /* Failure upon 'shrink'. Return original result */
306 return (result);
307 }
308
309 /* Save current position */
310 off_t const nCurPos = (off_t)lseek (m_fd, (off_t)0, SEEK_CUR);
311 if (nCurPos == (off_t)(-1))
312 return (result);
313
314 /* Try 'expand' via 'lseek()' and 'write()' */
315 if (-1 == lseek (m_fd, (off_t)(nSize - 1), SEEK_SET))
316 return (result);
317
318 if (-1 == write (m_fd, (char*)"", (size_t)1))
319 {
320 /* Failure. Restore saved position */
321 (void) lseek (m_fd, (off_t)(nCurPos), SEEK_SET);
322 return (result);
323 }
324
325 /* Success. Restore saved position */
326 if (-1 == lseek (m_fd, (off_t)nCurPos, SEEK_SET))
327 return (result);
328 }
329
330 OSL_FILE_TRACE("osl_setFileSize(%d, %lld) => %ld", m_fd, getSize(), nSize);
331 m_size = sal::static_int_cast< sal_uInt64 >(nSize);
332 return osl_File_E_None;
333 }
334
readAt(off_t nOffset,void * pBuffer,size_t nBytesRequested,sal_uInt64 * pBytesRead)335 oslFileError FileHandle_Impl::readAt (
336 off_t nOffset,
337 void * pBuffer,
338 size_t nBytesRequested,
339 sal_uInt64 * pBytesRead)
340 {
341 OSL_PRECOND((m_state & STATE_SEEKABLE), "FileHandle_Impl::readAt(): not seekable");
342 if (!(m_state & STATE_SEEKABLE))
343 return osl_File_E_SPIPE;
344
345 OSL_PRECOND((m_state & STATE_READABLE), "FileHandle_Impl::readAt(): not readable");
346 if (!(m_state & STATE_READABLE))
347 return osl_File_E_BADF;
348
349 #if defined(LINUX) || defined(SOLARIS) || defined(FREEBSD) || defined(MACOSX)
350
351 ssize_t nBytes = ::pread (m_fd, pBuffer, nBytesRequested, nOffset);
352 if ((-1 == nBytes) && (EOVERFLOW == errno))
353 {
354 /* Some 'pread()'s fail with EOVERFLOW when reading at (or past)
355 * end-of-file, different from 'lseek() + read()' behavior.
356 * Returning '0 bytes read' and 'osl_File_E_None' instead.
357 */
358 nBytes = 0;
359 }
360 if (-1 == nBytes)
361 return oslTranslateFileError (OSL_FET_ERROR, errno);
362
363 #else /* no pread(2) ! */
364
365 if (nOffset != m_offset)
366 {
367 if (-1 == ::lseek (m_fd, nOffset, SEEK_SET))
368 return oslTranslateFileError (OSL_FET_ERROR, errno);
369 m_offset = nOffset;
370 }
371
372 ssize_t nBytes = ::read (m_fd, pBuffer, nBytesRequested);
373 if (-1 == nBytes)
374 return oslTranslateFileError (OSL_FET_ERROR, errno);
375 m_offset += nBytes;
376
377 #endif /* no pread(2) ! */
378
379 OSL_FILE_TRACE("FileHandle_Impl::readAt(%d, %lld, %ld)", m_fd, nOffset, nBytes);
380 *pBytesRead = nBytes;
381 return osl_File_E_None;
382 }
383
writeAt(off_t nOffset,void const * pBuffer,size_t nBytesToWrite,sal_uInt64 * pBytesWritten)384 oslFileError FileHandle_Impl::writeAt (
385 off_t nOffset,
386 void const * pBuffer,
387 size_t nBytesToWrite,
388 sal_uInt64 * pBytesWritten)
389 {
390 OSL_PRECOND((m_state & STATE_SEEKABLE), "FileHandle_Impl::writeAt(): not seekable");
391 if (!(m_state & STATE_SEEKABLE))
392 return osl_File_E_SPIPE;
393
394 OSL_PRECOND((m_state & STATE_WRITEABLE), "FileHandle_Impl::writeAt(): not writeable");
395 if (!(m_state & STATE_WRITEABLE))
396 return osl_File_E_BADF;
397
398 #if defined(LINUX) || defined(SOLARIS) || defined(FREEBSD) || defined(MACOSX)
399
400 ssize_t nBytes = ::pwrite (m_fd, pBuffer, nBytesToWrite, nOffset);
401 if (-1 == nBytes)
402 return oslTranslateFileError (OSL_FET_ERROR, errno);
403
404 #else /* no pwrite(2) ! */
405
406 if (nOffset != m_offset)
407 {
408 if (-1 == ::lseek (m_fd, nOffset, SEEK_SET))
409 return oslTranslateFileError (OSL_FET_ERROR, errno);
410 m_offset = nOffset;
411 }
412
413 ssize_t nBytes = ::write (m_fd, pBuffer, nBytesToWrite);
414 if (-1 == nBytes)
415 return oslTranslateFileError (OSL_FET_ERROR, errno);
416 m_offset += nBytes;
417
418 #endif /* no pwrite(2) ! */
419
420 OSL_FILE_TRACE("FileHandle_Impl::writeAt(%d, %lld, %ld)", m_fd, nOffset, nBytes);
421 m_size = std::max (m_size, sal::static_int_cast< sal_uInt64 >(nOffset + nBytes));
422
423 *pBytesWritten = nBytes;
424 return osl_File_E_None;
425 }
426
readFileAt(off_t nOffset,void * pBuffer,size_t nBytesRequested,sal_uInt64 * pBytesRead)427 oslFileError FileHandle_Impl::readFileAt (
428 off_t nOffset,
429 void * pBuffer,
430 size_t nBytesRequested,
431 sal_uInt64 * pBytesRead)
432 {
433 if (0 == (m_state & STATE_SEEKABLE))
434 {
435 // not seekable (pipe)
436 ssize_t nBytes = ::read (m_fd, pBuffer, nBytesRequested);
437 if (-1 == nBytes)
438 return oslTranslateFileError (OSL_FET_ERROR, errno);
439 *pBytesRead = nBytes;
440 return osl_File_E_None;
441 }
442 else if (0 == m_buffer)
443 {
444 // not buffered
445 return readAt (nOffset, pBuffer, nBytesRequested, pBytesRead);
446 }
447 else
448 {
449 sal_uInt8 * buffer = static_cast<sal_uInt8*>(pBuffer);
450 for (*pBytesRead = 0; nBytesRequested > 0; )
451 {
452 off_t const bufptr = (nOffset / m_bufsiz) * m_bufsiz;
453 size_t const bufpos = (nOffset % m_bufsiz);
454
455 if (bufptr != m_bufptr)
456 {
457 // flush current buffer
458 oslFileError result = syncFile();
459 if (result != osl_File_E_None)
460 return (result);
461 m_bufptr = -1, m_buflen = 0;
462
463 if (nBytesRequested >= m_bufsiz)
464 {
465 // buffer too small, read through from file
466 sal_uInt64 uDone = 0;
467 result = readAt (nOffset, &(buffer[*pBytesRead]), nBytesRequested, &uDone);
468 if (result != osl_File_E_None)
469 return (result);
470
471 nBytesRequested -= uDone, *pBytesRead += uDone;
472 return osl_File_E_None;
473 }
474
475 // update buffer (pointer)
476 sal_uInt64 uDone = 0;
477 result = readAt (bufptr, m_buffer, m_bufsiz, &uDone);
478 if (result != osl_File_E_None)
479 return (result);
480 m_bufptr = bufptr, m_buflen = uDone;
481 }
482 if (bufpos >= m_buflen)
483 {
484 // end of file
485 return osl_File_E_None;
486 }
487
488 size_t const bytes = std::min (m_buflen - bufpos, nBytesRequested);
489 OSL_FILE_TRACE("FileHandle_Impl::readFileAt(%d, %lld, %ld)", m_fd, nOffset, bytes);
490
491 memcpy (&(buffer[*pBytesRead]), &(m_buffer[bufpos]), bytes);
492 nBytesRequested -= bytes, *pBytesRead += bytes, nOffset += bytes;
493 }
494 return osl_File_E_None;
495 }
496 }
497
writeFileAt(off_t nOffset,void const * pBuffer,size_t nBytesToWrite,sal_uInt64 * pBytesWritten)498 oslFileError FileHandle_Impl::writeFileAt (
499 off_t nOffset,
500 void const * pBuffer,
501 size_t nBytesToWrite,
502 sal_uInt64 * pBytesWritten)
503 {
504 if (0 == (m_state & STATE_SEEKABLE))
505 {
506 // not seekable (pipe)
507 ssize_t nBytes = ::write (m_fd, pBuffer, nBytesToWrite);
508 if (-1 == nBytes)
509 return oslTranslateFileError (OSL_FET_ERROR, errno);
510 *pBytesWritten = nBytes;
511 return osl_File_E_None;
512 }
513 else if (0 == m_buffer)
514 {
515 // not buffered
516 return writeAt (nOffset, pBuffer, nBytesToWrite, pBytesWritten);
517 }
518 else
519 {
520 sal_uInt8 const * buffer = static_cast<sal_uInt8 const *>(pBuffer);
521 for (*pBytesWritten = 0; nBytesToWrite > 0; )
522 {
523 off_t const bufptr = (nOffset / m_bufsiz) * m_bufsiz;
524 size_t const bufpos = (nOffset % m_bufsiz);
525 if (bufptr != m_bufptr)
526 {
527 // flush current buffer
528 oslFileError result = syncFile();
529 if (result != osl_File_E_None)
530 return (result);
531 m_bufptr = -1, m_buflen = 0;
532
533 if (nBytesToWrite >= m_bufsiz)
534 {
535 // buffer to small, write through to file
536 sal_uInt64 uDone = 0;
537 result = writeAt (nOffset, &(buffer[*pBytesWritten]), nBytesToWrite, &uDone);
538 if (result != osl_File_E_None)
539 return (result);
540 if (uDone != nBytesToWrite)
541 return osl_File_E_IO;
542
543 nBytesToWrite -= uDone, *pBytesWritten += uDone;
544 return osl_File_E_None;
545 }
546
547 // update buffer (pointer)
548 sal_uInt64 uDone = 0;
549 result = readAt (bufptr, m_buffer, m_bufsiz, &uDone);
550 if (result != osl_File_E_None)
551 return (result);
552 m_bufptr = bufptr, m_buflen = uDone;
553 }
554
555 size_t const bytes = std::min (m_bufsiz - bufpos, nBytesToWrite);
556 OSL_FILE_TRACE("FileHandle_Impl::writeFileAt(%d, %lld, %ld)", m_fd, nOffset, bytes);
557
558 memcpy (&(m_buffer[bufpos]), &(buffer[*pBytesWritten]), bytes);
559 nBytesToWrite -= bytes, *pBytesWritten += bytes, nOffset += bytes;
560
561 m_buflen = std::max(m_buflen, bufpos + bytes);
562 m_state |= STATE_MODIFIED;
563 }
564 return osl_File_E_None;
565 }
566 }
567
readLineAt(off_t nOffset,sal_Sequence ** ppSequence,sal_uInt64 * pBytesRead)568 oslFileError FileHandle_Impl::readLineAt (
569 off_t nOffset,
570 sal_Sequence ** ppSequence,
571 sal_uInt64 * pBytesRead)
572 {
573 oslFileError result = osl_File_E_None;
574
575 off_t bufptr = nOffset / m_bufsiz * m_bufsiz;
576 if (bufptr != m_bufptr)
577 {
578 /* flush current buffer */
579 result = syncFile();
580 if (result != osl_File_E_None)
581 return (result);
582
583 /* update buffer (pointer) */
584 sal_uInt64 uDone = 0;
585 result = readAt (bufptr, m_buffer, m_bufsiz, &uDone);
586 if (result != osl_File_E_None)
587 return (result);
588
589 m_bufptr = bufptr, m_buflen = uDone;
590 }
591
592 static int const LINE_STATE_BEGIN = 0;
593 static int const LINE_STATE_CR = 1;
594 static int const LINE_STATE_LF = 2;
595
596 size_t bufpos = nOffset - m_bufptr, curpos = bufpos, dstpos = 0;
597 int state = (bufpos >= m_buflen) ? LINE_STATE_LF : LINE_STATE_BEGIN;
598
599 for ( ; state != LINE_STATE_LF; )
600 {
601 if (curpos >= m_buflen)
602 {
603 /* buffer examined */
604 if (0 < (curpos - bufpos))
605 {
606 /* flush buffer to sequence */
607 result = writeSequence_Impl (
608 ppSequence, &dstpos, &(m_buffer[bufpos]), curpos - bufpos);
609 if (result != osl_File_E_None)
610 return (result);
611 *pBytesRead += curpos - bufpos, nOffset += curpos - bufpos;
612 }
613
614 bufptr = nOffset / m_bufsiz * m_bufsiz;
615 if (bufptr != m_bufptr)
616 {
617 /* update buffer (pointer) */
618 sal_uInt64 uDone = 0;
619 result = readAt (bufptr, m_buffer, m_bufsiz, &uDone);
620 if (result != osl_File_E_None)
621 return (result);
622 m_bufptr = bufptr, m_buflen = uDone;
623 }
624
625 bufpos = nOffset - m_bufptr, curpos = bufpos;
626 if (bufpos >= m_buflen)
627 break;
628 }
629 switch (state)
630 {
631 case LINE_STATE_CR:
632 state = LINE_STATE_LF;
633 switch (m_buffer[curpos])
634 {
635 case 0x0A: /* CRLF */
636 /* eat current char */
637 curpos++;
638 break;
639 default: /* single CR */
640 /* keep current char */
641 break;
642 }
643 break;
644 default:
645 /* determine next state */
646 switch (m_buffer[curpos])
647 {
648 case 0x0A: /* single LF */
649 state = LINE_STATE_LF;
650 break;
651 case 0x0D: /* CR */
652 state = LINE_STATE_CR;
653 break;
654 default: /* advance to next char */
655 curpos++;
656 break;
657 }
658 if (state != LINE_STATE_BEGIN)
659 {
660 /* store (and eat) the newline char */
661 m_buffer[curpos] = 0x0A, curpos++;
662
663 /* flush buffer to sequence */
664 result = writeSequence_Impl (
665 ppSequence, &dstpos, &(m_buffer[bufpos]), curpos - bufpos - 1);
666 if (result != osl_File_E_None)
667 return (result);
668 *pBytesRead += curpos - bufpos, nOffset += curpos - bufpos;
669 }
670 break;
671 }
672 }
673
674 result = writeSequence_Impl (ppSequence, &dstpos, 0, 0);
675 if (result != osl_File_E_None)
676 return (result);
677 if (0 < dstpos)
678 return osl_File_E_None;
679 if (bufpos >= m_buflen)
680 return osl_File_E_AGAIN;
681 return osl_File_E_None;
682 }
683
writeSequence_Impl(sal_Sequence ** ppSequence,size_t * pnOffset,const void * pBuffer,size_t nBytes)684 oslFileError FileHandle_Impl::writeSequence_Impl (
685 sal_Sequence ** ppSequence,
686 size_t * pnOffset,
687 const void * pBuffer,
688 size_t nBytes)
689 {
690 sal_Int32 nElements = *pnOffset + nBytes;
691 if (!*ppSequence)
692 {
693 /* construct sequence */
694 rtl_byte_sequence_constructNoDefault(ppSequence, nElements);
695 }
696 else if (nElements != (*ppSequence)->nElements)
697 {
698 /* resize sequence */
699 rtl_byte_sequence_realloc(ppSequence, nElements);
700 }
701 if (*ppSequence != 0)
702 {
703 /* fill sequence */
704 memcpy(&((*ppSequence)->elements[*pnOffset]), pBuffer, nBytes), *pnOffset += nBytes;
705 }
706 return (*ppSequence != 0) ? osl_File_E_None : osl_File_E_NOMEM;
707 }
708
syncFile()709 oslFileError FileHandle_Impl::syncFile()
710 {
711 oslFileError result = osl_File_E_None;
712 if (m_state & STATE_MODIFIED)
713 {
714 sal_uInt64 uDone = 0;
715 result = writeAt (m_bufptr, m_buffer, m_buflen, &uDone);
716 if (result != osl_File_E_None)
717 return (result);
718 if (uDone != m_buflen)
719 return osl_File_E_IO;
720 m_state &= ~STATE_MODIFIED;
721 }
722 return (result);
723 }
724
725 /****************************************************************************
726 * osl_createFileHandleFromFD
727 ***************************************************************************/
osl_createFileHandleFromFD(int fd)728 extern "C" oslFileHandle osl_createFileHandleFromFD( int fd )
729 {
730 if (-1 == fd)
731 return 0; // EINVAL
732
733 struct stat aFileStat;
734 if (-1 == fstat (fd, &aFileStat))
735 return 0; // EBADF
736
737 FileHandle_Impl * pImpl = new FileHandle_Impl (fd);
738 if (0 == pImpl)
739 return 0; // ENOMEM
740
741 // assume writeable
742 pImpl->m_state |= FileHandle_Impl::STATE_WRITEABLE;
743 if (!S_ISREG(aFileStat.st_mode))
744 {
745 /* not a regular file, mark not seekable */
746 pImpl->m_state &= ~FileHandle_Impl::STATE_SEEKABLE;
747 }
748 else
749 {
750 /* regular file, init current size */
751 pImpl->m_size = sal::static_int_cast< sal_uInt64 >(aFileStat.st_size);
752 }
753
754 OSL_FILE_TRACE("osl_createFileHandleFromFD(%d, writeable) => %s",
755 pImpl->m_fd, rtl_string_getStr(pImpl->m_strFilePath));
756 return (oslFileHandle)(pImpl);
757 }
758
759 /*******************************************************************
760 * osl_file_adjustLockFlags
761 ******************************************************************/
osl_file_adjustLockFlags(const char * path,int flags)762 static int osl_file_adjustLockFlags (const char * path, int flags)
763 {
764 #ifdef MACOSX
765 /*
766 * The AFP implementation of MacOS X 10.4 treats O_EXLOCK in a way
767 * that makes it impossible for AOO to create a backup copy of the
768 * file it keeps opened. OTOH O_SHLOCK for AFP behaves as desired by
769 * the AOO file handling, so we need to check the path of the file
770 * for the filesystem name.
771 */
772 struct statfs s;
773 if( 0 <= statfs( path, &s ) )
774 {
775 if( 0 == strncmp("afpfs", s.f_fstypename, 5) )
776 {
777 flags &= ~O_EXLOCK;
778 flags |= O_SHLOCK;
779 }
780 else
781 {
782 /* Needed flags to allow opening a webdav file */
783 flags &= ~(O_EXLOCK | O_SHLOCK | O_NONBLOCK);
784 }
785 }
786 #endif /* MACOSX */
787
788 (void) path;
789 return flags;
790 }
791
792 /****************************************************************************
793 * osl_file_queryLocking
794 ***************************************************************************/
795 struct Locking_Impl
796 {
797 int m_enabled;
Locking_ImplLocking_Impl798 Locking_Impl() : m_enabled(0)
799 {
800 #ifndef HAVE_O_EXLOCK
801 m_enabled = ((getenv("SAL_ENABLE_FILE_LOCKING") != 0) || (getenv("STAR_ENABLE_FILE_LOCKING") != 0));
802 #endif /* HAVE_O_EXLOCK */
803 }
804 };
osl_file_queryLocking(sal_uInt32 uFlags)805 static int osl_file_queryLocking (sal_uInt32 uFlags)
806 {
807 if (!(uFlags & osl_File_OpenFlag_NoLock))
808 {
809 if ((uFlags & osl_File_OpenFlag_Write) || (uFlags & osl_File_OpenFlag_Create))
810 {
811 static Locking_Impl g_locking;
812 return (g_locking.m_enabled != 0);
813 }
814 }
815 return 0;
816 }
817
818 /****************************************************************************
819 * osl_openFile
820 ***************************************************************************/
821 #ifdef HAVE_O_EXLOCK
822 #define OPEN_WRITE_FLAGS ( O_RDWR | O_EXLOCK | O_NONBLOCK )
823 #define OPEN_CREATE_FLAGS ( O_CREAT | O_EXCL | O_RDWR | O_EXLOCK | O_NONBLOCK )
824 #else
825 #define OPEN_WRITE_FLAGS ( O_RDWR )
826 #define OPEN_CREATE_FLAGS ( O_CREAT | O_EXCL | O_RDWR )
827 #endif
828
829 oslFileError
osl_openFile(rtl_uString * ustrFileURL,oslFileHandle * pHandle,sal_uInt32 uFlags)830 SAL_CALL osl_openFile( rtl_uString* ustrFileURL, oslFileHandle* pHandle, sal_uInt32 uFlags )
831 {
832 oslFileError eRet;
833
834 if ((ustrFileURL == 0) || (ustrFileURL->length == 0) || (pHandle == 0))
835 return osl_File_E_INVAL;
836
837 /* convert file URL to system path */
838 char buffer[PATH_MAX];
839 eRet = FileURLToPath (buffer, sizeof(buffer), ustrFileURL);
840 if (eRet != osl_File_E_None)
841 return eRet;
842 #ifdef MACOSX
843 if (macxp_resolveAlias (buffer, sizeof(buffer)) != 0)
844 return oslTranslateFileError (OSL_FET_ERROR, errno);
845 #endif /* MACOSX */
846
847 /* set mode and flags */
848 int mode = S_IRUSR | S_IRGRP | S_IROTH;
849 int flags = O_RDONLY;
850 if (uFlags & osl_File_OpenFlag_Write)
851 {
852 mode |= S_IWUSR | S_IWGRP | S_IWOTH;
853 flags = OPEN_WRITE_FLAGS;
854 }
855 if (uFlags & osl_File_OpenFlag_Create)
856 {
857 mode |= S_IWUSR | S_IWGRP | S_IWOTH;
858 flags = OPEN_CREATE_FLAGS;
859 }
860 if (uFlags & osl_File_OpenFlag_NoLock)
861 {
862 #ifdef HAVE_O_EXLOCK
863 flags &= ~(O_EXLOCK | O_SHLOCK | O_NONBLOCK);
864 #endif /* HAVE_O_EXLOCK */
865 }
866 else
867 {
868 flags = osl_file_adjustLockFlags (buffer, flags);
869 }
870
871 /* open the file */
872 int fd = open( buffer, flags, mode );
873 if (-1 == fd)
874 return oslTranslateFileError (OSL_FET_ERROR, errno);
875
876 /* reset O_NONBLOCK flag */
877 if (flags & O_NONBLOCK)
878 {
879 int f = fcntl (fd, F_GETFL, 0);
880 if (-1 == f)
881 {
882 eRet = oslTranslateFileError (OSL_FET_ERROR, errno);
883 (void) close(fd);
884 return eRet;
885 }
886 if (-1 == fcntl (fd, F_SETFL, (f & ~O_NONBLOCK)))
887 {
888 eRet = oslTranslateFileError (OSL_FET_ERROR, errno);
889 (void) close(fd);
890 return eRet;
891 }
892 }
893
894 /* get file status (mode, size) */
895 struct stat aFileStat;
896 if (-1 == fstat (fd, &aFileStat))
897 {
898 eRet = oslTranslateFileError (OSL_FET_ERROR, errno);
899 (void) close(fd);
900 return eRet;
901 }
902 if (!S_ISREG(aFileStat.st_mode))
903 {
904 /* we only open regular files here */
905 (void) close(fd);
906 return osl_File_E_INVAL;
907 }
908
909 if (osl_file_queryLocking (uFlags))
910 {
911 #ifdef MACOSX
912 if (-1 == flock (fd, LOCK_EX | LOCK_NB))
913 {
914 /* Mac OSX returns ENOTSUP for webdav drives. We should try read lock */
915 if ((errno != ENOTSUP) || ((-1 == flock (fd, LOCK_SH | LOCK_NB)) && (errno != ENOTSUP)))
916 {
917 eRet = oslTranslateFileError (OSL_FET_ERROR, errno);
918 (void) close(fd);
919 return eRet;
920 }
921 }
922 #else /* F_SETLK */
923 {
924 struct flock aflock;
925
926 aflock.l_type = F_WRLCK;
927 aflock.l_whence = SEEK_SET;
928 aflock.l_start = 0;
929 aflock.l_len = 0;
930
931 if (-1 == fcntl (fd, F_SETLK, &aflock))
932 {
933 eRet = oslTranslateFileError (OSL_FET_ERROR, errno);
934 (void) close(fd);
935 return eRet;
936 }
937 }
938 #endif /* F_SETLK */
939 }
940
941 /* allocate memory for impl structure */
942 FileHandle_Impl * pImpl = new FileHandle_Impl (fd, buffer);
943 if (!pImpl)
944 {
945 eRet = oslTranslateFileError (OSL_FET_ERROR, ENOMEM);
946 (void) close(fd);
947 return eRet;
948 }
949 if (flags & O_RDWR)
950 pImpl->m_state |= FileHandle_Impl::STATE_WRITEABLE;
951 pImpl->m_size = sal::static_int_cast< sal_uInt64 >(aFileStat.st_size);
952
953 OSL_TRACE("osl_openFile(%d, %s) => %s", pImpl->m_fd,
954 flags & O_RDWR ? "writeable":"readonly",
955 rtl_string_getStr(pImpl->m_strFilePath));
956
957 *pHandle = (oslFileHandle)(pImpl);
958 return osl_File_E_None;
959 }
960
961 /****************************************************************************/
962 /* osl_closeFile */
963 /****************************************************************************/
964 oslFileError
osl_closeFile(oslFileHandle Handle)965 SAL_CALL osl_closeFile( oslFileHandle Handle )
966 {
967 FileHandle_Impl* pImpl = static_cast<FileHandle_Impl*>(Handle);
968
969 if ((pImpl == 0) || (pImpl->m_fd < 0))
970 return osl_File_E_INVAL;
971
972 (void) pthread_mutex_lock (&(pImpl->m_mutex));
973
974 /* close(2) implicitly (and unconditionally) unlocks */
975 OSL_TRACE("osl_closeFile(%d) => %s", pImpl->m_fd, rtl_string_getStr(pImpl->m_strFilePath));
976 oslFileError result = pImpl->syncFile();
977 if (result != osl_File_E_None)
978 {
979 /* close, ignoring double failure */
980 (void) close (pImpl->m_fd);
981 }
982 else if (-1 == close (pImpl->m_fd))
983 {
984 /* translate error code */
985 result = oslTranslateFileError (OSL_FET_ERROR, errno);
986 }
987
988 (void) pthread_mutex_unlock (&(pImpl->m_mutex));
989 delete pImpl;
990 return (result);
991 }
992
993 /************************************************
994 * osl_syncFile
995 ***********************************************/
996 oslFileError
osl_syncFile(oslFileHandle Handle)997 SAL_CALL osl_syncFile(oslFileHandle Handle)
998 {
999 FileHandle_Impl* pImpl = static_cast<FileHandle_Impl*>(Handle);
1000
1001 if ((0 == pImpl) || (-1 == pImpl->m_fd))
1002 return osl_File_E_INVAL;
1003
1004 FileHandle_Impl::Guard lock (&(pImpl->m_mutex));
1005
1006 OSL_TRACE("osl_syncFile(%d)", pImpl->m_fd);
1007 oslFileError result = pImpl->syncFile();
1008 if (result != osl_File_E_None)
1009 return (result);
1010 if (-1 == fsync (pImpl->m_fd))
1011 return oslTranslateFileError (OSL_FET_ERROR, errno);
1012
1013 return osl_File_E_None;
1014 }
1015
1016 /*******************************************
1017 osl_mapFile
1018 ********************************************/
1019 oslFileError
osl_mapFile(oslFileHandle Handle,void ** ppAddr,sal_uInt64 uLength,sal_uInt64 uOffset,sal_uInt32 uFlags)1020 SAL_CALL osl_mapFile (
1021 oslFileHandle Handle,
1022 void** ppAddr,
1023 sal_uInt64 uLength,
1024 sal_uInt64 uOffset,
1025 sal_uInt32 uFlags
1026 )
1027 {
1028 FileHandle_Impl* pImpl = static_cast<FileHandle_Impl*>(Handle);
1029
1030 if ((0 == pImpl) || (-1 == pImpl->m_fd) || (0 == ppAddr))
1031 return osl_File_E_INVAL;
1032 *ppAddr = 0;
1033
1034 static sal_uInt64 const g_limit_size_t = std::numeric_limits< size_t >::max();
1035 if (g_limit_size_t < uLength)
1036 return osl_File_E_OVERFLOW;
1037 size_t const nLength = sal::static_int_cast< size_t >(uLength);
1038
1039 static sal_uInt64 const g_limit_off_t = std::numeric_limits< off_t >::max();
1040 if (g_limit_off_t < uOffset)
1041 return osl_File_E_OVERFLOW;
1042 off_t const nOffset = sal::static_int_cast< off_t >(uOffset);
1043
1044 void* p = mmap(NULL, nLength, PROT_READ, MAP_SHARED, pImpl->m_fd, nOffset);
1045 if (MAP_FAILED == p)
1046 return oslTranslateFileError(OSL_FET_ERROR, errno);
1047 *ppAddr = p;
1048
1049 if (uFlags & osl_File_MapFlag_RandomAccess)
1050 {
1051 // Determine memory pagesize.
1052 size_t const nPageSize = FileHandle_Impl::getpagesize();
1053 if (size_t(-1) != nPageSize)
1054 {
1055 /*
1056 * Pagein, touching first byte of every memory page.
1057 * Note: volatile disables optimizing the loop away.
1058 */
1059 sal_uInt8 * pData (reinterpret_cast<sal_uInt8*>(*ppAddr));
1060 size_t nSize (nLength);
1061
1062 volatile sal_uInt8 c = 0;
1063 while (nSize > nPageSize)
1064 {
1065 c ^= pData[0];
1066 pData += nPageSize;
1067 nSize -= nPageSize;
1068 }
1069 if (nSize > 0)
1070 {
1071 c^= pData[0];
1072 pData += nSize;
1073 nSize -= nSize;
1074 }
1075 }
1076 }
1077 if (uFlags & osl_File_MapFlag_WillNeed)
1078 {
1079 // On Linux, madvise(..., MADV_WILLNEED) appears to have the undesirable
1080 // effect of not returning until the data has actually been paged in, so
1081 // that its net effect would typically be to slow down the process
1082 // (which could start processing at the beginning of the data while the
1083 // OS simultaneously pages in the rest); on other platforms, it remains
1084 // to be evaluated whether madvise or equivalent is available and
1085 // actually useful:
1086 #if defined (FREEBSD) || defined (MACOSX)
1087 int e = posix_madvise(p, nLength, POSIX_MADV_WILLNEED);
1088 if (e != 0)
1089 {
1090 OSL_TRACE(
1091 "posix_madvise(..., POSIX_MADV_WILLNEED) failed with %d", e);
1092 }
1093 #elif defined SOLARIS
1094 if (madvise(static_cast< caddr_t >(p), nLength, MADV_WILLNEED) != 0)
1095 {
1096 OSL_TRACE("madvise(..., MADV_WILLNEED) failed with %d", errno);
1097 }
1098 #endif
1099 }
1100 return osl_File_E_None;
1101 }
1102
1103 /*******************************************
1104 osl_unmapFile
1105 ********************************************/
1106 oslFileError
osl_unmapFile(void * pAddr,sal_uInt64 uLength)1107 SAL_CALL osl_unmapFile (void* pAddr, sal_uInt64 uLength)
1108 {
1109 if (0 == pAddr)
1110 return osl_File_E_INVAL;
1111
1112 static sal_uInt64 const g_limit_size_t = std::numeric_limits< size_t >::max();
1113 if (g_limit_size_t < uLength)
1114 return osl_File_E_OVERFLOW;
1115 size_t const nLength = sal::static_int_cast< size_t >(uLength);
1116
1117 if (-1 == munmap(static_cast<char*>(pAddr), nLength))
1118 return oslTranslateFileError(OSL_FET_ERROR, errno);
1119
1120 return osl_File_E_None;
1121 }
1122
1123 /*******************************************
1124 osl_readLine
1125 ********************************************/
1126 oslFileError
osl_readLine(oslFileHandle Handle,sal_Sequence ** ppSequence)1127 SAL_CALL osl_readLine (
1128 oslFileHandle Handle,
1129 sal_Sequence ** ppSequence)
1130 {
1131 FileHandle_Impl * pImpl = static_cast<FileHandle_Impl*>(Handle);
1132
1133 if ((0 == pImpl) || (-1 == pImpl->m_fd) || (0 == ppSequence))
1134 return osl_File_E_INVAL;
1135 sal_uInt64 uBytesRead = 0;
1136
1137 // read at current fileptr; fileptr += uBytesRead;
1138 FileHandle_Impl::Guard lock (&(pImpl->m_mutex));
1139 oslFileError result = pImpl->readLineAt (
1140 pImpl->m_fileptr, ppSequence, &uBytesRead);
1141 if (result == osl_File_E_None)
1142 pImpl->m_fileptr += uBytesRead;
1143 return (result);
1144 }
1145
1146 /*******************************************
1147 osl_readFile
1148 ********************************************/
1149 oslFileError
osl_readFile(oslFileHandle Handle,void * pBuffer,sal_uInt64 uBytesRequested,sal_uInt64 * pBytesRead)1150 SAL_CALL osl_readFile (
1151 oslFileHandle Handle,
1152 void * pBuffer,
1153 sal_uInt64 uBytesRequested,
1154 sal_uInt64 * pBytesRead)
1155 {
1156 FileHandle_Impl* pImpl = static_cast<FileHandle_Impl*>(Handle);
1157
1158 if ((0 == pImpl) || (-1 == pImpl->m_fd) || (0 == pBuffer) || (0 == pBytesRead))
1159 return osl_File_E_INVAL;
1160
1161 static sal_uInt64 const g_limit_ssize_t = std::numeric_limits< ssize_t >::max();
1162 if (g_limit_ssize_t < uBytesRequested)
1163 return osl_File_E_OVERFLOW;
1164 size_t const nBytesRequested = sal::static_int_cast< size_t >(uBytesRequested);
1165
1166 // read at current fileptr; fileptr += *pBytesRead;
1167 FileHandle_Impl::Guard lock (&(pImpl->m_mutex));
1168 oslFileError result = pImpl->readFileAt (
1169 pImpl->m_fileptr, pBuffer, nBytesRequested, pBytesRead);
1170 if (result == osl_File_E_None)
1171 pImpl->m_fileptr += *pBytesRead;
1172 return (result);
1173 }
1174
1175 /*******************************************
1176 osl_writeFile
1177 ********************************************/
1178 oslFileError
osl_writeFile(oslFileHandle Handle,const void * pBuffer,sal_uInt64 uBytesToWrite,sal_uInt64 * pBytesWritten)1179 SAL_CALL osl_writeFile (
1180 oslFileHandle Handle,
1181 const void * pBuffer,
1182 sal_uInt64 uBytesToWrite,
1183 sal_uInt64 * pBytesWritten)
1184 {
1185 FileHandle_Impl* pImpl = static_cast<FileHandle_Impl*>(Handle);
1186
1187 if ((0 == pImpl) || (-1 == pImpl->m_fd) || (0 == pBuffer) || (0 == pBytesWritten))
1188 return osl_File_E_INVAL;
1189 if (0 == (pImpl->m_state & FileHandle_Impl::STATE_WRITEABLE))
1190 return osl_File_E_BADF;
1191
1192 static sal_uInt64 const g_limit_ssize_t = std::numeric_limits< ssize_t >::max();
1193 if (g_limit_ssize_t < uBytesToWrite)
1194 return osl_File_E_OVERFLOW;
1195 size_t const nBytesToWrite = sal::static_int_cast< size_t >(uBytesToWrite);
1196
1197 // write at current fileptr; fileptr += *pBytesWritten;
1198 FileHandle_Impl::Guard lock (&(pImpl->m_mutex));
1199 oslFileError result = pImpl->writeFileAt (
1200 pImpl->m_fileptr, pBuffer, nBytesToWrite, pBytesWritten);
1201 if (result == osl_File_E_None)
1202 pImpl->m_fileptr += *pBytesWritten;
1203 return (result);
1204 }
1205
1206 /*******************************************
1207 osl_readFileAt
1208 ********************************************/
1209 oslFileError
osl_readFileAt(oslFileHandle Handle,sal_uInt64 uOffset,void * pBuffer,sal_uInt64 uBytesRequested,sal_uInt64 * pBytesRead)1210 SAL_CALL osl_readFileAt (
1211 oslFileHandle Handle,
1212 sal_uInt64 uOffset,
1213 void* pBuffer,
1214 sal_uInt64 uBytesRequested,
1215 sal_uInt64* pBytesRead)
1216 {
1217 FileHandle_Impl* pImpl = static_cast<FileHandle_Impl*>(Handle);
1218
1219 if ((0 == pImpl) || (-1 == pImpl->m_fd) || (0 == pBuffer) || (0 == pBytesRead))
1220 return osl_File_E_INVAL;
1221 if (0 == (pImpl->m_state & FileHandle_Impl::STATE_SEEKABLE))
1222 return osl_File_E_SPIPE;
1223
1224 static sal_uInt64 const g_limit_off_t = std::numeric_limits< off_t >::max();
1225 if (g_limit_off_t < uOffset)
1226 return osl_File_E_OVERFLOW;
1227 off_t const nOffset = sal::static_int_cast< off_t >(uOffset);
1228
1229 static sal_uInt64 const g_limit_ssize_t = std::numeric_limits< ssize_t >::max();
1230 if (g_limit_ssize_t < uBytesRequested)
1231 return osl_File_E_OVERFLOW;
1232 size_t const nBytesRequested = sal::static_int_cast< size_t >(uBytesRequested);
1233
1234 // read at specified fileptr
1235 FileHandle_Impl::Guard lock (&(pImpl->m_mutex));
1236 return pImpl->readFileAt (nOffset, pBuffer, nBytesRequested, pBytesRead);
1237 }
1238
1239 /*******************************************
1240 osl_writeFileAt
1241 ********************************************/
1242 oslFileError
osl_writeFileAt(oslFileHandle Handle,sal_uInt64 uOffset,const void * pBuffer,sal_uInt64 uBytesToWrite,sal_uInt64 * pBytesWritten)1243 SAL_CALL osl_writeFileAt (
1244 oslFileHandle Handle,
1245 sal_uInt64 uOffset,
1246 const void* pBuffer,
1247 sal_uInt64 uBytesToWrite,
1248 sal_uInt64* pBytesWritten)
1249 {
1250 FileHandle_Impl* pImpl = static_cast<FileHandle_Impl*>(Handle);
1251
1252 if ((0 == pImpl) || (-1 == pImpl->m_fd) || (0 == pBuffer) || (0 == pBytesWritten))
1253 return osl_File_E_INVAL;
1254 if (0 == (pImpl->m_state & FileHandle_Impl::STATE_SEEKABLE))
1255 return osl_File_E_SPIPE;
1256 if (0 == (pImpl->m_state & FileHandle_Impl::STATE_WRITEABLE))
1257 return osl_File_E_BADF;
1258
1259 static sal_uInt64 const g_limit_off_t = std::numeric_limits< off_t >::max();
1260 if (g_limit_off_t < uOffset)
1261 return osl_File_E_OVERFLOW;
1262 off_t const nOffset = sal::static_int_cast< off_t >(uOffset);
1263
1264 static sal_uInt64 const g_limit_ssize_t = std::numeric_limits< ssize_t >::max();
1265 if (g_limit_ssize_t < uBytesToWrite)
1266 return osl_File_E_OVERFLOW;
1267 size_t const nBytesToWrite = sal::static_int_cast< size_t >(uBytesToWrite);
1268
1269 // write at specified fileptr
1270 FileHandle_Impl::Guard lock (&(pImpl->m_mutex));
1271 return pImpl->writeFileAt (nOffset, pBuffer, nBytesToWrite, pBytesWritten);
1272 }
1273
1274 /****************************************************************************/
1275 /* osl_isEndOfFile */
1276 /****************************************************************************/
1277 oslFileError
osl_isEndOfFile(oslFileHandle Handle,sal_Bool * pIsEOF)1278 SAL_CALL osl_isEndOfFile( oslFileHandle Handle, sal_Bool *pIsEOF )
1279 {
1280 FileHandle_Impl* pImpl = static_cast<FileHandle_Impl*>(Handle);
1281
1282 if ((0 == pImpl) || (-1 == pImpl->m_fd) || (0 == pIsEOF))
1283 return osl_File_E_INVAL;
1284
1285 FileHandle_Impl::Guard lock (&(pImpl->m_mutex));
1286 *pIsEOF = (pImpl->getPos() == pImpl->getSize());
1287 return osl_File_E_None;
1288 }
1289
1290 /************************************************
1291 * osl_getFilePos
1292 ***********************************************/
1293 oslFileError
osl_getFilePos(oslFileHandle Handle,sal_uInt64 * pPos)1294 SAL_CALL osl_getFilePos( oslFileHandle Handle, sal_uInt64* pPos )
1295 {
1296 FileHandle_Impl* pImpl = static_cast<FileHandle_Impl*>(Handle);
1297
1298 if ((0 == pImpl) || (-1 == pImpl->m_fd) || (0 == pPos))
1299 return osl_File_E_INVAL;
1300
1301 FileHandle_Impl::Guard lock (&(pImpl->m_mutex));
1302 *pPos = pImpl->getPos();
1303 return osl_File_E_None;
1304 }
1305
1306 /*******************************************
1307 osl_setFilePos
1308 ********************************************/
1309 oslFileError
osl_setFilePos(oslFileHandle Handle,sal_uInt32 uHow,sal_Int64 uOffset)1310 SAL_CALL osl_setFilePos (oslFileHandle Handle, sal_uInt32 uHow, sal_Int64 uOffset)
1311 {
1312 FileHandle_Impl* pImpl = static_cast<FileHandle_Impl*>(Handle);
1313
1314 if ((0 == pImpl) || (-1 == pImpl->m_fd))
1315 return osl_File_E_INVAL;
1316
1317 static sal_Int64 const g_limit_off_t = std::numeric_limits< off_t >::max();
1318 if (g_limit_off_t < uOffset)
1319 return osl_File_E_OVERFLOW;
1320 off_t nPos = 0, nOffset = sal::static_int_cast< off_t >(uOffset);
1321
1322 FileHandle_Impl::Guard lock (&(pImpl->m_mutex));
1323 switch(uHow)
1324 {
1325 case osl_Pos_Absolut:
1326 if (0 > nOffset)
1327 return osl_File_E_INVAL;
1328 break;
1329
1330 case osl_Pos_Current:
1331 nPos = sal::static_int_cast< off_t >(pImpl->getPos());
1332 if ((0 > nOffset) && (-1*nOffset > nPos))
1333 return osl_File_E_INVAL;
1334 if (g_limit_off_t < nPos + nOffset)
1335 return osl_File_E_OVERFLOW;
1336 break;
1337
1338 case osl_Pos_End:
1339 nPos = sal::static_int_cast< off_t >(pImpl->getSize());
1340 if ((0 > nOffset) && (-1*nOffset > nPos))
1341 return osl_File_E_INVAL;
1342 if (g_limit_off_t < nPos + nOffset)
1343 return osl_File_E_OVERFLOW;
1344 break;
1345
1346 default:
1347 return osl_File_E_INVAL;
1348 }
1349
1350 return pImpl->setPos (nPos + nOffset);
1351 }
1352
1353 /****************************************************************************
1354 * osl_getFileSize
1355 ****************************************************************************/
1356 oslFileError
osl_getFileSize(oslFileHandle Handle,sal_uInt64 * pSize)1357 SAL_CALL osl_getFileSize( oslFileHandle Handle, sal_uInt64* pSize )
1358 {
1359 FileHandle_Impl* pImpl = static_cast<FileHandle_Impl*>(Handle);
1360
1361 if ((0 == pImpl) || (-1 == pImpl->m_fd) || (0 == pSize))
1362 return osl_File_E_INVAL;
1363
1364 FileHandle_Impl::Guard lock (&(pImpl->m_mutex));
1365 *pSize = pImpl->getSize();
1366 return osl_File_E_None;
1367 }
1368
1369 /************************************************
1370 * osl_setFileSize
1371 ***********************************************/
1372 oslFileError
osl_setFileSize(oslFileHandle Handle,sal_uInt64 uSize)1373 SAL_CALL osl_setFileSize( oslFileHandle Handle, sal_uInt64 uSize )
1374 {
1375 FileHandle_Impl* pImpl = static_cast<FileHandle_Impl*>(Handle);
1376
1377 if ((0 == pImpl) || (-1 == pImpl->m_fd))
1378 return osl_File_E_INVAL;
1379 if (0 == (pImpl->m_state & FileHandle_Impl::STATE_WRITEABLE))
1380 return osl_File_E_BADF;
1381
1382 static sal_uInt64 const g_limit_off_t = std::numeric_limits< off_t >::max();
1383 if (g_limit_off_t < uSize)
1384 return osl_File_E_OVERFLOW;
1385
1386 oslFileError result = pImpl->syncFile();
1387 if (result != osl_File_E_None)
1388 return (result);
1389 pImpl->m_bufptr = -1, pImpl->m_buflen = 0;
1390
1391 return pImpl->setSize (uSize);
1392 }
1393