blob: 28081e2d7619b113255684cddd21f399f35e34c8 [file] [log] [blame]
/**************************************************************
*
* 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;
}