/**************************************************************
 * 
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 * 
 *   http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 * 
 *************************************************************/




/************************************************************************
 *   ToDo
 *
 *   Fix osl_getCanonicalName
 *
 *   - Fix: check for corresponding struct sizes in exported functions
 *   - check size/use of oslDirectory
 *   - check size/use of oslDirectoryItem
 *   - check size/use of oslFileStatus
 *   - check size/use of oslVolumeDeviceHandle
 *   - check size/use of oslVolumeInfo
 *   - check size/use of oslFileHandle
 ***********************************************************************/

#define INCL_DOSDEVIOCTL                        // OS2 device definitions

#include "system.h"
#include <rtl/alloc.h>

#include "osl/file.hxx"


#include <sal/types.h>
#include <osl/thread.h>
#include <osl/diagnose.h>
#include "file_error_transl.h"
#include <osl/time.h>

#ifndef _FILE_URL_H_
#include "file_url.h"
#endif

#include "file_path_helper.hxx"
#include "uunxapi.hxx"

#ifndef	_STRING_H_
#include <string.h>
#endif

#ifndef	_CTYPE_H_
#include <ctype.h>
#endif

#ifndef	_WCHAR_H_
#include <wchar.h>
#endif

#include <algorithm>

#include <limits>
#include <sys/mman.h>

#if OSL_DEBUG_LEVEL > 1
	extern void debug_ustring(rtl_uString*);
#endif


#ifdef DEBUG_OSL_FILE
#	define PERROR( a, b ) perror( a ); fprintf( stderr, b )
#else
#	define PERROR( a, b )
#endif

extern "C" oslFileHandle osl_createFileHandleFromFD( int fd );

    struct errentry errtable[] = {
        {  NO_ERROR,			 osl_File_E_None     },  /* 0 */
        {  ERROR_INVALID_FUNCTION,       osl_File_E_INVAL    },  /* 1 */
        {  ERROR_FILE_NOT_FOUND,         osl_File_E_NOENT    },  /* 2 */
        {  ERROR_PATH_NOT_FOUND,         osl_File_E_NOENT    },  /* 3 */
        {  ERROR_TOO_MANY_OPEN_FILES,    osl_File_E_MFILE    },  /* 4 */
        {  ERROR_ACCESS_DENIED,          osl_File_E_ACCES    },  /* 5 */
        {  ERROR_INVALID_HANDLE,         osl_File_E_BADF     },  /* 6 */
        {  ERROR_ARENA_TRASHED,          osl_File_E_NOMEM    },  /* 7 */
        {  ERROR_NOT_ENOUGH_MEMORY,      osl_File_E_NOMEM    },  /* 8 */
        {  ERROR_INVALID_BLOCK,          osl_File_E_NOMEM    },  /* 9 */
        {  ERROR_BAD_ENVIRONMENT,        osl_File_E_2BIG     },  /* 10 */
        {  ERROR_BAD_FORMAT,             osl_File_E_NOEXEC   },  /* 11 */
        {  ERROR_INVALID_ACCESS,         osl_File_E_INVAL    },  /* 12 */
        {  ERROR_INVALID_DATA,           osl_File_E_INVAL    },  /* 13 */
        {  ERROR_INVALID_DRIVE,          osl_File_E_NOENT    },  /* 15 */
        {  ERROR_CURRENT_DIRECTORY,      osl_File_E_ACCES    },  /* 16 */
        {  ERROR_NOT_SAME_DEVICE,        osl_File_E_XDEV     },  /* 17 */
        {  ERROR_NO_MORE_FILES,          osl_File_E_NOENT    },  /* 18 */
        {  ERROR_NOT_READY,              osl_File_E_NOTREADY },  /* 21 */
        {  ERROR_LOCK_VIOLATION,         osl_File_E_ACCES    },  /* 33 */
        {  ERROR_BAD_NETPATH,            osl_File_E_NOENT    },  /* 53 */
        {  ERROR_NETWORK_ACCESS_DENIED,  osl_File_E_ACCES    },  /* 65 */
        {  ERROR_BAD_NET_NAME,           osl_File_E_NOENT    },  /* 67 */
        {  ERROR_FILE_EXISTS,            osl_File_E_EXIST    },  /* 80 */
        {  ERROR_CANNOT_MAKE,            osl_File_E_ACCES    },  /* 82 */
        {  ERROR_FAIL_I24,               osl_File_E_ACCES    },  /* 83 */
        {  ERROR_INVALID_PARAMETER,      osl_File_E_INVAL    },  /* 87 */
        {  ERROR_NO_PROC_SLOTS,          osl_File_E_AGAIN    },  /* 89 */
        {  ERROR_DRIVE_LOCKED,           osl_File_E_ACCES    },  /* 108 */
        {  ERROR_BROKEN_PIPE,            osl_File_E_PIPE     },  /* 109 */
        {  ERROR_DISK_FULL,              osl_File_E_NOSPC    },  /* 112 */
        {  ERROR_INVALID_TARGET_HANDLE,  osl_File_E_BADF     },  /* 114 */
        {  ERROR_INVALID_HANDLE,         osl_File_E_INVAL    },  /* 124 */
        {  ERROR_WAIT_NO_CHILDREN,       osl_File_E_CHILD    },  /* 128 */
        {  ERROR_CHILD_NOT_COMPLETE,     osl_File_E_CHILD    },  /* 129 */
        {  ERROR_DIRECT_ACCESS_HANDLE,   osl_File_E_BADF     },  /* 130 */
        {  ERROR_NEGATIVE_SEEK,          osl_File_E_INVAL    },  /* 131 */
        {  ERROR_SEEK_ON_DEVICE,         osl_File_E_ACCES    },  /* 132 */
        {  ERROR_DIR_NOT_EMPTY,          osl_File_E_NOTEMPTY },  /* 145 */
        {  ERROR_NOT_LOCKED,             osl_File_E_ACCES    },  /* 158 */
        {  ERROR_BAD_PATHNAME,           osl_File_E_NOENT    },  /* 161 */
        {  ERROR_MAX_THRDS_REACHED,      osl_File_E_AGAIN    },  /* 164 */
        {  ERROR_LOCK_FAILED,            osl_File_E_ACCES    },  /* 167 */
        {  ERROR_ALREADY_EXISTS,         osl_File_E_EXIST    },  /* 183 */
        {  ERROR_FILENAME_EXCED_RANGE,   osl_File_E_NOENT    },  /* 206 */
        {  ERROR_NESTING_NOT_ALLOWED,    osl_File_E_AGAIN    },  /* 215 */
        {  ERROR_DIRECTORY,              osl_File_E_NOENT    },  /* 267 */
        //{  ERROR_NOT_ENOUGH_QUOTA,       osl_File_E_NOMEM    }    /* 1816 */
    };
    
    #define ELEMENTS_OF_ARRAY(arr) (sizeof(arr)/(sizeof((arr)[0])))

    //#####################################################
    oslFileError MapError(APIRET dwError)
    {        
        for (int i = 0; i < ELEMENTS_OF_ARRAY(errtable); ++i )
	    {
		    if (dwError == errtable[i].oscode)
			    return static_cast<oslFileError>(errtable[i].errnocode);
        }
        return osl_File_E_INVAL;
    }

#ifdef DEBUG_OSL_FILE
#   define OSL_FILE_TRACE 0 ? (void)(0) : osl_trace
#	define PERROR( a, b ) perror( a ); fprintf( stderr, b )
#else
#   define OSL_FILE_TRACE 1 ? (void)(0) : osl_trace
#	define PERROR( a, b )
#endif

//##################################################################
// File handle implementation
//##################################################################
struct FileHandle_Impl
{
    rtl_String * m_strFilePath; /* holds native file path */
    int          m_fd;

    /** State
     */
    enum StateBits
    {
        STATE_SEEKABLE  = 1, /* default */
        STATE_READABLE  = 2, /* default */
        STATE_WRITEABLE = 4, /* open() sets, write() requires, else osl_File_E_BADF */
        STATE_MODIFIED  = 8  /* write() sets, flush() resets  */
    };
    int          m_state;

	sal_uInt64   m_size;    /* file size */
	off_t     m_offset;  /* physical offset from begin of file */
	//off_t     m_filepos; /* logical offset from begin of file */
    off_t        m_fileptr; /* logical offset from begin of file */

	off_t     m_bufptr;  /* buffer offset from begin of file */
	size_t       m_buflen;  /* buffer filled [0, m_bufsiz - 1] */

	size_t       m_bufsiz;
	sal_uInt8 *  m_buffer;

    explicit FileHandle_Impl (int fd, char const * path = "<anon>");
	~FileHandle_Impl();

	static void*  operator new(size_t n);
	static void   operator delete(void * p, size_t);
	static size_t getpagesize();

	sal_uInt64    getPos() const;
	oslFileError  setPos (sal_uInt64 uPos);

	sal_uInt64    getSize() const;
	oslFileError  setSize (sal_uInt64 uPos);

    oslFileError readAt (
        off_t        nOffset,
        void *       pBuffer,
        size_t       nBytesRequested,
        sal_uInt64 * pBytesRead);

    oslFileError writeAt (
        off_t        nOffset,
        void const * pBuffer,
        size_t       nBytesToWrite,
        sal_uInt64 * pBytesWritten);

	oslFileError readFileAt (
		off_t        nOffset,
		void *       pBuffer,
		size_t       nBytesRequested,
		sal_uInt64 * pBytesRead);

	oslFileError writeFileAt (
		off_t        nOffset,
		void const * pBuffer,
		size_t       nBytesToWrite,
		sal_uInt64 * pBytesWritten);

	oslFileError readLineAt (
		LONGLONG        nOffset,
		sal_Sequence ** ppSequence,
		sal_uInt64 *    pBytesRead);

	oslFileError writeSequence_Impl (
		sal_Sequence ** ppSequence,
		size_t *        pnOffset,
		const void *    pBuffer,
		size_t          nBytes);

	oslFileError syncFile();

	/** Buffer cache / allocator.
	 */
	class Allocator
	{
		rtl_cache_type * m_cache;
		size_t           m_bufsiz;

		Allocator (Allocator const &);
		Allocator & operator= (Allocator const &);

	public:
		static Allocator & get();

		void allocate (sal_uInt8 ** ppBuffer, size_t * pnSize);
		void deallocate (sal_uInt8 * pBuffer);

	protected:
		Allocator();
		~Allocator();
	};
};

FileHandle_Impl::Allocator &
FileHandle_Impl::Allocator::get()
{
	static Allocator g_aBufferAllocator;
	return g_aBufferAllocator;
}

FileHandle_Impl::Allocator::Allocator()
	: m_cache  (0),
	  m_bufsiz (0)
{
	size_t const pagesize = FileHandle_Impl::getpagesize();
	m_cache = rtl_cache_create (
		"osl_file_buffer_cache", pagesize, 0, 0, 0, 0, 0, 0, 0);
	if (0 != m_cache)
		m_bufsiz = pagesize;
}

FileHandle_Impl::Allocator::~Allocator()
{
	rtl_cache_destroy(m_cache), m_cache = 0;
}

void FileHandle_Impl::Allocator::allocate (sal_uInt8 ** ppBuffer, size_t * pnSize)
{
	OSL_PRECOND((0 != ppBuffer) && (0 != pnSize), "FileHandle_Impl::Allocator::allocate(): contract violation");
	*ppBuffer = static_cast< sal_uInt8* >(rtl_cache_alloc(m_cache)), *pnSize = m_bufsiz;
}

void FileHandle_Impl::Allocator::deallocate (sal_uInt8 * pBuffer)
{
	if (0 != pBuffer)
		rtl_cache_free (m_cache, pBuffer);
}

FileHandle_Impl::FileHandle_Impl (int fd, char const * path)
    : m_strFilePath (0),
      m_fd      (fd),
      m_state   (STATE_SEEKABLE | STATE_READABLE),
      m_size    (0),
	  m_offset  (0),
      m_fileptr (0),
      m_bufptr  (-1),
      m_buflen  (0),
      m_bufsiz  (0),
      m_buffer  (0)
{
    rtl_string_newFromStr (&m_strFilePath, path);
	Allocator::get().allocate (&m_buffer, &m_bufsiz);
	if (m_buffer != 0)
		memset (m_buffer, 0, m_bufsiz);
}

FileHandle_Impl::~FileHandle_Impl()
{
	Allocator::get().deallocate (m_buffer), m_buffer = 0;
    rtl_string_release (m_strFilePath), m_strFilePath = 0;
}

void * FileHandle_Impl::operator new(size_t n)
{
	return rtl_allocateMemory(n);
}

void FileHandle_Impl::operator delete(void * p, size_t)
{
	rtl_freeMemory(p);
}

size_t FileHandle_Impl::getpagesize()
{
	ULONG ulPageSize;
	DosQuerySysInfo(QSV_PAGE_SIZE, QSV_PAGE_SIZE, &ulPageSize, sizeof(ULONG));
	return sal::static_int_cast< size_t >(ulPageSize);
}

sal_uInt64 FileHandle_Impl::getPos() const
{
	return sal::static_int_cast< sal_uInt64 >(m_fileptr);
}

oslFileError FileHandle_Impl::setPos (sal_uInt64 uPos)
{
	m_fileptr = sal::static_int_cast< LONGLONG >(uPos);
	return osl_File_E_None;
}

sal_uInt64 FileHandle_Impl::getSize() const
{
	LONGLONG bufend = std::max((LONGLONG)(0), m_bufptr) + m_buflen;
	return std::max(m_size, sal::static_int_cast< sal_uInt64 >(bufend));
}

oslFileError FileHandle_Impl::setSize (sal_uInt64 uSize)
{
	off_t const nSize = sal::static_int_cast< off_t >(uSize);
	if (-1 == ftruncate (m_fd, nSize))
	{
		/* Failure. Save original result. Try fallback algorithm */
		oslFileError result = oslTranslateFileError (OSL_FET_ERROR, errno);

		/* Check against current size. Fail upon 'shrink' */
		if (uSize <= getSize())
		{
			/* Failure upon 'shrink'. Return original result */
			return (result);
		}

		/* Save current position */
		off_t const nCurPos = (off_t)lseek (m_fd, (off_t)0, SEEK_CUR);
		if (nCurPos == (off_t)(-1))
			return (result);

		/* Try 'expand' via 'lseek()' and 'write()' */
		if (-1 == lseek (m_fd, (off_t)(nSize - 1), SEEK_SET))
			return (result);

		if (-1 == write (m_fd, (char*)"", (size_t)1))
		{
			/* Failure. Restore saved position */
			(void) lseek (m_fd, (off_t)(nCurPos), SEEK_SET);
			return (result);
		}

		/* Success. Restore saved position */
		if (-1 == lseek (m_fd, (off_t)nCurPos, SEEK_SET))
			return (result);
	}

	OSL_FILE_TRACE("osl_setFileSize(%d, %lld) => %ld", m_fd, getSize(), nSize);
	m_size = sal::static_int_cast< sal_uInt64 >(nSize);
	return osl_File_E_None;
}

oslFileError FileHandle_Impl::readAt (
    off_t        nOffset,
    void *       pBuffer,
    size_t       nBytesRequested,
    sal_uInt64 * pBytesRead)
{
    OSL_PRECOND((m_state & STATE_SEEKABLE), "FileHandle_Impl::readAt(): not seekable");
    if (!(m_state & STATE_SEEKABLE))
        return osl_File_E_SPIPE;

    OSL_PRECOND((m_state & STATE_READABLE), "FileHandle_Impl::readAt(): not readable");
    if (!(m_state & STATE_READABLE))
        return osl_File_E_BADF;

    if (nOffset != m_offset)
	{
		if (-1 == ::lseek (m_fd, nOffset, SEEK_SET))
			return oslTranslateFileError (OSL_FET_ERROR, errno);
		m_offset = nOffset;
	}

    ssize_t nBytes = ::read (m_fd, pBuffer, nBytesRequested);
    if (-1 == nBytes)
        return oslTranslateFileError (OSL_FET_ERROR, errno);
	m_offset += nBytes;

    OSL_FILE_TRACE("FileHandle_Impl::readAt(%d, %lld, %ld)", m_fd, nOffset, nBytes);
    *pBytesRead = nBytes;
    return osl_File_E_None;
}

oslFileError FileHandle_Impl::writeAt (
    off_t        nOffset,
    void const * pBuffer,
    size_t       nBytesToWrite,
    sal_uInt64 * pBytesWritten)
{
    OSL_PRECOND((m_state & STATE_SEEKABLE), "FileHandle_Impl::writeAt(): not seekable");
    if (!(m_state & STATE_SEEKABLE))
        return osl_File_E_SPIPE;

    OSL_PRECOND((m_state & STATE_WRITEABLE), "FileHandle_Impl::writeAt(): not writeable");
    if (!(m_state & STATE_WRITEABLE))
        return osl_File_E_BADF;

    if (nOffset != m_offset)
	{
		if (-1 == ::lseek (m_fd, nOffset, SEEK_SET))
			return oslTranslateFileError (OSL_FET_ERROR, errno);
		m_offset = nOffset;
	}

    ssize_t nBytes = ::write (m_fd, pBuffer, nBytesToWrite);
    if (-1 == nBytes)
        return oslTranslateFileError (OSL_FET_ERROR, errno);
	m_offset += nBytes;

    OSL_FILE_TRACE("FileHandle_Impl::writeAt(%d, %lld, %ld)", m_fd, nOffset, nBytes);
    m_size = std::max (m_size, sal::static_int_cast< sal_uInt64 >(nOffset + nBytes));

    *pBytesWritten = nBytes;
    return osl_File_E_None;
}

oslFileError FileHandle_Impl::readFileAt (
    off_t        nOffset,
    void *       pBuffer,
    size_t       nBytesRequested,
    sal_uInt64 * pBytesRead)
{
    if (0 == (m_state & STATE_SEEKABLE))
    {
        // not seekable (pipe)
        ssize_t nBytes = ::read (m_fd, pBuffer, nBytesRequested);
        if (-1 == nBytes)
            return oslTranslateFileError (OSL_FET_ERROR, errno);
        *pBytesRead = nBytes;
        return osl_File_E_None;
    }
    else if (0 == m_buffer)
    {
        // not buffered
        return readAt (nOffset, pBuffer, nBytesRequested, pBytesRead);
    }
    else
    {
        sal_uInt8 * buffer = static_cast<sal_uInt8*>(pBuffer);
        for (*pBytesRead = 0; nBytesRequested > 0; )
        {
            off_t  const bufptr = (nOffset / m_bufsiz) * m_bufsiz;
            size_t const bufpos = (nOffset % m_bufsiz);

            if (bufptr != m_bufptr)
            {
                // flush current buffer
                oslFileError result = syncFile();
                if (result != osl_File_E_None)
                    return (result);

                if (nBytesRequested >= m_bufsiz)
                {
                    // buffer too small, read through from file
                    sal_uInt64 uDone = 0;
                    result = readAt (nOffset, &(buffer[*pBytesRead]), nBytesRequested, &uDone);
                    if (result != osl_File_E_None)
                        return (result);

                    nBytesRequested -= uDone, *pBytesRead += uDone;
                    return osl_File_E_None;
                }

                // update buffer (pointer)
                sal_uInt64 uDone = 0;
                result = readAt (bufptr, m_buffer, m_bufsiz, &uDone);
                if (result != osl_File_E_None)
                    return (result);
                m_bufptr = bufptr, m_buflen = uDone;
            }
            if (bufpos >= m_buflen)
            {
                // end of file
                return osl_File_E_None;
            }

            size_t const bytes = std::min (m_buflen - bufpos, nBytesRequested);
            OSL_FILE_TRACE("FileHandle_Impl::readFileAt(%d, %lld, %ld)", m_fd, nOffset, bytes);

            memcpy (&(buffer[*pBytesRead]), &(m_buffer[bufpos]), bytes);
            nBytesRequested -= bytes, *pBytesRead += bytes, nOffset += bytes;
        }
        return osl_File_E_None;
    }
}

oslFileError FileHandle_Impl::writeFileAt (
    off_t        nOffset,
    void const * pBuffer,
    size_t       nBytesToWrite,
    sal_uInt64 * pBytesWritten)
{
    if (0 == (m_state & STATE_SEEKABLE))
    {
        // not seekable (pipe)
        ssize_t nBytes = ::write (m_fd, pBuffer, nBytesToWrite);
        if (-1 == nBytes)
            return oslTranslateFileError (OSL_FET_ERROR, errno);
        *pBytesWritten = nBytes;
        return osl_File_E_None;
    }
    else if (0 == m_buffer)
    {
        // not buffered
        return writeAt (nOffset, pBuffer, nBytesToWrite, pBytesWritten);
    }
    else
    {
        sal_uInt8 const * buffer = static_cast<sal_uInt8 const *>(pBuffer);
        for (*pBytesWritten = 0; nBytesToWrite > 0; )
        {
            off_t  const bufptr = (nOffset / m_bufsiz) * m_bufsiz;
            size_t const bufpos = (nOffset % m_bufsiz);
            if (bufptr != m_bufptr)
            {
                // flush current buffer
                oslFileError result = syncFile();
                if (result != osl_File_E_None)
                    return (result);

                if (nBytesToWrite >= m_bufsiz)
                {
                    // buffer to small, write through to file
                    sal_uInt64 uDone = 0;
                    result = writeAt (nOffset, &(buffer[*pBytesWritten]), nBytesToWrite, &uDone);
                    if (result != osl_File_E_None)
                        return (result);
                    if (uDone != nBytesToWrite)
                        return osl_File_E_IO;

                    nBytesToWrite -= uDone, *pBytesWritten += uDone;
                    return osl_File_E_None;
                }

                // update buffer (pointer)
                sal_uInt64 uDone = 0;
                result = readAt (bufptr, m_buffer, m_bufsiz, &uDone);
                if (result != osl_File_E_None)
                    return (result);
                m_bufptr = bufptr, m_buflen = uDone;
            }

            size_t const bytes = std::min (m_bufsiz - bufpos, nBytesToWrite);
            OSL_FILE_TRACE("FileHandle_Impl::writeFileAt(%d, %lld, %ld)", m_fd, nOffset, bytes);

            memcpy (&(m_buffer[bufpos]), &(buffer[*pBytesWritten]), bytes);
            nBytesToWrite -= bytes, *pBytesWritten += bytes, nOffset += bytes;

            m_buflen = std::max(m_buflen, bufpos + bytes);
            m_state |= STATE_MODIFIED;
        }
        return osl_File_E_None;
    }
}

oslFileError FileHandle_Impl::readLineAt (
    LONGLONG        nOffset,
    sal_Sequence ** ppSequence,
    sal_uInt64 *    pBytesRead)
{
    oslFileError result = osl_File_E_None;

    LONGLONG bufptr = (nOffset / m_bufsiz) * m_bufsiz;
    if (bufptr != m_bufptr)
    {
        /* flush current buffer */
        result = syncFile();
        if (result != osl_File_E_None)
            return (result);

        /* update buffer (pointer) */
        sal_uInt64 uDone = 0;
        result = readAt (bufptr, m_buffer, m_bufsiz, &uDone);
        if (result != osl_File_E_None)
            return (result);

        m_bufptr = bufptr, m_buflen = sal::static_int_cast< size_t >(uDone);
    }

    static int const LINE_STATE_BEGIN = 0;
    static int const LINE_STATE_CR    = 1;
    static int const LINE_STATE_LF    = 2;

    size_t bufpos = sal::static_int_cast< size_t >(nOffset - m_bufptr), curpos = bufpos, dstpos = 0;
    int    state  = (bufpos >= m_buflen) ? LINE_STATE_LF : LINE_STATE_BEGIN;

    for ( ; state != LINE_STATE_LF; )
    {
        if (curpos >= m_buflen)
        {
            /* buffer examined */
            if (0 < (curpos - bufpos))
            {
                /* flush buffer to sequence */
                result = writeSequence_Impl (
                    ppSequence, &dstpos, &(m_buffer[bufpos]), curpos - bufpos);
                if (result != osl_File_E_None)
                    return (result);
                *pBytesRead += curpos - bufpos, nOffset += curpos - bufpos;
            }

            bufptr = nOffset / m_bufsiz * m_bufsiz;
            if (bufptr != m_bufptr)
            {
                /* update buffer (pointer) */
                sal_uInt64 uDone = 0;
                result = readAt (bufptr, m_buffer, m_bufsiz, &uDone);
                if (result != osl_File_E_None)
                    return (result);
                m_bufptr = bufptr, m_buflen = sal::static_int_cast< size_t >(uDone);
            }

            bufpos = sal::static_int_cast< size_t >(nOffset - m_bufptr), curpos = bufpos;
            if (bufpos >= m_buflen)
                break;
        }
        switch (state)
        {
        case LINE_STATE_CR:
            state = LINE_STATE_LF;
            switch (m_buffer[curpos])
            {
            case 0x0A: /* CRLF */
                /* eat current char */
                curpos++;
                break;
            default: /* single CR */
                /* keep current char */
                break;
            }
            break;
        default:
            /* determine next state */
            switch (m_buffer[curpos])
            {
            case 0x0A: /* single LF */
                state = LINE_STATE_LF;
                break;
            case 0x0D: /* CR */
                state = LINE_STATE_CR;
                break;
            default: /* advance to next char */
                curpos++;
                break;
            }
            if (state != LINE_STATE_BEGIN)
            {
                /* store (and eat) the newline char */
                m_buffer[curpos] = 0x0A, curpos++;

                /* flush buffer to sequence */
                result = writeSequence_Impl (
                    ppSequence, &dstpos, &(m_buffer[bufpos]), curpos - bufpos - 1);
                if (result != osl_File_E_None)
                    return (result);
                *pBytesRead += curpos - bufpos, nOffset += curpos - bufpos;
            }
            break;
        }
    }

    result = writeSequence_Impl (ppSequence, &dstpos, 0, 0);
    if (result != osl_File_E_None)
        return (result);
    if (0 < dstpos)
        return osl_File_E_None;
    if (bufpos >= m_buflen)
        return osl_File_E_AGAIN;
    return osl_File_E_None;
}

oslFileError FileHandle_Impl::writeSequence_Impl (
    sal_Sequence ** ppSequence,
    size_t *        pnOffset,
    const void *    pBuffer,
    size_t          nBytes)
{
    sal_Int32 nElements = *pnOffset + nBytes;
    if (!*ppSequence)
    {
        /* construct sequence */
        rtl_byte_sequence_constructNoDefault(ppSequence, nElements);
    }
    else if (nElements != (*ppSequence)->nElements)
    {
        /* resize sequence */
        rtl_byte_sequence_realloc(ppSequence, nElements);
    }
    if (*ppSequence != 0)
    {
        /* fill sequence */
        memcpy(&((*ppSequence)->elements[*pnOffset]), pBuffer, nBytes), *pnOffset += nBytes;
    }
    return (*ppSequence != 0) ? osl_File_E_None : osl_File_E_NOMEM;
}

oslFileError FileHandle_Impl::syncFile()
{
	oslFileError result = osl_File_E_None;
	if (m_state & STATE_MODIFIED)
	{
		sal_uInt64 uDone = 0;
		result = writeAt (m_bufptr, m_buffer, m_buflen, &uDone);
		if (result != osl_File_E_None)
			return (result);
		if (uDone != m_buflen)
			return osl_File_E_IO;
		m_state &= ~STATE_MODIFIED;
	}
	return (result);
}


/******************************************************************************
 *
 *                  static members
 *
 *****************************************************************************/

static const char * pFileLockEnvVar = (char *) -1;


/******************************************************************************
 *
 *                  C-String Function Declarations
 *
 *****************************************************************************/

static oslFileError osl_psz_getVolumeInformation(const sal_Char* , oslVolumeInfo* pInfo, sal_uInt32 uFieldMask);
static oslFileError osl_psz_removeFile(const sal_Char* pszPath);
static oslFileError osl_psz_createDirectory(const sal_Char* pszPath);
static oslFileError osl_psz_removeDirectory(const sal_Char* pszPath);
static oslFileError osl_psz_copyFile(const sal_Char* pszPath, const sal_Char* pszDestPath);
static oslFileError osl_psz_moveFile(const sal_Char* pszPath, const sal_Char* pszDestPath);
static oslFileError osl_psz_setFileTime(const sal_Char* strFilePath, const TimeValue* pCreationTime, const TimeValue* pLastAccessTime, const TimeValue* pLastWriteTime);


/******************************************************************************
 *
 *                  Static Module Utility Function Declarations
 *
 *****************************************************************************/

static oslFileError  oslDoCopy(const sal_Char* pszSourceFileName, const sal_Char* pszDestFileName, mode_t nMode, size_t nSourceSize, int DestFileExists);
static oslFileError  oslChangeFileModes(const sal_Char* pszFileName, mode_t nMode, time_t nAcTime, time_t nModTime, uid_t nUID, gid_t nGID);
static int           oslDoCopyLink(const sal_Char* pszSourceFileName, const sal_Char* pszDestFileName);
static int           oslDoCopyFile(const sal_Char* pszSourceFileName, const sal_Char* pszDestFileName, size_t nSourceSize, mode_t mode);
static oslFileError  oslDoMoveFile(const sal_Char* pszPath, const sal_Char* pszDestPath);
rtl_uString*  oslMakeUStrFromPsz(const sal_Char* pszStr,rtl_uString** uStr);

/******************************************************************************
 *
 *                  Non-Static Utility Function Declarations
 *
 *****************************************************************************/

extern "C" int UnicodeToText( char *, size_t, const sal_Unicode *, sal_Int32 );
extern "C" int TextToUnicode(
    const char* text, size_t text_buffer_size,	sal_Unicode* unic_text, sal_Int32 unic_text_buffer_size);

/******************************************************************************
 *
 *                  'removeable device' aka floppy functions
 *
 *****************************************************************************/

static oslVolumeDeviceHandle  osl_isFloppyDrive(const sal_Char* pszPath);
static oslFileError   osl_mountFloppy(oslVolumeDeviceHandle hFloppy);
static oslFileError   osl_unmountFloppy(oslVolumeDeviceHandle hFloppy);

#ifdef DEBUG_OSL_FILE
static void           osl_printFloppyHandle(oslVolumeDeviceHandleImpl* hFloppy);
#endif

/**********************************************
 * _osl_openLocalRoot
 * enumerate available drives
 *********************************************/
static oslFileError _osl_openLocalRoot( rtl_uString *strDirectoryPath, oslDirectory *pDirectory)
{
	rtl_uString		*ustrSystemPath = NULL;
	oslFileError	error;
	
	if ( !pDirectory )
		return osl_File_E_INVAL;

	*pDirectory = NULL;

	error = osl_getSystemPathFromFileURL_Ex( strDirectoryPath, &ustrSystemPath, sal_False );

	if ( osl_File_E_None == error )
	{
		/* create and initialize impl structure */
		DirectoryImpl* pDirImpl = (DirectoryImpl*) rtl_allocateMemory( sizeof(DirectoryImpl) );
		if( pDirImpl )
		{
			ULONG   ulDriveNum;
			APIRET  rc;			
			pDirImpl->uType = DIRECTORYTYPE_LOCALROOT;
			pDirImpl->ustrPath = ustrSystemPath;
			rc = DosQueryCurrentDisk (&ulDriveNum, &pDirImpl->ulDriveMap);
			pDirImpl->pDirStruct = 0;
			pDirImpl->ulNextDrive = 1;
			pDirImpl->ulNextDriveMask = 1;
			
			// determine number of floppy-drives
			BYTE nFloppies;
			rc = DosDevConfig( (void*) &nFloppies, DEVINFO_FLOPPY );
			if (nFloppies == 0) {
				// if no floppies, start with 3rd drive (C:)
				pDirImpl->ulNextDrive = 3;
				pDirImpl->ulNextDriveMask <<= 2;
			} else if (nFloppies == 1) {
				// mask drive B (second bit) in this case
				pDirImpl->ulDriveMap &= ~0x02;
			}
			*pDirectory = (oslDirectory) pDirImpl;
			return osl_File_E_None;
		}
		else
		{
			errno = osl_File_E_NOMEM;
		}

	}

    rtl_uString_release( ustrSystemPath );
	return error;
}

/**********************************************
 * _osl_getNextDrive
 *********************************************/
static oslFileError SAL_CALL _osl_getNextDrive( 
	oslDirectory Directory, oslDirectoryItem *pItem, sal_uInt32 uHint )
{
	DirectoryImpl	*pDirImpl = (DirectoryImpl *)Directory;
	DirectoryItem_Impl	*pItemImpl = NULL;
    rtl_uString			* ustrDrive = NULL;
	BOOL				fSuccess;
	char				buffer[3];

	uHint = uHint; /* avoid warnings */
			
	if ( !pItem )
		return osl_File_E_INVAL;

	*pItem = NULL;

	if ( !pDirImpl )
		return osl_File_E_INVAL;

	while( pDirImpl->ulNextDrive <= 26)
	{
		// exit if  bit==1 -> drive found
		if (pDirImpl->ulDriveMap & pDirImpl->ulNextDriveMask) {

			/* convert file name to unicode */
			buffer[0] = '@' + pDirImpl->ulNextDrive;
			buffer[1] = ':';
			buffer[2] = 0;

			pItemImpl = (DirectoryItem_Impl*) rtl_allocateMemory(sizeof(DirectoryItem_Impl));
			if ( !pItemImpl )
				return osl_File_E_NOMEM;

			memset( pItemImpl, 0, sizeof(DirectoryItem_Impl) );
			pItemImpl->uType = DIRECTORYITEM_DRIVE;
			pItemImpl->nRefCount = 1;

			rtl_string2UString( &pItemImpl->ustrDrive, buffer, 3,
				osl_getThreadTextEncoding(), OSTRING_TO_OUSTRING_CVTFLAGS );
			OSL_ASSERT(pItemImpl->ustrDrive != 0);

			/* use drive as directory item */
			*pItem = (oslDirectoryItem) pItemImpl;
		}
		// scan next bit position
		pDirImpl->ulNextDrive++;
		pDirImpl->ulNextDriveMask <<= 1;
		
		if (*pItem)	// item assigned, return now.
			return osl_File_E_None;
	}

	// no more items
	return osl_File_E_NOENT;
}

/**********************************************
 * _osl_readdir_impl_
 *
 * readdir wrapper, filters out "." and ".."
 * on request
 *********************************************/

static struct dirent* _osl_readdir_impl_(DIR* pdir, sal_Bool bFilterLocalAndParentDir)
{
	struct dirent* pdirent;

	while ((pdirent = readdir(pdir)) != NULL)
	{
		if (bFilterLocalAndParentDir &&
			((0 == strcmp(pdirent->d_name, ".")) || (0 == strcmp(pdirent->d_name, ".."))))
			continue;
		else
			break;
	}

	return pdirent;
}

/*******************************************************************
 *	osl_openDirectory
 ******************************************************************/

oslFileError SAL_CALL osl_openDirectory(rtl_uString* ustrDirectoryURL, oslDirectory* pDirectory)
{
    rtl_uString* ustrSystemPath = NULL;
    oslFileError eRet;

    char path[PATH_MAX];

    OSL_ASSERT(ustrDirectoryURL && (ustrDirectoryURL->length > 0));
    OSL_ASSERT(pDirectory);

    if (0 == ustrDirectoryURL->length )
        return osl_File_E_INVAL;

	if ( 0 == rtl_ustr_compareIgnoreAsciiCase( ustrDirectoryURL->buffer, (const sal_Unicode*)L"file:///" ) )
		return _osl_openLocalRoot( ustrDirectoryURL, pDirectory );
	
    /* convert file URL to system path */
    eRet = osl_getSystemPathFromFileURL_Ex(ustrDirectoryURL, &ustrSystemPath, sal_False);

	if( osl_File_E_None != eRet )
        return eRet;

	osl_systemPathRemoveSeparator(ustrSystemPath);

    /* convert unicode path to text */
    if ( UnicodeToText( path, PATH_MAX, ustrSystemPath->buffer, ustrSystemPath->length ) )
    {
		// if only the drive is specified (x:), add a \ (x:\) otherwise current
		// directory is browsed instead of root.
		if (strlen( path) == 2 && path[1] == ':')
			strcat( path, "\\");
        /* open directory */
        DIR *pdir = opendir( path );

        if( pdir )
        {
            /* create and initialize impl structure */
            DirectoryImpl* pDirImpl = (DirectoryImpl*) rtl_allocateMemory( sizeof(DirectoryImpl) );

            if( pDirImpl )
            {
				pDirImpl->uType = DIRECTORYTYPE_FILESYSTEM;
                pDirImpl->pDirStruct = pdir;
                pDirImpl->ustrPath = ustrSystemPath;

                *pDirectory = (oslDirectory) pDirImpl;
                return osl_File_E_None;
            }
            else
            {
                errno = ENOMEM;
                closedir( pdir );
            }
        }
        else
            /* should be removed by optimizer in product version */
            PERROR( "osl_openDirectory", path );
    }

    rtl_uString_release( ustrSystemPath );

    return oslTranslateFileError(OSL_FET_ERROR, errno);
}


/****************************************************************************
 *	osl_getNextDirectoryItem
 ***************************************************************************/

oslFileError SAL_CALL osl_getNextDirectoryItem(oslDirectory Directory, oslDirectoryItem* pItem, sal_uInt32 uHint)
{
    DirectoryImpl* pDirImpl     = (DirectoryImpl*)Directory;
	DirectoryItem_Impl	*pItemImpl = NULL;
    rtl_uString*      ustrFileName = NULL;
    rtl_uString*      ustrFilePath = NULL;
    struct dirent*    pEntry;

    OSL_ASSERT(Directory);
    OSL_ASSERT(pItem);

    if ((NULL == Directory) || (NULL == pItem))
        return osl_File_E_INVAL;

	if ( pDirImpl->uType == DIRECTORYTYPE_LOCALROOT)
		return _osl_getNextDrive( Directory, pItem, uHint );

    pEntry = _osl_readdir_impl_(pDirImpl->pDirStruct, sal_True);

    if (NULL == pEntry)
        return osl_File_E_NOENT;

	pItemImpl = (DirectoryItem_Impl*) rtl_allocateMemory(sizeof(DirectoryItem_Impl));
	if ( !pItemImpl )
		return osl_File_E_NOMEM;
	
	memset( pItemImpl, 0, sizeof(DirectoryItem_Impl) );
	pItemImpl->uType = DIRECTORYITEM_FILE;
	pItemImpl->nRefCount = 1;
	pItemImpl->d_attr = pEntry->d_attr;

    /* convert file name to unicode */
    rtl_string2UString( &ustrFileName, pEntry->d_name, strlen( pEntry->d_name ),
        osl_getThreadTextEncoding(), OSTRING_TO_OUSTRING_CVTFLAGS );
    OSL_ASSERT(ustrFileName != 0);

	osl_systemPathMakeAbsolutePath(pDirImpl->ustrPath, ustrFileName, &pItemImpl->ustrFilePath);
    rtl_uString_release( ustrFileName );

	*pItem = (oslDirectoryItem)pItemImpl;
	return osl_File_E_None;
}

/****************************************************************************/
/*	osl_closeDirectory */
/****************************************************************************/

oslFileError SAL_CALL osl_closeDirectory( oslDirectory Directory )
{
    DirectoryImpl* pDirImpl = (DirectoryImpl*) Directory;
    oslFileError err = osl_File_E_None;

    OSL_ASSERT( Directory );

    if( NULL == pDirImpl )
        return osl_File_E_INVAL;

	switch ( pDirImpl->uType )
	{
	case DIRECTORYTYPE_FILESYSTEM:
		if( closedir( pDirImpl->pDirStruct ) )
			err = oslTranslateFileError(OSL_FET_ERROR, errno);
		break;
	case DIRECTORYTYPE_LOCALROOT:
		err = osl_File_E_None;
		break;
#if 0
	case DIRECTORYTYPE_NETROOT:
		{
			DWORD err = WNetCloseEnum(pDirImpl->hDirectory);
			eError = (err == NO_ERROR) ? osl_File_E_None : MapError(err);
		}
		break;
#endif
	default:
		OSL_ENSURE( 0, "Invalid directory type" );
		break;
	}

    /* cleanup members */
    rtl_uString_release( pDirImpl->ustrPath );

    rtl_freeMemory( pDirImpl );

    return err;
}

/****************************************************************************/
/*	osl_getDirectoryItem */
/****************************************************************************/

oslFileError SAL_CALL osl_getDirectoryItem( rtl_uString* ustrFileURL, oslDirectoryItem* pItem )
{
    rtl_uString* 	strSysFilePath = NULL;
    oslFileError 	error      = osl_File_E_INVAL;
	ULONG			dwPathType;
	PATHTYPE		type = PATHTYPE_FILE;

    OSL_ASSERT(ustrFileURL);
    OSL_ASSERT(pItem);

	/* Assume failure */
	if ( !pItem )
		return osl_File_E_INVAL;
	*pItem = NULL;

    if (0 == ustrFileURL->length || NULL == pItem)
        return osl_File_E_INVAL;

    error = osl_getSystemPathFromFileURL_Ex(ustrFileURL, &strSysFilePath, sal_False);

    if (osl_File_E_None != error)
        return error;

	dwPathType = IsValidFilePath( strSysFilePath->buffer, NULL, VALIDATEPATH_NORMAL );

	if ( dwPathType & PATHTYPE_IS_VOLUME )
		type = PATHTYPE_VOLUME;
	else if ( dwPathType & PATHTYPE_IS_SERVER )
		type = PATHTYPE_NETSERVER;
	else
		type = PATHTYPE_FILE;

	switch ( type )
	{
	case PATHTYPE_NETSERVER:
		{
			DirectoryItem_Impl*	pItemImpl = 
			    reinterpret_cast<DirectoryItem_Impl*>(rtl_allocateMemory(sizeof(DirectoryItem_Impl)));

			if ( !pItemImpl )
				error = osl_File_E_NOMEM;

			if ( osl_File_E_None == error )
			{
				memset( pItemImpl, 0, sizeof(DirectoryItem_Impl) );
				pItemImpl->uType = DIRECTORYITEM_SERVER;
				pItemImpl->nRefCount = 1;
				rtl_uString_assign( &pItemImpl->ustrFilePath, strSysFilePath );

				*pItem = pItemImpl;
			}
		}
		break;
	case PATHTYPE_VOLUME:
		{
			DirectoryItem_Impl*	pItemImpl = 
			    reinterpret_cast<DirectoryItem_Impl*>(rtl_allocateMemory(sizeof(DirectoryItem_Impl)));

			if ( !pItemImpl )
				error = osl_File_E_NOMEM;

			if ( osl_File_E_None == error )
			{
				memset( pItemImpl, 0, sizeof(DirectoryItem_Impl) );
				pItemImpl->uType = DIRECTORYITEM_DRIVE;
				pItemImpl->nRefCount = 1;
				rtl_uString_assign( &pItemImpl->ustrDrive, strSysFilePath );

				if ( pItemImpl->ustrDrive->buffer[pItemImpl->ustrDrive->length-1] != sal_Unicode('\\') )
					rtl_uString_newConcat( &pItemImpl->ustrDrive, 
											pItemImpl->ustrDrive, rtl::OUString::createFromAscii( "\\" ).pData);

				*pItem = pItemImpl;
			}
		}
		break;
	default:
	case PATHTYPE_FILE:
		{
			if ( strSysFilePath->length > 0 && strSysFilePath->buffer[strSysFilePath->length - 1] == '\\' )
				rtl_uString_newFromStr_WithLength( &strSysFilePath, strSysFilePath->buffer, strSysFilePath->length - 1 );

			if (0 == access_u(strSysFilePath, F_OK))
			{
				DirectoryItem_Impl	*pItemImpl = 
				    reinterpret_cast<DirectoryItem_Impl*>(rtl_allocateMemory(sizeof(DirectoryItem_Impl)));

				memset( pItemImpl, 0, sizeof(DirectoryItem_Impl) );
				pItemImpl->uType = DIRECTORYITEM_FILE;
				pItemImpl->nRefCount = 1;
				rtl_uString_assign( &pItemImpl->ustrFilePath, strSysFilePath );

				*pItem = pItemImpl;
			}
			else
				error = oslTranslateFileError(OSL_FET_ERROR, errno);
		}
		break;
	}

	if ( strSysFilePath )
		rtl_uString_release( strSysFilePath );

	return error;
}

/****************************************************************************/
/*	osl_acquireDirectoryItem */
/****************************************************************************/

oslFileError osl_acquireDirectoryItem( oslDirectoryItem Item )
{
    OSL_ASSERT( Item );
	DirectoryItem_Impl	*pItemImpl = (DirectoryItem_Impl *)Item;

	if ( !pItemImpl )
		return osl_File_E_INVAL;

	pItemImpl->nRefCount++;
    return osl_File_E_None;
}

/****************************************************************************/
/*	osl_releaseDirectoryItem */
/****************************************************************************/

oslFileError osl_releaseDirectoryItem( oslDirectoryItem Item )
{
    OSL_ASSERT( Item );
	DirectoryItem_Impl	*pItemImpl = (DirectoryItem_Impl *)Item;

	if ( !pItemImpl )
		return osl_File_E_INVAL;

	if ( ! --pItemImpl->nRefCount )
	{
		if (pItemImpl->ustrFilePath)
			rtl_uString_release( pItemImpl->ustrFilePath );
		if (pItemImpl->ustrDrive)
			rtl_uString_release( pItemImpl->ustrDrive );
		rtl_freeMemory( pItemImpl );
	}
	return osl_File_E_None;
}

/****************************************************************************
 *	osl_createFileHandleFromFD
 ***************************************************************************/
extern "C" oslFileHandle osl_createFileHandleFromFD( int fd )
{
    if (-1 == fd)
        return 0; // EINVAL

    struct stat aFileStat;
    if (-1 == fstat (fd, &aFileStat))
        return 0; // EBADF

	FileHandle_Impl * pImpl = new FileHandle_Impl (fd);
    if (0 == pImpl)
        return 0; // ENOMEM

    // assume writeable
    pImpl->m_state |= FileHandle_Impl::STATE_WRITEABLE;
    if (!S_ISREG(aFileStat.st_mode))
    {
        /* not a regular file, mark not seekable */
        pImpl->m_state &= ~FileHandle_Impl::STATE_SEEKABLE;
    }
    else
    {
        /* regular file, init current size */
        pImpl->m_size = sal::static_int_cast< sal_uInt64 >(aFileStat.st_size);
    }

    OSL_FILE_TRACE("osl_createFileHandleFromFD(%d, writeable) => %s",
                   pImpl->m_fd, rtl_string_getStr(pImpl->m_strFilePath));
	return (oslFileHandle)(pImpl);
}

/*******************************************************************
 * osl_file_adjustLockFlags
 ******************************************************************/
static int osl_file_adjustLockFlags (const char * path, int flags)
{
#ifdef MACOSX
    /*
     * The AFP implementation of MacOS X 10.4 treats O_EXLOCK in a way 
     * that makes it impossible for OOo to create a backup copy of the
     * file it keeps opened. OTOH O_SHLOCK for AFP behaves as desired by
     * the OOo file handling, so we need to check the path of the file
     * for the filesystem name.
     */
    struct statfs s;
    if( 0 <= statfs( path, &s ) )
    {
        if( 0 == strncmp("afpfs", s.f_fstypename, 5) )
        {
            flags &= ~O_EXLOCK;
            flags |=  O_SHLOCK;
        }    
        else
        {
            /* Needed flags to allow opening a webdav file */
            flags &= ~(O_EXLOCK | O_SHLOCK | O_NONBLOCK);
		}
    }
#endif /* MACOSX */

    (void) path;
    return flags;
}

/****************************************************************************
 *	osl_file_queryLocking
 ***************************************************************************/
struct Locking_Impl
{
    int m_enabled;
    Locking_Impl() : m_enabled(0)
    {
#ifndef HAVE_O_EXLOCK
        m_enabled = ((getenv("SAL_ENABLE_FILE_LOCKING") != 0) || (getenv("STAR_ENABLE_FILE_LOCKING") != 0));
#endif /* HAVE_O_EXLOCK */
    }
};
static int osl_file_queryLocking (sal_uInt32 uFlags)
{
    if (!(uFlags & osl_File_OpenFlag_NoLock))
    {
        if ((uFlags & osl_File_OpenFlag_Write) || (uFlags & osl_File_OpenFlag_Create))
        {
            static Locking_Impl g_locking;
            return (g_locking.m_enabled != 0);
        }
    }
    return 0;
}

/****************************************************************************
 *	osl_openFile
 ***************************************************************************/
#ifdef HAVE_O_EXLOCK
#define OPEN_WRITE_FLAGS ( O_RDWR | O_EXLOCK | O_NONBLOCK )
#define OPEN_CREATE_FLAGS ( O_CREAT | O_EXCL | O_RDWR | O_EXLOCK | O_NONBLOCK )
#else
#define OPEN_WRITE_FLAGS ( O_RDWR )
#define OPEN_CREATE_FLAGS ( O_CREAT | O_EXCL | O_RDWR )
#endif

oslFileError
SAL_CALL osl_openFile( rtl_uString* ustrFileURL, oslFileHandle* pHandle, sal_uInt32 uFlags )
{
    oslFileError eRet;

    if ((ustrFileURL == 0) || (ustrFileURL->length == 0) || (pHandle == 0))
        return osl_File_E_INVAL;

    /* convert file URL to system path */
    char buffer[PATH_MAX];
    eRet = FileURLToPath (buffer, sizeof(buffer), ustrFileURL);
    if (eRet != osl_File_E_None)
        return eRet;
#ifdef MACOSX 
    if (macxp_resolveAlias (buffer, sizeof(buffer)) != 0)
        return oslTranslateFileError (OSL_FET_ERROR, errno);
#endif /* MACOSX */

    /* set mode and flags */
    int mode  = S_IRUSR | S_IRGRP | S_IROTH;
    int flags = O_RDONLY;
    if (uFlags & osl_File_OpenFlag_Write)
    {
        mode |= S_IWUSR | S_IWGRP | S_IWOTH;
        flags = OPEN_WRITE_FLAGS;
    }
    if (uFlags & osl_File_OpenFlag_Create)
    {
        mode |= S_IWUSR | S_IWGRP | S_IWOTH;
        flags = OPEN_CREATE_FLAGS;
    }
    if (uFlags & osl_File_OpenFlag_NoLock)
    {
#ifdef HAVE_O_EXLOCK
        flags &= ~(O_EXLOCK | O_SHLOCK | O_NONBLOCK);
#endif /* HAVE_O_EXLOCK */
    }
    else
    {
        flags = osl_file_adjustLockFlags (buffer, flags);
    }

    /* open the file */
    int fd = open( buffer, flags | O_BINARY, mode );
    if (-1 == fd)
        return oslTranslateFileError (OSL_FET_ERROR, errno);

    /* reset O_NONBLOCK flag */
    if (flags & O_NONBLOCK)
    {
        int f = fcntl (fd, F_GETFL, 0);
        if (-1 == f)
        {
            eRet = oslTranslateFileError (OSL_FET_ERROR, errno);
            (void) close(fd);
            return eRet;
        }
        if (-1 == fcntl (fd, F_SETFL, (f & ~O_NONBLOCK)))
        {
            eRet = oslTranslateFileError (OSL_FET_ERROR, errno);
            (void) close(fd);
            return eRet;
        }
    }

    /* get file status (mode, size) */
    struct stat aFileStat;
    if (-1 == fstat (fd, &aFileStat))
    {
        eRet = oslTranslateFileError (OSL_FET_ERROR, errno);
        (void) close(fd);
        return eRet;
    }
    if (!S_ISREG(aFileStat.st_mode))
    {
        /* we only open regular files here */
        (void) close(fd);
        return osl_File_E_INVAL;
    }

    if (osl_file_queryLocking (uFlags))
    {
#ifdef MACOSX
        if (-1 == flock (fd, LOCK_EX | LOCK_NB))
        {
            /* Mac OSX returns ENOTSUP for webdav drives. We should try read lock */
            if ((errno != ENOTSUP) || ((-1 == flock (fd, LOCK_SH | LOCK_NB)) && (errno != ENOTSUP)))
            {
                eRet = oslTranslateFileError (OSL_FET_ERROR, errno);
                (void) close(fd);
                return eRet;
            }
        }
#else   /* F_SETLK */
        {
            struct flock aflock;

            aflock.l_type = F_WRLCK;
            aflock.l_whence = SEEK_SET;
            aflock.l_start = 0;
            aflock.l_len = 0;

            if (-1 == fcntl (fd, F_SETLK, &aflock))
            {
                eRet = oslTranslateFileError (OSL_FET_ERROR, errno);
                (void) close(fd);
                return eRet;
            }
        }
#endif  /* F_SETLK */
    }

    /* allocate memory for impl structure */
    FileHandle_Impl * pImpl = new FileHandle_Impl (fd, buffer);
    if (!pImpl)
    {
        eRet = oslTranslateFileError (OSL_FET_ERROR, ENOMEM);
        (void) close(fd);
        return eRet;
    }
    if (flags & O_RDWR)
        pImpl->m_state |= FileHandle_Impl::STATE_WRITEABLE;
    pImpl->m_size = sal::static_int_cast< sal_uInt64 >(aFileStat.st_size);

    OSL_TRACE("osl_openFile(%d, %s) => %s", pImpl->m_fd,
              flags & O_RDWR ? "writeable":"readonly",
              rtl_string_getStr(pImpl->m_strFilePath));

    *pHandle = (oslFileHandle)(pImpl);
    return osl_File_E_None;
}

/****************************************************************************/
/*	osl_closeFile */
/****************************************************************************/
oslFileError
SAL_CALL osl_closeFile( oslFileHandle Handle )
{
    FileHandle_Impl* pImpl = static_cast<FileHandle_Impl*>(Handle);

    if ((pImpl == 0) || (pImpl->m_fd < 0))
        return osl_File_E_INVAL;

    /* close(2) implicitly (and unconditionally) unlocks */
    OSL_TRACE("osl_closeFile(%d) => %s", pImpl->m_fd, rtl_string_getStr(pImpl->m_strFilePath));
    oslFileError result = pImpl->syncFile();
    if (result != osl_File_E_None)
    {
        /* close, ignoring double failure */
        (void) close (pImpl->m_fd);
    }
    else if (-1 == close (pImpl->m_fd))
    {
        /* translate error code */
        result = oslTranslateFileError (OSL_FET_ERROR, errno);
    }

    delete pImpl;
    return (result);
}

/************************************************
 * osl_syncFile
 ***********************************************/
oslFileError
SAL_CALL osl_syncFile(oslFileHandle Handle)
{
    FileHandle_Impl* pImpl = static_cast<FileHandle_Impl*>(Handle);
    
    if ((0 == pImpl) || (-1 == pImpl->m_fd))
        return osl_File_E_INVAL;

    OSL_FILE_TRACE("osl_syncFile(%d)", pImpl->m_fd);
    oslFileError result = pImpl->syncFile();
    if (result != osl_File_E_None)
        return (result);
    if (-1 == fsync (pImpl->m_fd))
        return oslTranslateFileError (OSL_FET_ERROR, errno);
    
    return osl_File_E_None;
}

/*******************************************
    osl_mapFile
********************************************/
oslFileError
SAL_CALL osl_mapFile (
	oslFileHandle Handle,
	void**        ppAddr,
	sal_uInt64    uLength,
	sal_uInt64    uOffset,
	sal_uInt32    uFlags
)
{
	FileHandle_Impl* pImpl = static_cast<FileHandle_Impl*>(Handle);

	if ((0 == pImpl) || (-1 == pImpl->m_fd) || (0 == ppAddr))
		return osl_File_E_INVAL;
	*ppAddr = 0;

	static sal_uInt64 const g_limit_size_t = std::numeric_limits< size_t >::max();
	if (g_limit_size_t < uLength)
		return osl_File_E_OVERFLOW;
	size_t const nLength = sal::static_int_cast< size_t >(uLength);

	static sal_uInt64 const g_limit_off_t = std::numeric_limits< off_t >::max();
	if (g_limit_off_t < uOffset)
		return osl_File_E_OVERFLOW;
	off_t const nOffset = sal::static_int_cast< off_t >(uOffset);

#ifdef SAL_OS2 // YD mmap does not support shared
	void* p = mmap(NULL, nLength, PROT_READ, MAP_PRIVATE, pImpl->m_fd, nOffset);
#else
	void* p = mmap(NULL, nLength, PROT_READ, MAP_SHARED, pImpl->m_fd, nOffset);
#endif
	if (MAP_FAILED == p)
		return oslTranslateFileError(OSL_FET_ERROR, errno);
	*ppAddr = p;

	if (uFlags & osl_File_MapFlag_RandomAccess)
	{
		// Determine memory pagesize.
		size_t const nPageSize = FileHandle_Impl::getpagesize();
		if (size_t(-1) != nPageSize)
		{
			/*
			 * Pagein, touching first byte of every memory page.
			 * Note: volatile disables optimizing the loop away.
			 */
			sal_uInt8 * pData (reinterpret_cast<sal_uInt8*>(*ppAddr));
			size_t      nSize (nLength);

			volatile sal_uInt8 c = 0;
			while (nSize > nPageSize)
			{
				c ^= pData[0];
				pData += nPageSize;
				nSize -= nPageSize;
			}
			if (nSize > 0)
			{
				c^= pData[0];
				pData += nSize;
				nSize -= nSize;
			}
		}
	}
	return osl_File_E_None;
}

/*******************************************
    osl_unmapFile
********************************************/
oslFileError
SAL_CALL osl_unmapFile (void* pAddr, sal_uInt64 uLength)
{
	if (0 == pAddr)
		return osl_File_E_INVAL;

	static sal_uInt64 const g_limit_size_t = std::numeric_limits< size_t >::max();
	if (g_limit_size_t < uLength)
		return osl_File_E_OVERFLOW;
	size_t const nLength = sal::static_int_cast< size_t >(uLength);

	if (-1 == munmap(static_cast<char*>(pAddr), nLength))
		return oslTranslateFileError(OSL_FET_ERROR, errno);

	return osl_File_E_None;
}

/*******************************************
    osl_readLine
********************************************/
oslFileError
SAL_CALL osl_readLine (
    oslFileHandle   Handle,
    sal_Sequence ** ppSequence)
{
    FileHandle_Impl * pImpl = static_cast<FileHandle_Impl*>(Handle);

    if ((0 == pImpl) || (-1 == pImpl->m_fd) || (0 == ppSequence))
        return osl_File_E_INVAL;
    sal_uInt64 uBytesRead = 0;

    // read at current fileptr; fileptr += uBytesRead;
    oslFileError result = pImpl->readLineAt (
        pImpl->m_fileptr, ppSequence, &uBytesRead);
    if (result == osl_File_E_None)
        pImpl->m_fileptr += uBytesRead;
    return (result);
}

/*******************************************
    osl_readFile
********************************************/
oslFileError
SAL_CALL osl_readFile (
    oslFileHandle Handle,
    void *        pBuffer,
    sal_uInt64    uBytesRequested,
    sal_uInt64 *  pBytesRead)
{
    FileHandle_Impl* pImpl = static_cast<FileHandle_Impl*>(Handle);

    if ((0 == pImpl) || (-1 == pImpl->m_fd) || (0 == pBuffer) || (0 == pBytesRead))
        return osl_File_E_INVAL;
    
	static sal_uInt64 const g_limit_ssize_t = std::numeric_limits< ssize_t >::max();
	if (g_limit_ssize_t < uBytesRequested)
		return osl_File_E_OVERFLOW;
	size_t const nBytesRequested = sal::static_int_cast< size_t >(uBytesRequested);

    // read at current fileptr; fileptr += *pBytesRead;
    oslFileError result = pImpl->readFileAt (
        pImpl->m_fileptr, pBuffer, nBytesRequested, pBytesRead);
    if (result == osl_File_E_None)
        pImpl->m_fileptr += *pBytesRead;
    return (result);
}

/*******************************************
    osl_writeFile
********************************************/
oslFileError
SAL_CALL osl_writeFile (
    oslFileHandle Handle,
    const void *  pBuffer,
    sal_uInt64    uBytesToWrite,
    sal_uInt64 *  pBytesWritten)
{
    FileHandle_Impl* pImpl = static_cast<FileHandle_Impl*>(Handle);

    if ((0 == pImpl) || (-1 == pImpl->m_fd) || (0 == pBuffer) || (0 == pBytesWritten))
        return osl_File_E_INVAL;
    if (0 == (pImpl->m_state & FileHandle_Impl::STATE_WRITEABLE))
        return osl_File_E_BADF;

	static sal_uInt64 const g_limit_ssize_t = std::numeric_limits< ssize_t >::max();
	if (g_limit_ssize_t < uBytesToWrite)
		return osl_File_E_OVERFLOW;
	size_t const nBytesToWrite = sal::static_int_cast< size_t >(uBytesToWrite);

    // write at current fileptr; fileptr += *pBytesWritten;
    oslFileError result = pImpl->writeFileAt (
        pImpl->m_fileptr, pBuffer, nBytesToWrite, pBytesWritten);
    if (result == osl_File_E_None)
        pImpl->m_fileptr += *pBytesWritten;
    return (result);
}

/*******************************************
    osl_readFileAt
********************************************/
oslFileError
SAL_CALL osl_readFileAt (
	oslFileHandle Handle,
	sal_uInt64    uOffset,
	void*         pBuffer,
	sal_uInt64    uBytesRequested,
	sal_uInt64*   pBytesRead)
{
	FileHandle_Impl* pImpl = static_cast<FileHandle_Impl*>(Handle);

	if ((0 == pImpl) || (-1 == pImpl->m_fd) || (0 == pBuffer) || (0 == pBytesRead))
		return osl_File_E_INVAL;
    if (0 == (pImpl->m_state & FileHandle_Impl::STATE_SEEKABLE))
        return osl_File_E_SPIPE;

	static sal_uInt64 const g_limit_off_t = std::numeric_limits< off_t >::max();
	if (g_limit_off_t < uOffset)
		return osl_File_E_OVERFLOW;
	off_t const nOffset = sal::static_int_cast< off_t >(uOffset);

	static sal_uInt64 const g_limit_ssize_t = std::numeric_limits< ssize_t >::max();
	if (g_limit_ssize_t < uBytesRequested)
		return osl_File_E_OVERFLOW;
	size_t const nBytesRequested = sal::static_int_cast< size_t >(uBytesRequested);

    // read at specified fileptr
    return pImpl->readFileAt (nOffset, pBuffer, nBytesRequested, pBytesRead);
}

/*******************************************
    osl_writeFileAt
********************************************/
oslFileError
SAL_CALL osl_writeFileAt (
	oslFileHandle Handle,
	sal_uInt64    uOffset,
	const void*   pBuffer,
	sal_uInt64    uBytesToWrite,
	sal_uInt64*   pBytesWritten)
{
	FileHandle_Impl* pImpl = static_cast<FileHandle_Impl*>(Handle);

	if ((0 == pImpl) || (-1 == pImpl->m_fd) || (0 == pBuffer) || (0 == pBytesWritten))
		return osl_File_E_INVAL;
    if (0 == (pImpl->m_state & FileHandle_Impl::STATE_SEEKABLE))
        return osl_File_E_SPIPE;
    if (0 == (pImpl->m_state & FileHandle_Impl::STATE_WRITEABLE))
        return osl_File_E_BADF;

	static sal_uInt64 const g_limit_off_t = std::numeric_limits< off_t >::max();
	if (g_limit_off_t < uOffset)
		return osl_File_E_OVERFLOW;
	off_t const nOffset = sal::static_int_cast< off_t >(uOffset);

	static sal_uInt64 const g_limit_ssize_t = std::numeric_limits< ssize_t >::max();
	if (g_limit_ssize_t < uBytesToWrite)
		return osl_File_E_OVERFLOW;
	size_t const nBytesToWrite = sal::static_int_cast< size_t >(uBytesToWrite);

    // write at specified fileptr
    return pImpl->writeFileAt (nOffset, pBuffer, nBytesToWrite, pBytesWritten);
}

/****************************************************************************/
/*	osl_isEndOfFile */
/****************************************************************************/
oslFileError
SAL_CALL osl_isEndOfFile( oslFileHandle Handle, sal_Bool *pIsEOF )
{
    FileHandle_Impl* pImpl = static_cast<FileHandle_Impl*>(Handle);

    if ((0 == pImpl) || (-1 == pImpl->m_fd) || (0 == pIsEOF))
        return osl_File_E_INVAL;

    *pIsEOF = (pImpl->getPos() == pImpl->getSize());
    return osl_File_E_None;
}

/************************************************
 * osl_getFilePos
 ***********************************************/
oslFileError
SAL_CALL osl_getFilePos( oslFileHandle Handle, sal_uInt64* pPos )
{
    FileHandle_Impl* pImpl = static_cast<FileHandle_Impl*>(Handle);

    if ((0 == pImpl) || (-1 == pImpl->m_fd) || (0 == pPos))
        return osl_File_E_INVAL;

    *pPos = pImpl->getPos();
    return osl_File_E_None;
}

/*******************************************
    osl_setFilePos
********************************************/
oslFileError
SAL_CALL osl_setFilePos (oslFileHandle Handle, sal_uInt32 uHow, sal_Int64 uOffset)
{
    FileHandle_Impl* pImpl = static_cast<FileHandle_Impl*>(Handle);

    if ((0 == pImpl) || (-1 == pImpl->m_fd))
        return osl_File_E_INVAL;

	static sal_Int64 const g_limit_off_t = std::numeric_limits< off_t >::max();
	if (g_limit_off_t < uOffset)
		return osl_File_E_OVERFLOW;
	off_t nPos = 0, nOffset = sal::static_int_cast< off_t >(uOffset);

    switch(uHow)
    {
        case osl_Pos_Absolut:
            if (0 > nOffset)
                return osl_File_E_INVAL;
            break;

        case osl_Pos_Current:
            nPos = sal::static_int_cast< off_t >(pImpl->getPos());
            if ((0 > nOffset) && (-1*nOffset > nPos))
                return osl_File_E_INVAL;
            if (g_limit_off_t < nPos + nOffset)
                return osl_File_E_OVERFLOW;
            break;

        case osl_Pos_End:
            nPos = sal::static_int_cast< off_t >(pImpl->getSize());
            if ((0 > nOffset) && (-1*nOffset > nPos))
                return osl_File_E_INVAL;
            if (g_limit_off_t < nPos + nOffset)
                return osl_File_E_OVERFLOW;
            break;

        default:
            return osl_File_E_INVAL;
    }

    return pImpl->setPos (nPos + nOffset);
}

/****************************************************************************
 *	osl_getFileSize
 ****************************************************************************/
oslFileError
SAL_CALL osl_getFileSize( oslFileHandle Handle, sal_uInt64* pSize )
{	
    FileHandle_Impl* pImpl = static_cast<FileHandle_Impl*>(Handle);

    if ((0 == pImpl) || (-1 == pImpl->m_fd) || (0 == pSize))
        return osl_File_E_INVAL;

    *pSize = pImpl->getSize();
    return osl_File_E_None;
}

/************************************************
 * osl_setFileSize
 ***********************************************/
oslFileError
SAL_CALL osl_setFileSize( oslFileHandle Handle, sal_uInt64 uSize )
{
    FileHandle_Impl* pImpl = static_cast<FileHandle_Impl*>(Handle);

    if ((0 == pImpl) || (-1 == pImpl->m_fd))
        return osl_File_E_INVAL;
    if (0 == (pImpl->m_state & FileHandle_Impl::STATE_WRITEABLE))
        return osl_File_E_BADF;

	static sal_uInt64 const g_limit_off_t = std::numeric_limits< off_t >::max();
	if (g_limit_off_t < uSize)
		return osl_File_E_OVERFLOW;

    oslFileError result = pImpl->syncFile();
    if (result != osl_File_E_None)
        return (result);
    pImpl->m_bufptr = -1, pImpl->m_buflen = 0;

    return pImpl->setSize (uSize);
}

/****************************************************************************/
/*	osl_moveFile */
/****************************************************************************/

oslFileError osl_moveFile( rtl_uString* ustrFileURL, rtl_uString* ustrDestURL )
{
    char srcPath[PATH_MAX];
    char destPath[PATH_MAX];
    oslFileError eRet;
    APIRET rc;

    OSL_ASSERT( ustrFileURL );
    OSL_ASSERT( ustrDestURL );

    /* convert source url to system path */
    eRet = FileURLToPath( srcPath, PATH_MAX, ustrFileURL );
    if( eRet != osl_File_E_None )
        return eRet;

    /* convert destination url to system path */
    eRet = FileURLToPath( destPath, PATH_MAX, ustrDestURL );
    if( eRet != osl_File_E_None )
        return eRet;

    //YD 01/05/06 rename() can overwrite existing files.
    rc = DosDelete( (PCSZ)destPath);
    rc = DosMove( (PCSZ)srcPath, (PCSZ)destPath);
    if (!rc)
        eRet = osl_File_E_None;
    else
        eRet = MapError( rc);

    return eRet;
}

/****************************************************************************/
/*	osl_copyFile */
/****************************************************************************/

#define TMP_DEST_FILE_EXTENSION ".osl-tmp"

static oslFileError oslDoCopy(const sal_Char* pszSourceFileName, const sal_Char* pszDestFileName, mode_t nMode, size_t nSourceSize, int DestFileExists)
{
    int      nRet=0;
    sal_Char pszTmpDestFile[PATH_MAX];
	size_t   size_tmp_dest_buff = sizeof(pszTmpDestFile);

	/* Quick fix for #106048, the whole copy file function seems
	   to be erroneous anyway and needs to be rewritten.
	   Besides osl_copyFile	is currently not used from OO/SO code.
	*/
	memset(pszTmpDestFile, 0, size_tmp_dest_buff);

    if ( DestFileExists )
    {
		strncpy(pszTmpDestFile, pszDestFileName, size_tmp_dest_buff - 1);

		if ((strlen(pszTmpDestFile) + strlen(TMP_DEST_FILE_EXTENSION)) >= size_tmp_dest_buff)
			return osl_File_E_NAMETOOLONG;

		strncat(pszTmpDestFile, TMP_DEST_FILE_EXTENSION, strlen(TMP_DEST_FILE_EXTENSION));

        /* FIXME: what if pszTmpDestFile already exists? */
        /*        with getcanonical??? */
        nRet=rename(pszDestFileName,pszTmpDestFile);
    }

    /* mfe: should be S_ISREG */
    if ( !S_ISLNK(nMode) )
    {
        /* copy SourceFile to DestFile */
        nRet = oslDoCopyFile(pszSourceFileName,pszDestFileName,nSourceSize, nMode);
    }
    /* mfe: OK redundant at the moment */
    else if ( S_ISLNK(nMode) )
    {
        nRet = oslDoCopyLink(pszSourceFileName,pszDestFileName);
    }
    else
    {
        /* mfe: what to do here? */
        nRet=ENOSYS;
    }

    if ( nRet > 0 && DestFileExists == 1 )
    {
        unlink(pszDestFileName);
        rename(pszTmpDestFile,pszDestFileName);
    }

    if ( nRet > 0 )
    {
        return oslTranslateFileError(OSL_FET_ERROR, nRet);
    }

    if ( DestFileExists == 1 )
    {
        unlink(pszTmpDestFile);
    }

    return osl_File_E_None;
}

/*****************************************
 * oslChangeFileModes
 ****************************************/

static oslFileError oslChangeFileModes( const sal_Char* pszFileName, mode_t nMode, time_t nAcTime, time_t nModTime, uid_t nUID, gid_t nGID)
{
    int nRet=0;
    struct utimbuf aTimeBuffer;

    nRet = chmod(pszFileName,nMode);
    if ( nRet < 0 )
    {
        nRet=errno;
        return oslTranslateFileError(OSL_FET_ERROR, nRet);
    }

    aTimeBuffer.actime=nAcTime;
    aTimeBuffer.modtime=nModTime;
    nRet=utime(pszFileName,&aTimeBuffer);
    if ( nRet < 0 )
    {
        nRet=errno;
        return oslTranslateFileError(OSL_FET_ERROR, nRet);
    }

    if ( nUID != getuid() )
    {
        nUID=getuid();
    }

    nRet=chown(pszFileName,nUID,nGID);
    if ( nRet < 0 )
    {
        nRet=errno;

        /* mfe: do not return an error here! */
        /* return oslTranslateFileError(nRet);*/
    }

    return osl_File_E_None;
}

/*****************************************
 * oslDoCopyLink
 ****************************************/

static int oslDoCopyLink(const sal_Char* pszSourceFileName, const sal_Char* pszDestFileName)
{
    int nRet=0;

    /* mfe: if dest file is symbolic link remove the link and place the file instead (hro says so) */
    /* mfe: if source is a link copy the link and not the file it points to (hro says so) */
    sal_Char pszLinkContent[PATH_MAX];

    pszLinkContent[0] = '\0';

    nRet = readlink(pszSourceFileName,pszLinkContent,PATH_MAX);

    if ( nRet < 0 )
    {
        nRet=errno;
        return nRet;
    }
	else
		pszLinkContent[ nRet ] = 0;

    nRet = symlink(pszLinkContent,pszDestFileName);

    if ( nRet < 0 )
    {
        nRet=errno;
        return nRet;
    }

    return 0;
}

/*****************************************
 * oslDoCopyFile
 ****************************************/

static int oslDoCopyFile(const sal_Char* pszSourceFileName, const sal_Char* pszDestFileName, size_t nSourceSize, mode_t mode)
{    
    int SourceFileFD=0;
    int DestFileFD=0;
    int nRet=0;
    void* pSourceFile=0;
	char	buffer[ 4096];

    SourceFileFD=open(pszSourceFileName,O_RDONLY | O_BINARY);
    if ( SourceFileFD < 0 )
    {		
        nRet=errno;
        return nRet;
    }
    
    DestFileFD=open(pszDestFileName, O_WRONLY | O_CREAT | O_BINARY, mode);
    if ( DestFileFD < 0 )
    {
        nRet=errno;
        close(SourceFileFD);
        return nRet;
    }

	/* HACK: because memory mapping fails on various 
	   platforms if the size of the source file is  0 byte */
	if (0 == nSourceSize)
	{						
		close(SourceFileFD);
		close(DestFileFD);
		return 0;
	}
	
	while( (nRet = read(SourceFileFD, buffer, sizeof(buffer))) !=0 )
	{
		nRet = write( DestFileFD, buffer, nRet);
	}
    
    close(SourceFileFD);
    close(DestFileFD);

    return nRet;
}

static oslFileError osl_psz_copyFile( const sal_Char* pszPath, const sal_Char* pszDestPath )
{
    time_t nAcTime=0;
    time_t nModTime=0;
    uid_t nUID=0;
    gid_t nGID=0;
    int nRet=0;
    mode_t nMode=0;
    struct stat aFileStat;
    oslFileError tErr=osl_File_E_invalidError;
    size_t nSourceSize=0;
    int DestFileExists=1;

    /* mfe: does the source file really exists? */
    nRet = lstat(pszPath,&aFileStat);

    if ( nRet < 0 )
    {
        nRet=errno;
        return oslTranslateFileError(OSL_FET_ERROR, nRet);
    }

    /* mfe: we do only copy files here! */
    if ( S_ISDIR(aFileStat.st_mode) )
    {
        return osl_File_E_ISDIR;
    }

    nSourceSize=(size_t)aFileStat.st_size;
    nMode=aFileStat.st_mode;
    nAcTime=aFileStat.st_atime;
    nModTime=aFileStat.st_mtime;
    nUID=aFileStat.st_uid;
    nGID=aFileStat.st_gid;

    nRet = stat(pszDestPath,&aFileStat);
    if ( nRet < 0 )
    {
        nRet=errno;

        if ( nRet == ENOENT )
        {
            DestFileExists=0;
        }
/*        return oslTranslateFileError(nRet);*/
    }

    /* mfe: the destination file must not be a directory! */
    if ( nRet == 0 && S_ISDIR(aFileStat.st_mode) )
    {
        return osl_File_E_ISDIR;
    }
    else
    {
        /* mfe: file does not exists or is no dir */
    }

    tErr = oslDoCopy(pszPath,pszDestPath,nMode,nSourceSize,DestFileExists);

    if ( tErr != osl_File_E_None )
    {
        return tErr;
    }

    /*
     *   mfe: ignore return code
     *        since only  the success of the copy is
     *        important
     */
    oslChangeFileModes(pszDestPath,nMode,nAcTime,nModTime,nUID,nGID);

    return tErr;
}

oslFileError osl_copyFile( rtl_uString* ustrFileURL, rtl_uString* ustrDestURL )
{
    char srcPath[PATH_MAX];
    char destPath[PATH_MAX];
    oslFileError eRet;
    APIRET rc;

    OSL_ASSERT( ustrFileURL );
    OSL_ASSERT( ustrDestURL );

    /* convert source url to system path */
    eRet = FileURLToPath( srcPath, PATH_MAX, ustrFileURL );
    if( eRet != osl_File_E_None )
        return eRet;

    /* convert destination url to system path */
    eRet = FileURLToPath( destPath, PATH_MAX, ustrDestURL );
    if( eRet != osl_File_E_None )
        return eRet;

    return osl_psz_copyFile( srcPath, destPath );
}

/****************************************************************************/
/*	osl_removeFile */
/****************************************************************************/

oslFileError osl_removeFile( rtl_uString* ustrFileURL )
{
    char path[PATH_MAX];
    oslFileError eRet;
    APIRET rc;

    OSL_ASSERT( ustrFileURL );

    /* convert file url to system path */
    eRet = FileURLToPath( path, PATH_MAX, ustrFileURL );
    if( eRet != osl_File_E_None )
        return eRet;

    rc = DosDelete( (PCSZ)path);
    if (!rc)
        eRet = osl_File_E_None;
    else
        eRet = MapError( rc);

    return eRet;
}

/****************************************************************************/
/*	osl_getVolumeInformation */
/****************************************************************************/

#define TXFSDC_BLOCKR         0x00              // block device removable
#define TXFSDC_GETBPB         0x00              // get device bpb info
#define TXFSBPB_REMOVABLE     0x08              // BPB attribute for removable

typedef struct drivecmd
{
   BYTE                cmd;                     // 0=unlock 1=lock 2=eject
   BYTE                drv;                     // 0=A, 1=B 2=C ...
} DRIVECMD;                                     // end of struct "drivecmd"

#pragma pack(push, 1)                           // byte packing
typedef struct txfs_ebpb                        // ext. boot parameter block
{                                               // at offset 0x0b in bootsector
   USHORT              SectSize;                // 0B bytes per sector
   BYTE                ClustSize;               // 0D sectors per cluster
   USHORT              FatOffset;               // 0E sectors to 1st FAT
   BYTE                NrOfFats;                // 10 nr of FATS     (FAT only)
   USHORT              RootEntries;             // 11 Max entries \ (FAT only)
   USHORT              Sectors;                 // 13 nr of sectors if <  64K
   BYTE                MediaType;               // 15 mediatype (F8 for HD)
   USHORT              FatSectors;              // 16 sectors/FAT (FAT only)
   USHORT              LogGeoSect;              // 18 sectors/Track
   USHORT              LogGeoHead;              // 1a nr of heads
   ULONG               HiddenSectors;           // 1c sector-offset from MBR/EBR
   ULONG               BigSectors;              // 20 nr of sectors if >= 64K
} TXFS_EBPB;                                    // last byte is at offset 0x23

typedef struct drivebpb
{
   TXFS_EBPB           ebpb;                    // extended BPB
   BYTE                reserved[6];
   USHORT              cyls;
   BYTE                type;
   USHORT              attributes;              // device attributes
   BYTE                fill[6];                 // documented for IOCtl
} DRIVEBPB;                                     // end of struct "drivebpb"

struct CDInfo {
    USHORT usCount;
    USHORT usFirst;
};

#pragma pack(pop)

/*****************************************************************************/
// Get number of cdrom readers
/*****************************************************************************/
BOOL GetCDInfo( CDInfo * pCDInfo )
{
    HFILE hFileCD;
    ULONG ulAction;

    if( NO_ERROR == DosOpen( (PCSZ)"\\DEV\\CD-ROM2$",
                            &hFileCD, &ulAction, 0, FILE_NORMAL,
                            OPEN_ACTION_OPEN_IF_EXISTS,
                            OPEN_SHARE_DENYNONE | OPEN_ACCESS_READONLY, NULL )) {
        ULONG  ulDataSize = sizeof(CDInfo);
        APIRET rc = DosDevIOCtl( hFileCD, 0x82, 0x60, NULL, 0,
                                 NULL, (PVOID)pCDInfo, ulDataSize, &ulDataSize);
        DosClose( hFileCD);
        if(rc == NO_ERROR)
            return TRUE;
    }
	// failed
    pCDInfo->usFirst = 0;
    pCDInfo->usCount = 0;
    return FALSE;
}

/*****************************************************************************/
// Determine if unit is a cdrom or not
/*****************************************************************************/
BOOL DriveIsCDROM(UINT uiDrive, CDInfo *pCDInfo)
{
	return (uiDrive >= pCDInfo->usFirst)
			&& (uiDrive < (pCDInfo->usFirst + pCDInfo->usCount));
}

/*****************************************************************************/
// Determine attached fstype, e.g. HPFS for specified drive
/*****************************************************************************/
BOOL TxFsType                                   // RET   FS type resolved
(
   char               *drive,                   // IN    Drive specification
   char               *fstype,                  // OUT   Attached FS type
   char               *details                  // OUT   details (UNC) or NULL
)
{
   BOOL                rc = FALSE;
   FSQBUFFER2         *fsinfo;                     // Attached FS info
   ULONG               fsdlen = 2048;              // Fs info data length

   strcpy(fstype, "none");
   if (details)
   {
      strcpy(details, "");
   }
   if ((fsinfo = (FSQBUFFER2*)calloc(1, fsdlen)) != NULL)
   {
      if (DosQFSAttach((PCSZ)drive, 0, 1, fsinfo, &fsdlen) == NO_ERROR)
      {
         strcpy(fstype, (char*) fsinfo->szName + fsinfo->cbName +1);
         if (details && (fsinfo->cbFSAData != 0))
         {
            strcpy( details, (char*) fsinfo->szName + fsinfo->cbName +
                                              fsinfo->cbFSDName +2);
         }
         rc = TRUE;
      }
      free(fsinfo);
   }
   return (rc);
}                                               // end 'TxFsType'
/*---------------------------------------------------------------------------*/


/*****************************************************************************/
// Determine if a driveletter represents a removable medium/device
/*****************************************************************************/
BOOL TxFsIsRemovable                            // RET   drive is removable
(
   char               *drive                    // IN    Driveletter to test
)
{
   BOOL                rc = FALSE;
   DRIVECMD            IOCtl;
   DRIVEBPB            RemAt;
   ULONG               DataLen;
   ULONG               ParmLen;
   BYTE                NoRem;

   DosError( FERR_DISABLEHARDERR);              // avoid 'not ready' popups

   ParmLen   = sizeof(IOCtl);
   IOCtl.cmd = TXFSDC_BLOCKR;
   IOCtl.drv = toupper(drive[0]) - 'A';
   DataLen   = sizeof(NoRem);

   if (DosDevIOCtl((HFILE) -1, IOCTL_DISK,
                               DSK_BLOCKREMOVABLE,
                               &IOCtl, ParmLen, &ParmLen,
                               &NoRem, DataLen, &DataLen) == NO_ERROR)
   {
      if (NoRem)                                // non-removable sofar, check
      {                                         // BPB as well (USB devices)
         ParmLen   = sizeof(IOCtl);
         IOCtl.cmd = TXFSDC_GETBPB;
         IOCtl.drv = toupper(drive[0]) - 'A';
         DataLen   = sizeof(RemAt);

         if (DosDevIOCtl((HFILE) -1, IOCTL_DISK,
                                     DSK_GETDEVICEPARAMS,
                                     &IOCtl, ParmLen, &ParmLen,
                                     &RemAt, DataLen, &DataLen) == NO_ERROR)

         {
            if (RemAt.attributes & TXFSBPB_REMOVABLE)
            {
               rc = TRUE;                       // removable, probably USB
            }
         }
      }
      else
      {
         rc = TRUE;                             // removable block device
      }
   }
   DosError( FERR_ENABLEHARDERR);               // enable criterror handler
   return (rc);
}                                               // end 'TxFsIsRemovable'
/*---------------------------------------------------------------------------*/

static oslFileError get_drive_type(const char* path, oslVolumeInfo* pInfo)
{
	char		Drive_Letter = toupper( *path);
	char		fstype[ 64];

	pInfo->uValidFields |= osl_VolumeInfo_Mask_Attributes;		

	// check for floppy A/B
    BYTE 	nFloppies;
	APIRET	rc;
    rc = DosDevConfig( (void*) &nFloppies, DEVINFO_FLOPPY );
	if ((Drive_Letter - 'A') < nFloppies) {
		pInfo->uAttributes |= osl_Volume_Attribute_Removeable;
		pInfo->uAttributes |= osl_Volume_Attribute_FloppyDisk;
		return osl_File_E_None;    
	}

	// query system for CD drives
	CDInfo cdInfo;
	GetCDInfo(&cdInfo);

	// query if drive is a CDROM
	if (DriveIsCDROM( Drive_Letter - 'A', &cdInfo))
		pInfo->uAttributes |= osl_Volume_Attribute_CompactDisc | osl_Volume_Attribute_Removeable;

	if (TxFsIsRemovable( (char*)path))
		pInfo->uAttributes |= osl_Volume_Attribute_Removeable;

	if (TxFsType( (char*)path, fstype, NULL) == FALSE) {
		// query failed, assume fixed disk
		pInfo->uAttributes |= osl_Volume_Attribute_FixedDisk;
		return osl_File_E_None;    
	}

	//- Note, connected Win-NT drives use the REAL FS-name like NTFS!
	if ((strncasecmp( fstype, "LAN", 3) == 0) 			//- OS/2 LAN drives
		|| (strncasecmp( fstype, "NDFS", 4) == 0)  	//- NetDrive
		|| (strncasecmp( fstype, "REMOTE", 5) == 0)  )  //- NT disconnected
		pInfo->uAttributes |= osl_Volume_Attribute_Remote;
	else if (strncasecmp( fstype, "RAMFS", 5) == 0)
		pInfo->uAttributes |= osl_Volume_Attribute_RAMDisk;
	else if ((strncasecmp( fstype, "CD",  2) == 0)	 	// OS2:CDFS, DOS/WIN:CDROM
		|| (strncasecmp( fstype, "UDF", 3) == 0)   ) 	// OS2:UDF DVD's
		pInfo->uAttributes |= osl_Volume_Attribute_CompactDisc | osl_Volume_Attribute_Removeable;
	else
		pInfo->uAttributes |= osl_Volume_Attribute_FixedDisk;

	return osl_File_E_None;    
}

//#############################################
inline bool is_volume_space_info_request(sal_uInt32 field_mask)
{
	return (field_mask & 
			(osl_VolumeInfo_Mask_TotalSpace | 
			 osl_VolumeInfo_Mask_UsedSpace  | 
			 osl_VolumeInfo_Mask_FreeSpace));
}

//#############################################
static void get_volume_space_information(const char* path, oslVolumeInfo *pInfo)
{
    FSALLOCATE aFSInfoBuf;
    ULONG nDriveNumber = toupper( *path) - 'A' + 1;

	// disable error popups
	DosError(FERR_DISABLEHARDERR);
    APIRET rc = DosQueryFSInfo( nDriveNumber, FSIL_ALLOC,
                                &aFSInfoBuf, sizeof(aFSInfoBuf) );
	// enable error popups
	DosError(FERR_ENABLEHARDERR);
	if (!rc)
	{			    			    
		uint64_t aBytesPerCluster( uint64_t(aFSInfoBuf.cbSector) *
								 uint64_t(aFSInfoBuf.cSectorUnit) );
		pInfo->uFreeSpace = aBytesPerCluster * uint64_t(aFSInfoBuf.cUnitAvail);
		pInfo->uTotalSpace = aBytesPerCluster * uint64_t(aFSInfoBuf.cUnit);
		pInfo->uUsedSpace    = pInfo->uTotalSpace - pInfo->uFreeSpace;
		pInfo->uValidFields |= osl_VolumeInfo_Mask_TotalSpace | 
							   osl_VolumeInfo_Mask_UsedSpace | 
							   osl_VolumeInfo_Mask_FreeSpace;
	}
}

//#############################################
inline bool is_filesystem_attributes_request(sal_uInt32 field_mask)
{
	return (field_mask & 
			(osl_VolumeInfo_Mask_MaxNameLength | 
			 osl_VolumeInfo_Mask_MaxPathLength | 
			 osl_VolumeInfo_Mask_FileSystemName | 
			 osl_VolumeInfo_Mask_FileSystemCaseHandling));
}

//#############################################
inline bool is_drivetype_request(sal_uInt32 field_mask)
{
	return (field_mask & osl_VolumeInfo_Mask_Attributes);
}

typedef struct _FSQBUFFER_
{
    FSQBUFFER2  aBuf;
    UCHAR       sBuf[64];
} FSQBUFFER_;

//#############################################
static oslFileError get_filesystem_attributes(const char* path, sal_uInt32 field_mask, oslVolumeInfo* pInfo)
{
	pInfo->uAttributes = 0;
	
	oslFileError osl_error = osl_File_E_None;
	
	// osl_get_drive_type must be called first because
	// this function resets osl_VolumeInfo_Mask_Attributes
	// on failure
	if (is_drivetype_request(field_mask))
		osl_error = get_drive_type(path, pInfo);
			
	if ((osl_File_E_None == osl_error) && is_filesystem_attributes_request(field_mask))
	{
		FSQBUFFER_	aBuf;
		ULONG       nBufLen;
		APIRET      nRet;

        nBufLen = sizeof( aBuf );
		// disable error popups
		DosError(FERR_DISABLEHARDERR);
        nRet = DosQueryFSAttach( (PCSZ)path, 0, FSAIL_QUERYNAME, (_FSQBUFFER2*) &aBuf, &nBufLen );
        if ( !nRet )
        {
            char *pType = (char*)(aBuf.aBuf.szName + aBuf.aBuf.cbName + 1);
			pInfo->uValidFields   |= osl_VolumeInfo_Mask_MaxNameLength;
			pInfo->uMaxNameLength  = _MAX_FNAME;
		
			pInfo->uValidFields   |= osl_VolumeInfo_Mask_MaxPathLength;
			pInfo->uMaxPathLength  = _MAX_PATH;

			pInfo->uValidFields   |= osl_VolumeInfo_Mask_FileSystemName;
			rtl_uString_newFromAscii(&pInfo->ustrFileSystemName, pType);

			// case is preserved always except for FAT
			if (strcmp( pType, "FAT" ))
				pInfo->uAttributes |= osl_Volume_Attribute_Case_Is_Preserved;
				
			pInfo->uValidFields |= osl_VolumeInfo_Mask_Attributes;
		}
		// enable error popups
		DosError(FERR_ENABLEHARDERR);
	}
	return osl_error;
}

oslFileError SAL_CALL osl_getVolumeInformation( rtl_uString* ustrDirectoryURL, oslVolumeInfo* pInfo, sal_uInt32 uFieldMask )
{
    char volume_root[PATH_MAX];
    oslFileError error;

    OSL_ASSERT( ustrDirectoryURL );
    OSL_ASSERT( pInfo );

    /* convert directory url to system path */
    error = FileURLToPath( volume_root, PATH_MAX, ustrDirectoryURL );
    if( error != osl_File_E_None )
        return error;

	if (!pInfo)
		return osl_File_E_INVAL;

	pInfo->uValidFields = 0;
    
    if ((error = get_filesystem_attributes(volume_root, uFieldMask, pInfo)) != osl_File_E_None)
        return error;

	if (is_volume_space_info_request(uFieldMask)) 
	    get_volume_space_information(volume_root, pInfo);

	if (uFieldMask & osl_VolumeInfo_Mask_DeviceHandle)
	{
		pInfo->uValidFields |= osl_VolumeInfo_Mask_DeviceHandle;
		rtl_uString* uVolumeRoot;
		rtl_uString_newFromAscii( &uVolumeRoot, volume_root);
		osl_getFileURLFromSystemPath( uVolumeRoot, (rtl_uString**)&pInfo->pDeviceHandle);
		rtl_uString_release( uVolumeRoot);
	}

	return osl_File_E_None;
}

/****************************************************************************/
/*	osl_getFileStatus */
/****************************************************************************/
static oslFileError _osl_getDriveInfo(
	oslDirectoryItem Item, oslFileStatus *pStatus, sal_uInt32 uFieldMask)
{
	DirectoryItem_Impl	*pItemImpl = (DirectoryItem_Impl *)Item;
	sal_Unicode			cDrive[3];
	sal_Unicode			cRoot[4];

	if ( !pItemImpl )
		return osl_File_E_INVAL;

	pStatus->uValidFields = 0;

	cDrive[0] = pItemImpl->ustrDrive->buffer[0];
	cDrive[1] = (sal_Unicode)':';
	cDrive[2] = 0;
	cRoot[0] = pItemImpl->ustrDrive->buffer[0];
	cRoot[1] = (sal_Unicode)':';
	cRoot[2] = 0;

	if ( uFieldMask & osl_FileStatus_Mask_FileName )
	{
		if ( pItemImpl->ustrDrive->buffer[0] == '\\' &&
			pItemImpl->ustrDrive->buffer[1] == '\\' )
		{
			LPCWSTR	lpFirstBkSlash = wcschr( (const wchar_t*)&pItemImpl->ustrDrive->buffer[2], '\\' );

			if ( lpFirstBkSlash && lpFirstBkSlash[1] )
			{
				LPCWSTR	lpLastBkSlash = wcschr( (const wchar_t*)&lpFirstBkSlash[1], '\\' );

				if ( lpLastBkSlash )
					rtl_uString_newFromStr_WithLength( &pStatus->ustrFileName, (sal_Unicode*)&lpFirstBkSlash[1], lpLastBkSlash - lpFirstBkSlash - 1 );
				else
					rtl_uString_newFromStr( &pStatus->ustrFileName, (sal_Unicode*)&lpFirstBkSlash[1] );
				pStatus->uValidFields |= osl_FileStatus_Mask_FileName;
			}
		}
		else 
		{
			FSINFO	aFSInfoBuf;
			ULONG   ulFSInfoLevel = FSIL_VOLSER;
			ULONG   nDriveNumber;
			char	szFileName[ _MAX_PATH];

			nDriveNumber = toupper(*cDrive) - 'A' + 1;
			memset( &aFSInfoBuf, 0, sizeof(FSINFO) );
			// disable error popups
			DosError(FERR_DISABLEHARDERR);
			APIRET rc = DosQueryFSInfo( nDriveNumber, ulFSInfoLevel, &aFSInfoBuf, sizeof(FSINFO) );
			// enable error popups
			DosError(FERR_ENABLEHARDERR);
			memset( szFileName, 0, sizeof( szFileName));
			*szFileName = toupper(*cDrive);
			strcat( szFileName, ": [");
			if ( !rc || aFSInfoBuf.vol.cch)
				strncat( szFileName, aFSInfoBuf.vol.szVolLabel, aFSInfoBuf.vol.cch);
			strcat( szFileName, "]");
			rtl_uString_newFromAscii( &pStatus->ustrFileName, szFileName );

			pStatus->uValidFields |= osl_FileStatus_Mask_FileName;
		}
	}

	pStatus->eType = osl_File_Type_Volume;
	pStatus->uValidFields |= osl_FileStatus_Mask_Type;

	if ( uFieldMask & osl_FileStatus_Mask_FileURL )
	{
		rtl_uString	*ustrSystemPath = NULL;

		rtl_uString_newFromStr( &ustrSystemPath, pItemImpl->ustrDrive->buffer );
		osl_getFileURLFromSystemPath( ustrSystemPath, &pStatus->ustrFileURL );
		rtl_uString_release( ustrSystemPath );
		pStatus->uValidFields |= osl_FileStatus_Mask_FileURL;
	}

	return osl_File_E_None;
}

oslFileError SAL_CALL osl_getFileStatus( 
    oslDirectoryItem Item, 
    oslFileStatus *pStatus, 
    sal_uInt32 uFieldMask )
{
	DirectoryItem_Impl	*pItemImpl = (DirectoryItem_Impl *)Item;
	struct stat file_stat;

	if ( !pItemImpl )
		return osl_File_E_INVAL;

	if ( pItemImpl->uType == DIRECTORYITEM_DRIVE)
		return _osl_getDriveInfo( Item, pStatus, uFieldMask );

	osl::lstat(pItemImpl->ustrFilePath, file_stat);
	if ( uFieldMask & osl_FileStatus_Mask_Validate )
	{
		uFieldMask &= ~	osl_FileStatus_Mask_Validate;
	}

	/* If no fields to retrieve left ignore pStatus */
	if ( !uFieldMask )
		return osl_File_E_None;

	/* Otherwise, this must be a valid pointer */
	if ( !pStatus )
		return osl_File_E_INVAL;

	if ( pStatus->uStructSize != sizeof(oslFileStatus) )
		return osl_File_E_INVAL;

	pStatus->uValidFields = 0;

	/* File time stamps */

	if ( (uFieldMask & osl_FileStatus_Mask_ModifyTime))
	{
	    pStatus->aModifyTime.Seconds  = file_stat.st_mtime;
    	pStatus->aModifyTime.Nanosec  = 0;
		pStatus->uValidFields |= osl_FileStatus_Mask_ModifyTime;
	}

	if ( (uFieldMask & osl_FileStatus_Mask_AccessTime))
	{
		pStatus->aAccessTime.Seconds  = file_stat.st_atime;
    	pStatus->aAccessTime.Nanosec  = 0;
		pStatus->uValidFields |= osl_FileStatus_Mask_AccessTime;
	}

	if ( (uFieldMask & osl_FileStatus_Mask_CreationTime))
	{
		pStatus->aAccessTime.Seconds  = file_stat.st_birthtime;
    	pStatus->aAccessTime.Nanosec  = 0;
		pStatus->uValidFields |= osl_FileStatus_Mask_CreationTime;
	}

	/* Most of the fields are already set, regardless of requiered fields */

	osl_systemPathGetFileNameOrLastDirectoryPart(pItemImpl->ustrFilePath, &pStatus->ustrFileName);
	pStatus->uValidFields |= osl_FileStatus_Mask_FileName;

	if (S_ISLNK(file_stat.st_mode)) 
	   pStatus->eType = osl_File_Type_Link;              
	else if (S_ISDIR(file_stat.st_mode))                	   
	   pStatus->eType = osl_File_Type_Directory;       
	else if (S_ISREG(file_stat.st_mode))       
	   pStatus->eType = osl_File_Type_Regular;
	else if (S_ISFIFO(file_stat.st_mode)) 
	   pStatus->eType = osl_File_Type_Fifo;      
	else if (S_ISSOCK(file_stat.st_mode)) 
	   pStatus->eType = osl_File_Type_Socket;       
	else if (S_ISCHR(file_stat.st_mode) || S_ISBLK(file_stat.st_mode))        
	   pStatus->eType = osl_File_Type_Special;    
	else 
	   pStatus->eType = osl_File_Type_Unknown;
	    
	pStatus->uValidFields |= osl_FileStatus_Mask_Type;

	pStatus->uAttributes = pItemImpl->d_attr;
	pStatus->uValidFields |= osl_FileStatus_Mask_Attributes;

	pStatus->uFileSize = file_stat.st_size;
	pStatus->uValidFields |= osl_FileStatus_Mask_FileSize;

	if ( uFieldMask & osl_FileStatus_Mask_LinkTargetURL )
	{
		rtl_uString	*ustrFullPath = NULL;

		rtl_uString_newFromStr( &ustrFullPath, rtl_uString_getStr(pItemImpl->ustrFilePath) );
		osl_getFileURLFromSystemPath( ustrFullPath, &pStatus->ustrLinkTargetURL );
		rtl_uString_release( ustrFullPath );

		pStatus->uValidFields |= osl_FileStatus_Mask_LinkTargetURL;
	}

	if ( uFieldMask & osl_FileStatus_Mask_FileURL )
	{
		rtl_uString	*ustrFullPath = NULL;

		rtl_uString_newFromStr( &ustrFullPath, rtl_uString_getStr(pItemImpl->ustrFilePath) );
		osl_getFileURLFromSystemPath( ustrFullPath, &pStatus->ustrFileURL );
		rtl_uString_release( ustrFullPath );
		pStatus->uValidFields |= osl_FileStatus_Mask_FileURL;
	}

	return osl_File_E_None;
}

/****************************************************************************/
/*	osl_createDirectory */
/****************************************************************************/

oslFileError osl_createDirectory( rtl_uString* ustrDirectoryURL )
{
    char path[PATH_MAX];
    oslFileError eRet;
	APIRET rc;

    OSL_ASSERT( ustrDirectoryURL );

    /* convert directory url to system path */
    eRet = FileURLToPath( path, PATH_MAX, ustrDirectoryURL );
    if( eRet != osl_File_E_None )
        return eRet;

    rc = DosCreateDir( (PCSZ)path, NULL);
    if (rc == ERROR_ACCESS_DENIED) 
       rc=ERROR_FILE_EXISTS;

    if (!rc)
        eRet = osl_File_E_None;
    else
        eRet = MapError( rc);

    return eRet;
}

/****************************************************************************/
/*	osl_removeDirectory */
/****************************************************************************/

oslFileError osl_removeDirectory( rtl_uString* ustrDirectoryURL )
{
    char path[PATH_MAX];
    oslFileError eRet;
	APIRET rc;

    OSL_ASSERT( ustrDirectoryURL );

    /* convert directory url to system path */
    eRet = FileURLToPath( path, PATH_MAX, ustrDirectoryURL );
    if( eRet != osl_File_E_None )
        return eRet;

    rc = DosDeleteDir( (PCSZ)path);
    if (!rc)
        eRet = osl_File_E_None;
    else
        eRet = MapError( rc);

    return eRet;
}

//#############################################
int path_make_parent(sal_Unicode* path)
{
	int i = rtl_ustr_lastIndexOfChar(path, '/');
	if (i == -1)
		i = rtl_ustr_lastIndexOfChar(path, '\\');
	
	if (i > 0)
	{
		*(path + i) = 0;
		return i;
	}
	else
		return 0;
}

//#############################################
int create_dir_with_callback(
	sal_Unicode* directory_path,
    oslDirectoryCreationCallbackFunc aDirectoryCreationCallbackFunc, 
    void* pData)
{
	int mode = S_IRWXU | S_IRWXG | S_IRWXO;
	
	if (osl::mkdir(directory_path, mode) == 0)
    {
    	if (aDirectoryCreationCallbackFunc)
        {
        	rtl::OUString url;                
            osl::FileBase::getFileURLFromSystemPath(directory_path, url);                                
            aDirectoryCreationCallbackFunc(pData, url.pData);
        }                
        return 0;
    }
    return errno;
}

//#############################################
oslFileError create_dir_recursively_(
	sal_Unicode* dir_path,
    oslDirectoryCreationCallbackFunc aDirectoryCreationCallbackFunc, 
    void* pData)
{   
	OSL_PRECOND((rtl_ustr_getLength(dir_path) > 0) && ((dir_path + (rtl_ustr_getLength(dir_path) - 1)) != (dir_path + rtl_ustr_lastIndexOfChar(dir_path, '/'))), \
	"Path must not end with a slash");
	     
	int native_err = create_dir_with_callback(
    	dir_path, aDirectoryCreationCallbackFunc, pData);
		
	if (native_err == 0)    
        return osl_File_E_None;
                        
    if (native_err != ENOENT)
    	return oslTranslateFileError(OSL_FET_ERROR, native_err);
    
	// we step back until '/a_dir' at maximum because
	// we should get an error unequal ENOENT when
	// we try to create 'a_dir' at '/' and would so 
	// return before	    
	int pos = path_make_parent(dir_path);
                    
    oslFileError osl_error = create_dir_recursively_(
    	dir_path, aDirectoryCreationCallbackFunc, pData);
                    
    if (osl_File_E_None != osl_error)
    	return osl_error;
                    
   	dir_path[pos] = '/';
                               
    return create_dir_recursively_(dir_path, aDirectoryCreationCallbackFunc, pData);     
}

//#######################################
oslFileError SAL_CALL osl_createDirectoryPath(
	rtl_uString* aDirectoryUrl, 
    oslDirectoryCreationCallbackFunc aDirectoryCreationCallbackFunc,
    void* pData)
{
    if (aDirectoryUrl == NULL)
        return osl_File_E_INVAL;
    
    rtl::OUString sys_path;         
    oslFileError osl_error = osl_getSystemPathFromFileURL_Ex(
        aDirectoryUrl, &sys_path.pData, sal_False);        
    
    if (osl_error != osl_File_E_None)
        return osl_error;
                                                                
    osl::systemPathRemoveSeparator(sys_path);
    
    // const_cast because sys_path is a local copy which we want to modify inplace instead of 
    // coyp it into another buffer on the heap again
	return create_dir_recursively_(sys_path.pData->buffer, aDirectoryCreationCallbackFunc, pData);			
}

/****************************************************************************/
/*	osl_getCanonicalName */
/****************************************************************************/

oslFileError osl_getCanonicalName( rtl_uString* ustrFileURL, rtl_uString** pustrValidURL )
{
	OSL_ENSURE(sal_False, "osl_getCanonicalName not implemented");

	rtl_uString_newFromString(pustrValidURL, ustrFileURL);
	return osl_File_E_None;
}


/****************************************************************************/
/*	osl_setFileAttributes */
/****************************************************************************/

oslFileError osl_setFileAttributes( rtl_uString* ustrFileURL, sal_uInt64 uAttributes )
{
    char         path[PATH_MAX];
    oslFileError eRet;
    FILESTATUS3  fsts3ConfigInfo;
    ULONG        ulBufSize     = sizeof(FILESTATUS3);
    APIRET       rc            = NO_ERROR;

    OSL_ASSERT( ustrFileURL );

    /* convert file url to system path */
    eRet = FileURLToPath( path, PATH_MAX, ustrFileURL );
    if( eRet != osl_File_E_None )
        return eRet;
 
    /* query current attributes */
    rc = DosQueryPathInfo( (PCSZ)path, FIL_STANDARD, &fsts3ConfigInfo, ulBufSize);
    if (rc != NO_ERROR)
        return MapError( rc);

    /* set/reset readonly/hidden (see w32\file.cxx) */
    fsts3ConfigInfo.attrFile &= ~(FILE_READONLY | FILE_HIDDEN);
    if ( uAttributes & osl_File_Attribute_ReadOnly )
        fsts3ConfigInfo.attrFile |= FILE_READONLY;
    if ( uAttributes & osl_File_Attribute_Hidden )
        fsts3ConfigInfo.attrFile |= FILE_HIDDEN;

    /* write new attributes */
    rc = DosSetPathInfo( (PCSZ)path, FIL_STANDARD, &fsts3ConfigInfo, ulBufSize, 0);
    if (rc != NO_ERROR)
        return MapError( rc);

    /* everything ok */
    return osl_File_E_None;
}

/****************************************************************************/
/*	osl_setFileTime */
/****************************************************************************/

oslFileError osl_setFileTime( rtl_uString* ustrFileURL, const TimeValue* pCreationTime,
                              const TimeValue* pLastAccessTime, const TimeValue* pLastWriteTime )
{
    char path[PATH_MAX];
    oslFileError eRet;

    OSL_ASSERT( ustrFileURL );

    /* convert file url to system path */
    eRet = FileURLToPath( path, PATH_MAX, ustrFileURL );
    if( eRet != osl_File_E_None )
        return eRet;

    return osl_psz_setFileTime( path, pCreationTime, pLastAccessTime, pLastWriteTime );
}

/******************************************************************************
 *
 *                  Exported Module Functions
 *             (independent of C or Unicode Strings)
 *
 *****************************************************************************/



/******************************************************************************
 *
 *                  C-String Versions of Exported Module Functions
 *
 *****************************************************************************/


/******************************************
 * osl_psz_setFileTime
 *****************************************/

static oslFileError osl_psz_setFileTime( const sal_Char* pszFilePath,
                                  const TimeValue* /*pCreationTime*/,
                                  const TimeValue* pLastAccessTime,
                                  const TimeValue* pLastWriteTime )
{
    int nRet=0;
    struct utimbuf aTimeBuffer;
    struct stat aFileStat;
#ifdef DEBUG_OSL_FILE
    struct tm* pTM=0;
#endif

    nRet = lstat(pszFilePath,&aFileStat);

    if ( nRet < 0 )
    {
        nRet=errno;
        return oslTranslateFileError(OSL_FET_ERROR, nRet);
    }

#ifdef DEBUG_OSL_FILE
    fprintf(stderr,"File Times are (in localtime):\n");
    pTM=localtime(&aFileStat.st_ctime);
    fprintf(stderr,"CreationTime is '%s'\n",asctime(pTM));
    pTM=localtime(&aFileStat.st_atime);
    fprintf(stderr,"AccessTime   is '%s'\n",asctime(pTM));
    pTM=localtime(&aFileStat.st_mtime);
    fprintf(stderr,"Modification is '%s'\n",asctime(pTM));

    fprintf(stderr,"File Times are (in UTC):\n");
    fprintf(stderr,"CreationTime is '%s'\n",ctime(&aFileStat.st_ctime));
    fprintf(stderr,"AccessTime   is '%s'\n",ctime(&aTimeBuffer.actime));
    fprintf(stderr,"Modification is '%s'\n",ctime(&aTimeBuffer.modtime));
#endif

    if ( pLastAccessTime != 0 )
    {
        aTimeBuffer.actime=pLastAccessTime->Seconds;
    }
    else
    {
        aTimeBuffer.actime=aFileStat.st_atime;
    }

    if ( pLastWriteTime != 0 )
    {
        aTimeBuffer.modtime=pLastWriteTime->Seconds;
    }
    else
    {
        aTimeBuffer.modtime=aFileStat.st_mtime;
    }

    /* mfe: Creation time not used here! */

#ifdef DEBUG_OSL_FILE
    fprintf(stderr,"File Times are (in localtime):\n");
    pTM=localtime(&aFileStat.st_ctime);
    fprintf(stderr,"CreationTime now '%s'\n",asctime(pTM));
    pTM=localtime(&aTimeBuffer.actime);
    fprintf(stderr,"AccessTime   now '%s'\n",asctime(pTM));
    pTM=localtime(&aTimeBuffer.modtime);
    fprintf(stderr,"Modification now '%s'\n",asctime(pTM));

    fprintf(stderr,"File Times are (in UTC):\n");
    fprintf(stderr,"CreationTime now '%s'\n",ctime(&aFileStat.st_ctime));
    fprintf(stderr,"AccessTime   now '%s'\n",ctime(&aTimeBuffer.actime));
    fprintf(stderr,"Modification now '%s'\n",ctime(&aTimeBuffer.modtime));
#endif

    nRet=utime(pszFilePath,&aTimeBuffer);
    if ( nRet < 0 )
    {
        nRet=errno;
        return oslTranslateFileError(OSL_FET_ERROR, nRet);
    }

    return osl_File_E_None;
}


/******************************************************************************
 *
 *                  Utility Functions
 *
 *****************************************************************************/


/*****************************************
 * oslMakeUStrFromPsz
 ****************************************/

rtl_uString* oslMakeUStrFromPsz(const sal_Char* pszStr, rtl_uString** ustrValid)
{
    rtl_string2UString(
        ustrValid,
        pszStr,
        rtl_str_getLength( pszStr ),
        osl_getThreadTextEncoding(),
        OUSTRING_TO_OSTRING_CVTFLAGS );
    OSL_ASSERT(*ustrValid != 0);

    return *ustrValid;
}

/*****************************************************************************
 * UnicodeToText
 * converting unicode to text manually saves us the penalty of a temporary
 * rtl_String object.
 ****************************************************************************/

int UnicodeToText( char * buffer, size_t bufLen, const sal_Unicode * uniText, sal_Int32 uniTextLen )
{
    rtl_UnicodeToTextConverter hConverter;
    sal_uInt32   nInfo;
    sal_Size   nSrcChars, nDestBytes;

    /* stolen from rtl/string.c */
    hConverter = rtl_createUnicodeToTextConverter( osl_getThreadTextEncoding() );

	nDestBytes = rtl_convertUnicodeToText( hConverter, 0, uniText, uniTextLen,
                                           buffer, bufLen,
                                           OUSTRING_TO_OSTRING_CVTFLAGS | RTL_UNICODETOTEXT_FLAGS_FLUSH,
                                           &nInfo, &nSrcChars );

    rtl_destroyUnicodeToTextConverter( hConverter );

    if( nInfo & RTL_UNICODETOTEXT_INFO_DESTBUFFERTOSMALL )
    {
        errno = EOVERFLOW;
        return 0;
    }

    /* ensure trailing '\0' */
    buffer[nDestBytes] = '\0';

    return nDestBytes;
}

/*****************************************************************************
   TextToUnicode

   @param text
          The text to convert.

   @param text_buffer_size
          The number of characters.

   @param unic_text
          The unicode buffer.

   @param unic_text_buffer_size
   		  The size in characters of the unicode buffer.

 ****************************************************************************/

int TextToUnicode(
	const char*  text,
	size_t       text_buffer_size,
	sal_Unicode* unic_text,
	sal_Int32    unic_text_buffer_size)
{
    rtl_TextToUnicodeConverter hConverter;
    sal_uInt32 nInfo;
    sal_Size nSrcChars;
    sal_Size nDestBytes;

    /* stolen from rtl/string.c */
    hConverter = rtl_createTextToUnicodeConverter(osl_getThreadTextEncoding());

	nDestBytes = rtl_convertTextToUnicode(hConverter,
										  0,
										  text,  text_buffer_size,
                                          unic_text, unic_text_buffer_size,
                                          OSTRING_TO_OUSTRING_CVTFLAGS | RTL_TEXTTOUNICODE_FLAGS_FLUSH,
                                          &nInfo, &nSrcChars);

    rtl_destroyTextToUnicodeConverter(hConverter);

    if (nInfo & RTL_TEXTTOUNICODE_INFO_DESTBUFFERTOSMALL)
    {
        errno = EOVERFLOW;
        return 0;
    }

    /* ensure trailing '\0' */
    unic_text[nDestBytes] = '\0';

    return nDestBytes;
}

/******************************************************************************
 *
 *                  GENERIC FLOPPY FUNCTIONS
 *
 *****************************************************************************/

/*****************************************
 * osl_unmountVolumeDevice
 ****************************************/
oslFileError osl_unmountVolumeDevice( oslVolumeDeviceHandle Handle )
{
	if ( Handle )
		return osl_File_E_None;
	else
		return osl_File_E_INVAL;
}

/*****************************************
 * osl_automountVolumeDevice
 ****************************************/
oslFileError osl_automountVolumeDevice( oslVolumeDeviceHandle Handle )
{
	if ( Handle )
		return osl_File_E_None;
	else
		return osl_File_E_INVAL;
}

/*****************************************
 * osl_getVolumeDeviceMountPath
 ****************************************/
oslFileError osl_getVolumeDeviceMountPath( oslVolumeDeviceHandle Handle, rtl_uString **pstrPath )
{
	if ( Handle && pstrPath )
	{
		rtl_uString_assign( pstrPath, (rtl_uString *)Handle );
		return osl_File_E_None;
	}
	else
		return osl_File_E_INVAL;
}

/*****************************************
 * osl_acquireVolumeDeviceHandle
 ****************************************/

oslFileError SAL_CALL osl_acquireVolumeDeviceHandle( oslVolumeDeviceHandle Handle )
{
	if ( Handle )
	{
		rtl_uString_acquire( (rtl_uString *)Handle );
		return osl_File_E_None;
	}
	else
		return osl_File_E_INVAL;
}

/*****************************************
 * osl_releaseVolumeDeviceHandle
 ****************************************/

oslFileError osl_releaseVolumeDeviceHandle( oslVolumeDeviceHandle Handle )
{
	if ( Handle )
	{
		rtl_uString_release( (rtl_uString *)Handle );
		return osl_File_E_None;
	}
	else
		return osl_File_E_INVAL;
}

/******************************************************************************
 *
 *                  OS/2 FLOPPY FUNCTIONS
 *
 *****************************************************************************/
static oslVolumeDeviceHandle osl_isFloppyDrive(const sal_Char* pszPath)
{
    return NULL;
}

