xref: /trunk/main/sal/osl/unx/file.cxx (revision 0170220d)
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